@tarviks/lexical-rich-editor 1.3.12 → 1.3.14
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 +78 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +79 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
5
5
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
6
6
|
import { useLexicalEditable } from '@lexical/react/useLexicalEditable';
|
|
7
7
|
import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
|
|
8
|
-
import { createCommand, $isTextNode, DecoratorNode, COMMAND_PRIORITY_HIGH, TextNode, ElementNode, SELECTION_CHANGE_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, $getSelection, $isRangeSelection, $findMatchingParent, COMMAND_PRIORITY_LOW,
|
|
8
|
+
import { createCommand, $isTextNode, DecoratorNode, COMMAND_PRIORITY_HIGH, TextNode, ElementNode, SELECTION_CHANGE_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, $getSelection, $isRangeSelection, KEY_DOWN_COMMAND, $isNodeSelection, $findMatchingParent, COMMAND_PRIORITY_LOW, $getNodeByKey, $createRangeSelection, $setSelection, $createParagraphNode, $insertNodes, $isRootOrShadowRoot, COMMAND_PRIORITY_EDITOR, PASTE_COMMAND, DRAGSTART_COMMAND, DRAGOVER_COMMAND, DROP_COMMAND, $getRoot, $createTextNode, $isElementNode, FORMAT_ELEMENT_COMMAND, CLICK_COMMAND, $applyNodeReplacement, FORMAT_TEXT_COMMAND, $isDecoratorNode, $getNearestNodeFromDOMNode, COMMAND_PRIORITY_CRITICAL, REDO_COMMAND, UNDO_COMMAND, getDOMSelection, KEY_ESCAPE_COMMAND, isHTMLElement, getDOMSelectionFromTarget, $isLineBreakNode, SKIP_SELECTION_FOCUS_TAG, createEditor, KEY_ENTER_COMMAND } from 'lexical';
|
|
9
9
|
import { mergeStyleSets, Stack, css, useTheme, Callout, TextField } from '@fluentui/react';
|
|
10
10
|
import { makeStyles, FluentProvider, webLightTheme, Menu, MenuTrigger, MenuPopover, MenuList, MenuGroup, MenuGroupHeader, MenuItem, MenuDivider, Dropdown, Option, Button, ToolbarDivider, MenuItemRadio, Field, Input, MessageBar, MessageBarBody, Popover, PopoverSurface, PopoverTrigger } from '@fluentui/react-components';
|
|
11
11
|
import { CodeHighlightNode, CodeNode, $isCodeHighlightNode } from '@lexical/code';
|
|
@@ -3198,12 +3198,16 @@ function splitHeadingsAtBrSequences(html) {
|
|
|
3198
3198
|
});
|
|
3199
3199
|
return doc.body.innerHTML;
|
|
3200
3200
|
}
|
|
3201
|
-
var CustomOnChangePlugin = ({ value, onChange }) => {
|
|
3201
|
+
var CustomOnChangePlugin = ({ value, onChange, isReadOnly }) => {
|
|
3202
3202
|
const [editor] = useLexicalComposerContext();
|
|
3203
3203
|
const initializedRef = useRef(false);
|
|
3204
|
+
const lastImportedValueRef = useRef(null);
|
|
3204
3205
|
useEffect(() => {
|
|
3205
|
-
if (!value
|
|
3206
|
+
if (!value) return;
|
|
3207
|
+
if (!isReadOnly && initializedRef.current) return;
|
|
3208
|
+
if (value === lastImportedValueRef.current) return;
|
|
3206
3209
|
initializedRef.current = true;
|
|
3210
|
+
lastImportedValueRef.current = value;
|
|
3207
3211
|
editor.update(() => {
|
|
3208
3212
|
const root = $getRoot();
|
|
3209
3213
|
root.clear();
|
|
@@ -3214,14 +3218,17 @@ var CustomOnChangePlugin = ({ value, onChange }) => {
|
|
|
3214
3218
|
const nodes = $generateNodesFromDOM(editor, dom);
|
|
3215
3219
|
root.append(...nodes);
|
|
3216
3220
|
});
|
|
3217
|
-
}, [editor, value]);
|
|
3221
|
+
}, [editor, value, isReadOnly]);
|
|
3218
3222
|
return /* @__PURE__ */ jsx(
|
|
3219
3223
|
OnChangePlugin,
|
|
3220
3224
|
{
|
|
3225
|
+
ignoreSelectionChange: true,
|
|
3221
3226
|
onChange: (editorState) => {
|
|
3222
3227
|
editorState.read(() => {
|
|
3223
3228
|
const raw = $generateHtmlFromNodes(editor);
|
|
3224
|
-
|
|
3229
|
+
const html = postProcessOutput(splitHeadingsAtBrSequences(raw));
|
|
3230
|
+
lastImportedValueRef.current = html;
|
|
3231
|
+
onChange(html);
|
|
3225
3232
|
});
|
|
3226
3233
|
}
|
|
3227
3234
|
}
|
|
@@ -4547,6 +4554,44 @@ function RefApiPlugin({
|
|
|
4547
4554
|
);
|
|
4548
4555
|
return null;
|
|
4549
4556
|
}
|
|
4557
|
+
function RobustCutPlugin() {
|
|
4558
|
+
const [editor] = useLexicalComposerContext();
|
|
4559
|
+
useEffect(() => {
|
|
4560
|
+
return editor.registerCommand(
|
|
4561
|
+
KEY_DOWN_COMMAND,
|
|
4562
|
+
(event) => {
|
|
4563
|
+
const isShiftDelete = event.key === "Delete" && event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey;
|
|
4564
|
+
if (!isShiftDelete) return false;
|
|
4565
|
+
let plainText = null;
|
|
4566
|
+
editor.getEditorState().read(() => {
|
|
4567
|
+
const selection = $getSelection();
|
|
4568
|
+
if ($isRangeSelection(selection) && !selection.isCollapsed()) {
|
|
4569
|
+
plainText = selection.getTextContent();
|
|
4570
|
+
} else if ($isNodeSelection(selection) && selection.getNodes().length > 0) {
|
|
4571
|
+
plainText = "";
|
|
4572
|
+
}
|
|
4573
|
+
});
|
|
4574
|
+
if (plainText === null) return false;
|
|
4575
|
+
event.preventDefault();
|
|
4576
|
+
editor.update(() => {
|
|
4577
|
+
const selection = $getSelection();
|
|
4578
|
+
if ($isRangeSelection(selection)) {
|
|
4579
|
+
selection.removeText();
|
|
4580
|
+
} else if ($isNodeSelection(selection)) {
|
|
4581
|
+
selection.getNodes().forEach((node) => node.remove());
|
|
4582
|
+
}
|
|
4583
|
+
});
|
|
4584
|
+
if (plainText && navigator.clipboard?.writeText) {
|
|
4585
|
+
navigator.clipboard.writeText(plainText).catch(() => {
|
|
4586
|
+
});
|
|
4587
|
+
}
|
|
4588
|
+
return true;
|
|
4589
|
+
},
|
|
4590
|
+
COMMAND_PRIORITY_HIGH
|
|
4591
|
+
);
|
|
4592
|
+
}, [editor]);
|
|
4593
|
+
return null;
|
|
4594
|
+
}
|
|
4550
4595
|
var CSS_ID = "__sc_styles__";
|
|
4551
4596
|
function injectCSS() {
|
|
4552
4597
|
if (document.getElementById(CSS_ID)) return;
|
|
@@ -5354,9 +5399,25 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5354
5399
|
const canShow = isInTable && !!anchorRect && isAnchorVisible && !disabled;
|
|
5355
5400
|
const handleStyle = React9.useMemo(() => {
|
|
5356
5401
|
if (!anchorRect) return void 0;
|
|
5357
|
-
const
|
|
5358
|
-
const
|
|
5359
|
-
const
|
|
5402
|
+
const BUTTON_SIZE = 28;
|
|
5403
|
+
const PAD = 8;
|
|
5404
|
+
const editorRect = editor.getRootElement()?.getBoundingClientRect();
|
|
5405
|
+
const clipRect = editorRect ? {
|
|
5406
|
+
top: Math.max(editorRect.top, 0),
|
|
5407
|
+
left: Math.max(editorRect.left, 0),
|
|
5408
|
+
right: Math.min(editorRect.right, window.innerWidth),
|
|
5409
|
+
bottom: Math.min(editorRect.bottom, window.innerHeight)
|
|
5410
|
+
} : { top: 0, left: 0, right: window.innerWidth, bottom: window.innerHeight };
|
|
5411
|
+
const isCellVisible = anchorRect.bottom > clipRect.top && anchorRect.top < clipRect.bottom && anchorRect.right > clipRect.left && anchorRect.left < clipRect.right;
|
|
5412
|
+
if (!isCellVisible) return void 0;
|
|
5413
|
+
const minTop = editorRect ? editorRect.top + PAD : PAD;
|
|
5414
|
+
const maxTop = editorRect ? Math.max(minTop, editorRect.bottom - BUTTON_SIZE - PAD) : window.innerHeight - BUTTON_SIZE - PAD;
|
|
5415
|
+
const minLeft = editorRect ? editorRect.left + PAD : PAD;
|
|
5416
|
+
const maxLeft = editorRect ? Math.max(minLeft, editorRect.right - BUTTON_SIZE - PAD) : window.innerWidth - BUTTON_SIZE - PAD;
|
|
5417
|
+
const top = Math.min(Math.max(anchorRect.top + 6, minTop), maxTop);
|
|
5418
|
+
const clampedCellRight = Math.min(anchorRect.right, maxLeft + BUTTON_SIZE);
|
|
5419
|
+
const rawLeft = contentRight !== null ? Math.max(anchorRect.left + 4, Math.min(contentRight + 4, clampedCellRight - 32)) : anchorRect.left + 8;
|
|
5420
|
+
const left = Math.min(Math.max(rawLeft, minLeft), maxLeft);
|
|
5360
5421
|
return {
|
|
5361
5422
|
position: "fixed",
|
|
5362
5423
|
top,
|
|
@@ -5366,7 +5427,7 @@ function TableActionMenuPlugin({ disabled = false }) {
|
|
|
5366
5427
|
// button renders behind the modal chrome in a full-page/Panel view.
|
|
5367
5428
|
zIndex: 10000010
|
|
5368
5429
|
};
|
|
5369
|
-
}, [anchorRect, contentRight]);
|
|
5430
|
+
}, [anchorRect, contentRight, editor]);
|
|
5370
5431
|
const dangerStyle = {
|
|
5371
5432
|
color: "var(--colorPaletteRedForeground1)"
|
|
5372
5433
|
};
|
|
@@ -8606,6 +8667,7 @@ var ContentEditorComponent = forwardRef(
|
|
|
8606
8667
|
/* @__PURE__ */ jsx(AutoLinkPlugin, { matchers: MATCHERS }),
|
|
8607
8668
|
/* @__PURE__ */ jsx(TablePlugin, { hasCellMerge: true, hasCellBackgroundColor: true }),
|
|
8608
8669
|
!isReadOnly && /* @__PURE__ */ jsx(YoutubeDeletePlugin, {}),
|
|
8670
|
+
!isReadOnly && /* @__PURE__ */ jsx(RobustCutPlugin, {}),
|
|
8609
8671
|
!isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsx(TableActionMenuPlugin, {}),
|
|
8610
8672
|
!isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsx(TableCellResizerPlugin, { anchorElem: floatingAnchorElem }),
|
|
8611
8673
|
!isReadOnly && /* @__PURE__ */ jsx(
|
|
@@ -8641,7 +8703,14 @@ var ContentEditorComponent = forwardRef(
|
|
|
8641
8703
|
}
|
|
8642
8704
|
),
|
|
8643
8705
|
!isReadOnly && props.showFloatingToolbar && /* @__PURE__ */ jsx(CharacterStylesPopupPlugin, {}),
|
|
8644
|
-
/* @__PURE__ */ jsx(
|
|
8706
|
+
/* @__PURE__ */ jsx(
|
|
8707
|
+
CustomOnChangePlugin,
|
|
8708
|
+
{
|
|
8709
|
+
value: props.value,
|
|
8710
|
+
onChange: props.onChange,
|
|
8711
|
+
isReadOnly
|
|
8712
|
+
}
|
|
8713
|
+
),
|
|
8645
8714
|
(props.wordLimit !== void 0 || props.required || props.minWords !== void 0 || props.maxWords !== void 0 || props.minChars !== void 0 || props.maxChars !== void 0 || props.noImages || props.maxImages !== void 0 || props.noLinks || props.maxLinks !== void 0 || props.noTables) && /* @__PURE__ */ jsx(ContentMetricsPlugin, { onMetricsChange: handleMetrics }),
|
|
8646
8715
|
/* @__PURE__ */ jsx(
|
|
8647
8716
|
RefApiPlugin,
|