@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.css +24 -24
- package/dist/index.css.map +1 -1
- package/dist/index.js +140 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +140 -58
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2900,6 +2900,54 @@ function useTiptapEditor(providedEditor) {
|
|
|
2900
2900
|
return editorState || { editor: null };
|
|
2901
2901
|
}
|
|
2902
2902
|
|
|
2903
|
+
// src/hooks/mark-preservers/mark-preserver.ts
|
|
2904
|
+
var MarkPreserver = class {
|
|
2905
|
+
static preservedMarks = /* @__PURE__ */ new Map();
|
|
2906
|
+
/**
|
|
2907
|
+
* Preserve marks before an action that will cause blur
|
|
2908
|
+
* Call this in onMouseDown or onPointerDown events
|
|
2909
|
+
*/
|
|
2910
|
+
static preserve(editor) {
|
|
2911
|
+
if (!editor) return;
|
|
2912
|
+
const { state } = editor;
|
|
2913
|
+
const { $from } = state.selection;
|
|
2914
|
+
const currentMarks = state.storedMarks || $from.marks();
|
|
2915
|
+
if (currentMarks.length > 0) {
|
|
2916
|
+
this.preservedMarks.set(editor, [...currentMarks]);
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
/**
|
|
2920
|
+
* Restore marks after an action completes
|
|
2921
|
+
* Call this after the editor action in onClick or in a setTimeout
|
|
2922
|
+
*/
|
|
2923
|
+
static restore(editor, delay = 0) {
|
|
2924
|
+
if (!editor) return;
|
|
2925
|
+
const marks = this.preservedMarks.get(editor);
|
|
2926
|
+
if (!marks) return;
|
|
2927
|
+
const restoreFn = () => {
|
|
2928
|
+
if (editor.isDestroyed) {
|
|
2929
|
+
this.preservedMarks.delete(editor);
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
const { state } = editor;
|
|
2933
|
+
editor.view.dispatch(state.tr.setStoredMarks(marks));
|
|
2934
|
+
this.preservedMarks.delete(editor);
|
|
2935
|
+
editor.commands.focus();
|
|
2936
|
+
};
|
|
2937
|
+
if (delay > 0) {
|
|
2938
|
+
setTimeout(restoreFn, delay);
|
|
2939
|
+
} else {
|
|
2940
|
+
restoreFn();
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
/**
|
|
2944
|
+
* Clear preserved marks for an editor
|
|
2945
|
+
*/
|
|
2946
|
+
static clear(editor) {
|
|
2947
|
+
this.preservedMarks.delete(editor);
|
|
2948
|
+
}
|
|
2949
|
+
};
|
|
2950
|
+
|
|
2903
2951
|
// src/components/tiptap-ui/heading-button/heading-button.tsx
|
|
2904
2952
|
var import_react28 = require("react");
|
|
2905
2953
|
|
|
@@ -3504,9 +3552,15 @@ var HeadingDropdownMenu = (0, import_react38.forwardRef)(
|
|
|
3504
3552
|
if (!editor || !canToggle2) return;
|
|
3505
3553
|
setIsOpen(open);
|
|
3506
3554
|
onOpenChange?.(open);
|
|
3555
|
+
if (!open) {
|
|
3556
|
+
MarkPreserver.restore(editor, 10);
|
|
3557
|
+
}
|
|
3507
3558
|
},
|
|
3508
3559
|
[canToggle2, editor, onOpenChange]
|
|
3509
3560
|
);
|
|
3561
|
+
const handlePointerDown = (0, import_react38.useCallback)(() => {
|
|
3562
|
+
MarkPreserver.preserve(editor);
|
|
3563
|
+
}, [editor]);
|
|
3510
3564
|
if (!isVisible) {
|
|
3511
3565
|
return null;
|
|
3512
3566
|
}
|
|
@@ -3522,6 +3576,7 @@ var HeadingDropdownMenu = (0, import_react38.forwardRef)(
|
|
|
3522
3576
|
"aria-label": "Format text as heading",
|
|
3523
3577
|
"aria-pressed": isActive,
|
|
3524
3578
|
tooltip: "Heading",
|
|
3579
|
+
onPointerDown: handlePointerDown,
|
|
3525
3580
|
...buttonProps,
|
|
3526
3581
|
ref,
|
|
3527
3582
|
children: [
|
|
@@ -4409,9 +4464,15 @@ function ListDropdownMenu({
|
|
|
4409
4464
|
(open) => {
|
|
4410
4465
|
setIsOpen(open);
|
|
4411
4466
|
onOpenChange?.(open);
|
|
4467
|
+
if (!open) {
|
|
4468
|
+
MarkPreserver.restore(editor, 10);
|
|
4469
|
+
}
|
|
4412
4470
|
},
|
|
4413
|
-
[onOpenChange]
|
|
4471
|
+
[onOpenChange, editor]
|
|
4414
4472
|
);
|
|
4473
|
+
const handlePointerDown = (0, import_react51.useCallback)(() => {
|
|
4474
|
+
MarkPreserver.preserve(editor);
|
|
4475
|
+
}, [editor]);
|
|
4415
4476
|
if (!isVisible) {
|
|
4416
4477
|
return null;
|
|
4417
4478
|
}
|
|
@@ -4428,6 +4489,7 @@ function ListDropdownMenu({
|
|
|
4428
4489
|
"data-disabled": !canToggle2,
|
|
4429
4490
|
"aria-label": "List options",
|
|
4430
4491
|
tooltip: "List",
|
|
4492
|
+
onPointerDown: handlePointerDown,
|
|
4431
4493
|
...props,
|
|
4432
4494
|
children: [
|
|
4433
4495
|
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Icon, { className: "tiptap-button-icon" }),
|
|
@@ -4449,56 +4511,6 @@ function ListDropdownMenu({
|
|
|
4449
4511
|
|
|
4450
4512
|
// src/components/tiptap-ui/blockquote-button/blockquote-button.tsx
|
|
4451
4513
|
var import_react52 = require("react");
|
|
4452
|
-
|
|
4453
|
-
// src/hooks/mark-preservers/mark-preserver.ts
|
|
4454
|
-
var MarkPreserver = class {
|
|
4455
|
-
static preservedMarks = /* @__PURE__ */ new Map();
|
|
4456
|
-
/**
|
|
4457
|
-
* Preserve marks before an action that will cause blur
|
|
4458
|
-
* Call this in onMouseDown or onPointerDown events
|
|
4459
|
-
*/
|
|
4460
|
-
static preserve(editor) {
|
|
4461
|
-
if (!editor) return;
|
|
4462
|
-
const { state } = editor;
|
|
4463
|
-
const { $from } = state.selection;
|
|
4464
|
-
const currentMarks = state.storedMarks || $from.marks();
|
|
4465
|
-
if (currentMarks.length > 0) {
|
|
4466
|
-
this.preservedMarks.set(editor, [...currentMarks]);
|
|
4467
|
-
}
|
|
4468
|
-
}
|
|
4469
|
-
/**
|
|
4470
|
-
* Restore marks after an action completes
|
|
4471
|
-
* Call this after the editor action in onClick or in a setTimeout
|
|
4472
|
-
*/
|
|
4473
|
-
static restore(editor, delay = 0) {
|
|
4474
|
-
if (!editor) return;
|
|
4475
|
-
const marks = this.preservedMarks.get(editor);
|
|
4476
|
-
if (!marks) return;
|
|
4477
|
-
const restoreFn = () => {
|
|
4478
|
-
if (editor.isDestroyed) {
|
|
4479
|
-
this.preservedMarks.delete(editor);
|
|
4480
|
-
return;
|
|
4481
|
-
}
|
|
4482
|
-
const { state } = editor;
|
|
4483
|
-
editor.view.dispatch(state.tr.setStoredMarks(marks));
|
|
4484
|
-
this.preservedMarks.delete(editor);
|
|
4485
|
-
editor.commands.focus();
|
|
4486
|
-
};
|
|
4487
|
-
if (delay > 0) {
|
|
4488
|
-
setTimeout(restoreFn, delay);
|
|
4489
|
-
} else {
|
|
4490
|
-
restoreFn();
|
|
4491
|
-
}
|
|
4492
|
-
}
|
|
4493
|
-
/**
|
|
4494
|
-
* Clear preserved marks for an editor
|
|
4495
|
-
*/
|
|
4496
|
-
static clear(editor) {
|
|
4497
|
-
this.preservedMarks.delete(editor);
|
|
4498
|
-
}
|
|
4499
|
-
};
|
|
4500
|
-
|
|
4501
|
-
// src/components/tiptap-ui/blockquote-button/blockquote-button.tsx
|
|
4502
4514
|
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
4503
4515
|
function BlockquoteShortcutBadge({
|
|
4504
4516
|
shortcutKeys = BLOCKQUOTE_SHORTCUT_KEY
|
|
@@ -7712,29 +7724,80 @@ var StylePersistence = import_core4.Extension.create({
|
|
|
7712
7724
|
excludedMarks: ["code", "codeBlock"]
|
|
7713
7725
|
};
|
|
7714
7726
|
},
|
|
7727
|
+
addStorage() {
|
|
7728
|
+
return {
|
|
7729
|
+
// Store marks temporarily when editor loses focus
|
|
7730
|
+
preservedMarks: null,
|
|
7731
|
+
// Store marks from the previous node (for Enter key handling)
|
|
7732
|
+
previousNodeMarks: null
|
|
7733
|
+
};
|
|
7734
|
+
},
|
|
7735
|
+
addKeyboardShortcuts() {
|
|
7736
|
+
return {
|
|
7737
|
+
// Handle Enter key to preserve marks when creating new paragraphs
|
|
7738
|
+
"Enter": ({ editor }) => {
|
|
7739
|
+
const { state } = editor;
|
|
7740
|
+
const { $from } = state.selection;
|
|
7741
|
+
const currentNode = $from.parent;
|
|
7742
|
+
const blockFont = currentNode.attrs.fontFamily;
|
|
7743
|
+
const blockColor = currentNode.attrs.color;
|
|
7744
|
+
if (blockFont || blockColor) {
|
|
7745
|
+
this.storage.previousNodeMarks = { blockFont, blockColor };
|
|
7746
|
+
}
|
|
7747
|
+
return false;
|
|
7748
|
+
},
|
|
7749
|
+
// Handle Shift+Enter (soft break) - same logic
|
|
7750
|
+
"Shift-Enter": ({ editor }) => {
|
|
7751
|
+
const { state } = editor;
|
|
7752
|
+
const { $from } = state.selection;
|
|
7753
|
+
const currentNode = $from.parent;
|
|
7754
|
+
const blockFont = currentNode.attrs.fontFamily;
|
|
7755
|
+
const blockColor = currentNode.attrs.color;
|
|
7756
|
+
if (blockFont || blockColor) {
|
|
7757
|
+
this.storage.previousNodeMarks = { blockFont, blockColor };
|
|
7758
|
+
}
|
|
7759
|
+
return false;
|
|
7760
|
+
}
|
|
7761
|
+
};
|
|
7762
|
+
},
|
|
7715
7763
|
onSelectionUpdate({ editor }) {
|
|
7716
7764
|
const excludedMarks = this.options.excludedMarks;
|
|
7717
|
-
syncStoredMarks(editor, excludedMarks);
|
|
7765
|
+
syncStoredMarks(editor, excludedMarks, this.storage);
|
|
7718
7766
|
},
|
|
7719
7767
|
onFocus({ editor }) {
|
|
7720
7768
|
const excludedMarks = this.options.excludedMarks;
|
|
7721
|
-
|
|
7769
|
+
if (this.storage.preservedMarks) {
|
|
7770
|
+
editor.view.dispatch(
|
|
7771
|
+
editor.state.tr.setStoredMarks(this.storage.preservedMarks)
|
|
7772
|
+
);
|
|
7773
|
+
this.storage.preservedMarks = null;
|
|
7774
|
+
}
|
|
7775
|
+
syncStoredMarks(editor, excludedMarks, this.storage);
|
|
7776
|
+
},
|
|
7777
|
+
onBlur({ editor }) {
|
|
7778
|
+
const { state } = editor;
|
|
7779
|
+
const { $from } = state.selection;
|
|
7780
|
+
const currentMarks = state.storedMarks || $from.marks();
|
|
7781
|
+
const hasTextStyle = currentMarks.some((mark) => mark.type.name === "textStyle");
|
|
7782
|
+
if (hasTextStyle) {
|
|
7783
|
+
this.storage.preservedMarks = currentMarks;
|
|
7784
|
+
}
|
|
7722
7785
|
},
|
|
7723
7786
|
onCreate({ editor }) {
|
|
7724
7787
|
const excludedMarks = this.options.excludedMarks;
|
|
7725
|
-
syncStoredMarks(editor, excludedMarks);
|
|
7788
|
+
syncStoredMarks(editor, excludedMarks, this.storage);
|
|
7726
7789
|
},
|
|
7727
7790
|
onTransaction({ editor, transaction }) {
|
|
7728
7791
|
if (!transaction.selectionSet && !transaction.docChanged) return;
|
|
7729
7792
|
const excludedMarks = this.options.excludedMarks;
|
|
7730
7793
|
requestAnimationFrame(() => {
|
|
7731
7794
|
if (!editor.isDestroyed) {
|
|
7732
|
-
syncStoredMarks(editor, excludedMarks);
|
|
7795
|
+
syncStoredMarks(editor, excludedMarks, this.storage);
|
|
7733
7796
|
}
|
|
7734
7797
|
});
|
|
7735
7798
|
}
|
|
7736
7799
|
});
|
|
7737
|
-
function syncStoredMarks(editor, excludedMarks) {
|
|
7800
|
+
function syncStoredMarks(editor, excludedMarks, storage) {
|
|
7738
7801
|
const { state } = editor;
|
|
7739
7802
|
const { $from } = state.selection;
|
|
7740
7803
|
const marks = $from.marks();
|
|
@@ -7753,8 +7816,27 @@ function syncStoredMarks(editor, excludedMarks) {
|
|
|
7753
7816
|
return;
|
|
7754
7817
|
}
|
|
7755
7818
|
const parentNode = $from.parent;
|
|
7756
|
-
|
|
7757
|
-
|
|
7819
|
+
let blockFont = parentNode.attrs.fontFamily;
|
|
7820
|
+
let blockColor = parentNode.attrs.color;
|
|
7821
|
+
if ((!blockFont || !blockColor) && storage?.previousNodeMarks) {
|
|
7822
|
+
if (!blockFont && storage.previousNodeMarks.blockFont) {
|
|
7823
|
+
blockFont = storage.previousNodeMarks.blockFont;
|
|
7824
|
+
}
|
|
7825
|
+
if (!blockColor && storage.previousNodeMarks.blockColor) {
|
|
7826
|
+
blockColor = storage.previousNodeMarks.blockColor;
|
|
7827
|
+
}
|
|
7828
|
+
if (blockFont || blockColor) {
|
|
7829
|
+
const depth = $from.depth;
|
|
7830
|
+
const nodePos = $from.before(depth);
|
|
7831
|
+
const node = $from.node(depth);
|
|
7832
|
+
const newAttrs = { ...node.attrs };
|
|
7833
|
+
if (blockFont) newAttrs.fontFamily = blockFont;
|
|
7834
|
+
if (blockColor) newAttrs.color = blockColor;
|
|
7835
|
+
const tr = state.tr.setNodeMarkup(nodePos, void 0, newAttrs);
|
|
7836
|
+
editor.view.dispatch(tr);
|
|
7837
|
+
}
|
|
7838
|
+
storage.previousNodeMarks = null;
|
|
7839
|
+
}
|
|
7758
7840
|
if (!blockFont && !blockColor) {
|
|
7759
7841
|
return;
|
|
7760
7842
|
}
|