@overlap/rte 0.1.1 → 0.1.2
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 +62 -68
- package/dist/components/Editor.d.ts.map +1 -1
- package/dist/components/Icons.d.ts +3 -1
- package/dist/components/Icons.d.ts.map +1 -1
- package/dist/index.d.ts +59 -45
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +470 -197
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +472 -196
- package/dist/index.js.map +1 -1
- package/dist/plugins/blockFormat.d.ts +7 -0
- package/dist/plugins/blockFormat.d.ts.map +1 -0
- package/dist/plugins/headings.d.ts +1 -1
- package/dist/plugins/headings.d.ts.map +1 -1
- package/dist/plugins/index.d.ts +8 -2
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/listIndent.d.ts +10 -0
- package/dist/plugins/listIndent.d.ts.map +1 -0
- package/dist/plugins/optional.d.ts +1 -1
- package/dist/plugins/optional.d.ts.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +17 -5
- package/src/components/Editor.tsx +92 -49
- package/src/components/Icons.tsx +306 -77
- package/src/index.ts +18 -18
- package/src/plugins/blockFormat.tsx +194 -0
- package/src/plugins/headings.tsx +39 -28
- package/src/plugins/index.tsx +161 -0
- package/src/plugins/listIndent.tsx +90 -0
- package/src/plugins/optional.tsx +216 -194
- package/src/types.ts +3 -0
- package/src/plugins/index.ts +0 -54
package/dist/index.js
CHANGED
|
@@ -5,50 +5,78 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
var React = require('react');
|
|
7
7
|
|
|
8
|
-
const BoldIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z" }) }));
|
|
9
|
-
const ItalicIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z" }) }));
|
|
10
|
-
const UnderlineIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z" }) }));
|
|
11
|
-
const UndoIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z" }) }));
|
|
12
|
-
const RedoIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z" }) }));
|
|
13
|
-
const ClearFormattingIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.
|
|
14
|
-
const LinkIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z" }) }));
|
|
15
|
-
const QuoteIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z" }) }));
|
|
16
|
-
const BulletListIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z" }) }));
|
|
17
|
-
const NumberedListIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 11.9V11H2zm6-5v2h14V6H8zm0 14h14v-2H8v2zm0-6h14v-2H8v2z" }) }));
|
|
18
|
-
const TextColorIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M2 20h20v4H2v-4zm3.49-3h2.42l1.27-3.58h5.64L16.09 17h2.42L13.25 3h-2.5L5.49 17zm4.22-5.61l2.03-5.79h.12l2.03 5.79H9.71z" }) }));
|
|
19
|
-
const BackgroundColorIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.
|
|
20
|
-
const HeadingIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M5 4v3h5.5v12h3V7H19V4H5z" }) }));
|
|
21
|
-
const FontSizeIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M9 4v3h5v12h3V7h5V4H9zm-6 8h3v8h3v-8h3V10H3z" }) }));
|
|
22
|
-
const ImageIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z" }) }));
|
|
23
|
-
const CloseIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }));
|
|
24
|
-
const LoadingIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z" }) }));
|
|
25
|
-
const UploadIcon = ({ width = 18, height = 18, className }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z" }) }));
|
|
8
|
+
const BoldIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z" }) }));
|
|
9
|
+
const ItalicIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z" }) }));
|
|
10
|
+
const UnderlineIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z" }) }));
|
|
11
|
+
const UndoIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z" }) }));
|
|
12
|
+
const RedoIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z" }) }));
|
|
13
|
+
const ClearFormattingIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsxs("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: [jsxRuntime.jsx("path", { d: "M6 5v3h5v11h2V8h5V5H6z" }), jsxRuntime.jsx("path", { d: "M20.5 3.5L3.5 20.5l1.06 1.06L21.56 4.56z" })] }));
|
|
14
|
+
const LinkIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z" }) }));
|
|
15
|
+
const QuoteIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z" }) }));
|
|
16
|
+
const BulletListIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z" }) }));
|
|
17
|
+
const NumberedListIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 11.9V11H2zm6-5v2h14V6H8zm0 14h14v-2H8v2zm0-6h14v-2H8v2z" }) }));
|
|
18
|
+
const TextColorIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M2 20h20v4H2v-4zm3.49-3h2.42l1.27-3.58h5.64L16.09 17h2.42L13.25 3h-2.5L5.49 17zm4.22-5.61l2.03-5.79h.12l2.03 5.79H9.71z" }) }));
|
|
19
|
+
const BackgroundColorIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsxs("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: [jsxRuntime.jsx("path", { d: "M17.5 4.5c-1.95 0-4.05.4-5.5 1.5-1.45-1.1-3.55-1.5-5.5-1.5-1.45 0-2.99.22-4.28.79C1.49 5.62 1 6.33 1 7.14v11.28c0 1.3 1.22 2.26 2.48 1.94.98-.25 2.02-.36 3.02-.36 1.56 0 3.22.26 4.56.92.6.3 1.28.3 1.88 0 1.34-.67 3-.92 4.56-.92 1 0 2.04.11 3.02.36C22.78 20.68 24 19.72 24 18.42V7.14c0-.81-.49-1.52-1.22-1.85-1.29-.57-2.83-.79-4.28-.79zM21 17.23c0 .63-.58 1.09-1.2.98-.75-.14-1.53-.2-2.3-.2-1.7 0-4.15.65-5.5 1.5V8c1.35-.85 3.8-1.5 5.5-1.5.77 0 1.55.06 2.3.2.62.11 1.2.58 1.2 1.18v9.35z" }), jsxRuntime.jsx("rect", { x: "4", y: "13", width: "16", height: "6", fill: "currentColor", opacity: "0.5" })] }));
|
|
20
|
+
const HeadingIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M5 4v3h5.5v12h3V7H19V4H5z" }) }));
|
|
21
|
+
const FontSizeIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M9 4v3h5v12h3V7h5V4H9zm-6 8h3v8h3v-8h3V10H3z" }) }));
|
|
22
|
+
const ImageIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z" }) }));
|
|
23
|
+
const CloseIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }));
|
|
24
|
+
const LoadingIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z" }) }));
|
|
25
|
+
const UploadIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z" }) }));
|
|
26
|
+
const IndentIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M3 21h18v-2H3v2zM3 8l4 4-4 4V8zm8 9h10v-2H11v2zM3 3v2h18V3H3zm8 6h10V7H11v2zm0 4h10v-2H11v2z" }) }));
|
|
27
|
+
const OutdentIcon = ({ width = 18, height = 18, className, }) => (jsxRuntime.jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsxRuntime.jsx("path", { d: "M3 21h18v-2H3v2zM11 8l4 4-4 4V8zM3 3v2h18V3H3zm0 4h10v2H3V7zm0 4h10v2H3v-2zm0 4h18v2H3v-2z" }) }));
|
|
26
28
|
const iconMap = {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
29
|
+
"mdi:format-bold": BoldIcon,
|
|
30
|
+
"mdi:format-italic": ItalicIcon,
|
|
31
|
+
"mdi:format-underline": UnderlineIcon,
|
|
32
|
+
"mdi:undo": UndoIcon,
|
|
33
|
+
"mdi:redo": RedoIcon,
|
|
34
|
+
"mdi:format-clear": ClearFormattingIcon,
|
|
35
|
+
"mdi:link": LinkIcon,
|
|
36
|
+
"mdi:format-quote-close": QuoteIcon,
|
|
37
|
+
"mdi:format-list-bulleted": BulletListIcon,
|
|
38
|
+
"mdi:format-list-numbered": NumberedListIcon,
|
|
39
|
+
"mdi:format-color-text": TextColorIcon,
|
|
40
|
+
"mdi:format-color-fill": BackgroundColorIcon,
|
|
41
|
+
"mdi:format-header-1": HeadingIcon,
|
|
42
|
+
"mdi:format-size": FontSizeIcon,
|
|
43
|
+
"mdi:image": ImageIcon,
|
|
44
|
+
"mdi:close": CloseIcon,
|
|
45
|
+
"mdi:loading": LoadingIcon,
|
|
46
|
+
"mdi:upload": UploadIcon,
|
|
47
|
+
"mdi:format-indent-increase": IndentIcon,
|
|
48
|
+
"mdi:format-indent-decrease": OutdentIcon,
|
|
45
49
|
};
|
|
46
50
|
const Icon = ({ icon, width = 18, height = 18, className }) => {
|
|
47
51
|
const IconComponent = iconMap[icon];
|
|
48
52
|
if (!IconComponent) {
|
|
49
|
-
return jsxRuntime.jsx("span", { style: { width, height, display:
|
|
53
|
+
return jsxRuntime.jsx("span", { style: { width, height, display: "inline-block" } });
|
|
50
54
|
}
|
|
51
|
-
return jsxRuntime.jsx(IconComponent, { width: width, height: height, className: className });
|
|
55
|
+
return (jsxRuntime.jsx(IconComponent, { width: width, height: height, className: className }));
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const Dropdown = ({ icon, label, options, onSelect, currentValue, disabled, }) => {
|
|
59
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
60
|
+
const dropdownRef = React.useRef(null);
|
|
61
|
+
React.useEffect(() => {
|
|
62
|
+
const handleClickOutside = (event) => {
|
|
63
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
64
|
+
setIsOpen(false);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
if (isOpen) {
|
|
68
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
69
|
+
}
|
|
70
|
+
return () => {
|
|
71
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
72
|
+
};
|
|
73
|
+
}, [isOpen]);
|
|
74
|
+
const handleSelect = (value) => {
|
|
75
|
+
onSelect(value);
|
|
76
|
+
setIsOpen(false);
|
|
77
|
+
};
|
|
78
|
+
const currentOption = options.find(opt => opt.value === currentValue);
|
|
79
|
+
return (jsxRuntime.jsxs("div", { className: "rte-dropdown", ref: dropdownRef, children: [jsxRuntime.jsxs("button", { type: "button", onClick: () => !disabled && setIsOpen(!isOpen), disabled: disabled, className: `rte-toolbar-button rte-dropdown-button ${currentOption ? 'rte-dropdown-button-has-value' : ''}`, title: label, "aria-label": label, children: [jsxRuntime.jsx(Icon, { icon: icon, width: 18, height: 18 }), currentOption && (jsxRuntime.jsx("span", { className: "rte-dropdown-value", children: currentOption.label }))] }), isOpen && (jsxRuntime.jsx("div", { className: "rte-dropdown-menu", children: options.map((option) => (jsxRuntime.jsxs("button", { type: "button", className: `rte-dropdown-item ${currentValue === option.value ? 'rte-dropdown-item-active' : ''}`, onClick: () => handleSelect(option.value), children: [option.color && (jsxRuntime.jsx("span", { className: `rte-dropdown-color-preview ${currentValue === option.value ? 'active' : ''}`, style: { backgroundColor: option.color } })), option.preview && !option.headingPreview && (jsxRuntime.jsx("span", { className: "rte-dropdown-fontsize-preview", style: { fontSize: `${option.preview}px` }, children: "Aa" })), option.headingPreview && (jsxRuntime.jsx("span", { className: `rte-dropdown-heading-preview ${option.headingPreview}`, children: option.headingPreview === 'p' ? 'Normal' : option.headingPreview.toUpperCase() })), option.icon && jsxRuntime.jsx(Icon, { icon: option.icon, width: 16, height: 16 }), jsxRuntime.jsx("span", { style: { flex: 1, fontWeight: currentValue === option.value ? 600 : 400 }, children: option.label })] }, option.value))) }))] }));
|
|
52
80
|
};
|
|
53
81
|
|
|
54
82
|
const IconWrapper = ({ icon, width = 18, height = 18, className }) => {
|
|
@@ -111,6 +139,168 @@ function createCommandPlugin(name, command, icon, label) {
|
|
|
111
139
|
};
|
|
112
140
|
}
|
|
113
141
|
|
|
142
|
+
const defaultHeadings$2 = ["h1", "h2", "h3"];
|
|
143
|
+
const headingLabels$1 = {
|
|
144
|
+
h1: "Überschrift 1",
|
|
145
|
+
h2: "Überschrift 2",
|
|
146
|
+
h3: "Überschrift 3",
|
|
147
|
+
h4: "Überschrift 4",
|
|
148
|
+
h5: "Überschrift 5",
|
|
149
|
+
h6: "Überschrift 6",
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Erstellt ein Block-Format-Plugin, das Headlines, Listen und Quote in einem Dropdown kombiniert
|
|
153
|
+
* @param headings - Array von Heading-Levels (z.B. ["h1", "h2", "h3"])
|
|
154
|
+
*/
|
|
155
|
+
function createBlockFormatPlugin(headings = defaultHeadings$2) {
|
|
156
|
+
const options = [
|
|
157
|
+
{ value: "p", label: "Normal", headingPreview: "p" },
|
|
158
|
+
...headings.map((h) => ({
|
|
159
|
+
value: h,
|
|
160
|
+
label: headingLabels$1[h] || h.toUpperCase(),
|
|
161
|
+
headingPreview: h,
|
|
162
|
+
})),
|
|
163
|
+
{
|
|
164
|
+
value: "ul",
|
|
165
|
+
label: "Aufzählungsliste",
|
|
166
|
+
icon: "mdi:format-list-bulleted",
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
value: "ol",
|
|
170
|
+
label: "Nummerierte Liste",
|
|
171
|
+
icon: "mdi:format-list-numbered",
|
|
172
|
+
},
|
|
173
|
+
{ value: "blockquote", label: "Zitat", icon: "mdi:format-quote-close" },
|
|
174
|
+
];
|
|
175
|
+
return {
|
|
176
|
+
name: "blockFormat",
|
|
177
|
+
type: "block",
|
|
178
|
+
renderButton: (props) => {
|
|
179
|
+
// Aktuelles Format bestimmen
|
|
180
|
+
const editor = props.editorAPI;
|
|
181
|
+
let currentValue = props.currentValue;
|
|
182
|
+
if (!currentValue && editor) {
|
|
183
|
+
const selection = editor.getSelection();
|
|
184
|
+
if (selection && selection.rangeCount > 0) {
|
|
185
|
+
const range = selection.getRangeAt(0);
|
|
186
|
+
const container = range.commonAncestorContainer;
|
|
187
|
+
const element = container.nodeType === Node.TEXT_NODE
|
|
188
|
+
? container.parentElement
|
|
189
|
+
: container;
|
|
190
|
+
if (element) {
|
|
191
|
+
const tagName = element.tagName.toLowerCase();
|
|
192
|
+
// Prüfe auf Heading
|
|
193
|
+
if (headings.includes(tagName)) {
|
|
194
|
+
currentValue = tagName;
|
|
195
|
+
}
|
|
196
|
+
// Prüfe auf Blockquote
|
|
197
|
+
else if (element.closest("blockquote")) {
|
|
198
|
+
currentValue = "blockquote";
|
|
199
|
+
}
|
|
200
|
+
// Prüfe auf Liste
|
|
201
|
+
else if (element.closest("ul")) {
|
|
202
|
+
currentValue = "ul";
|
|
203
|
+
}
|
|
204
|
+
else if (element.closest("ol")) {
|
|
205
|
+
currentValue = "ol";
|
|
206
|
+
}
|
|
207
|
+
// Prüfe auf Paragraph
|
|
208
|
+
else if (tagName === "p") {
|
|
209
|
+
currentValue = "p";
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return (jsxRuntime.jsx(Dropdown, { icon: "mdi:format-header-1", label: "Format", options: options, onSelect: (value) => {
|
|
215
|
+
// onSelect wird von der Toolbar übergeben und ruft handlePluginClick auf
|
|
216
|
+
if (props.onSelect) {
|
|
217
|
+
props.onSelect(value);
|
|
218
|
+
}
|
|
219
|
+
}, currentValue: currentValue, disabled: props.disabled }));
|
|
220
|
+
},
|
|
221
|
+
getCurrentValue: (editor) => {
|
|
222
|
+
const selection = editor.getSelection();
|
|
223
|
+
if (!selection || selection.rangeCount === 0)
|
|
224
|
+
return undefined;
|
|
225
|
+
const range = selection.getRangeAt(0);
|
|
226
|
+
const container = range.commonAncestorContainer;
|
|
227
|
+
const element = container.nodeType === Node.TEXT_NODE
|
|
228
|
+
? container.parentElement
|
|
229
|
+
: container;
|
|
230
|
+
if (!element)
|
|
231
|
+
return undefined;
|
|
232
|
+
const tagName = element.tagName.toLowerCase();
|
|
233
|
+
// Prüfe auf Heading
|
|
234
|
+
if (headings.includes(tagName)) {
|
|
235
|
+
return tagName;
|
|
236
|
+
}
|
|
237
|
+
// Prüfe auf Blockquote
|
|
238
|
+
if (element.closest("blockquote")) {
|
|
239
|
+
return "blockquote";
|
|
240
|
+
}
|
|
241
|
+
// Prüfe auf Liste
|
|
242
|
+
if (element.closest("ul")) {
|
|
243
|
+
return "ul";
|
|
244
|
+
}
|
|
245
|
+
if (element.closest("ol")) {
|
|
246
|
+
return "ol";
|
|
247
|
+
}
|
|
248
|
+
// Prüfe auf Paragraph
|
|
249
|
+
if (tagName === "p") {
|
|
250
|
+
return "p";
|
|
251
|
+
}
|
|
252
|
+
return undefined;
|
|
253
|
+
},
|
|
254
|
+
execute: (editor, value) => {
|
|
255
|
+
if (!value)
|
|
256
|
+
return;
|
|
257
|
+
if (value === "ul") {
|
|
258
|
+
editor.executeCommand("insertUnorderedList");
|
|
259
|
+
}
|
|
260
|
+
else if (value === "ol") {
|
|
261
|
+
editor.executeCommand("insertOrderedList");
|
|
262
|
+
}
|
|
263
|
+
else if (value === "blockquote") {
|
|
264
|
+
const selection = editor.getSelection();
|
|
265
|
+
if (selection && selection.rangeCount > 0) {
|
|
266
|
+
const range = selection.getRangeAt(0);
|
|
267
|
+
const container = range.commonAncestorContainer;
|
|
268
|
+
const element = container.nodeType === Node.TEXT_NODE
|
|
269
|
+
? container.parentElement
|
|
270
|
+
: container;
|
|
271
|
+
if (element?.closest("blockquote")) {
|
|
272
|
+
editor.executeCommand("formatBlock", "<p>");
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
editor.executeCommand("formatBlock", "<blockquote>");
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
editor.executeCommand("formatBlock", `<${value}>`);
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
isActive: (editor) => {
|
|
284
|
+
const selection = editor.getSelection();
|
|
285
|
+
if (!selection || selection.rangeCount === 0)
|
|
286
|
+
return false;
|
|
287
|
+
const range = selection.getRangeAt(0);
|
|
288
|
+
const container = range.commonAncestorContainer;
|
|
289
|
+
const element = container.nodeType === Node.TEXT_NODE
|
|
290
|
+
? container.parentElement
|
|
291
|
+
: container;
|
|
292
|
+
if (!element)
|
|
293
|
+
return false;
|
|
294
|
+
const tagName = element.tagName.toLowerCase();
|
|
295
|
+
return (headings.includes(tagName) ||
|
|
296
|
+
element.closest("blockquote") !== null ||
|
|
297
|
+
element.closest("ul") !== null ||
|
|
298
|
+
element.closest("ol") !== null);
|
|
299
|
+
},
|
|
300
|
+
canExecute: () => true,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
114
304
|
/**
|
|
115
305
|
* Clear Formatting Plugin - Entfernt alle Formatierungen
|
|
116
306
|
*/
|
|
@@ -127,50 +317,89 @@ const clearFormattingPlugin = {
|
|
|
127
317
|
},
|
|
128
318
|
};
|
|
129
319
|
|
|
320
|
+
const defaultHeadings$1 = ["h1", "h2", "h3"];
|
|
130
321
|
/**
|
|
131
322
|
* Standard-Plugins
|
|
132
323
|
*/
|
|
133
|
-
const boldPlugin = createInlinePlugin(
|
|
134
|
-
const italicPlugin = createInlinePlugin(
|
|
135
|
-
const underlinePlugin = createInlinePlugin(
|
|
136
|
-
const undoPlugin = createCommandPlugin(
|
|
137
|
-
const redoPlugin = createCommandPlugin(
|
|
324
|
+
const boldPlugin = createInlinePlugin("bold", "bold", "mdi:format-bold", "Fett");
|
|
325
|
+
const italicPlugin = createInlinePlugin("italic", "italic", "mdi:format-italic", "Kursiv");
|
|
326
|
+
const underlinePlugin = createInlinePlugin("underline", "underline", "mdi:format-underline", "Unterstrichen");
|
|
327
|
+
const undoPlugin = createCommandPlugin("undo", "undo", "mdi:undo", "Rückgängig");
|
|
328
|
+
const redoPlugin = createCommandPlugin("redo", "redo", "mdi:redo", "Wiederholen");
|
|
329
|
+
/**
|
|
330
|
+
* Indent List Item Plugin (Tab für Unterliste)
|
|
331
|
+
*/
|
|
332
|
+
const indentListItemPlugin = {
|
|
333
|
+
name: "indentListItem",
|
|
334
|
+
type: "command",
|
|
335
|
+
renderButton: (props) => (jsxRuntime.jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: "rte-toolbar-button", title: "Einr\u00FCcken (Unterliste)", "aria-label": "Einr\u00FCcken (Unterliste)", children: jsxRuntime.jsx(IconWrapper, { icon: "mdi:format-indent-increase", width: 18, height: 18 }) })),
|
|
336
|
+
execute: (editor) => {
|
|
337
|
+
editor.indentListItem();
|
|
338
|
+
},
|
|
339
|
+
canExecute: (editor) => {
|
|
340
|
+
const selection = editor.getSelection();
|
|
341
|
+
if (!selection || selection.rangeCount === 0)
|
|
342
|
+
return false;
|
|
343
|
+
const range = selection.getRangeAt(0);
|
|
344
|
+
const container = range.commonAncestorContainer;
|
|
345
|
+
const listItem = container.nodeType === Node.TEXT_NODE
|
|
346
|
+
? container.parentElement?.closest("li")
|
|
347
|
+
: container.closest("li");
|
|
348
|
+
return listItem !== null;
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
/**
|
|
352
|
+
* Outdent List Item Plugin (Shift+Tab)
|
|
353
|
+
*/
|
|
354
|
+
const outdentListItemPlugin = {
|
|
355
|
+
name: "outdentListItem",
|
|
356
|
+
type: "command",
|
|
357
|
+
renderButton: (props) => (jsxRuntime.jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: "rte-toolbar-button", title: "Ausr\u00FCcken", "aria-label": "Ausr\u00FCcken", children: jsxRuntime.jsx(IconWrapper, { icon: "mdi:format-indent-decrease", width: 18, height: 18 }) })),
|
|
358
|
+
execute: (editor) => {
|
|
359
|
+
editor.outdentListItem();
|
|
360
|
+
},
|
|
361
|
+
canExecute: (editor) => {
|
|
362
|
+
const selection = editor.getSelection();
|
|
363
|
+
if (!selection || selection.rangeCount === 0)
|
|
364
|
+
return false;
|
|
365
|
+
const range = selection.getRangeAt(0);
|
|
366
|
+
const container = range.commonAncestorContainer;
|
|
367
|
+
const listItem = container.nodeType === Node.TEXT_NODE
|
|
368
|
+
? container.parentElement?.closest("li")
|
|
369
|
+
: container.closest("li");
|
|
370
|
+
if (!listItem)
|
|
371
|
+
return false;
|
|
372
|
+
// Prüfe ob in verschachtelter Liste
|
|
373
|
+
const list = listItem.parentElement;
|
|
374
|
+
if (!list || (list.tagName !== "UL" && list.tagName !== "OL"))
|
|
375
|
+
return false;
|
|
376
|
+
const parentListItem = list.parentElement;
|
|
377
|
+
return parentListItem !== null && parentListItem.tagName === "LI";
|
|
378
|
+
},
|
|
379
|
+
};
|
|
138
380
|
/**
|
|
139
381
|
* Standard-Plugin-Liste
|
|
382
|
+
* Die Plugins werden hier direkt referenziert, um sicherzustellen, dass sie in defaultPlugins enthalten sind
|
|
140
383
|
*/
|
|
384
|
+
const _indentPlugin = indentListItemPlugin;
|
|
385
|
+
const _outdentPlugin = outdentListItemPlugin;
|
|
386
|
+
/**
|
|
387
|
+
* Standard Block-Format Plugin (Headlines, Listen, Quote in einem Dropdown)
|
|
388
|
+
* Verwendet standardmäßig h1, h2, h3, kann aber über Editor-Props angepasst werden
|
|
389
|
+
*/
|
|
390
|
+
const defaultBlockFormatPlugin = createBlockFormatPlugin(defaultHeadings$1);
|
|
141
391
|
const defaultPlugins = [
|
|
142
392
|
undoPlugin,
|
|
143
393
|
redoPlugin,
|
|
144
394
|
boldPlugin,
|
|
145
395
|
italicPlugin,
|
|
146
396
|
underlinePlugin,
|
|
397
|
+
defaultBlockFormatPlugin,
|
|
147
398
|
clearFormattingPlugin,
|
|
399
|
+
_indentPlugin,
|
|
400
|
+
_outdentPlugin,
|
|
148
401
|
];
|
|
149
402
|
|
|
150
|
-
const Dropdown = ({ icon, label, options, onSelect, currentValue, disabled, }) => {
|
|
151
|
-
const [isOpen, setIsOpen] = React.useState(false);
|
|
152
|
-
const dropdownRef = React.useRef(null);
|
|
153
|
-
React.useEffect(() => {
|
|
154
|
-
const handleClickOutside = (event) => {
|
|
155
|
-
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
156
|
-
setIsOpen(false);
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
if (isOpen) {
|
|
160
|
-
document.addEventListener('mousedown', handleClickOutside);
|
|
161
|
-
}
|
|
162
|
-
return () => {
|
|
163
|
-
document.removeEventListener('mousedown', handleClickOutside);
|
|
164
|
-
};
|
|
165
|
-
}, [isOpen]);
|
|
166
|
-
const handleSelect = (value) => {
|
|
167
|
-
onSelect(value);
|
|
168
|
-
setIsOpen(false);
|
|
169
|
-
};
|
|
170
|
-
const currentOption = options.find(opt => opt.value === currentValue);
|
|
171
|
-
return (jsxRuntime.jsxs("div", { className: "rte-dropdown", ref: dropdownRef, children: [jsxRuntime.jsxs("button", { type: "button", onClick: () => !disabled && setIsOpen(!isOpen), disabled: disabled, className: `rte-toolbar-button rte-dropdown-button ${currentOption ? 'rte-dropdown-button-has-value' : ''}`, title: label, "aria-label": label, children: [jsxRuntime.jsx(Icon, { icon: icon, width: 18, height: 18 }), currentOption && (jsxRuntime.jsx("span", { className: "rte-dropdown-value", children: currentOption.label }))] }), isOpen && (jsxRuntime.jsx("div", { className: "rte-dropdown-menu", children: options.map((option) => (jsxRuntime.jsxs("button", { type: "button", className: `rte-dropdown-item ${currentValue === option.value ? 'rte-dropdown-item-active' : ''}`, onClick: () => handleSelect(option.value), children: [option.color && (jsxRuntime.jsx("span", { className: `rte-dropdown-color-preview ${currentValue === option.value ? 'active' : ''}`, style: { backgroundColor: option.color } })), option.preview && !option.headingPreview && (jsxRuntime.jsx("span", { className: "rte-dropdown-fontsize-preview", style: { fontSize: `${option.preview}px` }, children: "Aa" })), option.headingPreview && (jsxRuntime.jsx("span", { className: `rte-dropdown-heading-preview ${option.headingPreview}`, children: option.headingPreview === 'p' ? 'Normal' : option.headingPreview.toUpperCase() })), option.icon && jsxRuntime.jsx(Icon, { icon: option.icon, width: 16, height: 16 }), jsxRuntime.jsx("span", { style: { flex: 1, fontWeight: currentValue === option.value ? 600 : 400 }, children: option.label })] }, option.value))) }))] }));
|
|
172
|
-
};
|
|
173
|
-
|
|
174
403
|
/**
|
|
175
404
|
* Liest die aktuelle Font-Size aus dem DOM an der Cursor-Position
|
|
176
405
|
*/
|
|
@@ -488,64 +717,6 @@ function createFontSizePlugin(fontSizes = [12, 14, 16, 18, 20, 24]) {
|
|
|
488
717
|
};
|
|
489
718
|
}
|
|
490
719
|
|
|
491
|
-
const defaultHeadings = ['h1', 'h2', 'h3'];
|
|
492
|
-
const headingLabels = {
|
|
493
|
-
h1: 'Überschrift 1',
|
|
494
|
-
h2: 'Überschrift 2',
|
|
495
|
-
h3: 'Überschrift 3',
|
|
496
|
-
h4: 'Überschrift 4',
|
|
497
|
-
h5: 'Überschrift 5',
|
|
498
|
-
h6: 'Überschrift 6',
|
|
499
|
-
};
|
|
500
|
-
function createHeadingsPlugin(headings = defaultHeadings) {
|
|
501
|
-
const options = [
|
|
502
|
-
{ value: 'p', label: 'Normal', headingPreview: 'p' },
|
|
503
|
-
...headings.map(h => ({
|
|
504
|
-
value: h,
|
|
505
|
-
label: headingLabels[h] || h.toUpperCase(),
|
|
506
|
-
headingPreview: h,
|
|
507
|
-
})),
|
|
508
|
-
];
|
|
509
|
-
return {
|
|
510
|
-
name: 'headings',
|
|
511
|
-
type: 'block',
|
|
512
|
-
renderButton: (props) => {
|
|
513
|
-
// Aktuelles Heading aus State Reflection
|
|
514
|
-
const currentValue = props.currentValue || (props.editorAPI ? getCurrentHeading(props.editorAPI, headings) : undefined);
|
|
515
|
-
return (jsxRuntime.jsx(Dropdown, { icon: "mdi:format-header-1", label: "\u00DCberschrift", options: options, onSelect: (value) => {
|
|
516
|
-
if (props.onSelect) {
|
|
517
|
-
props.onSelect(value);
|
|
518
|
-
}
|
|
519
|
-
else {
|
|
520
|
-
props.onClick();
|
|
521
|
-
}
|
|
522
|
-
}, currentValue: currentValue, disabled: props.disabled }));
|
|
523
|
-
},
|
|
524
|
-
getCurrentValue: (editor) => {
|
|
525
|
-
return getCurrentHeading(editor, headings);
|
|
526
|
-
},
|
|
527
|
-
execute: (editor, value) => {
|
|
528
|
-
const tag = value || 'p';
|
|
529
|
-
editor.executeCommand('formatBlock', `<${tag}>`);
|
|
530
|
-
},
|
|
531
|
-
isActive: (editor) => {
|
|
532
|
-
const selection = editor.getSelection();
|
|
533
|
-
if (!selection || selection.rangeCount === 0)
|
|
534
|
-
return false;
|
|
535
|
-
const range = selection.getRangeAt(0);
|
|
536
|
-
const container = range.commonAncestorContainer;
|
|
537
|
-
const element = container.nodeType === Node.TEXT_NODE
|
|
538
|
-
? container.parentElement
|
|
539
|
-
: container;
|
|
540
|
-
if (!element)
|
|
541
|
-
return false;
|
|
542
|
-
const tagName = element.tagName.toLowerCase();
|
|
543
|
-
return headings.includes(tagName);
|
|
544
|
-
},
|
|
545
|
-
canExecute: () => true,
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
|
-
|
|
549
720
|
/**
|
|
550
721
|
* Image-Plugin mit URL-Eingabe und File-Upload
|
|
551
722
|
*/
|
|
@@ -1341,8 +1512,16 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
|
|
|
1341
1512
|
allPlugins.push(createTextColorPlugin(colors));
|
|
1342
1513
|
allPlugins.push(createBackgroundColorPlugin(colors));
|
|
1343
1514
|
}
|
|
1515
|
+
// BlockFormat Plugin ist bereits in defaultPlugins enthalten
|
|
1516
|
+
// Wenn custom headings angegeben sind, ersetze das Standard-Plugin
|
|
1344
1517
|
if (headings && headings.length > 0) {
|
|
1345
|
-
|
|
1518
|
+
// Entferne das Standard-BlockFormat-Plugin
|
|
1519
|
+
const blockFormatIndex = allPlugins.findIndex((p) => p.name === "blockFormat");
|
|
1520
|
+
if (blockFormatIndex !== -1) {
|
|
1521
|
+
allPlugins.splice(blockFormatIndex, 1);
|
|
1522
|
+
}
|
|
1523
|
+
// Füge das Plugin mit custom Headlines hinzu
|
|
1524
|
+
allPlugins.push(createBlockFormatPlugin(headings));
|
|
1346
1525
|
}
|
|
1347
1526
|
allPlugins.push(createImagePlugin(onImageUpload));
|
|
1348
1527
|
return allPlugins;
|
|
@@ -1356,7 +1535,7 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
|
|
|
1356
1535
|
}
|
|
1357
1536
|
}, [onChange]);
|
|
1358
1537
|
const restoreSelection = React.useCallback((editor) => {
|
|
1359
|
-
if (typeof window ===
|
|
1538
|
+
if (typeof window === "undefined" || typeof document === "undefined")
|
|
1360
1539
|
return;
|
|
1361
1540
|
const range = document.createRange();
|
|
1362
1541
|
const selection = window.getSelection();
|
|
@@ -1549,7 +1728,7 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
|
|
|
1549
1728
|
return {
|
|
1550
1729
|
executeCommand,
|
|
1551
1730
|
getSelection: () => {
|
|
1552
|
-
if (typeof window ===
|
|
1731
|
+
if (typeof window === "undefined")
|
|
1553
1732
|
return null;
|
|
1554
1733
|
return window.getSelection();
|
|
1555
1734
|
},
|
|
@@ -1741,6 +1920,40 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
|
|
|
1741
1920
|
}, 0);
|
|
1742
1921
|
}
|
|
1743
1922
|
},
|
|
1923
|
+
indentListItem: () => {
|
|
1924
|
+
const editor = editorRef.current;
|
|
1925
|
+
if (!editor)
|
|
1926
|
+
return;
|
|
1927
|
+
const selection = window.getSelection();
|
|
1928
|
+
if (selection && selection.rangeCount > 0) {
|
|
1929
|
+
const currentContent = domToContent(editor);
|
|
1930
|
+
historyRef.current.push(currentContent);
|
|
1931
|
+
indentListItem(selection);
|
|
1932
|
+
setTimeout(() => {
|
|
1933
|
+
if (editor) {
|
|
1934
|
+
const content = domToContent(editor);
|
|
1935
|
+
notifyChange(content);
|
|
1936
|
+
}
|
|
1937
|
+
}, 0);
|
|
1938
|
+
}
|
|
1939
|
+
},
|
|
1940
|
+
outdentListItem: () => {
|
|
1941
|
+
const editor = editorRef.current;
|
|
1942
|
+
if (!editor)
|
|
1943
|
+
return;
|
|
1944
|
+
const selection = window.getSelection();
|
|
1945
|
+
if (selection && selection.rangeCount > 0) {
|
|
1946
|
+
const currentContent = domToContent(editor);
|
|
1947
|
+
historyRef.current.push(currentContent);
|
|
1948
|
+
outdentListItem(selection);
|
|
1949
|
+
setTimeout(() => {
|
|
1950
|
+
if (editor) {
|
|
1951
|
+
const content = domToContent(editor);
|
|
1952
|
+
notifyChange(content);
|
|
1953
|
+
}
|
|
1954
|
+
}, 0);
|
|
1955
|
+
}
|
|
1956
|
+
},
|
|
1744
1957
|
};
|
|
1745
1958
|
}, [
|
|
1746
1959
|
notifyChange,
|
|
@@ -1781,46 +1994,45 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
|
|
|
1781
1994
|
const handleKeyDown = (e) => {
|
|
1782
1995
|
const isModifierPressed = e.metaKey || e.ctrlKey;
|
|
1783
1996
|
if (e.key === "Tab" && !isModifierPressed && !e.altKey) {
|
|
1997
|
+
// Immer preventDefault aufrufen (wie Lexical), damit Tab den Fokus nicht aus dem Editor entfernt
|
|
1998
|
+
e.preventDefault();
|
|
1999
|
+
e.stopPropagation();
|
|
2000
|
+
e.stopImmediatePropagation();
|
|
1784
2001
|
const selection = window.getSelection();
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
editor.contains(selection.getRangeAt(0).commonAncestorContainer);
|
|
1788
|
-
const isEditorFocused = document.activeElement === editor ||
|
|
1789
|
-
editor.contains(document.activeElement) ||
|
|
1790
|
-
isSelectionInEditor;
|
|
1791
|
-
if (!isEditorFocused) {
|
|
2002
|
+
if (!selection || selection.rangeCount === 0) {
|
|
2003
|
+
// Keine Selection: Tab verhindern, Fokus bleibt im Editor
|
|
1792
2004
|
return;
|
|
1793
2005
|
}
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
if (
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
}
|
|
1814
|
-
setTimeout(() => {
|
|
1815
|
-
if (editor) {
|
|
1816
|
-
const content = domToContent(editor);
|
|
1817
|
-
notifyChange(content);
|
|
1818
|
-
}
|
|
1819
|
-
}, 0);
|
|
1820
|
-
return;
|
|
2006
|
+
const range = selection.getRangeAt(0);
|
|
2007
|
+
const container = range.commonAncestorContainer;
|
|
2008
|
+
if (!editor.contains(container)) {
|
|
2009
|
+
// Container nicht im Editor: Tab verhindern
|
|
2010
|
+
return;
|
|
2011
|
+
}
|
|
2012
|
+
// Prüfe ob wir in einer Liste sind
|
|
2013
|
+
const listItem = container.nodeType === Node.TEXT_NODE
|
|
2014
|
+
? container.parentElement?.closest("li")
|
|
2015
|
+
: container.closest("li");
|
|
2016
|
+
if (listItem && editor.contains(listItem)) {
|
|
2017
|
+
// In Liste: Indent/Outdent durchführen
|
|
2018
|
+
const currentContent = domToContent(editor);
|
|
2019
|
+
historyRef.current.push(currentContent);
|
|
2020
|
+
if (e.shiftKey) {
|
|
2021
|
+
outdentListItem(selection);
|
|
2022
|
+
}
|
|
2023
|
+
else {
|
|
2024
|
+
indentListItem(selection);
|
|
1821
2025
|
}
|
|
2026
|
+
setTimeout(() => {
|
|
2027
|
+
if (editor) {
|
|
2028
|
+
const content = domToContent(editor);
|
|
2029
|
+
notifyChange(content);
|
|
2030
|
+
}
|
|
2031
|
+
}, 0);
|
|
2032
|
+
return;
|
|
1822
2033
|
}
|
|
1823
|
-
|
|
2034
|
+
// Nicht in Liste: Tab verhindern, aber kein Tab-Zeichen einfügen
|
|
2035
|
+
// Der Fokus bleibt im Editor (durch preventDefault)
|
|
1824
2036
|
}
|
|
1825
2037
|
if (isModifierPressed && e.key === "z" && !e.shiftKey) {
|
|
1826
2038
|
e.preventDefault();
|
|
@@ -1835,10 +2047,10 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
|
|
|
1835
2047
|
}
|
|
1836
2048
|
};
|
|
1837
2049
|
editor.addEventListener("input", handleInput);
|
|
1838
|
-
editor.addEventListener("keydown", handleKeyDown);
|
|
2050
|
+
editor.addEventListener("keydown", handleKeyDown, true);
|
|
1839
2051
|
return () => {
|
|
1840
2052
|
editor.removeEventListener("input", handleInput);
|
|
1841
|
-
editor.removeEventListener("keydown", handleKeyDown);
|
|
2053
|
+
editor.removeEventListener("keydown", handleKeyDown, true);
|
|
1842
2054
|
if (inputTimeout) {
|
|
1843
2055
|
clearTimeout(inputTimeout);
|
|
1844
2056
|
}
|
|
@@ -1914,15 +2126,76 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
|
|
|
1914
2126
|
return (jsxRuntime.jsxs("div", { className: `rte-container ${className || ""}`, style: containerStyle, children: [jsxRuntime.jsx(Toolbar, { plugins: plugins, editorAPI: editorAPI, className: toolbarClassName }), jsxRuntime.jsx("div", { ref: editorRef, contentEditable: true, className: `rte-editor ${editorClassName || ""}`, "data-placeholder": placeholder, onPaste: handlePaste, suppressContentEditableWarning: true })] }));
|
|
1915
2127
|
};
|
|
1916
2128
|
|
|
2129
|
+
const defaultHeadings = ["h1", "h2", "h3"];
|
|
2130
|
+
const headingLabels = {
|
|
2131
|
+
h1: "Überschrift 1",
|
|
2132
|
+
h2: "Überschrift 2",
|
|
2133
|
+
h3: "Überschrift 3",
|
|
2134
|
+
h4: "Überschrift 4",
|
|
2135
|
+
h5: "Überschrift 5",
|
|
2136
|
+
h6: "Überschrift 6",
|
|
2137
|
+
};
|
|
2138
|
+
function createHeadingsPlugin(headings = defaultHeadings) {
|
|
2139
|
+
const options = [
|
|
2140
|
+
{ value: "p", label: "Normal", headingPreview: "p" },
|
|
2141
|
+
...headings.map((h) => ({
|
|
2142
|
+
value: h,
|
|
2143
|
+
label: headingLabels[h] || h.toUpperCase(),
|
|
2144
|
+
headingPreview: h,
|
|
2145
|
+
})),
|
|
2146
|
+
];
|
|
2147
|
+
return {
|
|
2148
|
+
name: "headings",
|
|
2149
|
+
type: "block",
|
|
2150
|
+
renderButton: (props) => {
|
|
2151
|
+
// Aktuelles Heading aus State Reflection
|
|
2152
|
+
const currentValue = props.currentValue ||
|
|
2153
|
+
(props.editorAPI
|
|
2154
|
+
? getCurrentHeading(props.editorAPI, headings)
|
|
2155
|
+
: undefined);
|
|
2156
|
+
return (jsxRuntime.jsx(Dropdown, { icon: "mdi:format-header-1", label: "\u00DCberschrift", options: options, onSelect: (value) => {
|
|
2157
|
+
if (props.onSelect) {
|
|
2158
|
+
props.onSelect(value);
|
|
2159
|
+
}
|
|
2160
|
+
else {
|
|
2161
|
+
props.onClick();
|
|
2162
|
+
}
|
|
2163
|
+
}, currentValue: currentValue, disabled: props.disabled }));
|
|
2164
|
+
},
|
|
2165
|
+
getCurrentValue: (editor) => {
|
|
2166
|
+
return getCurrentHeading(editor, headings);
|
|
2167
|
+
},
|
|
2168
|
+
execute: (editor, value) => {
|
|
2169
|
+
const tag = value || "p";
|
|
2170
|
+
editor.executeCommand("formatBlock", `<${tag}>`);
|
|
2171
|
+
},
|
|
2172
|
+
isActive: (editor) => {
|
|
2173
|
+
const selection = editor.getSelection();
|
|
2174
|
+
if (!selection || selection.rangeCount === 0)
|
|
2175
|
+
return false;
|
|
2176
|
+
const range = selection.getRangeAt(0);
|
|
2177
|
+
const container = range.commonAncestorContainer;
|
|
2178
|
+
const element = container.nodeType === Node.TEXT_NODE
|
|
2179
|
+
? container.parentElement
|
|
2180
|
+
: container;
|
|
2181
|
+
if (!element)
|
|
2182
|
+
return false;
|
|
2183
|
+
const tagName = element.tagName.toLowerCase();
|
|
2184
|
+
return headings.includes(tagName);
|
|
2185
|
+
},
|
|
2186
|
+
canExecute: () => true,
|
|
2187
|
+
};
|
|
2188
|
+
}
|
|
2189
|
+
|
|
1917
2190
|
/**
|
|
1918
2191
|
* Link-Plugin mit verbesserter Funktionalität
|
|
1919
2192
|
*/
|
|
1920
2193
|
function createLinkPlugin() {
|
|
1921
2194
|
return {
|
|
1922
|
-
name:
|
|
1923
|
-
type:
|
|
1924
|
-
command:
|
|
1925
|
-
renderButton: (props) => (jsxRuntime.jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: `rte-toolbar-button ${props.isActive ?
|
|
2195
|
+
name: "link",
|
|
2196
|
+
type: "inline",
|
|
2197
|
+
command: "createLink",
|
|
2198
|
+
renderButton: (props) => (jsxRuntime.jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: `rte-toolbar-button ${props.isActive ? "rte-toolbar-button-active" : ""}`, title: "Link einf\u00FCgen", "aria-label": "Link einf\u00FCgen", children: jsxRuntime.jsx(IconWrapper, { icon: "mdi:link", width: 18, height: 18 }) })),
|
|
1926
2199
|
execute: (editor) => {
|
|
1927
2200
|
const selection = editor.getSelection();
|
|
1928
2201
|
if (!selection || selection.rangeCount === 0)
|
|
@@ -1933,7 +2206,7 @@ function createLinkPlugin() {
|
|
|
1933
2206
|
? container.parentElement
|
|
1934
2207
|
: container;
|
|
1935
2208
|
// Prüfe ob bereits ein Link vorhanden ist
|
|
1936
|
-
const existingLink = element?.closest(
|
|
2209
|
+
const existingLink = element?.closest("a");
|
|
1937
2210
|
if (existingLink) {
|
|
1938
2211
|
// Link entfernen
|
|
1939
2212
|
const parent = existingLink.parentNode;
|
|
@@ -1952,9 +2225,9 @@ function createLinkPlugin() {
|
|
|
1952
2225
|
}
|
|
1953
2226
|
else {
|
|
1954
2227
|
// Neuen Link einfügen
|
|
1955
|
-
const url = prompt(
|
|
2228
|
+
const url = prompt("URL eingeben:");
|
|
1956
2229
|
if (url) {
|
|
1957
|
-
editor.executeCommand(
|
|
2230
|
+
editor.executeCommand("createLink", url);
|
|
1958
2231
|
}
|
|
1959
2232
|
}
|
|
1960
2233
|
},
|
|
@@ -1969,7 +2242,7 @@ function createLinkPlugin() {
|
|
|
1969
2242
|
: container;
|
|
1970
2243
|
if (!element)
|
|
1971
2244
|
return false;
|
|
1972
|
-
return element.closest(
|
|
2245
|
+
return element.closest("a") !== null;
|
|
1973
2246
|
},
|
|
1974
2247
|
getCurrentValue: (editor) => {
|
|
1975
2248
|
const selection = editor.getSelection();
|
|
@@ -1982,7 +2255,7 @@ function createLinkPlugin() {
|
|
|
1982
2255
|
: container;
|
|
1983
2256
|
if (!element)
|
|
1984
2257
|
return undefined;
|
|
1985
|
-
const link = element.closest(
|
|
2258
|
+
const link = element.closest("a");
|
|
1986
2259
|
return link ? link.href : undefined;
|
|
1987
2260
|
},
|
|
1988
2261
|
canExecute: (editor) => {
|
|
@@ -1996,10 +2269,10 @@ const linkPlugin = createLinkPlugin();
|
|
|
1996
2269
|
* Blockquote-Plugin
|
|
1997
2270
|
*/
|
|
1998
2271
|
const blockquotePlugin = {
|
|
1999
|
-
name:
|
|
2000
|
-
type:
|
|
2001
|
-
command:
|
|
2002
|
-
renderButton: (props) => (jsxRuntime.jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: `rte-toolbar-button ${props.isActive ?
|
|
2272
|
+
name: "blockquote",
|
|
2273
|
+
type: "block",
|
|
2274
|
+
command: "formatBlock",
|
|
2275
|
+
renderButton: (props) => (jsxRuntime.jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: `rte-toolbar-button ${props.isActive ? "rte-toolbar-button-active" : ""}`, title: "Zitat", "aria-label": "Zitat", children: jsxRuntime.jsx(IconWrapper, { icon: "mdi:format-quote-close", width: 18, height: 18 }) })),
|
|
2003
2276
|
execute: (editor) => {
|
|
2004
2277
|
const selection = editor.getSelection();
|
|
2005
2278
|
if (!selection || selection.rangeCount === 0)
|
|
@@ -2011,12 +2284,12 @@ const blockquotePlugin = {
|
|
|
2011
2284
|
: container;
|
|
2012
2285
|
if (!element)
|
|
2013
2286
|
return;
|
|
2014
|
-
const isBlockquote = element.closest(
|
|
2287
|
+
const isBlockquote = element.closest("blockquote") !== null;
|
|
2015
2288
|
if (isBlockquote) {
|
|
2016
|
-
editor.executeCommand(
|
|
2289
|
+
editor.executeCommand("formatBlock", "<p>");
|
|
2017
2290
|
}
|
|
2018
2291
|
else {
|
|
2019
|
-
editor.executeCommand(
|
|
2292
|
+
editor.executeCommand("formatBlock", "<blockquote>");
|
|
2020
2293
|
}
|
|
2021
2294
|
},
|
|
2022
2295
|
isActive: (editor) => {
|
|
@@ -2030,7 +2303,7 @@ const blockquotePlugin = {
|
|
|
2030
2303
|
: container;
|
|
2031
2304
|
if (!element)
|
|
2032
2305
|
return false;
|
|
2033
|
-
return element.closest(
|
|
2306
|
+
return element.closest("blockquote") !== null;
|
|
2034
2307
|
},
|
|
2035
2308
|
canExecute: (editor) => {
|
|
2036
2309
|
const selection = editor.getSelection();
|
|
@@ -2041,17 +2314,17 @@ const blockquotePlugin = {
|
|
|
2041
2314
|
* Unordered List Plugin
|
|
2042
2315
|
*/
|
|
2043
2316
|
const unorderedListPlugin = {
|
|
2044
|
-
name:
|
|
2045
|
-
type:
|
|
2046
|
-
command:
|
|
2047
|
-
renderButton: (props) => (jsxRuntime.jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: `rte-toolbar-button ${props.isActive ?
|
|
2317
|
+
name: "unorderedList",
|
|
2318
|
+
type: "block",
|
|
2319
|
+
command: "insertUnorderedList",
|
|
2320
|
+
renderButton: (props) => (jsxRuntime.jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: `rte-toolbar-button ${props.isActive ? "rte-toolbar-button-active" : ""}`, title: "Aufz\u00E4hlungsliste", "aria-label": "Aufz\u00E4hlungsliste", children: jsxRuntime.jsx(IconWrapper, { icon: "mdi:format-list-bulleted", width: 18, height: 18 }) })),
|
|
2048
2321
|
execute: (editor) => {
|
|
2049
|
-
editor.executeCommand(
|
|
2322
|
+
editor.executeCommand("insertUnorderedList");
|
|
2050
2323
|
},
|
|
2051
2324
|
isActive: (editor) => {
|
|
2052
|
-
if (typeof document ===
|
|
2325
|
+
if (typeof document === "undefined")
|
|
2053
2326
|
return false;
|
|
2054
|
-
return document.queryCommandState(
|
|
2327
|
+
return document.queryCommandState("insertUnorderedList");
|
|
2055
2328
|
},
|
|
2056
2329
|
canExecute: (editor) => {
|
|
2057
2330
|
const selection = editor.getSelection();
|
|
@@ -2062,17 +2335,17 @@ const unorderedListPlugin = {
|
|
|
2062
2335
|
* Ordered List Plugin
|
|
2063
2336
|
*/
|
|
2064
2337
|
const orderedListPlugin = {
|
|
2065
|
-
name:
|
|
2066
|
-
type:
|
|
2067
|
-
command:
|
|
2068
|
-
renderButton: (props) => (jsxRuntime.jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: `rte-toolbar-button ${props.isActive ?
|
|
2338
|
+
name: "orderedList",
|
|
2339
|
+
type: "block",
|
|
2340
|
+
command: "insertOrderedList",
|
|
2341
|
+
renderButton: (props) => (jsxRuntime.jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: `rte-toolbar-button ${props.isActive ? "rte-toolbar-button-active" : ""}`, title: "Nummerierte Liste", "aria-label": "Nummerierte Liste", children: jsxRuntime.jsx(IconWrapper, { icon: "mdi:format-list-numbered", width: 18, height: 18 }) })),
|
|
2069
2342
|
execute: (editor) => {
|
|
2070
|
-
editor.executeCommand(
|
|
2343
|
+
editor.executeCommand("insertOrderedList");
|
|
2071
2344
|
},
|
|
2072
2345
|
isActive: (editor) => {
|
|
2073
|
-
if (typeof document ===
|
|
2346
|
+
if (typeof document === "undefined")
|
|
2074
2347
|
return false;
|
|
2075
|
-
return document.queryCommandState(
|
|
2348
|
+
return document.queryCommandState("insertOrderedList");
|
|
2076
2349
|
},
|
|
2077
2350
|
canExecute: (editor) => {
|
|
2078
2351
|
const selection = editor.getSelection();
|
|
@@ -2090,6 +2363,7 @@ exports.clearFormattingPlugin = clearFormattingPlugin;
|
|
|
2090
2363
|
exports.contentToDOM = contentToDOM;
|
|
2091
2364
|
exports.contentToHTML = contentToHTML;
|
|
2092
2365
|
exports.createBackgroundColorPlugin = createBackgroundColorPlugin;
|
|
2366
|
+
exports.createBlockFormatPlugin = createBlockFormatPlugin;
|
|
2093
2367
|
exports.createEmptyContent = createEmptyContent;
|
|
2094
2368
|
exports.createFontSizePlugin = createFontSizePlugin;
|
|
2095
2369
|
exports.createHeadingsPlugin = createHeadingsPlugin;
|
|
@@ -2105,10 +2379,12 @@ exports.getCurrentHeading = getCurrentHeading;
|
|
|
2105
2379
|
exports.getCurrentTextColor = getCurrentTextColor;
|
|
2106
2380
|
exports.htmlToContent = htmlToContent;
|
|
2107
2381
|
exports.indentListItem = indentListItem;
|
|
2382
|
+
exports.indentListItemPlugin = indentListItemPlugin;
|
|
2108
2383
|
exports.italicPlugin = italicPlugin;
|
|
2109
2384
|
exports.linkPlugin = linkPlugin;
|
|
2110
2385
|
exports.orderedListPlugin = orderedListPlugin;
|
|
2111
2386
|
exports.outdentListItem = outdentListItem;
|
|
2387
|
+
exports.outdentListItemPlugin = outdentListItemPlugin;
|
|
2112
2388
|
exports.redoPlugin = redoPlugin;
|
|
2113
2389
|
exports.underlinePlugin = underlinePlugin;
|
|
2114
2390
|
exports.undoPlugin = undoPlugin;
|