@tarviks/lexical-rich-editor 1.3.10 → 1.3.12
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 +127 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +128 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -906,6 +906,7 @@ var init_InlineImageComponent = __esm({
|
|
|
906
906
|
"data-position": position,
|
|
907
907
|
style: {
|
|
908
908
|
display: "block",
|
|
909
|
+
maxWidth: "100%",
|
|
909
910
|
height,
|
|
910
911
|
width
|
|
911
912
|
},
|
|
@@ -1095,14 +1096,17 @@ var init_InlineImageComponent = __esm({
|
|
|
1095
1096
|
InlineImageComponent_default = InlineImageComponent;
|
|
1096
1097
|
}
|
|
1097
1098
|
});
|
|
1098
|
-
var InlineImageComponent2, $convertInlineImageElement, InlineImageNode, $createInlineImageNode, $isInlineImageNode;
|
|
1099
|
+
var InlineImageComponent2, INLINE_IMAGE_MARKER_ATTR, $convertInlineImageElement, InlineImageNode, $createInlineImageNode, $isInlineImageNode;
|
|
1099
1100
|
var init_InlineImageNode = __esm({
|
|
1100
1101
|
"src/Nodes/InlineImageNode.tsx"() {
|
|
1101
1102
|
InlineImageComponent2 = React9__namespace.lazy(() => Promise.resolve().then(() => (init_InlineImageComponent(), InlineImageComponent_exports)));
|
|
1103
|
+
INLINE_IMAGE_MARKER_ATTR = "data-lexical-inline-image";
|
|
1102
1104
|
$convertInlineImageElement = (domNode) => {
|
|
1103
1105
|
if (lexical.isHTMLElement(domNode) && domNode.nodeName === "IMG") {
|
|
1104
1106
|
const { alt: altText, src, width, height } = domNode;
|
|
1105
|
-
const
|
|
1107
|
+
const positionAttr = domNode.getAttribute("data-position");
|
|
1108
|
+
const position = positionAttr === "left" || positionAttr === "right" || positionAttr === "full" ? positionAttr : void 0;
|
|
1109
|
+
const node = $createInlineImageNode({ altText, height, position, src, width });
|
|
1106
1110
|
return { node };
|
|
1107
1111
|
}
|
|
1108
1112
|
return null;
|
|
@@ -1146,10 +1150,15 @@ var init_InlineImageNode = __esm({
|
|
|
1146
1150
|
}
|
|
1147
1151
|
static importDOM() {
|
|
1148
1152
|
return {
|
|
1149
|
-
img: (node) =>
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
+
img: (node) => {
|
|
1154
|
+
if (lexical.isHTMLElement(node) && node.hasAttribute(INLINE_IMAGE_MARKER_ATTR)) {
|
|
1155
|
+
return {
|
|
1156
|
+
conversion: $convertInlineImageElement,
|
|
1157
|
+
priority: 3
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
return null;
|
|
1161
|
+
}
|
|
1153
1162
|
};
|
|
1154
1163
|
}
|
|
1155
1164
|
constructor(src, altText, position, width, height, showCaption, caption, key) {
|
|
@@ -1168,6 +1177,11 @@ var init_InlineImageNode = __esm({
|
|
|
1168
1177
|
element.setAttribute("alt", this.__altText);
|
|
1169
1178
|
element.setAttribute("width", this.__width.toString());
|
|
1170
1179
|
element.setAttribute("height", this.__height.toString());
|
|
1180
|
+
element.setAttribute(INLINE_IMAGE_MARKER_ATTR, "true");
|
|
1181
|
+
if (this.__position) {
|
|
1182
|
+
element.setAttribute("data-position", this.__position);
|
|
1183
|
+
_InlineImageNode.applyPositionStyle(element, this.__position);
|
|
1184
|
+
}
|
|
1171
1185
|
return { element };
|
|
1172
1186
|
}
|
|
1173
1187
|
exportJSON() {
|
|
@@ -1225,12 +1239,34 @@ var init_InlineImageNode = __esm({
|
|
|
1225
1239
|
}
|
|
1226
1240
|
}
|
|
1227
1241
|
// View
|
|
1242
|
+
// The position-left/right/full behavior is also defined in the package's
|
|
1243
|
+
// CSS file as `.inline-editor-image.position-*` rules, but that file is a
|
|
1244
|
+
// separate import (`@tarviks/lexical-rich-editor/dist/index.css`) a
|
|
1245
|
+
// consuming app can forget to include. Applying it as inline styles here
|
|
1246
|
+
// too means positioning still works even when that stylesheet isn't
|
|
1247
|
+
// loaded, instead of silently no-op'ing back to normal block flow.
|
|
1248
|
+
static applyPositionStyle(span, position) {
|
|
1249
|
+
span.style.removeProperty("float");
|
|
1250
|
+
span.style.removeProperty("display");
|
|
1251
|
+
span.style.removeProperty("margin");
|
|
1252
|
+
if (position === "left") {
|
|
1253
|
+
span.style.float = "left";
|
|
1254
|
+
span.style.margin = "4px 8px 4px 0";
|
|
1255
|
+
} else if (position === "right") {
|
|
1256
|
+
span.style.float = "right";
|
|
1257
|
+
span.style.margin = "4px 0 4px 8px";
|
|
1258
|
+
} else if (position === "full") {
|
|
1259
|
+
span.style.display = "block";
|
|
1260
|
+
span.style.margin = "8px 0";
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1228
1263
|
createDOM(config) {
|
|
1229
1264
|
const span = document.createElement("span");
|
|
1230
1265
|
const className = `${config.theme.inlineImage} position-${this.__position}`;
|
|
1231
1266
|
if (className !== void 0) {
|
|
1232
1267
|
span.className = className;
|
|
1233
1268
|
}
|
|
1269
|
+
_InlineImageNode.applyPositionStyle(span, this.__position);
|
|
1234
1270
|
return span;
|
|
1235
1271
|
}
|
|
1236
1272
|
updateDOM(prevNode, dom, config) {
|
|
@@ -1240,6 +1276,7 @@ var init_InlineImageNode = __esm({
|
|
|
1240
1276
|
if (className !== void 0) {
|
|
1241
1277
|
dom.className = className;
|
|
1242
1278
|
}
|
|
1279
|
+
_InlineImageNode.applyPositionStyle(dom, position);
|
|
1243
1280
|
}
|
|
1244
1281
|
return false;
|
|
1245
1282
|
}
|
|
@@ -2193,6 +2230,48 @@ function $createYouTubeNode(videoID, width = DEFAULT_WIDTH, height = DEFAULT_HEI
|
|
|
2193
2230
|
function $isYouTubeNode(node) {
|
|
2194
2231
|
return node instanceof YouTubeNode;
|
|
2195
2232
|
}
|
|
2233
|
+
var PRESERVED_STYLE_PROPS = [
|
|
2234
|
+
["fontFamily", "font-family"],
|
|
2235
|
+
["fontSize", "font-size"],
|
|
2236
|
+
["color", "color"],
|
|
2237
|
+
["backgroundColor", "background-color"]
|
|
2238
|
+
];
|
|
2239
|
+
var $convertSpanElementWithStyle = (domNode) => {
|
|
2240
|
+
const style = domNode.style;
|
|
2241
|
+
const cssParts = [];
|
|
2242
|
+
for (const [domProp, cssProp] of PRESERVED_STYLE_PROPS) {
|
|
2243
|
+
const value = style[domProp];
|
|
2244
|
+
if (value) cssParts.push(`${cssProp}: ${value}`);
|
|
2245
|
+
}
|
|
2246
|
+
const cssText = cssParts.length > 0 ? `${cssParts.join("; ")};` : "";
|
|
2247
|
+
const fontWeight = style.fontWeight;
|
|
2248
|
+
const textDecoration = style.textDecoration.split(" ");
|
|
2249
|
+
const hasBoldFontWeight = fontWeight === "700" || fontWeight === "bold";
|
|
2250
|
+
const hasLinethroughTextDecoration = textDecoration.includes("line-through");
|
|
2251
|
+
const hasItalicFontStyle = style.fontStyle === "italic";
|
|
2252
|
+
const hasUnderlineTextDecoration = textDecoration.includes("underline");
|
|
2253
|
+
const verticalAlign = style.verticalAlign;
|
|
2254
|
+
return {
|
|
2255
|
+
node: null,
|
|
2256
|
+
forChild: (lexicalNode) => {
|
|
2257
|
+
if (!lexical.$isTextNode(lexicalNode)) return lexicalNode;
|
|
2258
|
+
if (cssText) lexicalNode.setStyle(cssText);
|
|
2259
|
+
if (hasBoldFontWeight && !lexicalNode.hasFormat("bold")) lexicalNode.toggleFormat("bold");
|
|
2260
|
+
if (hasLinethroughTextDecoration && !lexicalNode.hasFormat("strikethrough")) lexicalNode.toggleFormat("strikethrough");
|
|
2261
|
+
if (hasItalicFontStyle && !lexicalNode.hasFormat("italic")) lexicalNode.toggleFormat("italic");
|
|
2262
|
+
if (hasUnderlineTextDecoration && !lexicalNode.hasFormat("underline")) lexicalNode.toggleFormat("underline");
|
|
2263
|
+
if (verticalAlign === "sub" && !lexicalNode.hasFormat("subscript")) lexicalNode.toggleFormat("subscript");
|
|
2264
|
+
if (verticalAlign === "super" && !lexicalNode.hasFormat("superscript")) lexicalNode.toggleFormat("superscript");
|
|
2265
|
+
return lexicalNode;
|
|
2266
|
+
}
|
|
2267
|
+
};
|
|
2268
|
+
};
|
|
2269
|
+
var preserveTextStyleImportMap = {
|
|
2270
|
+
span: () => ({
|
|
2271
|
+
conversion: $convertSpanElementWithStyle,
|
|
2272
|
+
priority: 0
|
|
2273
|
+
})
|
|
2274
|
+
};
|
|
2196
2275
|
var normalize = (s) => (s ?? "").replace(/\s+/g, " ").trim();
|
|
2197
2276
|
function readContextWindow(maxChars = 300, cursorIndex) {
|
|
2198
2277
|
const full = normalize(lexical.$getRoot().getTextContent());
|
|
@@ -2966,6 +3045,8 @@ var ALLOWED_ATTRS = /* @__PURE__ */ new Set([
|
|
|
2966
3045
|
"data-lex-block",
|
|
2967
3046
|
"data-kind",
|
|
2968
3047
|
"data-lexical-decorator",
|
|
3048
|
+
"data-lexical-inline-image",
|
|
3049
|
+
"data-position",
|
|
2969
3050
|
// Misc
|
|
2970
3051
|
"title",
|
|
2971
3052
|
"allowfullscreen"
|
|
@@ -5120,11 +5201,37 @@ function SpellCheckPlugin({
|
|
|
5120
5201
|
}
|
|
5121
5202
|
) : null;
|
|
5122
5203
|
}
|
|
5204
|
+
function getScrollClipAncestor(el) {
|
|
5205
|
+
let node = el.parentElement;
|
|
5206
|
+
while (node) {
|
|
5207
|
+
const style = getComputedStyle(node);
|
|
5208
|
+
if ((style.overflowY === "auto" || style.overflowY === "scroll") && node.scrollHeight > node.clientHeight) {
|
|
5209
|
+
return node;
|
|
5210
|
+
}
|
|
5211
|
+
node = node.parentElement;
|
|
5212
|
+
}
|
|
5213
|
+
return null;
|
|
5214
|
+
}
|
|
5215
|
+
var BUTTON_VERTICAL_FOOTPRINT = 34;
|
|
5216
|
+
function isRectVisible(rect, cellDom) {
|
|
5217
|
+
if (rect.width === 0 && rect.height === 0) return false;
|
|
5218
|
+
const clipAncestor = getScrollClipAncestor(cellDom);
|
|
5219
|
+
const containerRect = clipAncestor?.getBoundingClientRect();
|
|
5220
|
+
const visibleTop = containerRect ? Math.max(0, containerRect.top) : 0;
|
|
5221
|
+
const visibleBottom = containerRect ? Math.min(window.innerHeight, containerRect.bottom) : window.innerHeight;
|
|
5222
|
+
const visibleLeft = containerRect ? Math.max(0, containerRect.left) : 0;
|
|
5223
|
+
const visibleRight = containerRect ? Math.min(window.innerWidth, containerRect.right) : window.innerWidth;
|
|
5224
|
+
if (rect.top < visibleTop) return false;
|
|
5225
|
+
if (rect.top + BUTTON_VERTICAL_FOOTPRINT > visibleBottom) return false;
|
|
5226
|
+
if (rect.left >= visibleRight || rect.right <= visibleLeft) return false;
|
|
5227
|
+
return true;
|
|
5228
|
+
}
|
|
5123
5229
|
function TableActionMenuPlugin({ disabled = false }) {
|
|
5124
5230
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
5125
5231
|
const portalContainer = useFloatingPortalContainer(editor);
|
|
5126
5232
|
const [isInTable, setIsInTable] = React9__namespace.useState(false);
|
|
5127
5233
|
const [anchorRect, setAnchorRect] = React9__namespace.useState(null);
|
|
5234
|
+
const [isAnchorVisible, setIsAnchorVisible] = React9__namespace.useState(false);
|
|
5128
5235
|
const [contentRight, setContentRight] = React9__namespace.useState(null);
|
|
5129
5236
|
const [open, setOpen] = React9__namespace.useState(false);
|
|
5130
5237
|
const openRef = React9__namespace.useRef(false);
|
|
@@ -5150,8 +5257,10 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5150
5257
|
if (tableNode) {
|
|
5151
5258
|
const dom = editor.getElementByKey(tableNode.getKey());
|
|
5152
5259
|
if (dom) {
|
|
5260
|
+
const rect = dom.getBoundingClientRect();
|
|
5153
5261
|
setIsInTable(true);
|
|
5154
|
-
setAnchorRect(
|
|
5262
|
+
setAnchorRect(rect);
|
|
5263
|
+
setIsAnchorVisible(isRectVisible(rect, dom));
|
|
5155
5264
|
setContentRight(null);
|
|
5156
5265
|
return;
|
|
5157
5266
|
}
|
|
@@ -5160,6 +5269,7 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5160
5269
|
if (!lexical.$isRangeSelection(selection)) {
|
|
5161
5270
|
setIsInTable(false);
|
|
5162
5271
|
setAnchorRect(null);
|
|
5272
|
+
setIsAnchorVisible(false);
|
|
5163
5273
|
setContentRight(null);
|
|
5164
5274
|
return;
|
|
5165
5275
|
}
|
|
@@ -5168,6 +5278,7 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5168
5278
|
if (!cellNode || !table.$isTableCellNode(cellNode)) {
|
|
5169
5279
|
setIsInTable(false);
|
|
5170
5280
|
setAnchorRect(null);
|
|
5281
|
+
setIsAnchorVisible(false);
|
|
5171
5282
|
setContentRight(null);
|
|
5172
5283
|
return;
|
|
5173
5284
|
}
|
|
@@ -5175,11 +5286,14 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5175
5286
|
if (!cellDom) {
|
|
5176
5287
|
setIsInTable(false);
|
|
5177
5288
|
setAnchorRect(null);
|
|
5289
|
+
setIsAnchorVisible(false);
|
|
5178
5290
|
setContentRight(null);
|
|
5179
5291
|
return;
|
|
5180
5292
|
}
|
|
5293
|
+
const cellRect = cellDom.getBoundingClientRect();
|
|
5181
5294
|
setIsInTable(true);
|
|
5182
|
-
setAnchorRect(
|
|
5295
|
+
setAnchorRect(cellRect);
|
|
5296
|
+
setIsAnchorVisible(isRectVisible(cellRect, cellDom));
|
|
5183
5297
|
setContentRight(measureContentRight(cellDom));
|
|
5184
5298
|
if (lexical.$isRangeSelection(selection)) {
|
|
5185
5299
|
savedAnchorRef.current = {
|
|
@@ -5258,7 +5372,7 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5258
5372
|
lexical.COMMAND_PRIORITY_HIGH
|
|
5259
5373
|
);
|
|
5260
5374
|
}, [editor, disabled]);
|
|
5261
|
-
const canShow = isInTable && !!anchorRect && !disabled;
|
|
5375
|
+
const canShow = isInTable && !!anchorRect && isAnchorVisible && !disabled;
|
|
5262
5376
|
const handleStyle = React9__namespace.useMemo(() => {
|
|
5263
5377
|
if (!anchorRect) return void 0;
|
|
5264
5378
|
const top = Math.max(8, anchorRect.top + 6);
|
|
@@ -8217,7 +8331,10 @@ var ContentEditorComponent = React9.forwardRef(
|
|
|
8217
8331
|
AutocompleteNode,
|
|
8218
8332
|
SpellErrorNode,
|
|
8219
8333
|
HtmlBlockNode
|
|
8220
|
-
]
|
|
8334
|
+
],
|
|
8335
|
+
html: {
|
|
8336
|
+
import: preserveTextStyleImportMap
|
|
8337
|
+
}
|
|
8221
8338
|
};
|
|
8222
8339
|
props.onBeforeInitialize?.(config);
|
|
8223
8340
|
return config;
|