@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 CHANGED
@@ -3219,12 +3219,16 @@ function splitHeadingsAtBrSequences(html) {
3219
3219
  });
3220
3220
  return doc.body.innerHTML;
3221
3221
  }
3222
- var CustomOnChangePlugin = ({ value, onChange }) => {
3222
+ var CustomOnChangePlugin = ({ value, onChange, isReadOnly }) => {
3223
3223
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
3224
3224
  const initializedRef = React9.useRef(false);
3225
+ const lastImportedValueRef = React9.useRef(null);
3225
3226
  React9.useEffect(() => {
3226
- if (!value || initializedRef.current) return;
3227
+ if (!value) return;
3228
+ if (!isReadOnly && initializedRef.current) return;
3229
+ if (value === lastImportedValueRef.current) return;
3227
3230
  initializedRef.current = true;
3231
+ lastImportedValueRef.current = value;
3228
3232
  editor.update(() => {
3229
3233
  const root = lexical.$getRoot();
3230
3234
  root.clear();
@@ -3235,14 +3239,17 @@ var CustomOnChangePlugin = ({ value, onChange }) => {
3235
3239
  const nodes = html.$generateNodesFromDOM(editor, dom);
3236
3240
  root.append(...nodes);
3237
3241
  });
3238
- }, [editor, value]);
3242
+ }, [editor, value, isReadOnly]);
3239
3243
  return /* @__PURE__ */ jsxRuntime.jsx(
3240
3244
  LexicalOnChangePlugin.OnChangePlugin,
3241
3245
  {
3246
+ ignoreSelectionChange: true,
3242
3247
  onChange: (editorState) => {
3243
3248
  editorState.read(() => {
3244
3249
  const raw = html.$generateHtmlFromNodes(editor);
3245
- onChange(postProcessOutput(splitHeadingsAtBrSequences(raw)));
3250
+ const html$1 = postProcessOutput(splitHeadingsAtBrSequences(raw));
3251
+ lastImportedValueRef.current = html$1;
3252
+ onChange(html$1);
3246
3253
  });
3247
3254
  }
3248
3255
  }
@@ -4568,6 +4575,44 @@ function RefApiPlugin({
4568
4575
  );
4569
4576
  return null;
4570
4577
  }
4578
+ function RobustCutPlugin() {
4579
+ const [editor] = LexicalComposerContext.useLexicalComposerContext();
4580
+ React9.useEffect(() => {
4581
+ return editor.registerCommand(
4582
+ lexical.KEY_DOWN_COMMAND,
4583
+ (event) => {
4584
+ const isShiftDelete = event.key === "Delete" && event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey;
4585
+ if (!isShiftDelete) return false;
4586
+ let plainText = null;
4587
+ editor.getEditorState().read(() => {
4588
+ const selection = lexical.$getSelection();
4589
+ if (lexical.$isRangeSelection(selection) && !selection.isCollapsed()) {
4590
+ plainText = selection.getTextContent();
4591
+ } else if (lexical.$isNodeSelection(selection) && selection.getNodes().length > 0) {
4592
+ plainText = "";
4593
+ }
4594
+ });
4595
+ if (plainText === null) return false;
4596
+ event.preventDefault();
4597
+ editor.update(() => {
4598
+ const selection = lexical.$getSelection();
4599
+ if (lexical.$isRangeSelection(selection)) {
4600
+ selection.removeText();
4601
+ } else if (lexical.$isNodeSelection(selection)) {
4602
+ selection.getNodes().forEach((node) => node.remove());
4603
+ }
4604
+ });
4605
+ if (plainText && navigator.clipboard?.writeText) {
4606
+ navigator.clipboard.writeText(plainText).catch(() => {
4607
+ });
4608
+ }
4609
+ return true;
4610
+ },
4611
+ lexical.COMMAND_PRIORITY_HIGH
4612
+ );
4613
+ }, [editor]);
4614
+ return null;
4615
+ }
4571
4616
  var CSS_ID = "__sc_styles__";
4572
4617
  function injectCSS() {
4573
4618
  if (document.getElementById(CSS_ID)) return;
@@ -5375,9 +5420,25 @@ function TableActionMenuPlugin({ disabled = false }) {
5375
5420
  const canShow = isInTable && !!anchorRect && isAnchorVisible && !disabled;
5376
5421
  const handleStyle = React9__namespace.useMemo(() => {
5377
5422
  if (!anchorRect) return void 0;
5378
- const top = Math.max(8, anchorRect.top + 6);
5379
- const clampedCellRight = Math.min(anchorRect.right, window.innerWidth - 8);
5380
- const left = contentRight !== null ? Math.max(anchorRect.left + 4, Math.min(contentRight + 4, clampedCellRight - 32)) : Math.max(8, anchorRect.left + 8);
5423
+ const BUTTON_SIZE = 28;
5424
+ const PAD = 8;
5425
+ const editorRect = editor.getRootElement()?.getBoundingClientRect();
5426
+ const clipRect = editorRect ? {
5427
+ top: Math.max(editorRect.top, 0),
5428
+ left: Math.max(editorRect.left, 0),
5429
+ right: Math.min(editorRect.right, window.innerWidth),
5430
+ bottom: Math.min(editorRect.bottom, window.innerHeight)
5431
+ } : { top: 0, left: 0, right: window.innerWidth, bottom: window.innerHeight };
5432
+ const isCellVisible = anchorRect.bottom > clipRect.top && anchorRect.top < clipRect.bottom && anchorRect.right > clipRect.left && anchorRect.left < clipRect.right;
5433
+ if (!isCellVisible) return void 0;
5434
+ const minTop = editorRect ? editorRect.top + PAD : PAD;
5435
+ const maxTop = editorRect ? Math.max(minTop, editorRect.bottom - BUTTON_SIZE - PAD) : window.innerHeight - BUTTON_SIZE - PAD;
5436
+ const minLeft = editorRect ? editorRect.left + PAD : PAD;
5437
+ const maxLeft = editorRect ? Math.max(minLeft, editorRect.right - BUTTON_SIZE - PAD) : window.innerWidth - BUTTON_SIZE - PAD;
5438
+ const top = Math.min(Math.max(anchorRect.top + 6, minTop), maxTop);
5439
+ const clampedCellRight = Math.min(anchorRect.right, maxLeft + BUTTON_SIZE);
5440
+ const rawLeft = contentRight !== null ? Math.max(anchorRect.left + 4, Math.min(contentRight + 4, clampedCellRight - 32)) : anchorRect.left + 8;
5441
+ const left = Math.min(Math.max(rawLeft, minLeft), maxLeft);
5381
5442
  return {
5382
5443
  position: "fixed",
5383
5444
  top,
@@ -5387,7 +5448,7 @@ function TableActionMenuPlugin({ disabled = false }) {
5387
5448
  // button renders behind the modal chrome in a full-page/Panel view.
5388
5449
  zIndex: 10000010
5389
5450
  };
5390
- }, [anchorRect, contentRight]);
5451
+ }, [anchorRect, contentRight, editor]);
5391
5452
  const dangerStyle = {
5392
5453
  color: "var(--colorPaletteRedForeground1)"
5393
5454
  };
@@ -8627,6 +8688,7 @@ var ContentEditorComponent = React9.forwardRef(
8627
8688
  /* @__PURE__ */ jsxRuntime.jsx(LexicalAutoLinkPlugin.AutoLinkPlugin, { matchers: MATCHERS }),
8628
8689
  /* @__PURE__ */ jsxRuntime.jsx(LexicalTablePlugin.TablePlugin, { hasCellMerge: true, hasCellBackgroundColor: true }),
8629
8690
  !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(YoutubeDeletePlugin, {}),
8691
+ !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(RobustCutPlugin, {}),
8630
8692
  !isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsxRuntime.jsx(TableActionMenuPlugin, {}),
8631
8693
  !isReadOnly && floatingAnchorElem && /* @__PURE__ */ jsxRuntime.jsx(TableCellResizerPlugin, { anchorElem: floatingAnchorElem }),
8632
8694
  !isReadOnly && /* @__PURE__ */ jsxRuntime.jsx(
@@ -8662,7 +8724,14 @@ var ContentEditorComponent = React9.forwardRef(
8662
8724
  }
8663
8725
  ),
8664
8726
  !isReadOnly && props.showFloatingToolbar && /* @__PURE__ */ jsxRuntime.jsx(CharacterStylesPopupPlugin, {}),
8665
- /* @__PURE__ */ jsxRuntime.jsx(CustomOnChangePlugin, { value: props.value, onChange: props.onChange }),
8727
+ /* @__PURE__ */ jsxRuntime.jsx(
8728
+ CustomOnChangePlugin,
8729
+ {
8730
+ value: props.value,
8731
+ onChange: props.onChange,
8732
+ isReadOnly
8733
+ }
8734
+ ),
8666
8735
  (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__ */ jsxRuntime.jsx(ContentMetricsPlugin, { onMetricsChange: handleMetrics }),
8667
8736
  /* @__PURE__ */ jsxRuntime.jsx(
8668
8737
  RefApiPlugin,