@overlap/rte 1.0.8 → 1.0.10
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/components/Dropdown.d.ts.map +1 -1
- package/dist/components/FloatingToolbar.d.ts.map +1 -1
- package/dist/hooks/useEditorEvents.d.ts.map +1 -1
- package/dist/index.esm.js +188 -33
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +187 -32
- package/dist/index.js.map +1 -1
- package/dist/plugins/table.d.ts.map +1 -1
- package/dist/styles.css +21 -17
- package/dist/utils/content.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -87,10 +87,45 @@ const Icon = ({ icon, width = 18, height = 18, className }) => {
|
|
|
87
87
|
const Dropdown = ({ icon, label, options, onSelect, currentValue, disabled, showCustomColorInput, }) => {
|
|
88
88
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
89
89
|
const [customColor, setCustomColor] = React.useState("#000000");
|
|
90
|
+
const [menuPos, setMenuPos] = React.useState({ top: 0, left: 0 });
|
|
90
91
|
const dropdownRef = React.useRef(null);
|
|
92
|
+
const menuRef = React.useRef(null);
|
|
93
|
+
const buttonRef = React.useRef(null);
|
|
94
|
+
const updateMenuPosition = React.useCallback(() => {
|
|
95
|
+
if (!buttonRef.current)
|
|
96
|
+
return;
|
|
97
|
+
const rect = buttonRef.current.getBoundingClientRect();
|
|
98
|
+
const pad = 8;
|
|
99
|
+
let top = rect.bottom + 4;
|
|
100
|
+
let left = rect.left;
|
|
101
|
+
const menuEl = menuRef.current;
|
|
102
|
+
if (menuEl) {
|
|
103
|
+
const menuW = menuEl.offsetWidth;
|
|
104
|
+
const menuH = menuEl.offsetHeight;
|
|
105
|
+
if (left + menuW > window.innerWidth - pad) {
|
|
106
|
+
left = window.innerWidth - menuW - pad;
|
|
107
|
+
}
|
|
108
|
+
if (left < pad)
|
|
109
|
+
left = pad;
|
|
110
|
+
if (top + menuH > window.innerHeight - pad) {
|
|
111
|
+
top = rect.top - menuH - 4;
|
|
112
|
+
}
|
|
113
|
+
if (top < pad)
|
|
114
|
+
top = pad;
|
|
115
|
+
}
|
|
116
|
+
setMenuPos({ top, left });
|
|
117
|
+
}, []);
|
|
118
|
+
React.useEffect(() => {
|
|
119
|
+
if (!isOpen)
|
|
120
|
+
return;
|
|
121
|
+
updateMenuPosition();
|
|
122
|
+
requestAnimationFrame(updateMenuPosition);
|
|
123
|
+
}, [isOpen, updateMenuPosition]);
|
|
91
124
|
React.useEffect(() => {
|
|
92
125
|
const handleClickOutside = (event) => {
|
|
93
|
-
|
|
126
|
+
const target = event.target;
|
|
127
|
+
if (dropdownRef.current && !dropdownRef.current.contains(target) &&
|
|
128
|
+
(!menuRef.current || !menuRef.current.contains(target))) {
|
|
94
129
|
setIsOpen(false);
|
|
95
130
|
}
|
|
96
131
|
};
|
|
@@ -106,7 +141,6 @@ const Dropdown = ({ icon, label, options, onSelect, currentValue, disabled, show
|
|
|
106
141
|
setIsOpen(false);
|
|
107
142
|
};
|
|
108
143
|
const currentOption = options.find(opt => opt.value === currentValue);
|
|
109
|
-
// Close on Escape key
|
|
110
144
|
React.useEffect(() => {
|
|
111
145
|
if (!isOpen)
|
|
112
146
|
return;
|
|
@@ -119,21 +153,26 @@ const Dropdown = ({ icon, label, options, onSelect, currentValue, disabled, show
|
|
|
119
153
|
document.addEventListener("keydown", handleKeyDown);
|
|
120
154
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
121
155
|
}, [isOpen]);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
156
|
+
const menuContent = isOpen ? (jsxRuntime.jsxs("div", { ref: menuRef, className: "rte-dropdown-menu", role: "listbox", "aria-label": label, style: {
|
|
157
|
+
position: 'fixed',
|
|
158
|
+
top: menuPos.top,
|
|
159
|
+
left: menuPos.left,
|
|
160
|
+
}, onMouseDown: (e) => e.preventDefault(), children: [options.map((option) => (jsxRuntime.jsxs("button", { type: "button", role: "option", "aria-selected": currentValue === option.value, 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))), showCustomColorInput && (jsxRuntime.jsxs("div", { className: "rte-color-custom-input", onMouseDown: (e) => e.stopPropagation(), children: [jsxRuntime.jsx("input", { type: "color", value: customColor, onChange: (e) => setCustomColor(e.target.value), title: "Pick a color" }), jsxRuntime.jsx("input", { type: "text", value: customColor, onChange: (e) => {
|
|
161
|
+
const v = e.target.value;
|
|
162
|
+
setCustomColor(v);
|
|
163
|
+
}, placeholder: "#000000", maxLength: 7, onKeyDown: (e) => {
|
|
164
|
+
if (e.key === "Enter") {
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
if (/^#[0-9a-fA-F]{3,6}$/.test(customColor)) {
|
|
167
|
+
handleSelect(customColor);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
} }), jsxRuntime.jsx("button", { type: "button", className: "rte-color-custom-apply", onClick: () => {
|
|
171
|
+
if (/^#[0-9a-fA-F]{3,6}$/.test(customColor)) {
|
|
172
|
+
handleSelect(customColor);
|
|
173
|
+
}
|
|
174
|
+
}, children: "Apply" })] }))] })) : null;
|
|
175
|
+
return (jsxRuntime.jsxs("div", { className: "rte-dropdown", ref: dropdownRef, onMouseDown: (e) => e.preventDefault(), children: [jsxRuntime.jsxs("button", { ref: buttonRef, 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, "aria-expanded": isOpen, "aria-haspopup": "listbox", children: [jsxRuntime.jsx(Icon, { icon: icon, width: 18, height: 18 }), currentOption && (jsxRuntime.jsx("span", { className: "rte-dropdown-value", children: currentOption.label }))] }), menuContent && reactDom.createPortal(menuContent, document.body)] }));
|
|
137
176
|
};
|
|
138
177
|
|
|
139
178
|
/**
|
|
@@ -808,7 +847,7 @@ const ALLOWED_CONTENT_TAGS = new Set([
|
|
|
808
847
|
"ul", "ol", "li", "a", "strong", "em", "u", "s", "del",
|
|
809
848
|
"sub", "sup", "code", "pre", "blockquote", "br", "hr",
|
|
810
849
|
"img", "table", "thead", "tbody", "tr", "th", "td",
|
|
811
|
-
"b", "i", "strike",
|
|
850
|
+
"b", "i", "strike", "font",
|
|
812
851
|
]);
|
|
813
852
|
/** Checks if an attribute key is safe to set on a DOM element. */
|
|
814
853
|
function isSafeAttribute(key) {
|
|
@@ -1016,6 +1055,7 @@ function domToContent(element) {
|
|
|
1016
1055
|
"sub",
|
|
1017
1056
|
"sup",
|
|
1018
1057
|
"code",
|
|
1058
|
+
"font",
|
|
1019
1059
|
].includes(tagName)) {
|
|
1020
1060
|
const children = [];
|
|
1021
1061
|
Array.from(el.childNodes).forEach((child) => {
|
|
@@ -1105,6 +1145,46 @@ function domToContent(element) {
|
|
|
1105
1145
|
});
|
|
1106
1146
|
}
|
|
1107
1147
|
}
|
|
1148
|
+
// <font> from execCommand('foreColor') or pasted HTML
|
|
1149
|
+
if (tagName === "font") {
|
|
1150
|
+
const fontAttrs = {};
|
|
1151
|
+
const colorAttr = el.getAttribute("color");
|
|
1152
|
+
if (colorAttr)
|
|
1153
|
+
fontAttrs.color = colorAttr;
|
|
1154
|
+
const sizeAttr = el.getAttribute("size");
|
|
1155
|
+
if (sizeAttr) {
|
|
1156
|
+
const sizeMap = {
|
|
1157
|
+
"1": "10px", "2": "13px", "3": "16px", "4": "18px",
|
|
1158
|
+
"5": "24px", "6": "32px", "7": "48px",
|
|
1159
|
+
};
|
|
1160
|
+
const mapped = sizeMap[sizeAttr];
|
|
1161
|
+
if (mapped)
|
|
1162
|
+
fontAttrs.fontSize = mapped;
|
|
1163
|
+
}
|
|
1164
|
+
const style = el.getAttribute("style") || "";
|
|
1165
|
+
if (style) {
|
|
1166
|
+
style.split(";").forEach((rule) => {
|
|
1167
|
+
const [key, value] = rule
|
|
1168
|
+
.split(":")
|
|
1169
|
+
.map((s) => s.trim());
|
|
1170
|
+
if (key && value) {
|
|
1171
|
+
if (key === "font-size")
|
|
1172
|
+
fontAttrs.fontSize = value;
|
|
1173
|
+
else if (key === "color")
|
|
1174
|
+
fontAttrs.color = value;
|
|
1175
|
+
else if (key === "background-color")
|
|
1176
|
+
fontAttrs.backgroundColor = value;
|
|
1177
|
+
}
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
return {
|
|
1181
|
+
type: "span",
|
|
1182
|
+
children: children.length > 0 ? children : undefined,
|
|
1183
|
+
attributes: Object.keys(fontAttrs).length > 0
|
|
1184
|
+
? fontAttrs
|
|
1185
|
+
: undefined,
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1108
1188
|
// Map tag names to semantic types
|
|
1109
1189
|
const type = tagName === "strong" || tagName === "b"
|
|
1110
1190
|
? "bold"
|
|
@@ -2123,6 +2203,61 @@ function useEditorEvents({ editorRef, historyRef, isUpdatingRef, mountedRef, not
|
|
|
2123
2203
|
}, 0);
|
|
2124
2204
|
return;
|
|
2125
2205
|
}
|
|
2206
|
+
// Exit code block: Enter on empty last line escapes <pre>
|
|
2207
|
+
if (e.key === "Enter" &&
|
|
2208
|
+
!e.shiftKey &&
|
|
2209
|
+
!isModifierPressed) {
|
|
2210
|
+
const sel = window.getSelection();
|
|
2211
|
+
if (sel && sel.rangeCount > 0 && sel.isCollapsed) {
|
|
2212
|
+
const range = sel.getRangeAt(0);
|
|
2213
|
+
const node = range.startContainer;
|
|
2214
|
+
const pre = (node instanceof HTMLElement
|
|
2215
|
+
? node
|
|
2216
|
+
: node.parentElement)?.closest("pre");
|
|
2217
|
+
if (pre && pre.lastChild) {
|
|
2218
|
+
const lastChild = pre.lastChild;
|
|
2219
|
+
const cursorInPre = node === pre &&
|
|
2220
|
+
range.startOffset === pre.childNodes.length;
|
|
2221
|
+
const cursorAtEndOfLastText = node.nodeType === Node.TEXT_NODE &&
|
|
2222
|
+
node === lastChild &&
|
|
2223
|
+
range.startOffset ===
|
|
2224
|
+
(node.textContent?.length ?? 0);
|
|
2225
|
+
const isAtEnd = cursorInPre || cursorAtEndOfLastText;
|
|
2226
|
+
const lastIsBr = lastChild instanceof HTMLElement &&
|
|
2227
|
+
lastChild.tagName === "BR";
|
|
2228
|
+
const endsWithNewline = node.nodeType === Node.TEXT_NODE &&
|
|
2229
|
+
(node.textContent || "").endsWith("\n");
|
|
2230
|
+
if (isAtEnd && (lastIsBr || endsWithNewline)) {
|
|
2231
|
+
e.preventDefault();
|
|
2232
|
+
if (lastIsBr) {
|
|
2233
|
+
pre.removeChild(lastChild);
|
|
2234
|
+
}
|
|
2235
|
+
else if (node.nodeType === Node.TEXT_NODE &&
|
|
2236
|
+
node.textContent) {
|
|
2237
|
+
node.textContent =
|
|
2238
|
+
node.textContent.replace(/\n$/, "");
|
|
2239
|
+
}
|
|
2240
|
+
if (!pre.textContent &&
|
|
2241
|
+
!pre.querySelector("br")) {
|
|
2242
|
+
pre.appendChild(document.createElement("br"));
|
|
2243
|
+
}
|
|
2244
|
+
const p = document.createElement("p");
|
|
2245
|
+
p.appendChild(document.createElement("br"));
|
|
2246
|
+
pre.parentNode?.insertBefore(p, pre.nextSibling);
|
|
2247
|
+
const newRange = document.createRange();
|
|
2248
|
+
newRange.setStart(p, 0);
|
|
2249
|
+
newRange.collapse(true);
|
|
2250
|
+
sel.removeAllRanges();
|
|
2251
|
+
sel.addRange(newRange);
|
|
2252
|
+
const content = domToContent(editor);
|
|
2253
|
+
const serializedSel = serializeSelection(editor);
|
|
2254
|
+
historyRef.current.push(content, serializedSel);
|
|
2255
|
+
notifyChange(content);
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2126
2261
|
// Auto-link: convert URLs to <a> tags on space/enter
|
|
2127
2262
|
if (!isModifierPressed && (e.key === " " || e.key === "Enter")) {
|
|
2128
2263
|
handleAutoLink(editor, e);
|
|
@@ -4017,7 +4152,7 @@ function createAdvancedLinkPlugin(options = {}) {
|
|
|
4017
4152
|
/** Pre-built link plugin with just target enabled (no custom fields). */
|
|
4018
4153
|
const advancedLinkPlugin = createAdvancedLinkPlugin();
|
|
4019
4154
|
|
|
4020
|
-
const InsertTableDialog = ({ onInsert, onClose, }) => {
|
|
4155
|
+
const InsertTableDialog = ({ onInsert, onClose, anchorRect, }) => {
|
|
4021
4156
|
const [rows, setRows] = React.useState(3);
|
|
4022
4157
|
const [cols, setCols] = React.useState(3);
|
|
4023
4158
|
const dialogRef = React.useRef(null);
|
|
@@ -4031,7 +4166,25 @@ const InsertTableDialog = ({ onInsert, onClose, }) => {
|
|
|
4031
4166
|
document.addEventListener("mousedown", handler);
|
|
4032
4167
|
return () => document.removeEventListener("mousedown", handler);
|
|
4033
4168
|
}, [onClose]);
|
|
4034
|
-
|
|
4169
|
+
const style = { position: "fixed" };
|
|
4170
|
+
if (anchorRect) {
|
|
4171
|
+
const pad = 8;
|
|
4172
|
+
let top = anchorRect.bottom + 4;
|
|
4173
|
+
let left = anchorRect.left;
|
|
4174
|
+
if (left + 220 > window.innerWidth - pad) {
|
|
4175
|
+
left = window.innerWidth - 220 - pad;
|
|
4176
|
+
}
|
|
4177
|
+
if (left < pad)
|
|
4178
|
+
left = pad;
|
|
4179
|
+
if (top + 200 > window.innerHeight - pad) {
|
|
4180
|
+
top = anchorRect.top - 200 - 4;
|
|
4181
|
+
}
|
|
4182
|
+
if (top < pad)
|
|
4183
|
+
top = pad;
|
|
4184
|
+
style.top = top;
|
|
4185
|
+
style.left = left;
|
|
4186
|
+
}
|
|
4187
|
+
return reactDom.createPortal(jsxRuntime.jsxs("div", { className: "rte-table-insert-dialog", ref: dialogRef, style: style, onMouseDown: (e) => e.preventDefault(), children: [jsxRuntime.jsx("div", { className: "rte-table-insert-title", children: "Insert Table" }), jsxRuntime.jsxs("div", { className: "rte-table-insert-fields", children: [jsxRuntime.jsxs("label", { className: "rte-table-insert-label", children: [jsxRuntime.jsx("span", { children: "Zeilen" }), jsxRuntime.jsx("input", { type: "number", min: 1, max: 20, value: rows, onChange: (e) => setRows(Math.max(1, Math.min(20, parseInt(e.target.value) || 1))), className: "rte-table-insert-input", onMouseDown: (e) => e.stopPropagation() })] }), jsxRuntime.jsxs("label", { className: "rte-table-insert-label", children: [jsxRuntime.jsx("span", { children: "Spalten" }), jsxRuntime.jsx("input", { type: "number", min: 1, max: 10, value: cols, onChange: (e) => setCols(Math.max(1, Math.min(10, parseInt(e.target.value) || 1))), className: "rte-table-insert-input", onMouseDown: (e) => e.stopPropagation() })] })] }), jsxRuntime.jsx("button", { type: "button", className: "rte-table-insert-btn", onClick: () => onInsert(rows, cols), children: "Insert" })] }), document.body);
|
|
4035
4188
|
};
|
|
4036
4189
|
const TableContextMenu = ({ x, y, onClose, }) => {
|
|
4037
4190
|
const ref = React.useRef(null);
|
|
@@ -4052,6 +4205,14 @@ const TableContextMenu = ({ x, y, onClose, }) => {
|
|
|
4052
4205
|
};
|
|
4053
4206
|
const TableToolbarButton = (props) => {
|
|
4054
4207
|
const [showDialog, setShowDialog] = React.useState(false);
|
|
4208
|
+
const btnRef = React.useRef(null);
|
|
4209
|
+
const [anchorRect, setAnchorRect] = React.useState(null);
|
|
4210
|
+
const handleToggle = React.useCallback(() => {
|
|
4211
|
+
if (!showDialog && btnRef.current) {
|
|
4212
|
+
setAnchorRect(btnRef.current.getBoundingClientRect());
|
|
4213
|
+
}
|
|
4214
|
+
setShowDialog((v) => !v);
|
|
4215
|
+
}, [showDialog]);
|
|
4055
4216
|
const handleInsert = React.useCallback((rows, cols) => {
|
|
4056
4217
|
setShowDialog(false);
|
|
4057
4218
|
if (!props.editorAPI)
|
|
@@ -4060,7 +4221,6 @@ const TableToolbarButton = (props) => {
|
|
|
4060
4221
|
if (!sel || sel.rangeCount === 0)
|
|
4061
4222
|
return;
|
|
4062
4223
|
const range = sel.getRangeAt(0);
|
|
4063
|
-
// Find the editor's contentEditable root
|
|
4064
4224
|
const container = range.commonAncestorContainer;
|
|
4065
4225
|
const editorEl = container.nodeType === Node.TEXT_NODE
|
|
4066
4226
|
? container.parentElement
|
|
@@ -4069,7 +4229,6 @@ const TableToolbarButton = (props) => {
|
|
|
4069
4229
|
if (!editorRoot)
|
|
4070
4230
|
return;
|
|
4071
4231
|
const table = createTable(rows, cols);
|
|
4072
|
-
// Insert after the current block element
|
|
4073
4232
|
let block = editorEl;
|
|
4074
4233
|
while (block &&
|
|
4075
4234
|
block !== editorRoot &&
|
|
@@ -4082,11 +4241,9 @@ const TableToolbarButton = (props) => {
|
|
|
4082
4241
|
else {
|
|
4083
4242
|
editorRoot.appendChild(table);
|
|
4084
4243
|
}
|
|
4085
|
-
// Add a paragraph after the table so the user can continue typing
|
|
4086
4244
|
const p = document.createElement("p");
|
|
4087
4245
|
p.innerHTML = "<br>";
|
|
4088
4246
|
table.parentNode?.insertBefore(p, table.nextSibling);
|
|
4089
|
-
// Focus the first cell
|
|
4090
4247
|
const firstCell = table.querySelector("td, th");
|
|
4091
4248
|
if (firstCell) {
|
|
4092
4249
|
const newRange = document.createRange();
|
|
@@ -4096,7 +4253,7 @@ const TableToolbarButton = (props) => {
|
|
|
4096
4253
|
sel.addRange(newRange);
|
|
4097
4254
|
}
|
|
4098
4255
|
}, [props.editorAPI]);
|
|
4099
|
-
return (jsxRuntime.jsxs(
|
|
4256
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { ref: btnRef, type: "button", onClick: handleToggle, disabled: props.disabled, className: `rte-toolbar-button ${props.isActive ? "rte-toolbar-button-active" : ""}`, title: "Table", "aria-label": "Table", children: jsxRuntime.jsx(IconWrapper, { icon: "mdi:table", width: 18, height: 18 }) }), showDialog && (jsxRuntime.jsx(InsertTableDialog, { onInsert: handleInsert, onClose: () => setShowDialog(false), anchorRect: anchorRect }))] }));
|
|
4100
4257
|
};
|
|
4101
4258
|
/* ══════════════════════════════════════════════════════════════════════════
|
|
4102
4259
|
Table Plugin export
|
|
@@ -4306,10 +4463,10 @@ const FloatingToolbar = ({ plugins, editorAPI, editorElement, }) => {
|
|
|
4306
4463
|
}
|
|
4307
4464
|
// Center horizontally on the selection, clamp to viewport
|
|
4308
4465
|
let left = rect.left + rect.width / 2 - toolbarW / 2;
|
|
4309
|
-
if (left < pad)
|
|
4310
|
-
left = pad;
|
|
4311
4466
|
if (left + toolbarW > vw - pad)
|
|
4312
4467
|
left = vw - toolbarW - pad;
|
|
4468
|
+
if (left < pad)
|
|
4469
|
+
left = pad;
|
|
4313
4470
|
setPos({ top, left, visible: true });
|
|
4314
4471
|
}, [editorElement]);
|
|
4315
4472
|
// Debounce via requestAnimationFrame for smooth repositioning
|
|
@@ -4354,16 +4511,14 @@ const FloatingToolbar = ({ plugins, editorAPI, editorElement, }) => {
|
|
|
4354
4511
|
requestAnimationFrame(() => scheduleUpdate());
|
|
4355
4512
|
}, [editorAPI, scheduleUpdate]);
|
|
4356
4513
|
const isHidden = !pos.visible || leftPlugins.length === 0;
|
|
4357
|
-
return (jsxRuntime.jsx("div", { ref: toolbarRef, className: "rte-floating-toolbar", style: {
|
|
4514
|
+
return reactDom.createPortal(jsxRuntime.jsx("div", { ref: toolbarRef, className: "rte-floating-toolbar", style: {
|
|
4358
4515
|
position: "fixed",
|
|
4359
4516
|
top: pos.top,
|
|
4360
4517
|
left: pos.left,
|
|
4361
4518
|
visibility: isHidden ? "hidden" : "visible",
|
|
4362
4519
|
opacity: isHidden ? 0 : 1,
|
|
4363
4520
|
pointerEvents: isHidden ? "none" : "auto",
|
|
4364
|
-
},
|
|
4365
|
-
// Prevent selection loss when clicking toolbar buttons
|
|
4366
|
-
onMouseDown: (e) => e.preventDefault(), children: jsxRuntime.jsxs("div", { className: "rte-floating-toolbar-content", children: [jsxRuntime.jsx("div", { className: "rte-toolbar-left", children: leftPlugins.map((plugin) => {
|
|
4521
|
+
}, onMouseDown: (e) => e.preventDefault(), children: jsxRuntime.jsxs("div", { className: "rte-floating-toolbar-content", children: [jsxRuntime.jsx("div", { className: "rte-toolbar-left", children: leftPlugins.map((plugin) => {
|
|
4367
4522
|
if (!plugin.renderButton)
|
|
4368
4523
|
return null;
|
|
4369
4524
|
const isActive = plugin.isActive
|
|
@@ -4397,7 +4552,7 @@ const FloatingToolbar = ({ plugins, editorAPI, editorElement, }) => {
|
|
|
4397
4552
|
disabled: !canExecute,
|
|
4398
4553
|
editorAPI,
|
|
4399
4554
|
});
|
|
4400
|
-
})()] }))] }) }));
|
|
4555
|
+
})()] }))] }) }), document.body);
|
|
4401
4556
|
};
|
|
4402
4557
|
|
|
4403
4558
|
/**
|