@tarviks/lexical-rich-editor 1.3.9 → 1.3.11
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.js +91 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +91 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -885,6 +885,7 @@ var init_InlineImageComponent = __esm({
|
|
|
885
885
|
"data-position": position,
|
|
886
886
|
style: {
|
|
887
887
|
display: "block",
|
|
888
|
+
maxWidth: "100%",
|
|
888
889
|
height,
|
|
889
890
|
width
|
|
890
891
|
},
|
|
@@ -1074,14 +1075,17 @@ var init_InlineImageComponent = __esm({
|
|
|
1074
1075
|
InlineImageComponent_default = InlineImageComponent;
|
|
1075
1076
|
}
|
|
1076
1077
|
});
|
|
1077
|
-
var InlineImageComponent2, $convertInlineImageElement, InlineImageNode, $createInlineImageNode, $isInlineImageNode;
|
|
1078
|
+
var InlineImageComponent2, INLINE_IMAGE_MARKER_ATTR, $convertInlineImageElement, InlineImageNode, $createInlineImageNode, $isInlineImageNode;
|
|
1078
1079
|
var init_InlineImageNode = __esm({
|
|
1079
1080
|
"src/Nodes/InlineImageNode.tsx"() {
|
|
1080
1081
|
InlineImageComponent2 = React9.lazy(() => Promise.resolve().then(() => (init_InlineImageComponent(), InlineImageComponent_exports)));
|
|
1082
|
+
INLINE_IMAGE_MARKER_ATTR = "data-lexical-inline-image";
|
|
1081
1083
|
$convertInlineImageElement = (domNode) => {
|
|
1082
1084
|
if (isHTMLElement(domNode) && domNode.nodeName === "IMG") {
|
|
1083
1085
|
const { alt: altText, src, width, height } = domNode;
|
|
1084
|
-
const
|
|
1086
|
+
const positionAttr = domNode.getAttribute("data-position");
|
|
1087
|
+
const position = positionAttr === "left" || positionAttr === "right" || positionAttr === "full" ? positionAttr : void 0;
|
|
1088
|
+
const node = $createInlineImageNode({ altText, height, position, src, width });
|
|
1085
1089
|
return { node };
|
|
1086
1090
|
}
|
|
1087
1091
|
return null;
|
|
@@ -1125,10 +1129,15 @@ var init_InlineImageNode = __esm({
|
|
|
1125
1129
|
}
|
|
1126
1130
|
static importDOM() {
|
|
1127
1131
|
return {
|
|
1128
|
-
img: (node) =>
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
+
img: (node) => {
|
|
1133
|
+
if (isHTMLElement(node) && node.hasAttribute(INLINE_IMAGE_MARKER_ATTR)) {
|
|
1134
|
+
return {
|
|
1135
|
+
conversion: $convertInlineImageElement,
|
|
1136
|
+
priority: 3
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
return null;
|
|
1140
|
+
}
|
|
1132
1141
|
};
|
|
1133
1142
|
}
|
|
1134
1143
|
constructor(src, altText, position, width, height, showCaption, caption, key) {
|
|
@@ -1147,6 +1156,11 @@ var init_InlineImageNode = __esm({
|
|
|
1147
1156
|
element.setAttribute("alt", this.__altText);
|
|
1148
1157
|
element.setAttribute("width", this.__width.toString());
|
|
1149
1158
|
element.setAttribute("height", this.__height.toString());
|
|
1159
|
+
element.setAttribute(INLINE_IMAGE_MARKER_ATTR, "true");
|
|
1160
|
+
if (this.__position) {
|
|
1161
|
+
element.setAttribute("data-position", this.__position);
|
|
1162
|
+
_InlineImageNode.applyPositionStyle(element, this.__position);
|
|
1163
|
+
}
|
|
1150
1164
|
return { element };
|
|
1151
1165
|
}
|
|
1152
1166
|
exportJSON() {
|
|
@@ -1204,12 +1218,34 @@ var init_InlineImageNode = __esm({
|
|
|
1204
1218
|
}
|
|
1205
1219
|
}
|
|
1206
1220
|
// View
|
|
1221
|
+
// The position-left/right/full behavior is also defined in the package's
|
|
1222
|
+
// CSS file as `.inline-editor-image.position-*` rules, but that file is a
|
|
1223
|
+
// separate import (`@tarviks/lexical-rich-editor/dist/index.css`) a
|
|
1224
|
+
// consuming app can forget to include. Applying it as inline styles here
|
|
1225
|
+
// too means positioning still works even when that stylesheet isn't
|
|
1226
|
+
// loaded, instead of silently no-op'ing back to normal block flow.
|
|
1227
|
+
static applyPositionStyle(span, position) {
|
|
1228
|
+
span.style.removeProperty("float");
|
|
1229
|
+
span.style.removeProperty("display");
|
|
1230
|
+
span.style.removeProperty("margin");
|
|
1231
|
+
if (position === "left") {
|
|
1232
|
+
span.style.float = "left";
|
|
1233
|
+
span.style.margin = "4px 8px 4px 0";
|
|
1234
|
+
} else if (position === "right") {
|
|
1235
|
+
span.style.float = "right";
|
|
1236
|
+
span.style.margin = "4px 0 4px 8px";
|
|
1237
|
+
} else if (position === "full") {
|
|
1238
|
+
span.style.display = "block";
|
|
1239
|
+
span.style.margin = "8px 0";
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1207
1242
|
createDOM(config) {
|
|
1208
1243
|
const span = document.createElement("span");
|
|
1209
1244
|
const className = `${config.theme.inlineImage} position-${this.__position}`;
|
|
1210
1245
|
if (className !== void 0) {
|
|
1211
1246
|
span.className = className;
|
|
1212
1247
|
}
|
|
1248
|
+
_InlineImageNode.applyPositionStyle(span, this.__position);
|
|
1213
1249
|
return span;
|
|
1214
1250
|
}
|
|
1215
1251
|
updateDOM(prevNode, dom, config) {
|
|
@@ -1219,6 +1255,7 @@ var init_InlineImageNode = __esm({
|
|
|
1219
1255
|
if (className !== void 0) {
|
|
1220
1256
|
dom.className = className;
|
|
1221
1257
|
}
|
|
1258
|
+
_InlineImageNode.applyPositionStyle(dom, position);
|
|
1222
1259
|
}
|
|
1223
1260
|
return false;
|
|
1224
1261
|
}
|
|
@@ -2945,6 +2982,8 @@ var ALLOWED_ATTRS = /* @__PURE__ */ new Set([
|
|
|
2945
2982
|
"data-lex-block",
|
|
2946
2983
|
"data-kind",
|
|
2947
2984
|
"data-lexical-decorator",
|
|
2985
|
+
"data-lexical-inline-image",
|
|
2986
|
+
"data-position",
|
|
2948
2987
|
// Misc
|
|
2949
2988
|
"title",
|
|
2950
2989
|
"allowfullscreen"
|
|
@@ -5099,11 +5138,35 @@ function SpellCheckPlugin({
|
|
|
5099
5138
|
}
|
|
5100
5139
|
) : null;
|
|
5101
5140
|
}
|
|
5141
|
+
function getScrollClipAncestor(el) {
|
|
5142
|
+
let node = el.parentElement;
|
|
5143
|
+
while (node) {
|
|
5144
|
+
const style = getComputedStyle(node);
|
|
5145
|
+
if ((style.overflowY === "auto" || style.overflowY === "scroll") && node.scrollHeight > node.clientHeight) {
|
|
5146
|
+
return node;
|
|
5147
|
+
}
|
|
5148
|
+
node = node.parentElement;
|
|
5149
|
+
}
|
|
5150
|
+
return null;
|
|
5151
|
+
}
|
|
5152
|
+
function isRectVisible(rect, cellDom) {
|
|
5153
|
+
if (rect.width === 0 && rect.height === 0) return false;
|
|
5154
|
+
if (rect.bottom <= 0 || rect.top >= window.innerHeight) return false;
|
|
5155
|
+
if (rect.right <= 0 || rect.left >= window.innerWidth) return false;
|
|
5156
|
+
const clipAncestor = getScrollClipAncestor(cellDom);
|
|
5157
|
+
if (clipAncestor) {
|
|
5158
|
+
const containerRect = clipAncestor.getBoundingClientRect();
|
|
5159
|
+
if (rect.bottom <= containerRect.top || rect.top >= containerRect.bottom) return false;
|
|
5160
|
+
if (rect.right <= containerRect.left || rect.left >= containerRect.right) return false;
|
|
5161
|
+
}
|
|
5162
|
+
return true;
|
|
5163
|
+
}
|
|
5102
5164
|
function TableActionMenuPlugin({ disabled = false }) {
|
|
5103
5165
|
const [editor] = useLexicalComposerContext();
|
|
5104
5166
|
const portalContainer = useFloatingPortalContainer(editor);
|
|
5105
5167
|
const [isInTable, setIsInTable] = React9.useState(false);
|
|
5106
5168
|
const [anchorRect, setAnchorRect] = React9.useState(null);
|
|
5169
|
+
const [isAnchorVisible, setIsAnchorVisible] = React9.useState(false);
|
|
5107
5170
|
const [contentRight, setContentRight] = React9.useState(null);
|
|
5108
5171
|
const [open, setOpen] = React9.useState(false);
|
|
5109
5172
|
const openRef = React9.useRef(false);
|
|
@@ -5129,8 +5192,10 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5129
5192
|
if (tableNode) {
|
|
5130
5193
|
const dom = editor.getElementByKey(tableNode.getKey());
|
|
5131
5194
|
if (dom) {
|
|
5195
|
+
const rect = dom.getBoundingClientRect();
|
|
5132
5196
|
setIsInTable(true);
|
|
5133
|
-
setAnchorRect(
|
|
5197
|
+
setAnchorRect(rect);
|
|
5198
|
+
setIsAnchorVisible(isRectVisible(rect, dom));
|
|
5134
5199
|
setContentRight(null);
|
|
5135
5200
|
return;
|
|
5136
5201
|
}
|
|
@@ -5139,6 +5204,7 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5139
5204
|
if (!$isRangeSelection(selection)) {
|
|
5140
5205
|
setIsInTable(false);
|
|
5141
5206
|
setAnchorRect(null);
|
|
5207
|
+
setIsAnchorVisible(false);
|
|
5142
5208
|
setContentRight(null);
|
|
5143
5209
|
return;
|
|
5144
5210
|
}
|
|
@@ -5147,6 +5213,7 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5147
5213
|
if (!cellNode || !$isTableCellNode(cellNode)) {
|
|
5148
5214
|
setIsInTable(false);
|
|
5149
5215
|
setAnchorRect(null);
|
|
5216
|
+
setIsAnchorVisible(false);
|
|
5150
5217
|
setContentRight(null);
|
|
5151
5218
|
return;
|
|
5152
5219
|
}
|
|
@@ -5154,11 +5221,14 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5154
5221
|
if (!cellDom) {
|
|
5155
5222
|
setIsInTable(false);
|
|
5156
5223
|
setAnchorRect(null);
|
|
5224
|
+
setIsAnchorVisible(false);
|
|
5157
5225
|
setContentRight(null);
|
|
5158
5226
|
return;
|
|
5159
5227
|
}
|
|
5228
|
+
const cellRect = cellDom.getBoundingClientRect();
|
|
5160
5229
|
setIsInTable(true);
|
|
5161
|
-
setAnchorRect(
|
|
5230
|
+
setAnchorRect(cellRect);
|
|
5231
|
+
setIsAnchorVisible(isRectVisible(cellRect, cellDom));
|
|
5162
5232
|
setContentRight(measureContentRight(cellDom));
|
|
5163
5233
|
if ($isRangeSelection(selection)) {
|
|
5164
5234
|
savedAnchorRef.current = {
|
|
@@ -5184,6 +5254,18 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5184
5254
|
})
|
|
5185
5255
|
);
|
|
5186
5256
|
}, [editor, updateFromSelection]);
|
|
5257
|
+
React9.useEffect(() => {
|
|
5258
|
+
const root = editor.getRootElement();
|
|
5259
|
+
const reposition = () => updateFromSelection();
|
|
5260
|
+
window.addEventListener("resize", reposition);
|
|
5261
|
+
window.addEventListener("scroll", reposition, true);
|
|
5262
|
+
root?.addEventListener("scroll", reposition, { passive: true });
|
|
5263
|
+
return () => {
|
|
5264
|
+
window.removeEventListener("resize", reposition);
|
|
5265
|
+
window.removeEventListener("scroll", reposition, true);
|
|
5266
|
+
root?.removeEventListener("scroll", reposition);
|
|
5267
|
+
};
|
|
5268
|
+
}, [editor, updateFromSelection]);
|
|
5187
5269
|
React9.useEffect(() => {
|
|
5188
5270
|
return editor.registerCommand(
|
|
5189
5271
|
KEY_DOWN_COMMAND,
|
|
@@ -5225,7 +5307,7 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5225
5307
|
COMMAND_PRIORITY_HIGH
|
|
5226
5308
|
);
|
|
5227
5309
|
}, [editor, disabled]);
|
|
5228
|
-
const canShow = isInTable && !!anchorRect && !disabled;
|
|
5310
|
+
const canShow = isInTable && !!anchorRect && isAnchorVisible && !disabled;
|
|
5229
5311
|
const handleStyle = React9.useMemo(() => {
|
|
5230
5312
|
if (!anchorRect) return void 0;
|
|
5231
5313
|
const top = Math.max(8, anchorRect.top + 6);
|