@overlap/rte 0.1.0 → 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/dist/index.esm.js CHANGED
@@ -1,50 +1,78 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
3
3
 
4
- const BoldIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
5
- const ItalicIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z" }) }));
6
- const UnderlineIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
7
- const UndoIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
8
- const RedoIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
9
- const ClearFormattingIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M6 5v.18L8.82 8h2.4L7.73 4.36C7.26 3.85 6.61 3.5 6 3.5c-1.11 0-2 .89-2 2 0 .61.35 1.26.86 1.73L6 5zm14.27 2.5L18.73 9H21v1h-4.27L15 8.27l1.23-1.23c.5-.5 1.15-.73 1.77-.73 1.11 0 2 .89 2 2 0 .62-.23 1.27-.73 1.77L18.27 13H21v1h-5.27l-2-2H9.73l-2 2H3v-1h4.27l2-2H7v-1h2.73l2-2H12v-1h-2.27l2-2h4.54zM5 15h14v2H5v-2z" }) }));
10
- const LinkIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
11
- const QuoteIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z" }) }));
12
- const BulletListIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
13
- const NumberedListIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 11.9V11H2zm6-5v2h14V6H8zm0 14h14v-2H8v2zm0-6h14v-2H8v2z" }) }));
14
- const TextColorIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
15
- const BackgroundColorIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3-1.05 0-1.96.54-2.5 1.35l-.5.67-.5-.68C10.96 2.54 10.05 2 9 2 7.34 2 6 3.34 6 5c0 .35.07.69.18 1H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM9 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15H4v-2h16v2zm0-5H4V8h5.08L7 10.83 8.62 12 11 8.76l1-1.36 1 1.36L15.38 12 17 10.83 14.92 8H20v6z" }) }));
16
- const HeadingIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M5 4v3h5.5v12h3V7H19V4H5z" }) }));
17
- const FontSizeIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M9 4v3h5v12h3V7h5V4H9zm-6 8h3v8h3v-8h3V10H3z" }) }));
18
- const ImageIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
19
- const CloseIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
20
- const LoadingIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
21
- const UploadIcon = ({ width = 18, height = 18, className }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z" }) }));
4
+ const BoldIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
5
+ const ItalicIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z" }) }));
6
+ const UnderlineIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
7
+ const UndoIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
8
+ const RedoIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
9
+ const ClearFormattingIcon = ({ width = 18, height = 18, className, }) => (jsxs("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: [jsx("path", { d: "M6 5v3h5v11h2V8h5V5H6z" }), jsx("path", { d: "M20.5 3.5L3.5 20.5l1.06 1.06L21.56 4.56z" })] }));
10
+ const LinkIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
11
+ const QuoteIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z" }) }));
12
+ const BulletListIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
13
+ const NumberedListIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 11.9V11H2zm6-5v2h14V6H8zm0 14h14v-2H8v2zm0-6h14v-2H8v2z" }) }));
14
+ const TextColorIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
15
+ const BackgroundColorIcon = ({ width = 18, height = 18, className, }) => (jsxs("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: [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" }), jsx("rect", { x: "4", y: "13", width: "16", height: "6", fill: "currentColor", opacity: "0.5" })] }));
16
+ const HeadingIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M5 4v3h5.5v12h3V7H19V4H5z" }) }));
17
+ const FontSizeIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M9 4v3h5v12h3V7h5V4H9zm-6 8h3v8h3v-8h3V10H3z" }) }));
18
+ const ImageIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
19
+ const CloseIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
20
+ const LoadingIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: 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" }) }));
21
+ const UploadIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z" }) }));
22
+ const IndentIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M3 21h18v-2H3v2zM3 8l4 4-4 4V8zm8 9h10v-2H11v2zM3 3v2h18V3H3zm8 6h10V7H11v2zm0 4h10v-2H11v2z" }) }));
23
+ const OutdentIcon = ({ width = 18, height = 18, className, }) => (jsx("svg", { width: width, height: height, viewBox: "0 0 24 24", fill: "currentColor", className: className, children: jsx("path", { d: "M3 21h18v-2H3v2zM11 8l4 4-4 4V8zM3 3v2h18V3H3zm0 4h10v2H3V7zm0 4h10v2H3v-2zm0 4h18v2H3v-2z" }) }));
22
24
  const iconMap = {
23
- 'mdi:format-bold': BoldIcon,
24
- 'mdi:format-italic': ItalicIcon,
25
- 'mdi:format-underline': UnderlineIcon,
26
- 'mdi:undo': UndoIcon,
27
- 'mdi:redo': RedoIcon,
28
- 'mdi:format-clear': ClearFormattingIcon,
29
- 'mdi:link': LinkIcon,
30
- 'mdi:format-quote-close': QuoteIcon,
31
- 'mdi:format-list-bulleted': BulletListIcon,
32
- 'mdi:format-list-numbered': NumberedListIcon,
33
- 'mdi:format-color-text': TextColorIcon,
34
- 'mdi:format-color-fill': BackgroundColorIcon,
35
- 'mdi:format-header-1': HeadingIcon,
36
- 'mdi:format-size': FontSizeIcon,
37
- 'mdi:image': ImageIcon,
38
- 'mdi:close': CloseIcon,
39
- 'mdi:loading': LoadingIcon,
40
- 'mdi:upload': UploadIcon,
25
+ "mdi:format-bold": BoldIcon,
26
+ "mdi:format-italic": ItalicIcon,
27
+ "mdi:format-underline": UnderlineIcon,
28
+ "mdi:undo": UndoIcon,
29
+ "mdi:redo": RedoIcon,
30
+ "mdi:format-clear": ClearFormattingIcon,
31
+ "mdi:link": LinkIcon,
32
+ "mdi:format-quote-close": QuoteIcon,
33
+ "mdi:format-list-bulleted": BulletListIcon,
34
+ "mdi:format-list-numbered": NumberedListIcon,
35
+ "mdi:format-color-text": TextColorIcon,
36
+ "mdi:format-color-fill": BackgroundColorIcon,
37
+ "mdi:format-header-1": HeadingIcon,
38
+ "mdi:format-size": FontSizeIcon,
39
+ "mdi:image": ImageIcon,
40
+ "mdi:close": CloseIcon,
41
+ "mdi:loading": LoadingIcon,
42
+ "mdi:upload": UploadIcon,
43
+ "mdi:format-indent-increase": IndentIcon,
44
+ "mdi:format-indent-decrease": OutdentIcon,
41
45
  };
42
46
  const Icon = ({ icon, width = 18, height = 18, className }) => {
43
47
  const IconComponent = iconMap[icon];
44
48
  if (!IconComponent) {
45
- return jsx("span", { style: { width, height, display: 'inline-block' } });
49
+ return jsx("span", { style: { width, height, display: "inline-block" } });
46
50
  }
47
- return jsx(IconComponent, { width: width, height: height, className: className });
51
+ return (jsx(IconComponent, { width: width, height: height, className: className }));
52
+ };
53
+
54
+ const Dropdown = ({ icon, label, options, onSelect, currentValue, disabled, }) => {
55
+ const [isOpen, setIsOpen] = useState(false);
56
+ const dropdownRef = useRef(null);
57
+ useEffect(() => {
58
+ const handleClickOutside = (event) => {
59
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
60
+ setIsOpen(false);
61
+ }
62
+ };
63
+ if (isOpen) {
64
+ document.addEventListener('mousedown', handleClickOutside);
65
+ }
66
+ return () => {
67
+ document.removeEventListener('mousedown', handleClickOutside);
68
+ };
69
+ }, [isOpen]);
70
+ const handleSelect = (value) => {
71
+ onSelect(value);
72
+ setIsOpen(false);
73
+ };
74
+ const currentOption = options.find(opt => opt.value === currentValue);
75
+ return (jsxs("div", { className: "rte-dropdown", ref: dropdownRef, children: [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: [jsx(Icon, { icon: icon, width: 18, height: 18 }), currentOption && (jsx("span", { className: "rte-dropdown-value", children: currentOption.label }))] }), isOpen && (jsx("div", { className: "rte-dropdown-menu", children: options.map((option) => (jsxs("button", { type: "button", className: `rte-dropdown-item ${currentValue === option.value ? 'rte-dropdown-item-active' : ''}`, onClick: () => handleSelect(option.value), children: [option.color && (jsx("span", { className: `rte-dropdown-color-preview ${currentValue === option.value ? 'active' : ''}`, style: { backgroundColor: option.color } })), option.preview && !option.headingPreview && (jsx("span", { className: "rte-dropdown-fontsize-preview", style: { fontSize: `${option.preview}px` }, children: "Aa" })), option.headingPreview && (jsx("span", { className: `rte-dropdown-heading-preview ${option.headingPreview}`, children: option.headingPreview === 'p' ? 'Normal' : option.headingPreview.toUpperCase() })), option.icon && jsx(Icon, { icon: option.icon, width: 16, height: 16 }), jsx("span", { style: { flex: 1, fontWeight: currentValue === option.value ? 600 : 400 }, children: option.label })] }, option.value))) }))] }));
48
76
  };
49
77
 
50
78
  const IconWrapper = ({ icon, width = 18, height = 18, className }) => {
@@ -107,6 +135,168 @@ function createCommandPlugin(name, command, icon, label) {
107
135
  };
108
136
  }
109
137
 
138
+ const defaultHeadings$2 = ["h1", "h2", "h3"];
139
+ const headingLabels$1 = {
140
+ h1: "Überschrift 1",
141
+ h2: "Überschrift 2",
142
+ h3: "Überschrift 3",
143
+ h4: "Überschrift 4",
144
+ h5: "Überschrift 5",
145
+ h6: "Überschrift 6",
146
+ };
147
+ /**
148
+ * Erstellt ein Block-Format-Plugin, das Headlines, Listen und Quote in einem Dropdown kombiniert
149
+ * @param headings - Array von Heading-Levels (z.B. ["h1", "h2", "h3"])
150
+ */
151
+ function createBlockFormatPlugin(headings = defaultHeadings$2) {
152
+ const options = [
153
+ { value: "p", label: "Normal", headingPreview: "p" },
154
+ ...headings.map((h) => ({
155
+ value: h,
156
+ label: headingLabels$1[h] || h.toUpperCase(),
157
+ headingPreview: h,
158
+ })),
159
+ {
160
+ value: "ul",
161
+ label: "Aufzählungsliste",
162
+ icon: "mdi:format-list-bulleted",
163
+ },
164
+ {
165
+ value: "ol",
166
+ label: "Nummerierte Liste",
167
+ icon: "mdi:format-list-numbered",
168
+ },
169
+ { value: "blockquote", label: "Zitat", icon: "mdi:format-quote-close" },
170
+ ];
171
+ return {
172
+ name: "blockFormat",
173
+ type: "block",
174
+ renderButton: (props) => {
175
+ // Aktuelles Format bestimmen
176
+ const editor = props.editorAPI;
177
+ let currentValue = props.currentValue;
178
+ if (!currentValue && editor) {
179
+ const selection = editor.getSelection();
180
+ if (selection && selection.rangeCount > 0) {
181
+ const range = selection.getRangeAt(0);
182
+ const container = range.commonAncestorContainer;
183
+ const element = container.nodeType === Node.TEXT_NODE
184
+ ? container.parentElement
185
+ : container;
186
+ if (element) {
187
+ const tagName = element.tagName.toLowerCase();
188
+ // Prüfe auf Heading
189
+ if (headings.includes(tagName)) {
190
+ currentValue = tagName;
191
+ }
192
+ // Prüfe auf Blockquote
193
+ else if (element.closest("blockquote")) {
194
+ currentValue = "blockquote";
195
+ }
196
+ // Prüfe auf Liste
197
+ else if (element.closest("ul")) {
198
+ currentValue = "ul";
199
+ }
200
+ else if (element.closest("ol")) {
201
+ currentValue = "ol";
202
+ }
203
+ // Prüfe auf Paragraph
204
+ else if (tagName === "p") {
205
+ currentValue = "p";
206
+ }
207
+ }
208
+ }
209
+ }
210
+ return (jsx(Dropdown, { icon: "mdi:format-header-1", label: "Format", options: options, onSelect: (value) => {
211
+ // onSelect wird von der Toolbar übergeben und ruft handlePluginClick auf
212
+ if (props.onSelect) {
213
+ props.onSelect(value);
214
+ }
215
+ }, currentValue: currentValue, disabled: props.disabled }));
216
+ },
217
+ getCurrentValue: (editor) => {
218
+ const selection = editor.getSelection();
219
+ if (!selection || selection.rangeCount === 0)
220
+ return undefined;
221
+ const range = selection.getRangeAt(0);
222
+ const container = range.commonAncestorContainer;
223
+ const element = container.nodeType === Node.TEXT_NODE
224
+ ? container.parentElement
225
+ : container;
226
+ if (!element)
227
+ return undefined;
228
+ const tagName = element.tagName.toLowerCase();
229
+ // Prüfe auf Heading
230
+ if (headings.includes(tagName)) {
231
+ return tagName;
232
+ }
233
+ // Prüfe auf Blockquote
234
+ if (element.closest("blockquote")) {
235
+ return "blockquote";
236
+ }
237
+ // Prüfe auf Liste
238
+ if (element.closest("ul")) {
239
+ return "ul";
240
+ }
241
+ if (element.closest("ol")) {
242
+ return "ol";
243
+ }
244
+ // Prüfe auf Paragraph
245
+ if (tagName === "p") {
246
+ return "p";
247
+ }
248
+ return undefined;
249
+ },
250
+ execute: (editor, value) => {
251
+ if (!value)
252
+ return;
253
+ if (value === "ul") {
254
+ editor.executeCommand("insertUnorderedList");
255
+ }
256
+ else if (value === "ol") {
257
+ editor.executeCommand("insertOrderedList");
258
+ }
259
+ else if (value === "blockquote") {
260
+ const selection = editor.getSelection();
261
+ if (selection && selection.rangeCount > 0) {
262
+ const range = selection.getRangeAt(0);
263
+ const container = range.commonAncestorContainer;
264
+ const element = container.nodeType === Node.TEXT_NODE
265
+ ? container.parentElement
266
+ : container;
267
+ if (element?.closest("blockquote")) {
268
+ editor.executeCommand("formatBlock", "<p>");
269
+ }
270
+ else {
271
+ editor.executeCommand("formatBlock", "<blockquote>");
272
+ }
273
+ }
274
+ }
275
+ else {
276
+ editor.executeCommand("formatBlock", `<${value}>`);
277
+ }
278
+ },
279
+ isActive: (editor) => {
280
+ const selection = editor.getSelection();
281
+ if (!selection || selection.rangeCount === 0)
282
+ return false;
283
+ const range = selection.getRangeAt(0);
284
+ const container = range.commonAncestorContainer;
285
+ const element = container.nodeType === Node.TEXT_NODE
286
+ ? container.parentElement
287
+ : container;
288
+ if (!element)
289
+ return false;
290
+ const tagName = element.tagName.toLowerCase();
291
+ return (headings.includes(tagName) ||
292
+ element.closest("blockquote") !== null ||
293
+ element.closest("ul") !== null ||
294
+ element.closest("ol") !== null);
295
+ },
296
+ canExecute: () => true,
297
+ };
298
+ }
299
+
110
300
  /**
111
301
  * Clear Formatting Plugin - Entfernt alle Formatierungen
112
302
  */
@@ -123,50 +313,89 @@ const clearFormattingPlugin = {
123
313
  },
124
314
  };
125
315
 
316
+ const defaultHeadings$1 = ["h1", "h2", "h3"];
126
317
  /**
127
318
  * Standard-Plugins
128
319
  */
129
- const boldPlugin = createInlinePlugin('bold', 'bold', 'mdi:format-bold', 'Fett');
130
- const italicPlugin = createInlinePlugin('italic', 'italic', 'mdi:format-italic', 'Kursiv');
131
- const underlinePlugin = createInlinePlugin('underline', 'underline', 'mdi:format-underline', 'Unterstrichen');
132
- const undoPlugin = createCommandPlugin('undo', 'undo', 'mdi:undo', 'Rückgängig');
133
- const redoPlugin = createCommandPlugin('redo', 'redo', 'mdi:redo', 'Wiederholen');
320
+ const boldPlugin = createInlinePlugin("bold", "bold", "mdi:format-bold", "Fett");
321
+ const italicPlugin = createInlinePlugin("italic", "italic", "mdi:format-italic", "Kursiv");
322
+ const underlinePlugin = createInlinePlugin("underline", "underline", "mdi:format-underline", "Unterstrichen");
323
+ const undoPlugin = createCommandPlugin("undo", "undo", "mdi:undo", "Rückgängig");
324
+ const redoPlugin = createCommandPlugin("redo", "redo", "mdi:redo", "Wiederholen");
325
+ /**
326
+ * Indent List Item Plugin (Tab für Unterliste)
327
+ */
328
+ const indentListItemPlugin = {
329
+ name: "indentListItem",
330
+ type: "command",
331
+ renderButton: (props) => (jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: "rte-toolbar-button", title: "Einr\u00FCcken (Unterliste)", "aria-label": "Einr\u00FCcken (Unterliste)", children: jsx(IconWrapper, { icon: "mdi:format-indent-increase", width: 18, height: 18 }) })),
332
+ execute: (editor) => {
333
+ editor.indentListItem();
334
+ },
335
+ canExecute: (editor) => {
336
+ const selection = editor.getSelection();
337
+ if (!selection || selection.rangeCount === 0)
338
+ return false;
339
+ const range = selection.getRangeAt(0);
340
+ const container = range.commonAncestorContainer;
341
+ const listItem = container.nodeType === Node.TEXT_NODE
342
+ ? container.parentElement?.closest("li")
343
+ : container.closest("li");
344
+ return listItem !== null;
345
+ },
346
+ };
347
+ /**
348
+ * Outdent List Item Plugin (Shift+Tab)
349
+ */
350
+ const outdentListItemPlugin = {
351
+ name: "outdentListItem",
352
+ type: "command",
353
+ renderButton: (props) => (jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, className: "rte-toolbar-button", title: "Ausr\u00FCcken", "aria-label": "Ausr\u00FCcken", children: jsx(IconWrapper, { icon: "mdi:format-indent-decrease", width: 18, height: 18 }) })),
354
+ execute: (editor) => {
355
+ editor.outdentListItem();
356
+ },
357
+ canExecute: (editor) => {
358
+ const selection = editor.getSelection();
359
+ if (!selection || selection.rangeCount === 0)
360
+ return false;
361
+ const range = selection.getRangeAt(0);
362
+ const container = range.commonAncestorContainer;
363
+ const listItem = container.nodeType === Node.TEXT_NODE
364
+ ? container.parentElement?.closest("li")
365
+ : container.closest("li");
366
+ if (!listItem)
367
+ return false;
368
+ // Prüfe ob in verschachtelter Liste
369
+ const list = listItem.parentElement;
370
+ if (!list || (list.tagName !== "UL" && list.tagName !== "OL"))
371
+ return false;
372
+ const parentListItem = list.parentElement;
373
+ return parentListItem !== null && parentListItem.tagName === "LI";
374
+ },
375
+ };
134
376
  /**
135
377
  * Standard-Plugin-Liste
378
+ * Die Plugins werden hier direkt referenziert, um sicherzustellen, dass sie in defaultPlugins enthalten sind
136
379
  */
380
+ const _indentPlugin = indentListItemPlugin;
381
+ const _outdentPlugin = outdentListItemPlugin;
382
+ /**
383
+ * Standard Block-Format Plugin (Headlines, Listen, Quote in einem Dropdown)
384
+ * Verwendet standardmäßig h1, h2, h3, kann aber über Editor-Props angepasst werden
385
+ */
386
+ const defaultBlockFormatPlugin = createBlockFormatPlugin(defaultHeadings$1);
137
387
  const defaultPlugins = [
138
388
  undoPlugin,
139
389
  redoPlugin,
140
390
  boldPlugin,
141
391
  italicPlugin,
142
392
  underlinePlugin,
393
+ defaultBlockFormatPlugin,
143
394
  clearFormattingPlugin,
395
+ _indentPlugin,
396
+ _outdentPlugin,
144
397
  ];
145
398
 
146
- const Dropdown = ({ icon, label, options, onSelect, currentValue, disabled, }) => {
147
- const [isOpen, setIsOpen] = useState(false);
148
- const dropdownRef = useRef(null);
149
- useEffect(() => {
150
- const handleClickOutside = (event) => {
151
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
152
- setIsOpen(false);
153
- }
154
- };
155
- if (isOpen) {
156
- document.addEventListener('mousedown', handleClickOutside);
157
- }
158
- return () => {
159
- document.removeEventListener('mousedown', handleClickOutside);
160
- };
161
- }, [isOpen]);
162
- const handleSelect = (value) => {
163
- onSelect(value);
164
- setIsOpen(false);
165
- };
166
- const currentOption = options.find(opt => opt.value === currentValue);
167
- return (jsxs("div", { className: "rte-dropdown", ref: dropdownRef, children: [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: [jsx(Icon, { icon: icon, width: 18, height: 18 }), currentOption && (jsx("span", { className: "rte-dropdown-value", children: currentOption.label }))] }), isOpen && (jsx("div", { className: "rte-dropdown-menu", children: options.map((option) => (jsxs("button", { type: "button", className: `rte-dropdown-item ${currentValue === option.value ? 'rte-dropdown-item-active' : ''}`, onClick: () => handleSelect(option.value), children: [option.color && (jsx("span", { className: `rte-dropdown-color-preview ${currentValue === option.value ? 'active' : ''}`, style: { backgroundColor: option.color } })), option.preview && !option.headingPreview && (jsx("span", { className: "rte-dropdown-fontsize-preview", style: { fontSize: `${option.preview}px` }, children: "Aa" })), option.headingPreview && (jsx("span", { className: `rte-dropdown-heading-preview ${option.headingPreview}`, children: option.headingPreview === 'p' ? 'Normal' : option.headingPreview.toUpperCase() })), option.icon && jsx(Icon, { icon: option.icon, width: 16, height: 16 }), jsx("span", { style: { flex: 1, fontWeight: currentValue === option.value ? 600 : 400 }, children: option.label })] }, option.value))) }))] }));
168
- };
169
-
170
399
  /**
171
400
  * Liest die aktuelle Font-Size aus dem DOM an der Cursor-Position
172
401
  */
@@ -484,64 +713,6 @@ function createFontSizePlugin(fontSizes = [12, 14, 16, 18, 20, 24]) {
484
713
  };
485
714
  }
486
715
 
487
- const defaultHeadings = ['h1', 'h2', 'h3'];
488
- const headingLabels = {
489
- h1: 'Überschrift 1',
490
- h2: 'Überschrift 2',
491
- h3: 'Überschrift 3',
492
- h4: 'Überschrift 4',
493
- h5: 'Überschrift 5',
494
- h6: 'Überschrift 6',
495
- };
496
- function createHeadingsPlugin(headings = defaultHeadings) {
497
- const options = [
498
- { value: 'p', label: 'Normal', headingPreview: 'p' },
499
- ...headings.map(h => ({
500
- value: h,
501
- label: headingLabels[h] || h.toUpperCase(),
502
- headingPreview: h,
503
- })),
504
- ];
505
- return {
506
- name: 'headings',
507
- type: 'block',
508
- renderButton: (props) => {
509
- // Aktuelles Heading aus State Reflection
510
- const currentValue = props.currentValue || (props.editorAPI ? getCurrentHeading(props.editorAPI, headings) : undefined);
511
- return (jsx(Dropdown, { icon: "mdi:format-header-1", label: "\u00DCberschrift", options: options, onSelect: (value) => {
512
- if (props.onSelect) {
513
- props.onSelect(value);
514
- }
515
- else {
516
- props.onClick();
517
- }
518
- }, currentValue: currentValue, disabled: props.disabled }));
519
- },
520
- getCurrentValue: (editor) => {
521
- return getCurrentHeading(editor, headings);
522
- },
523
- execute: (editor, value) => {
524
- const tag = value || 'p';
525
- editor.executeCommand('formatBlock', `<${tag}>`);
526
- },
527
- isActive: (editor) => {
528
- const selection = editor.getSelection();
529
- if (!selection || selection.rangeCount === 0)
530
- return false;
531
- const range = selection.getRangeAt(0);
532
- const container = range.commonAncestorContainer;
533
- const element = container.nodeType === Node.TEXT_NODE
534
- ? container.parentElement
535
- : container;
536
- if (!element)
537
- return false;
538
- const tagName = element.tagName.toLowerCase();
539
- return headings.includes(tagName);
540
- },
541
- canExecute: () => true,
542
- };
543
- }
544
-
545
716
  /**
546
717
  * Image-Plugin mit URL-Eingabe und File-Upload
547
718
  */
@@ -1337,8 +1508,16 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
1337
1508
  allPlugins.push(createTextColorPlugin(colors));
1338
1509
  allPlugins.push(createBackgroundColorPlugin(colors));
1339
1510
  }
1511
+ // BlockFormat Plugin ist bereits in defaultPlugins enthalten
1512
+ // Wenn custom headings angegeben sind, ersetze das Standard-Plugin
1340
1513
  if (headings && headings.length > 0) {
1341
- allPlugins.push(createHeadingsPlugin(headings));
1514
+ // Entferne das Standard-BlockFormat-Plugin
1515
+ const blockFormatIndex = allPlugins.findIndex((p) => p.name === "blockFormat");
1516
+ if (blockFormatIndex !== -1) {
1517
+ allPlugins.splice(blockFormatIndex, 1);
1518
+ }
1519
+ // Füge das Plugin mit custom Headlines hinzu
1520
+ allPlugins.push(createBlockFormatPlugin(headings));
1342
1521
  }
1343
1522
  allPlugins.push(createImagePlugin(onImageUpload));
1344
1523
  return allPlugins;
@@ -1352,7 +1531,7 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
1352
1531
  }
1353
1532
  }, [onChange]);
1354
1533
  const restoreSelection = useCallback((editor) => {
1355
- if (typeof window === 'undefined' || typeof document === 'undefined')
1534
+ if (typeof window === "undefined" || typeof document === "undefined")
1356
1535
  return;
1357
1536
  const range = document.createRange();
1358
1537
  const selection = window.getSelection();
@@ -1545,7 +1724,7 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
1545
1724
  return {
1546
1725
  executeCommand,
1547
1726
  getSelection: () => {
1548
- if (typeof window === 'undefined')
1727
+ if (typeof window === "undefined")
1549
1728
  return null;
1550
1729
  return window.getSelection();
1551
1730
  },
@@ -1737,6 +1916,40 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
1737
1916
  }, 0);
1738
1917
  }
1739
1918
  },
1919
+ indentListItem: () => {
1920
+ const editor = editorRef.current;
1921
+ if (!editor)
1922
+ return;
1923
+ const selection = window.getSelection();
1924
+ if (selection && selection.rangeCount > 0) {
1925
+ const currentContent = domToContent(editor);
1926
+ historyRef.current.push(currentContent);
1927
+ indentListItem(selection);
1928
+ setTimeout(() => {
1929
+ if (editor) {
1930
+ const content = domToContent(editor);
1931
+ notifyChange(content);
1932
+ }
1933
+ }, 0);
1934
+ }
1935
+ },
1936
+ outdentListItem: () => {
1937
+ const editor = editorRef.current;
1938
+ if (!editor)
1939
+ return;
1940
+ const selection = window.getSelection();
1941
+ if (selection && selection.rangeCount > 0) {
1942
+ const currentContent = domToContent(editor);
1943
+ historyRef.current.push(currentContent);
1944
+ outdentListItem(selection);
1945
+ setTimeout(() => {
1946
+ if (editor) {
1947
+ const content = domToContent(editor);
1948
+ notifyChange(content);
1949
+ }
1950
+ }, 0);
1951
+ }
1952
+ },
1740
1953
  };
1741
1954
  }, [
1742
1955
  notifyChange,
@@ -1777,46 +1990,45 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
1777
1990
  const handleKeyDown = (e) => {
1778
1991
  const isModifierPressed = e.metaKey || e.ctrlKey;
1779
1992
  if (e.key === "Tab" && !isModifierPressed && !e.altKey) {
1993
+ // Immer preventDefault aufrufen (wie Lexical), damit Tab den Fokus nicht aus dem Editor entfernt
1994
+ e.preventDefault();
1995
+ e.stopPropagation();
1996
+ e.stopImmediatePropagation();
1780
1997
  const selection = window.getSelection();
1781
- const isSelectionInEditor = selection &&
1782
- selection.rangeCount > 0 &&
1783
- editor.contains(selection.getRangeAt(0).commonAncestorContainer);
1784
- const isEditorFocused = document.activeElement === editor ||
1785
- editor.contains(document.activeElement) ||
1786
- isSelectionInEditor;
1787
- if (!isEditorFocused) {
1998
+ if (!selection || selection.rangeCount === 0) {
1999
+ // Keine Selection: Tab verhindern, Fokus bleibt im Editor
1788
2000
  return;
1789
2001
  }
1790
- e.preventDefault();
1791
- e.stopPropagation();
1792
- if (isSelectionInEditor &&
1793
- selection &&
1794
- selection.rangeCount > 0) {
1795
- const range = selection.getRangeAt(0);
1796
- const container = range.commonAncestorContainer;
1797
- const listItem = container.nodeType === Node.TEXT_NODE
1798
- ? container.parentElement?.closest("li")
1799
- : container.closest("li");
1800
- if (listItem && editor.contains(listItem)) {
1801
- e.stopImmediatePropagation();
1802
- const currentContent = domToContent(editor);
1803
- historyRef.current.push(currentContent);
1804
- if (e.shiftKey) {
1805
- outdentListItem(selection);
1806
- }
1807
- else {
1808
- indentListItem(selection);
1809
- }
1810
- setTimeout(() => {
1811
- if (editor) {
1812
- const content = domToContent(editor);
1813
- notifyChange(content);
1814
- }
1815
- }, 0);
1816
- return;
2002
+ const range = selection.getRangeAt(0);
2003
+ const container = range.commonAncestorContainer;
2004
+ if (!editor.contains(container)) {
2005
+ // Container nicht im Editor: Tab verhindern
2006
+ return;
2007
+ }
2008
+ // Prüfe ob wir in einer Liste sind
2009
+ const listItem = container.nodeType === Node.TEXT_NODE
2010
+ ? container.parentElement?.closest("li")
2011
+ : container.closest("li");
2012
+ if (listItem && editor.contains(listItem)) {
2013
+ // In Liste: Indent/Outdent durchführen
2014
+ const currentContent = domToContent(editor);
2015
+ historyRef.current.push(currentContent);
2016
+ if (e.shiftKey) {
2017
+ outdentListItem(selection);
2018
+ }
2019
+ else {
2020
+ indentListItem(selection);
1817
2021
  }
2022
+ setTimeout(() => {
2023
+ if (editor) {
2024
+ const content = domToContent(editor);
2025
+ notifyChange(content);
2026
+ }
2027
+ }, 0);
2028
+ return;
1818
2029
  }
1819
- document.execCommand("insertText", false, "\t");
2030
+ // Nicht in Liste: Tab verhindern, aber kein Tab-Zeichen einfügen
2031
+ // Der Fokus bleibt im Editor (durch preventDefault)
1820
2032
  }
1821
2033
  if (isModifierPressed && e.key === "z" && !e.shiftKey) {
1822
2034
  e.preventDefault();
@@ -1831,10 +2043,10 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
1831
2043
  }
1832
2044
  };
1833
2045
  editor.addEventListener("input", handleInput);
1834
- editor.addEventListener("keydown", handleKeyDown);
2046
+ editor.addEventListener("keydown", handleKeyDown, true);
1835
2047
  return () => {
1836
2048
  editor.removeEventListener("input", handleInput);
1837
- editor.removeEventListener("keydown", handleKeyDown);
2049
+ editor.removeEventListener("keydown", handleKeyDown, true);
1838
2050
  if (inputTimeout) {
1839
2051
  clearTimeout(inputTimeout);
1840
2052
  }
@@ -1910,15 +2122,76 @@ const Editor = ({ initialContent, onChange, plugins: providedPlugins, placeholde
1910
2122
  return (jsxs("div", { className: `rte-container ${className || ""}`, style: containerStyle, children: [jsx(Toolbar, { plugins: plugins, editorAPI: editorAPI, className: toolbarClassName }), jsx("div", { ref: editorRef, contentEditable: true, className: `rte-editor ${editorClassName || ""}`, "data-placeholder": placeholder, onPaste: handlePaste, suppressContentEditableWarning: true })] }));
1911
2123
  };
1912
2124
 
2125
+ const defaultHeadings = ["h1", "h2", "h3"];
2126
+ const headingLabels = {
2127
+ h1: "Überschrift 1",
2128
+ h2: "Überschrift 2",
2129
+ h3: "Überschrift 3",
2130
+ h4: "Überschrift 4",
2131
+ h5: "Überschrift 5",
2132
+ h6: "Überschrift 6",
2133
+ };
2134
+ function createHeadingsPlugin(headings = defaultHeadings) {
2135
+ const options = [
2136
+ { value: "p", label: "Normal", headingPreview: "p" },
2137
+ ...headings.map((h) => ({
2138
+ value: h,
2139
+ label: headingLabels[h] || h.toUpperCase(),
2140
+ headingPreview: h,
2141
+ })),
2142
+ ];
2143
+ return {
2144
+ name: "headings",
2145
+ type: "block",
2146
+ renderButton: (props) => {
2147
+ // Aktuelles Heading aus State Reflection
2148
+ const currentValue = props.currentValue ||
2149
+ (props.editorAPI
2150
+ ? getCurrentHeading(props.editorAPI, headings)
2151
+ : undefined);
2152
+ return (jsx(Dropdown, { icon: "mdi:format-header-1", label: "\u00DCberschrift", options: options, onSelect: (value) => {
2153
+ if (props.onSelect) {
2154
+ props.onSelect(value);
2155
+ }
2156
+ else {
2157
+ props.onClick();
2158
+ }
2159
+ }, currentValue: currentValue, disabled: props.disabled }));
2160
+ },
2161
+ getCurrentValue: (editor) => {
2162
+ return getCurrentHeading(editor, headings);
2163
+ },
2164
+ execute: (editor, value) => {
2165
+ const tag = value || "p";
2166
+ editor.executeCommand("formatBlock", `<${tag}>`);
2167
+ },
2168
+ isActive: (editor) => {
2169
+ const selection = editor.getSelection();
2170
+ if (!selection || selection.rangeCount === 0)
2171
+ return false;
2172
+ const range = selection.getRangeAt(0);
2173
+ const container = range.commonAncestorContainer;
2174
+ const element = container.nodeType === Node.TEXT_NODE
2175
+ ? container.parentElement
2176
+ : container;
2177
+ if (!element)
2178
+ return false;
2179
+ const tagName = element.tagName.toLowerCase();
2180
+ return headings.includes(tagName);
2181
+ },
2182
+ canExecute: () => true,
2183
+ };
2184
+ }
2185
+
1913
2186
  /**
1914
2187
  * Link-Plugin mit verbesserter Funktionalität
1915
2188
  */
1916
2189
  function createLinkPlugin() {
1917
2190
  return {
1918
- name: 'link',
1919
- type: 'inline',
1920
- command: 'createLink',
1921
- renderButton: (props) => (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: jsx(IconWrapper, { icon: "mdi:link", width: 18, height: 18 }) })),
2191
+ name: "link",
2192
+ type: "inline",
2193
+ command: "createLink",
2194
+ renderButton: (props) => (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: jsx(IconWrapper, { icon: "mdi:link", width: 18, height: 18 }) })),
1922
2195
  execute: (editor) => {
1923
2196
  const selection = editor.getSelection();
1924
2197
  if (!selection || selection.rangeCount === 0)
@@ -1929,7 +2202,7 @@ function createLinkPlugin() {
1929
2202
  ? container.parentElement
1930
2203
  : container;
1931
2204
  // Prüfe ob bereits ein Link vorhanden ist
1932
- const existingLink = element?.closest('a');
2205
+ const existingLink = element?.closest("a");
1933
2206
  if (existingLink) {
1934
2207
  // Link entfernen
1935
2208
  const parent = existingLink.parentNode;
@@ -1948,9 +2221,9 @@ function createLinkPlugin() {
1948
2221
  }
1949
2222
  else {
1950
2223
  // Neuen Link einfügen
1951
- const url = prompt('URL eingeben:');
2224
+ const url = prompt("URL eingeben:");
1952
2225
  if (url) {
1953
- editor.executeCommand('createLink', url);
2226
+ editor.executeCommand("createLink", url);
1954
2227
  }
1955
2228
  }
1956
2229
  },
@@ -1965,7 +2238,7 @@ function createLinkPlugin() {
1965
2238
  : container;
1966
2239
  if (!element)
1967
2240
  return false;
1968
- return element.closest('a') !== null;
2241
+ return element.closest("a") !== null;
1969
2242
  },
1970
2243
  getCurrentValue: (editor) => {
1971
2244
  const selection = editor.getSelection();
@@ -1978,7 +2251,7 @@ function createLinkPlugin() {
1978
2251
  : container;
1979
2252
  if (!element)
1980
2253
  return undefined;
1981
- const link = element.closest('a');
2254
+ const link = element.closest("a");
1982
2255
  return link ? link.href : undefined;
1983
2256
  },
1984
2257
  canExecute: (editor) => {
@@ -1992,10 +2265,10 @@ const linkPlugin = createLinkPlugin();
1992
2265
  * Blockquote-Plugin
1993
2266
  */
1994
2267
  const blockquotePlugin = {
1995
- name: 'blockquote',
1996
- type: 'block',
1997
- command: 'formatBlock',
1998
- renderButton: (props) => (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: jsx(IconWrapper, { icon: "mdi:format-quote-close", width: 18, height: 18 }) })),
2268
+ name: "blockquote",
2269
+ type: "block",
2270
+ command: "formatBlock",
2271
+ renderButton: (props) => (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: jsx(IconWrapper, { icon: "mdi:format-quote-close", width: 18, height: 18 }) })),
1999
2272
  execute: (editor) => {
2000
2273
  const selection = editor.getSelection();
2001
2274
  if (!selection || selection.rangeCount === 0)
@@ -2007,12 +2280,12 @@ const blockquotePlugin = {
2007
2280
  : container;
2008
2281
  if (!element)
2009
2282
  return;
2010
- const isBlockquote = element.closest('blockquote') !== null;
2283
+ const isBlockquote = element.closest("blockquote") !== null;
2011
2284
  if (isBlockquote) {
2012
- editor.executeCommand('formatBlock', '<p>');
2285
+ editor.executeCommand("formatBlock", "<p>");
2013
2286
  }
2014
2287
  else {
2015
- editor.executeCommand('formatBlock', '<blockquote>');
2288
+ editor.executeCommand("formatBlock", "<blockquote>");
2016
2289
  }
2017
2290
  },
2018
2291
  isActive: (editor) => {
@@ -2026,7 +2299,7 @@ const blockquotePlugin = {
2026
2299
  : container;
2027
2300
  if (!element)
2028
2301
  return false;
2029
- return element.closest('blockquote') !== null;
2302
+ return element.closest("blockquote") !== null;
2030
2303
  },
2031
2304
  canExecute: (editor) => {
2032
2305
  const selection = editor.getSelection();
@@ -2037,17 +2310,17 @@ const blockquotePlugin = {
2037
2310
  * Unordered List Plugin
2038
2311
  */
2039
2312
  const unorderedListPlugin = {
2040
- name: 'unorderedList',
2041
- type: 'block',
2042
- command: 'insertUnorderedList',
2043
- renderButton: (props) => (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: jsx(IconWrapper, { icon: "mdi:format-list-bulleted", width: 18, height: 18 }) })),
2313
+ name: "unorderedList",
2314
+ type: "block",
2315
+ command: "insertUnorderedList",
2316
+ renderButton: (props) => (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: jsx(IconWrapper, { icon: "mdi:format-list-bulleted", width: 18, height: 18 }) })),
2044
2317
  execute: (editor) => {
2045
- editor.executeCommand('insertUnorderedList');
2318
+ editor.executeCommand("insertUnorderedList");
2046
2319
  },
2047
2320
  isActive: (editor) => {
2048
- if (typeof document === 'undefined')
2321
+ if (typeof document === "undefined")
2049
2322
  return false;
2050
- return document.queryCommandState('insertUnorderedList');
2323
+ return document.queryCommandState("insertUnorderedList");
2051
2324
  },
2052
2325
  canExecute: (editor) => {
2053
2326
  const selection = editor.getSelection();
@@ -2058,17 +2331,17 @@ const unorderedListPlugin = {
2058
2331
  * Ordered List Plugin
2059
2332
  */
2060
2333
  const orderedListPlugin = {
2061
- name: 'orderedList',
2062
- type: 'block',
2063
- command: 'insertOrderedList',
2064
- renderButton: (props) => (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: jsx(IconWrapper, { icon: "mdi:format-list-numbered", width: 18, height: 18 }) })),
2334
+ name: "orderedList",
2335
+ type: "block",
2336
+ command: "insertOrderedList",
2337
+ renderButton: (props) => (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: jsx(IconWrapper, { icon: "mdi:format-list-numbered", width: 18, height: 18 }) })),
2065
2338
  execute: (editor) => {
2066
- editor.executeCommand('insertOrderedList');
2339
+ editor.executeCommand("insertOrderedList");
2067
2340
  },
2068
2341
  isActive: (editor) => {
2069
- if (typeof document === 'undefined')
2342
+ if (typeof document === "undefined")
2070
2343
  return false;
2071
- return document.queryCommandState('insertOrderedList');
2344
+ return document.queryCommandState("insertOrderedList");
2072
2345
  },
2073
2346
  canExecute: (editor) => {
2074
2347
  const selection = editor.getSelection();
@@ -2076,5 +2349,5 @@ const orderedListPlugin = {
2076
2349
  },
2077
2350
  };
2078
2351
 
2079
- export { Dropdown, Editor, HistoryManager, Toolbar, blockquotePlugin, boldPlugin, clearFormattingPlugin, contentToDOM, contentToHTML, createBackgroundColorPlugin, createEmptyContent, createFontSizePlugin, createHeadingsPlugin, createImagePlugin, createLinkPlugin, createTextColorPlugin, Editor as default, defaultPlugins, domToContent, getCurrentBackgroundColor, getCurrentFontSize, getCurrentHeading, getCurrentTextColor, htmlToContent, indentListItem, italicPlugin, linkPlugin, orderedListPlugin, outdentListItem, redoPlugin, underlinePlugin, undoPlugin, unorderedListPlugin };
2352
+ export { Dropdown, Editor, HistoryManager, Toolbar, blockquotePlugin, boldPlugin, clearFormattingPlugin, contentToDOM, contentToHTML, createBackgroundColorPlugin, createBlockFormatPlugin, createEmptyContent, createFontSizePlugin, createHeadingsPlugin, createImagePlugin, createLinkPlugin, createTextColorPlugin, Editor as default, defaultPlugins, domToContent, getCurrentBackgroundColor, getCurrentFontSize, getCurrentHeading, getCurrentTextColor, htmlToContent, indentListItem, indentListItemPlugin, italicPlugin, linkPlugin, orderedListPlugin, outdentListItem, outdentListItemPlugin, redoPlugin, underlinePlugin, undoPlugin, unorderedListPlugin };
2080
2353
  //# sourceMappingURL=index.esm.js.map