@mhamz.01/easyflow-texteditor 0.1.149 → 0.1.151

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.mjs CHANGED
@@ -2874,6 +2874,54 @@ function useTiptapEditor(providedEditor) {
2874
2874
  return editorState || { editor: null };
2875
2875
  }
2876
2876
 
2877
+ // src/hooks/mark-preservers/mark-preserver.ts
2878
+ var MarkPreserver = class {
2879
+ static preservedMarks = /* @__PURE__ */ new Map();
2880
+ /**
2881
+ * Preserve marks before an action that will cause blur
2882
+ * Call this in onMouseDown or onPointerDown events
2883
+ */
2884
+ static preserve(editor) {
2885
+ if (!editor) return;
2886
+ const { state } = editor;
2887
+ const { $from } = state.selection;
2888
+ const currentMarks = state.storedMarks || $from.marks();
2889
+ if (currentMarks.length > 0) {
2890
+ this.preservedMarks.set(editor, [...currentMarks]);
2891
+ }
2892
+ }
2893
+ /**
2894
+ * Restore marks after an action completes
2895
+ * Call this after the editor action in onClick or in a setTimeout
2896
+ */
2897
+ static restore(editor, delay = 0) {
2898
+ if (!editor) return;
2899
+ const marks = this.preservedMarks.get(editor);
2900
+ if (!marks) return;
2901
+ const restoreFn = () => {
2902
+ if (editor.isDestroyed) {
2903
+ this.preservedMarks.delete(editor);
2904
+ return;
2905
+ }
2906
+ const { state } = editor;
2907
+ editor.view.dispatch(state.tr.setStoredMarks(marks));
2908
+ this.preservedMarks.delete(editor);
2909
+ editor.commands.focus();
2910
+ };
2911
+ if (delay > 0) {
2912
+ setTimeout(restoreFn, delay);
2913
+ } else {
2914
+ restoreFn();
2915
+ }
2916
+ }
2917
+ /**
2918
+ * Clear preserved marks for an editor
2919
+ */
2920
+ static clear(editor) {
2921
+ this.preservedMarks.delete(editor);
2922
+ }
2923
+ };
2924
+
2877
2925
  // src/components/tiptap-ui/heading-button/heading-button.tsx
2878
2926
  import { forwardRef as forwardRef6, useCallback as useCallback8 } from "react";
2879
2927
 
@@ -3478,9 +3526,15 @@ var HeadingDropdownMenu = forwardRef9(
3478
3526
  if (!editor || !canToggle2) return;
3479
3527
  setIsOpen(open);
3480
3528
  onOpenChange?.(open);
3529
+ if (!open) {
3530
+ MarkPreserver.restore(editor, 10);
3531
+ }
3481
3532
  },
3482
3533
  [canToggle2, editor, onOpenChange]
3483
3534
  );
3535
+ const handlePointerDown = useCallback10(() => {
3536
+ MarkPreserver.preserve(editor);
3537
+ }, [editor]);
3484
3538
  if (!isVisible) {
3485
3539
  return null;
3486
3540
  }
@@ -3496,6 +3550,7 @@ var HeadingDropdownMenu = forwardRef9(
3496
3550
  "aria-label": "Format text as heading",
3497
3551
  "aria-pressed": isActive,
3498
3552
  tooltip: "Heading",
3553
+ onPointerDown: handlePointerDown,
3499
3554
  ...buttonProps,
3500
3555
  ref,
3501
3556
  children: [
@@ -4383,9 +4438,15 @@ function ListDropdownMenu({
4383
4438
  (open) => {
4384
4439
  setIsOpen(open);
4385
4440
  onOpenChange?.(open);
4441
+ if (!open) {
4442
+ MarkPreserver.restore(editor, 10);
4443
+ }
4386
4444
  },
4387
- [onOpenChange]
4445
+ [onOpenChange, editor]
4388
4446
  );
4447
+ const handlePointerDown = useCallback15(() => {
4448
+ MarkPreserver.preserve(editor);
4449
+ }, [editor]);
4389
4450
  if (!isVisible) {
4390
4451
  return null;
4391
4452
  }
@@ -4402,6 +4463,7 @@ function ListDropdownMenu({
4402
4463
  "data-disabled": !canToggle2,
4403
4464
  "aria-label": "List options",
4404
4465
  tooltip: "List",
4466
+ onPointerDown: handlePointerDown,
4405
4467
  ...props,
4406
4468
  children: [
4407
4469
  /* @__PURE__ */ jsx44(Icon, { className: "tiptap-button-icon" }),
@@ -4423,56 +4485,6 @@ function ListDropdownMenu({
4423
4485
 
4424
4486
  // src/components/tiptap-ui/blockquote-button/blockquote-button.tsx
4425
4487
  import { forwardRef as forwardRef12, useCallback as useCallback16 } from "react";
4426
-
4427
- // src/hooks/mark-preservers/mark-preserver.ts
4428
- var MarkPreserver = class {
4429
- static preservedMarks = /* @__PURE__ */ new Map();
4430
- /**
4431
- * Preserve marks before an action that will cause blur
4432
- * Call this in onMouseDown or onPointerDown events
4433
- */
4434
- static preserve(editor) {
4435
- if (!editor) return;
4436
- const { state } = editor;
4437
- const { $from } = state.selection;
4438
- const currentMarks = state.storedMarks || $from.marks();
4439
- if (currentMarks.length > 0) {
4440
- this.preservedMarks.set(editor, [...currentMarks]);
4441
- }
4442
- }
4443
- /**
4444
- * Restore marks after an action completes
4445
- * Call this after the editor action in onClick or in a setTimeout
4446
- */
4447
- static restore(editor, delay = 0) {
4448
- if (!editor) return;
4449
- const marks = this.preservedMarks.get(editor);
4450
- if (!marks) return;
4451
- const restoreFn = () => {
4452
- if (editor.isDestroyed) {
4453
- this.preservedMarks.delete(editor);
4454
- return;
4455
- }
4456
- const { state } = editor;
4457
- editor.view.dispatch(state.tr.setStoredMarks(marks));
4458
- this.preservedMarks.delete(editor);
4459
- editor.commands.focus();
4460
- };
4461
- if (delay > 0) {
4462
- setTimeout(restoreFn, delay);
4463
- } else {
4464
- restoreFn();
4465
- }
4466
- }
4467
- /**
4468
- * Clear preserved marks for an editor
4469
- */
4470
- static clear(editor) {
4471
- this.preservedMarks.delete(editor);
4472
- }
4473
- };
4474
-
4475
- // src/components/tiptap-ui/blockquote-button/blockquote-button.tsx
4476
4488
  import { Fragment as Fragment7, jsx as jsx45, jsxs as jsxs26 } from "react/jsx-runtime";
4477
4489
  function BlockquoteShortcutBadge({
4478
4490
  shortcutKeys = BLOCKQUOTE_SHORTCUT_KEY
@@ -7686,29 +7698,80 @@ var StylePersistence = Extension2.create({
7686
7698
  excludedMarks: ["code", "codeBlock"]
7687
7699
  };
7688
7700
  },
7701
+ addStorage() {
7702
+ return {
7703
+ // Store marks temporarily when editor loses focus
7704
+ preservedMarks: null,
7705
+ // Store marks from the previous node (for Enter key handling)
7706
+ previousNodeMarks: null
7707
+ };
7708
+ },
7709
+ addKeyboardShortcuts() {
7710
+ return {
7711
+ // Handle Enter key to preserve marks when creating new paragraphs
7712
+ "Enter": ({ editor }) => {
7713
+ const { state } = editor;
7714
+ const { $from } = state.selection;
7715
+ const currentNode = $from.parent;
7716
+ const blockFont = currentNode.attrs.fontFamily;
7717
+ const blockColor = currentNode.attrs.color;
7718
+ if (blockFont || blockColor) {
7719
+ this.storage.previousNodeMarks = { blockFont, blockColor };
7720
+ }
7721
+ return false;
7722
+ },
7723
+ // Handle Shift+Enter (soft break) - same logic
7724
+ "Shift-Enter": ({ editor }) => {
7725
+ const { state } = editor;
7726
+ const { $from } = state.selection;
7727
+ const currentNode = $from.parent;
7728
+ const blockFont = currentNode.attrs.fontFamily;
7729
+ const blockColor = currentNode.attrs.color;
7730
+ if (blockFont || blockColor) {
7731
+ this.storage.previousNodeMarks = { blockFont, blockColor };
7732
+ }
7733
+ return false;
7734
+ }
7735
+ };
7736
+ },
7689
7737
  onSelectionUpdate({ editor }) {
7690
7738
  const excludedMarks = this.options.excludedMarks;
7691
- syncStoredMarks(editor, excludedMarks);
7739
+ syncStoredMarks(editor, excludedMarks, this.storage);
7692
7740
  },
7693
7741
  onFocus({ editor }) {
7694
7742
  const excludedMarks = this.options.excludedMarks;
7695
- syncStoredMarks(editor, excludedMarks);
7743
+ if (this.storage.preservedMarks) {
7744
+ editor.view.dispatch(
7745
+ editor.state.tr.setStoredMarks(this.storage.preservedMarks)
7746
+ );
7747
+ this.storage.preservedMarks = null;
7748
+ }
7749
+ syncStoredMarks(editor, excludedMarks, this.storage);
7750
+ },
7751
+ onBlur({ editor }) {
7752
+ const { state } = editor;
7753
+ const { $from } = state.selection;
7754
+ const currentMarks = state.storedMarks || $from.marks();
7755
+ const hasTextStyle = currentMarks.some((mark) => mark.type.name === "textStyle");
7756
+ if (hasTextStyle) {
7757
+ this.storage.preservedMarks = currentMarks;
7758
+ }
7696
7759
  },
7697
7760
  onCreate({ editor }) {
7698
7761
  const excludedMarks = this.options.excludedMarks;
7699
- syncStoredMarks(editor, excludedMarks);
7762
+ syncStoredMarks(editor, excludedMarks, this.storage);
7700
7763
  },
7701
7764
  onTransaction({ editor, transaction }) {
7702
7765
  if (!transaction.selectionSet && !transaction.docChanged) return;
7703
7766
  const excludedMarks = this.options.excludedMarks;
7704
7767
  requestAnimationFrame(() => {
7705
7768
  if (!editor.isDestroyed) {
7706
- syncStoredMarks(editor, excludedMarks);
7769
+ syncStoredMarks(editor, excludedMarks, this.storage);
7707
7770
  }
7708
7771
  });
7709
7772
  }
7710
7773
  });
7711
- function syncStoredMarks(editor, excludedMarks) {
7774
+ function syncStoredMarks(editor, excludedMarks, storage) {
7712
7775
  const { state } = editor;
7713
7776
  const { $from } = state.selection;
7714
7777
  const marks = $from.marks();
@@ -7727,8 +7790,27 @@ function syncStoredMarks(editor, excludedMarks) {
7727
7790
  return;
7728
7791
  }
7729
7792
  const parentNode = $from.parent;
7730
- const blockFont = parentNode.attrs.fontFamily;
7731
- const blockColor = parentNode.attrs.color;
7793
+ let blockFont = parentNode.attrs.fontFamily;
7794
+ let blockColor = parentNode.attrs.color;
7795
+ if ((!blockFont || !blockColor) && storage?.previousNodeMarks) {
7796
+ if (!blockFont && storage.previousNodeMarks.blockFont) {
7797
+ blockFont = storage.previousNodeMarks.blockFont;
7798
+ }
7799
+ if (!blockColor && storage.previousNodeMarks.blockColor) {
7800
+ blockColor = storage.previousNodeMarks.blockColor;
7801
+ }
7802
+ if (blockFont || blockColor) {
7803
+ const depth = $from.depth;
7804
+ const nodePos = $from.before(depth);
7805
+ const node = $from.node(depth);
7806
+ const newAttrs = { ...node.attrs };
7807
+ if (blockFont) newAttrs.fontFamily = blockFont;
7808
+ if (blockColor) newAttrs.color = blockColor;
7809
+ const tr = state.tr.setNodeMarkup(nodePos, void 0, newAttrs);
7810
+ editor.view.dispatch(tr);
7811
+ }
7812
+ storage.previousNodeMarks = null;
7813
+ }
7732
7814
  if (!blockFont && !blockColor) {
7733
7815
  return;
7734
7816
  }