@tiptap/core 2.2.5 → 2.3.0
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.cjs +114 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +114 -34
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +114 -34
- package/dist/index.umd.js.map +1 -1
- package/dist/packages/core/src/Editor.d.ts +1 -2
- package/dist/packages/core/src/commands/insertContent.d.ts +2 -0
- package/dist/packages/core/src/commands/insertContentAt.d.ts +2 -0
- package/dist/packages/core/src/extensions/clipboardTextSerializer.d.ts +4 -1
- package/dist/packages/core/src/types.d.ts +5 -0
- package/package.json +2 -2
- package/src/Editor.ts +16 -3
- package/src/InputRule.ts +20 -0
- package/src/NodePos.ts +2 -2
- package/src/PasteRule.ts +76 -27
- package/src/commands/insertContent.ts +2 -0
- package/src/commands/insertContentAt.ts +22 -4
- package/src/extensions/clipboardTextSerializer.ts +14 -1
- package/src/extensions/keymap.ts +1 -1
- package/src/helpers/getTextBetween.ts +5 -1
- package/src/types.ts +5 -0
package/dist/index.cjs
CHANGED
|
@@ -665,6 +665,23 @@ function inputRulesPlugin(props) {
|
|
|
665
665
|
if (stored) {
|
|
666
666
|
return stored;
|
|
667
667
|
}
|
|
668
|
+
// if InputRule is triggered by insertContent()
|
|
669
|
+
const simulatedInputMeta = tr.getMeta('applyInputRules');
|
|
670
|
+
const isSimulatedInput = !!simulatedInputMeta;
|
|
671
|
+
if (isSimulatedInput) {
|
|
672
|
+
setTimeout(() => {
|
|
673
|
+
const { from, text } = simulatedInputMeta;
|
|
674
|
+
const to = from + text.length;
|
|
675
|
+
run$1({
|
|
676
|
+
editor,
|
|
677
|
+
from,
|
|
678
|
+
to,
|
|
679
|
+
text,
|
|
680
|
+
rules,
|
|
681
|
+
plugin,
|
|
682
|
+
});
|
|
683
|
+
});
|
|
684
|
+
}
|
|
668
685
|
return tr.selectionSet || tr.docChanged ? null : prev;
|
|
669
686
|
},
|
|
670
687
|
},
|
|
@@ -796,6 +813,14 @@ function run(config) {
|
|
|
796
813
|
const success = handlers.every(handler => handler !== null);
|
|
797
814
|
return success;
|
|
798
815
|
}
|
|
816
|
+
const createClipboardPasteEvent = (text) => {
|
|
817
|
+
var _a;
|
|
818
|
+
const event = new ClipboardEvent('paste', {
|
|
819
|
+
clipboardData: new DataTransfer(),
|
|
820
|
+
});
|
|
821
|
+
(_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.setData('text/html', text);
|
|
822
|
+
return event;
|
|
823
|
+
};
|
|
799
824
|
/**
|
|
800
825
|
* Create an paste rules plugin. When enabled, it will cause pasted
|
|
801
826
|
* text that matches any of the given rules to trigger the rule’s
|
|
@@ -808,6 +833,28 @@ function pasteRulesPlugin(props) {
|
|
|
808
833
|
let isDroppedFromProseMirror = false;
|
|
809
834
|
let pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null;
|
|
810
835
|
let dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
|
|
836
|
+
const processEvent = ({ state, from, to, rule, pasteEvt, }) => {
|
|
837
|
+
const tr = state.tr;
|
|
838
|
+
const chainableState = createChainableState({
|
|
839
|
+
state,
|
|
840
|
+
transaction: tr,
|
|
841
|
+
});
|
|
842
|
+
const handler = run({
|
|
843
|
+
editor,
|
|
844
|
+
state: chainableState,
|
|
845
|
+
from: Math.max(from - 1, 0),
|
|
846
|
+
to: to.b - 1,
|
|
847
|
+
rule,
|
|
848
|
+
pasteEvent: pasteEvt,
|
|
849
|
+
dropEvent,
|
|
850
|
+
});
|
|
851
|
+
if (!handler || !tr.steps.length) {
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
|
|
855
|
+
pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null;
|
|
856
|
+
return tr;
|
|
857
|
+
};
|
|
811
858
|
const plugins = rules.map(rule => {
|
|
812
859
|
return new state.Plugin({
|
|
813
860
|
// we register a global drag handler to track the current drag source element
|
|
@@ -845,38 +892,39 @@ function pasteRulesPlugin(props) {
|
|
|
845
892
|
const transaction = transactions[0];
|
|
846
893
|
const isPaste = transaction.getMeta('uiEvent') === 'paste' && !isPastedFromProseMirror;
|
|
847
894
|
const isDrop = transaction.getMeta('uiEvent') === 'drop' && !isDroppedFromProseMirror;
|
|
848
|
-
if
|
|
895
|
+
// if PasteRule is triggered by insertContent()
|
|
896
|
+
const simulatedPasteMeta = transaction.getMeta('applyPasteRules');
|
|
897
|
+
const isSimulatedPaste = !!simulatedPasteMeta;
|
|
898
|
+
if (!isPaste && !isDrop && !isSimulatedPaste) {
|
|
849
899
|
return;
|
|
850
900
|
}
|
|
851
|
-
//
|
|
901
|
+
// Handle simulated paste
|
|
902
|
+
if (isSimulatedPaste) {
|
|
903
|
+
const { from, text } = simulatedPasteMeta;
|
|
904
|
+
const to = from + text.length;
|
|
905
|
+
const pasteEvt = createClipboardPasteEvent(text);
|
|
906
|
+
return processEvent({
|
|
907
|
+
rule,
|
|
908
|
+
state,
|
|
909
|
+
from,
|
|
910
|
+
to: { b: to },
|
|
911
|
+
pasteEvt,
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
// handle actual paste/drop
|
|
852
915
|
const from = oldState.doc.content.findDiffStart(state.doc.content);
|
|
853
916
|
const to = oldState.doc.content.findDiffEnd(state.doc.content);
|
|
917
|
+
// stop if there is no changed range
|
|
854
918
|
if (!isNumber(from) || !to || from === to.b) {
|
|
855
919
|
return;
|
|
856
920
|
}
|
|
857
|
-
|
|
858
|
-
// so we can use a single transaction for all paste rules
|
|
859
|
-
const tr = state.tr;
|
|
860
|
-
const chainableState = createChainableState({
|
|
861
|
-
state,
|
|
862
|
-
transaction: tr,
|
|
863
|
-
});
|
|
864
|
-
const handler = run({
|
|
865
|
-
editor,
|
|
866
|
-
state: chainableState,
|
|
867
|
-
from: Math.max(from - 1, 0),
|
|
868
|
-
to: to.b - 1,
|
|
921
|
+
return processEvent({
|
|
869
922
|
rule,
|
|
870
|
-
|
|
871
|
-
|
|
923
|
+
state,
|
|
924
|
+
from,
|
|
925
|
+
to,
|
|
926
|
+
pasteEvt: pasteEvent,
|
|
872
927
|
});
|
|
873
|
-
// stop if there are no changes
|
|
874
|
-
if (!handler || !tr.steps.length) {
|
|
875
|
-
return;
|
|
876
|
-
}
|
|
877
|
-
dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
|
|
878
|
-
pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null;
|
|
879
|
-
return tr;
|
|
880
928
|
},
|
|
881
929
|
});
|
|
882
930
|
});
|
|
@@ -1220,8 +1268,10 @@ function getTextBetween(startNode, range, options) {
|
|
|
1220
1268
|
range,
|
|
1221
1269
|
});
|
|
1222
1270
|
}
|
|
1271
|
+
// do not descend into child nodes when there exists a serializer
|
|
1272
|
+
return false;
|
|
1223
1273
|
}
|
|
1224
|
-
|
|
1274
|
+
if (node.isText) {
|
|
1225
1275
|
text += (_a = node === null || node === void 0 ? void 0 : node.text) === null || _a === void 0 ? void 0 : _a.slice(Math.max(from, pos) - pos, to - pos); // eslint-disable-line
|
|
1226
1276
|
separated = false;
|
|
1227
1277
|
}
|
|
@@ -1241,6 +1291,11 @@ function getTextSerializersFromSchema(schema) {
|
|
|
1241
1291
|
|
|
1242
1292
|
const ClipboardTextSerializer = Extension.create({
|
|
1243
1293
|
name: 'clipboardTextSerializer',
|
|
1294
|
+
addOptions() {
|
|
1295
|
+
return {
|
|
1296
|
+
blockSeparator: undefined,
|
|
1297
|
+
};
|
|
1298
|
+
},
|
|
1244
1299
|
addProseMirrorPlugins() {
|
|
1245
1300
|
return [
|
|
1246
1301
|
new state.Plugin({
|
|
@@ -1256,6 +1311,9 @@ const ClipboardTextSerializer = Extension.create({
|
|
|
1256
1311
|
const textSerializers = getTextSerializersFromSchema(schema);
|
|
1257
1312
|
const range = { from, to };
|
|
1258
1313
|
return getTextBetween(doc, range, {
|
|
1314
|
+
...(this.options.blockSeparator !== undefined
|
|
1315
|
+
? { blockSeparator: this.options.blockSeparator }
|
|
1316
|
+
: {}),
|
|
1259
1317
|
textSerializers,
|
|
1260
1318
|
});
|
|
1261
1319
|
},
|
|
@@ -1662,6 +1720,8 @@ const insertContentAt = (position, value, options) => ({ tr, dispatch, editor })
|
|
|
1662
1720
|
options = {
|
|
1663
1721
|
parseOptions: {},
|
|
1664
1722
|
updateSelection: true,
|
|
1723
|
+
applyInputRules: false,
|
|
1724
|
+
applyPasteRules: false,
|
|
1665
1725
|
...options,
|
|
1666
1726
|
};
|
|
1667
1727
|
const content = createNodeFromContent(value, editor.schema, {
|
|
@@ -1697,28 +1757,37 @@ const insertContentAt = (position, value, options) => ({ tr, dispatch, editor })
|
|
|
1697
1757
|
to += 1;
|
|
1698
1758
|
}
|
|
1699
1759
|
}
|
|
1760
|
+
let newContent;
|
|
1700
1761
|
// if there is only plain text we have to use `insertText`
|
|
1701
1762
|
// because this will keep the current marks
|
|
1702
1763
|
if (isOnlyTextContent) {
|
|
1703
1764
|
// if value is string, we can use it directly
|
|
1704
1765
|
// otherwise if it is an array, we have to join it
|
|
1705
1766
|
if (Array.isArray(value)) {
|
|
1706
|
-
|
|
1767
|
+
newContent = value.map(v => v.text || '').join('');
|
|
1707
1768
|
}
|
|
1708
1769
|
else if (typeof value === 'object' && !!value && !!value.text) {
|
|
1709
|
-
|
|
1770
|
+
newContent = value.text;
|
|
1710
1771
|
}
|
|
1711
1772
|
else {
|
|
1712
|
-
|
|
1773
|
+
newContent = value;
|
|
1713
1774
|
}
|
|
1775
|
+
tr.insertText(newContent, from, to);
|
|
1714
1776
|
}
|
|
1715
1777
|
else {
|
|
1716
|
-
|
|
1778
|
+
newContent = content;
|
|
1779
|
+
tr.replaceWith(from, to, newContent);
|
|
1717
1780
|
}
|
|
1718
1781
|
// set cursor at end of inserted content
|
|
1719
1782
|
if (options.updateSelection) {
|
|
1720
1783
|
selectionToInsertionEnd(tr, tr.steps.length - 1, -1);
|
|
1721
1784
|
}
|
|
1785
|
+
if (options.applyInputRules) {
|
|
1786
|
+
tr.setMeta('applyInputRules', { from, text: newContent });
|
|
1787
|
+
}
|
|
1788
|
+
if (options.applyPasteRules) {
|
|
1789
|
+
tr.setMeta('applyPasteRules', { from, text: newContent });
|
|
1790
|
+
}
|
|
1722
1791
|
}
|
|
1723
1792
|
return true;
|
|
1724
1793
|
};
|
|
@@ -3213,7 +3282,7 @@ const Keymap = Extension.create({
|
|
|
3213
3282
|
const { selection, doc } = tr;
|
|
3214
3283
|
const { empty, $anchor } = selection;
|
|
3215
3284
|
const { pos, parent } = $anchor;
|
|
3216
|
-
const $parentPos = $anchor.parent.isTextblock ? tr.doc.resolve(pos - 1) : $anchor;
|
|
3285
|
+
const $parentPos = $anchor.parent.isTextblock && pos > 0 ? tr.doc.resolve(pos - 1) : $anchor;
|
|
3217
3286
|
const parentIsIsolating = $parentPos.parent.type.spec.isolating;
|
|
3218
3287
|
const parentPos = $anchor.pos - $anchor.parentOffset;
|
|
3219
3288
|
const isAtStart = (parentIsIsolating && $parentPos.parent.childCount === 1)
|
|
@@ -3329,7 +3398,7 @@ const Tabindex = Extension.create({
|
|
|
3329
3398
|
},
|
|
3330
3399
|
});
|
|
3331
3400
|
|
|
3332
|
-
var
|
|
3401
|
+
var index = /*#__PURE__*/Object.freeze({
|
|
3333
3402
|
__proto__: null,
|
|
3334
3403
|
ClipboardTextSerializer: ClipboardTextSerializer,
|
|
3335
3404
|
Commands: Commands,
|
|
@@ -3433,7 +3502,7 @@ class NodePos {
|
|
|
3433
3502
|
const children = [];
|
|
3434
3503
|
this.node.content.forEach((node, offset) => {
|
|
3435
3504
|
const isBlock = node.isBlock && !node.isTextblock;
|
|
3436
|
-
const targetPos = this.pos + offset +
|
|
3505
|
+
const targetPos = this.pos + offset + 1;
|
|
3437
3506
|
const $pos = this.resolvedPos.doc.resolve(targetPos);
|
|
3438
3507
|
if (!isBlock && $pos.depth <= this.depth) {
|
|
3439
3508
|
return;
|
|
@@ -3482,7 +3551,7 @@ class NodePos {
|
|
|
3482
3551
|
querySelectorAll(selector, attributes = {}, firstItemOnly = false) {
|
|
3483
3552
|
let nodes = [];
|
|
3484
3553
|
// iterate through children recursively finding all nodes which match the selector with the node name
|
|
3485
|
-
if (
|
|
3554
|
+
if (!this.children || this.children.length === 0) {
|
|
3486
3555
|
return nodes;
|
|
3487
3556
|
}
|
|
3488
3557
|
this.children.forEach(childPos => {
|
|
@@ -3619,6 +3688,7 @@ class Editor extends EventEmitter {
|
|
|
3619
3688
|
editable: true,
|
|
3620
3689
|
editorProps: {},
|
|
3621
3690
|
parseOptions: {},
|
|
3691
|
+
coreExtensionOptions: {},
|
|
3622
3692
|
enableInputRules: true,
|
|
3623
3693
|
enablePasteRules: true,
|
|
3624
3694
|
enableCoreExtensions: true,
|
|
@@ -3764,7 +3834,17 @@ class Editor extends EventEmitter {
|
|
|
3764
3834
|
* Creates an extension manager.
|
|
3765
3835
|
*/
|
|
3766
3836
|
createExtensionManager() {
|
|
3767
|
-
|
|
3837
|
+
var _a, _b;
|
|
3838
|
+
const coreExtensions = this.options.enableCoreExtensions ? [
|
|
3839
|
+
Editable,
|
|
3840
|
+
ClipboardTextSerializer.configure({
|
|
3841
|
+
blockSeparator: (_b = (_a = this.options.coreExtensionOptions) === null || _a === void 0 ? void 0 : _a.clipboardTextSerializer) === null || _b === void 0 ? void 0 : _b.blockSeparator,
|
|
3842
|
+
}),
|
|
3843
|
+
Commands,
|
|
3844
|
+
FocusEvents,
|
|
3845
|
+
Keymap,
|
|
3846
|
+
Tabindex,
|
|
3847
|
+
] : [];
|
|
3768
3848
|
const allExtensions = [...coreExtensions, ...this.options.extensions].filter(extension => {
|
|
3769
3849
|
return ['extension', 'node', 'mark'].includes(extension === null || extension === void 0 ? void 0 : extension.type);
|
|
3770
3850
|
});
|
|
@@ -4635,7 +4715,7 @@ exports.defaultBlockAt = defaultBlockAt;
|
|
|
4635
4715
|
exports.deleteProps = deleteProps;
|
|
4636
4716
|
exports.elementFromString = elementFromString;
|
|
4637
4717
|
exports.escapeForRegEx = escapeForRegEx;
|
|
4638
|
-
exports.extensions =
|
|
4718
|
+
exports.extensions = index;
|
|
4639
4719
|
exports.findChildren = findChildren;
|
|
4640
4720
|
exports.findChildrenInRange = findChildrenInRange;
|
|
4641
4721
|
exports.findDuplicates = findDuplicates;
|