@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.js
CHANGED
|
@@ -661,6 +661,23 @@ function inputRulesPlugin(props) {
|
|
|
661
661
|
if (stored) {
|
|
662
662
|
return stored;
|
|
663
663
|
}
|
|
664
|
+
// if InputRule is triggered by insertContent()
|
|
665
|
+
const simulatedInputMeta = tr.getMeta('applyInputRules');
|
|
666
|
+
const isSimulatedInput = !!simulatedInputMeta;
|
|
667
|
+
if (isSimulatedInput) {
|
|
668
|
+
setTimeout(() => {
|
|
669
|
+
const { from, text } = simulatedInputMeta;
|
|
670
|
+
const to = from + text.length;
|
|
671
|
+
run$1({
|
|
672
|
+
editor,
|
|
673
|
+
from,
|
|
674
|
+
to,
|
|
675
|
+
text,
|
|
676
|
+
rules,
|
|
677
|
+
plugin,
|
|
678
|
+
});
|
|
679
|
+
});
|
|
680
|
+
}
|
|
664
681
|
return tr.selectionSet || tr.docChanged ? null : prev;
|
|
665
682
|
},
|
|
666
683
|
},
|
|
@@ -792,6 +809,14 @@ function run(config) {
|
|
|
792
809
|
const success = handlers.every(handler => handler !== null);
|
|
793
810
|
return success;
|
|
794
811
|
}
|
|
812
|
+
const createClipboardPasteEvent = (text) => {
|
|
813
|
+
var _a;
|
|
814
|
+
const event = new ClipboardEvent('paste', {
|
|
815
|
+
clipboardData: new DataTransfer(),
|
|
816
|
+
});
|
|
817
|
+
(_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.setData('text/html', text);
|
|
818
|
+
return event;
|
|
819
|
+
};
|
|
795
820
|
/**
|
|
796
821
|
* Create an paste rules plugin. When enabled, it will cause pasted
|
|
797
822
|
* text that matches any of the given rules to trigger the rule’s
|
|
@@ -804,6 +829,28 @@ function pasteRulesPlugin(props) {
|
|
|
804
829
|
let isDroppedFromProseMirror = false;
|
|
805
830
|
let pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null;
|
|
806
831
|
let dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
|
|
832
|
+
const processEvent = ({ state, from, to, rule, pasteEvt, }) => {
|
|
833
|
+
const tr = state.tr;
|
|
834
|
+
const chainableState = createChainableState({
|
|
835
|
+
state,
|
|
836
|
+
transaction: tr,
|
|
837
|
+
});
|
|
838
|
+
const handler = run({
|
|
839
|
+
editor,
|
|
840
|
+
state: chainableState,
|
|
841
|
+
from: Math.max(from - 1, 0),
|
|
842
|
+
to: to.b - 1,
|
|
843
|
+
rule,
|
|
844
|
+
pasteEvent: pasteEvt,
|
|
845
|
+
dropEvent,
|
|
846
|
+
});
|
|
847
|
+
if (!handler || !tr.steps.length) {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
|
|
851
|
+
pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null;
|
|
852
|
+
return tr;
|
|
853
|
+
};
|
|
807
854
|
const plugins = rules.map(rule => {
|
|
808
855
|
return new Plugin({
|
|
809
856
|
// we register a global drag handler to track the current drag source element
|
|
@@ -841,38 +888,39 @@ function pasteRulesPlugin(props) {
|
|
|
841
888
|
const transaction = transactions[0];
|
|
842
889
|
const isPaste = transaction.getMeta('uiEvent') === 'paste' && !isPastedFromProseMirror;
|
|
843
890
|
const isDrop = transaction.getMeta('uiEvent') === 'drop' && !isDroppedFromProseMirror;
|
|
844
|
-
if
|
|
891
|
+
// if PasteRule is triggered by insertContent()
|
|
892
|
+
const simulatedPasteMeta = transaction.getMeta('applyPasteRules');
|
|
893
|
+
const isSimulatedPaste = !!simulatedPasteMeta;
|
|
894
|
+
if (!isPaste && !isDrop && !isSimulatedPaste) {
|
|
845
895
|
return;
|
|
846
896
|
}
|
|
847
|
-
//
|
|
897
|
+
// Handle simulated paste
|
|
898
|
+
if (isSimulatedPaste) {
|
|
899
|
+
const { from, text } = simulatedPasteMeta;
|
|
900
|
+
const to = from + text.length;
|
|
901
|
+
const pasteEvt = createClipboardPasteEvent(text);
|
|
902
|
+
return processEvent({
|
|
903
|
+
rule,
|
|
904
|
+
state,
|
|
905
|
+
from,
|
|
906
|
+
to: { b: to },
|
|
907
|
+
pasteEvt,
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
// handle actual paste/drop
|
|
848
911
|
const from = oldState.doc.content.findDiffStart(state.doc.content);
|
|
849
912
|
const to = oldState.doc.content.findDiffEnd(state.doc.content);
|
|
913
|
+
// stop if there is no changed range
|
|
850
914
|
if (!isNumber(from) || !to || from === to.b) {
|
|
851
915
|
return;
|
|
852
916
|
}
|
|
853
|
-
|
|
854
|
-
// so we can use a single transaction for all paste rules
|
|
855
|
-
const tr = state.tr;
|
|
856
|
-
const chainableState = createChainableState({
|
|
857
|
-
state,
|
|
858
|
-
transaction: tr,
|
|
859
|
-
});
|
|
860
|
-
const handler = run({
|
|
861
|
-
editor,
|
|
862
|
-
state: chainableState,
|
|
863
|
-
from: Math.max(from - 1, 0),
|
|
864
|
-
to: to.b - 1,
|
|
917
|
+
return processEvent({
|
|
865
918
|
rule,
|
|
866
|
-
|
|
867
|
-
|
|
919
|
+
state,
|
|
920
|
+
from,
|
|
921
|
+
to,
|
|
922
|
+
pasteEvt: pasteEvent,
|
|
868
923
|
});
|
|
869
|
-
// stop if there are no changes
|
|
870
|
-
if (!handler || !tr.steps.length) {
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
|
|
874
|
-
pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null;
|
|
875
|
-
return tr;
|
|
876
924
|
},
|
|
877
925
|
});
|
|
878
926
|
});
|
|
@@ -1216,8 +1264,10 @@ function getTextBetween(startNode, range, options) {
|
|
|
1216
1264
|
range,
|
|
1217
1265
|
});
|
|
1218
1266
|
}
|
|
1267
|
+
// do not descend into child nodes when there exists a serializer
|
|
1268
|
+
return false;
|
|
1219
1269
|
}
|
|
1220
|
-
|
|
1270
|
+
if (node.isText) {
|
|
1221
1271
|
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
|
|
1222
1272
|
separated = false;
|
|
1223
1273
|
}
|
|
@@ -1237,6 +1287,11 @@ function getTextSerializersFromSchema(schema) {
|
|
|
1237
1287
|
|
|
1238
1288
|
const ClipboardTextSerializer = Extension.create({
|
|
1239
1289
|
name: 'clipboardTextSerializer',
|
|
1290
|
+
addOptions() {
|
|
1291
|
+
return {
|
|
1292
|
+
blockSeparator: undefined,
|
|
1293
|
+
};
|
|
1294
|
+
},
|
|
1240
1295
|
addProseMirrorPlugins() {
|
|
1241
1296
|
return [
|
|
1242
1297
|
new Plugin({
|
|
@@ -1252,6 +1307,9 @@ const ClipboardTextSerializer = Extension.create({
|
|
|
1252
1307
|
const textSerializers = getTextSerializersFromSchema(schema);
|
|
1253
1308
|
const range = { from, to };
|
|
1254
1309
|
return getTextBetween(doc, range, {
|
|
1310
|
+
...(this.options.blockSeparator !== undefined
|
|
1311
|
+
? { blockSeparator: this.options.blockSeparator }
|
|
1312
|
+
: {}),
|
|
1255
1313
|
textSerializers,
|
|
1256
1314
|
});
|
|
1257
1315
|
},
|
|
@@ -1658,6 +1716,8 @@ const insertContentAt = (position, value, options) => ({ tr, dispatch, editor })
|
|
|
1658
1716
|
options = {
|
|
1659
1717
|
parseOptions: {},
|
|
1660
1718
|
updateSelection: true,
|
|
1719
|
+
applyInputRules: false,
|
|
1720
|
+
applyPasteRules: false,
|
|
1661
1721
|
...options,
|
|
1662
1722
|
};
|
|
1663
1723
|
const content = createNodeFromContent(value, editor.schema, {
|
|
@@ -1693,28 +1753,37 @@ const insertContentAt = (position, value, options) => ({ tr, dispatch, editor })
|
|
|
1693
1753
|
to += 1;
|
|
1694
1754
|
}
|
|
1695
1755
|
}
|
|
1756
|
+
let newContent;
|
|
1696
1757
|
// if there is only plain text we have to use `insertText`
|
|
1697
1758
|
// because this will keep the current marks
|
|
1698
1759
|
if (isOnlyTextContent) {
|
|
1699
1760
|
// if value is string, we can use it directly
|
|
1700
1761
|
// otherwise if it is an array, we have to join it
|
|
1701
1762
|
if (Array.isArray(value)) {
|
|
1702
|
-
|
|
1763
|
+
newContent = value.map(v => v.text || '').join('');
|
|
1703
1764
|
}
|
|
1704
1765
|
else if (typeof value === 'object' && !!value && !!value.text) {
|
|
1705
|
-
|
|
1766
|
+
newContent = value.text;
|
|
1706
1767
|
}
|
|
1707
1768
|
else {
|
|
1708
|
-
|
|
1769
|
+
newContent = value;
|
|
1709
1770
|
}
|
|
1771
|
+
tr.insertText(newContent, from, to);
|
|
1710
1772
|
}
|
|
1711
1773
|
else {
|
|
1712
|
-
|
|
1774
|
+
newContent = content;
|
|
1775
|
+
tr.replaceWith(from, to, newContent);
|
|
1713
1776
|
}
|
|
1714
1777
|
// set cursor at end of inserted content
|
|
1715
1778
|
if (options.updateSelection) {
|
|
1716
1779
|
selectionToInsertionEnd(tr, tr.steps.length - 1, -1);
|
|
1717
1780
|
}
|
|
1781
|
+
if (options.applyInputRules) {
|
|
1782
|
+
tr.setMeta('applyInputRules', { from, text: newContent });
|
|
1783
|
+
}
|
|
1784
|
+
if (options.applyPasteRules) {
|
|
1785
|
+
tr.setMeta('applyPasteRules', { from, text: newContent });
|
|
1786
|
+
}
|
|
1718
1787
|
}
|
|
1719
1788
|
return true;
|
|
1720
1789
|
};
|
|
@@ -3209,7 +3278,7 @@ const Keymap = Extension.create({
|
|
|
3209
3278
|
const { selection, doc } = tr;
|
|
3210
3279
|
const { empty, $anchor } = selection;
|
|
3211
3280
|
const { pos, parent } = $anchor;
|
|
3212
|
-
const $parentPos = $anchor.parent.isTextblock ? tr.doc.resolve(pos - 1) : $anchor;
|
|
3281
|
+
const $parentPos = $anchor.parent.isTextblock && pos > 0 ? tr.doc.resolve(pos - 1) : $anchor;
|
|
3213
3282
|
const parentIsIsolating = $parentPos.parent.type.spec.isolating;
|
|
3214
3283
|
const parentPos = $anchor.pos - $anchor.parentOffset;
|
|
3215
3284
|
const isAtStart = (parentIsIsolating && $parentPos.parent.childCount === 1)
|
|
@@ -3325,7 +3394,7 @@ const Tabindex = Extension.create({
|
|
|
3325
3394
|
},
|
|
3326
3395
|
});
|
|
3327
3396
|
|
|
3328
|
-
var
|
|
3397
|
+
var index = /*#__PURE__*/Object.freeze({
|
|
3329
3398
|
__proto__: null,
|
|
3330
3399
|
ClipboardTextSerializer: ClipboardTextSerializer,
|
|
3331
3400
|
Commands: Commands,
|
|
@@ -3429,7 +3498,7 @@ class NodePos {
|
|
|
3429
3498
|
const children = [];
|
|
3430
3499
|
this.node.content.forEach((node, offset) => {
|
|
3431
3500
|
const isBlock = node.isBlock && !node.isTextblock;
|
|
3432
|
-
const targetPos = this.pos + offset +
|
|
3501
|
+
const targetPos = this.pos + offset + 1;
|
|
3433
3502
|
const $pos = this.resolvedPos.doc.resolve(targetPos);
|
|
3434
3503
|
if (!isBlock && $pos.depth <= this.depth) {
|
|
3435
3504
|
return;
|
|
@@ -3478,7 +3547,7 @@ class NodePos {
|
|
|
3478
3547
|
querySelectorAll(selector, attributes = {}, firstItemOnly = false) {
|
|
3479
3548
|
let nodes = [];
|
|
3480
3549
|
// iterate through children recursively finding all nodes which match the selector with the node name
|
|
3481
|
-
if (
|
|
3550
|
+
if (!this.children || this.children.length === 0) {
|
|
3482
3551
|
return nodes;
|
|
3483
3552
|
}
|
|
3484
3553
|
this.children.forEach(childPos => {
|
|
@@ -3615,6 +3684,7 @@ class Editor extends EventEmitter {
|
|
|
3615
3684
|
editable: true,
|
|
3616
3685
|
editorProps: {},
|
|
3617
3686
|
parseOptions: {},
|
|
3687
|
+
coreExtensionOptions: {},
|
|
3618
3688
|
enableInputRules: true,
|
|
3619
3689
|
enablePasteRules: true,
|
|
3620
3690
|
enableCoreExtensions: true,
|
|
@@ -3760,7 +3830,17 @@ class Editor extends EventEmitter {
|
|
|
3760
3830
|
* Creates an extension manager.
|
|
3761
3831
|
*/
|
|
3762
3832
|
createExtensionManager() {
|
|
3763
|
-
|
|
3833
|
+
var _a, _b;
|
|
3834
|
+
const coreExtensions = this.options.enableCoreExtensions ? [
|
|
3835
|
+
Editable,
|
|
3836
|
+
ClipboardTextSerializer.configure({
|
|
3837
|
+
blockSeparator: (_b = (_a = this.options.coreExtensionOptions) === null || _a === void 0 ? void 0 : _a.clipboardTextSerializer) === null || _b === void 0 ? void 0 : _b.blockSeparator,
|
|
3838
|
+
}),
|
|
3839
|
+
Commands,
|
|
3840
|
+
FocusEvents,
|
|
3841
|
+
Keymap,
|
|
3842
|
+
Tabindex,
|
|
3843
|
+
] : [];
|
|
3764
3844
|
const allExtensions = [...coreExtensions, ...this.options.extensions].filter(extension => {
|
|
3765
3845
|
return ['extension', 'node', 'mark'].includes(extension === null || extension === void 0 ? void 0 : extension.type);
|
|
3766
3846
|
});
|
|
@@ -4611,5 +4691,5 @@ class Tracker {
|
|
|
4611
4691
|
}
|
|
4612
4692
|
}
|
|
4613
4693
|
|
|
4614
|
-
export { CommandManager, Editor, Extension, InputRule, Mark, Node, NodePos, NodeView, PasteRule, Tracker, callOrReturn, combineTransactionSteps, createChainableState, createDocument, createNodeFromContent, createStyleTag, defaultBlockAt, deleteProps, elementFromString, escapeForRegEx, extensions, findChildren, findChildrenInRange, findDuplicates, findParentNode, findParentNodeClosestToPos, fromString, generateHTML, generateJSON, generateText, getAttributes, getAttributesFromExtensions, getChangedRanges, getDebugJSON, getExtensionField, getHTMLFromFragment, getMarkAttributes, getMarkRange, getMarkType, getMarksBetween, getNodeAtPosition, getNodeAttributes, getNodeType, getRenderedAttributes, getSchema, getSchemaByResolvedExtensions, getSchemaTypeByName, getSchemaTypeNameByName, getSplittedAttributes, getText, getTextBetween, getTextContentFromNodes, getTextSerializersFromSchema, injectExtensionAttributesToParseRule, inputRulesPlugin, isActive, isAtEndOfNode, isAtStartOfNode, isEmptyObject, isExtensionRulesEnabled, isFunction, isList, isMacOS, isMarkActive, isNodeActive, isNodeEmpty, isNodeSelection, isNumber, isPlainObject, isRegExp, isString, isTextSelection, isiOS, markInputRule, markPasteRule, mergeAttributes, mergeDeep, minMax, nodeInputRule, nodePasteRule, objectIncludes, pasteRulesPlugin, posToDOMRect, removeDuplicates, resolveFocusPosition, selectionToInsertionEnd, splitExtensions, textInputRule, textPasteRule, textblockTypeInputRule, wrappingInputRule };
|
|
4694
|
+
export { CommandManager, Editor, Extension, InputRule, Mark, Node, NodePos, NodeView, PasteRule, Tracker, callOrReturn, combineTransactionSteps, createChainableState, createDocument, createNodeFromContent, createStyleTag, defaultBlockAt, deleteProps, elementFromString, escapeForRegEx, index as extensions, findChildren, findChildrenInRange, findDuplicates, findParentNode, findParentNodeClosestToPos, fromString, generateHTML, generateJSON, generateText, getAttributes, getAttributesFromExtensions, getChangedRanges, getDebugJSON, getExtensionField, getHTMLFromFragment, getMarkAttributes, getMarkRange, getMarkType, getMarksBetween, getNodeAtPosition, getNodeAttributes, getNodeType, getRenderedAttributes, getSchema, getSchemaByResolvedExtensions, getSchemaTypeByName, getSchemaTypeNameByName, getSplittedAttributes, getText, getTextBetween, getTextContentFromNodes, getTextSerializersFromSchema, injectExtensionAttributesToParseRule, inputRulesPlugin, isActive, isAtEndOfNode, isAtStartOfNode, isEmptyObject, isExtensionRulesEnabled, isFunction, isList, isMacOS, isMarkActive, isNodeActive, isNodeEmpty, isNodeSelection, isNumber, isPlainObject, isRegExp, isString, isTextSelection, isiOS, markInputRule, markPasteRule, mergeAttributes, mergeDeep, minMax, nodeInputRule, nodePasteRule, objectIncludes, pasteRulesPlugin, posToDOMRect, removeDuplicates, resolveFocusPosition, selectionToInsertionEnd, splitExtensions, textInputRule, textPasteRule, textblockTypeInputRule, wrappingInputRule };
|
|
4615
4695
|
//# sourceMappingURL=index.js.map
|