@tiptap/core 2.0.0-beta.180 → 2.0.0-beta.183
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/packages/core/src/Mark.d.ts +8 -0
- package/dist/packages/core/src/pasteRules/index.d.ts +1 -0
- package/dist/packages/core/src/pasteRules/nodePasteRule.d.ts +12 -0
- package/dist/tiptap-core.cjs.js +83 -57
- package/dist/tiptap-core.cjs.js.map +1 -1
- package/dist/tiptap-core.esm.js +83 -58
- package/dist/tiptap-core.esm.js.map +1 -1
- package/dist/tiptap-core.umd.js +83 -57
- package/dist/tiptap-core.umd.js.map +1 -1
- package/package.json +9 -9
- package/src/CommandManager.ts +2 -2
- package/src/Editor.ts +1 -0
- package/src/ExtensionManager.ts +13 -4
- package/src/Mark.ts +39 -0
- package/src/PasteRule.ts +2 -2
- package/src/commands/focus.ts +3 -1
- package/src/commands/setContent.ts +1 -4
- package/src/commands/setNodeSelection.ts +3 -5
- package/src/commands/splitBlock.ts +1 -12
- package/src/extensions/focusEvents.ts +2 -2
- package/src/helpers/getTextContentFromNodes.ts +1 -1
- package/src/helpers/isNodeSelection.ts +1 -3
- package/src/helpers/isTextSelection.ts +1 -3
- package/src/pasteRules/index.ts +1 -0
- package/src/pasteRules/nodePasteRule.ts +39 -0
- package/dist/packages/core/src/utilities/isClass.d.ts +0 -1
- package/dist/packages/core/src/utilities/isObject.d.ts +0 -1
- package/src/utilities/isClass.ts +0 -7
- package/src/utilities/isObject.ts +0 -10
|
@@ -245,6 +245,10 @@ declare module '@tiptap/core' {
|
|
|
245
245
|
storage: Storage;
|
|
246
246
|
parent: ParentConfig<MarkConfig<Options, Storage>>['excludes'];
|
|
247
247
|
}) => MarkSpec['excludes']);
|
|
248
|
+
/**
|
|
249
|
+
* Marks this Mark as exitable
|
|
250
|
+
*/
|
|
251
|
+
exitable?: boolean | (() => boolean);
|
|
248
252
|
/**
|
|
249
253
|
* Group
|
|
250
254
|
*/
|
|
@@ -316,4 +320,8 @@ export declare class Mark<Options = any, Storage = any> {
|
|
|
316
320
|
static create<O = any, S = any>(config?: Partial<MarkConfig<O, S>>): Mark<O, S>;
|
|
317
321
|
configure(options?: Partial<Options>): Mark<Options, Storage>;
|
|
318
322
|
extend<ExtendedOptions = Options, ExtendedStorage = Storage>(extendedConfig?: Partial<MarkConfig<ExtendedOptions, ExtendedStorage>>): Mark<ExtendedOptions, ExtendedStorage>;
|
|
323
|
+
static handleExit({ editor, mark, }: {
|
|
324
|
+
editor: Editor;
|
|
325
|
+
mark: Mark;
|
|
326
|
+
}): boolean;
|
|
319
327
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { NodeType } from 'prosemirror-model';
|
|
2
|
+
import { PasteRule } from '../PasteRule';
|
|
3
|
+
import { ExtendedRegExpMatchArray } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* Build an paste rule that adds a node when the
|
|
6
|
+
* matched text is pasted into it.
|
|
7
|
+
*/
|
|
8
|
+
export declare function nodePasteRule(config: {
|
|
9
|
+
find: RegExp;
|
|
10
|
+
type: NodeType;
|
|
11
|
+
getAttributes?: Record<string, any> | ((match: ExtendedRegExpMatchArray) => Record<string, any>) | false | null;
|
|
12
|
+
}): PasteRule;
|
package/dist/tiptap-core.cjs.js
CHANGED
|
@@ -109,13 +109,13 @@ class CommandManager {
|
|
|
109
109
|
}
|
|
110
110
|
createCan(startTr) {
|
|
111
111
|
const { rawCommands, state } = this;
|
|
112
|
-
const dispatch =
|
|
112
|
+
const dispatch = false;
|
|
113
113
|
const tr = startTr || state.tr;
|
|
114
114
|
const props = this.buildProps(tr, dispatch);
|
|
115
115
|
const formattedCommands = Object.fromEntries(Object
|
|
116
116
|
.entries(rawCommands)
|
|
117
117
|
.map(([name, command]) => {
|
|
118
|
-
return [name, (...args) => command(...args)({ ...props, dispatch })];
|
|
118
|
+
return [name, (...args) => command(...args)({ ...props, dispatch: undefined })];
|
|
119
119
|
}));
|
|
120
120
|
return {
|
|
121
121
|
...formattedCommands,
|
|
@@ -546,10 +546,10 @@ function isExtensionRulesEnabled(extension, enabled) {
|
|
|
546
546
|
const getTextContentFromNodes = ($from, maxMatch = 500) => {
|
|
547
547
|
let textBefore = '';
|
|
548
548
|
$from.parent.nodesBetween(Math.max(0, $from.parentOffset - maxMatch), $from.parentOffset, (node, pos, parent, index) => {
|
|
549
|
-
var _a, _b;
|
|
549
|
+
var _a, _b, _c;
|
|
550
550
|
textBefore += ((_b = (_a = node.type.spec).toText) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
|
551
551
|
node, pos, parent, index,
|
|
552
|
-
})) ||
|
|
552
|
+
})) || ((_c = $from.nodeBefore) === null || _c === void 0 ? void 0 : _c.text) || '%leaf%';
|
|
553
553
|
});
|
|
554
554
|
return textBefore;
|
|
555
555
|
};
|
|
@@ -862,7 +862,7 @@ function pasteRulesPlugin(props) {
|
|
|
862
862
|
editor,
|
|
863
863
|
state: chainableState,
|
|
864
864
|
from: Math.max(from - 1, 0),
|
|
865
|
-
to: to.b,
|
|
865
|
+
to: to.b - 1,
|
|
866
866
|
rule,
|
|
867
867
|
});
|
|
868
868
|
// stop if there are no changes
|
|
@@ -1020,15 +1020,21 @@ class ExtensionManager {
|
|
|
1020
1020
|
};
|
|
1021
1021
|
const plugins = [];
|
|
1022
1022
|
const addKeyboardShortcuts = getExtensionField(extension, 'addKeyboardShortcuts', context);
|
|
1023
|
+
let defaultBindings = {};
|
|
1024
|
+
// bind exit handling
|
|
1025
|
+
if (extension.type === 'mark' && extension.config.exitable) {
|
|
1026
|
+
defaultBindings.ArrowRight = () => Mark.handleExit({ editor, mark: extension });
|
|
1027
|
+
}
|
|
1023
1028
|
if (addKeyboardShortcuts) {
|
|
1024
1029
|
const bindings = Object.fromEntries(Object
|
|
1025
1030
|
.entries(addKeyboardShortcuts())
|
|
1026
1031
|
.map(([shortcut, method]) => {
|
|
1027
1032
|
return [shortcut, () => method({ editor })];
|
|
1028
1033
|
}));
|
|
1029
|
-
|
|
1030
|
-
plugins.push(keyMapPlugin);
|
|
1034
|
+
defaultBindings = { ...defaultBindings, ...bindings };
|
|
1031
1035
|
}
|
|
1036
|
+
const keyMapPlugin = prosemirrorKeymap.keymap(defaultBindings);
|
|
1037
|
+
plugins.push(keyMapPlugin);
|
|
1032
1038
|
const addInputRules = getExtensionField(extension, 'addInputRules', context);
|
|
1033
1039
|
if (isExtensionRulesEnabled(extension, editor.options.enableInputRules) && addInputRules) {
|
|
1034
1040
|
inputRules.push(...addInputRules());
|
|
@@ -1451,23 +1457,8 @@ const first = commands => props => {
|
|
|
1451
1457
|
return false;
|
|
1452
1458
|
};
|
|
1453
1459
|
|
|
1454
|
-
function isClass(value) {
|
|
1455
|
-
var _a;
|
|
1456
|
-
if (((_a = value.constructor) === null || _a === void 0 ? void 0 : _a.toString().substring(0, 5)) !== 'class') {
|
|
1457
|
-
return false;
|
|
1458
|
-
}
|
|
1459
|
-
return true;
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
function isObject(value) {
|
|
1463
|
-
return (value
|
|
1464
|
-
&& typeof value === 'object'
|
|
1465
|
-
&& !Array.isArray(value)
|
|
1466
|
-
&& !isClass(value));
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
1460
|
function isTextSelection(value) {
|
|
1470
|
-
return
|
|
1461
|
+
return value instanceof prosemirrorState.TextSelection;
|
|
1471
1462
|
}
|
|
1472
1463
|
|
|
1473
1464
|
function minMax(value = 0, min = 0, max = 0) {
|
|
@@ -1537,7 +1528,9 @@ const focus = (position = null, options = {}) => ({ editor, view, tr, dispatch,
|
|
|
1537
1528
|
delayedFocus();
|
|
1538
1529
|
return true;
|
|
1539
1530
|
}
|
|
1540
|
-
|
|
1531
|
+
// pass through tr.doc instead of editor.state.doc
|
|
1532
|
+
// since transactions could change the editors state before this command has been run
|
|
1533
|
+
const selection = resolveFocusPosition(tr.doc, position) || editor.state.selection;
|
|
1541
1534
|
const isSameSelection = editor.state.selection.eq(selection);
|
|
1542
1535
|
if (dispatch) {
|
|
1543
1536
|
if (!isSameSelection) {
|
|
@@ -1936,10 +1929,8 @@ function createDocument(content, schema, parseOptions = {}) {
|
|
|
1936
1929
|
const setContent = (content, emitUpdate = false, parseOptions = {}) => ({ tr, editor, dispatch }) => {
|
|
1937
1930
|
const { doc } = tr;
|
|
1938
1931
|
const document = createDocument(content, editor.schema, parseOptions);
|
|
1939
|
-
const selection = prosemirrorState.TextSelection.create(doc, 0, doc.content.size);
|
|
1940
1932
|
if (dispatch) {
|
|
1941
|
-
tr.
|
|
1942
|
-
.replaceSelectionWith(document, false)
|
|
1933
|
+
tr.replaceWith(0, doc.content.size, document)
|
|
1943
1934
|
.setMeta('preventUpdate', !emitUpdate);
|
|
1944
1935
|
}
|
|
1945
1936
|
return true;
|
|
@@ -2040,10 +2031,8 @@ const setNode = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) =>
|
|
|
2040
2031
|
const setNodeSelection = position => ({ tr, dispatch }) => {
|
|
2041
2032
|
if (dispatch) {
|
|
2042
2033
|
const { doc } = tr;
|
|
2043
|
-
const
|
|
2044
|
-
const
|
|
2045
|
-
const resolvedPos = minMax(position, minPos, maxPos);
|
|
2046
|
-
const selection = prosemirrorState.NodeSelection.create(doc, resolvedPos);
|
|
2034
|
+
const from = minMax(position, 0, doc.content.size);
|
|
2035
|
+
const selection = prosemirrorState.NodeSelection.create(doc, from);
|
|
2047
2036
|
tr.setSelection(selection);
|
|
2048
2037
|
}
|
|
2049
2038
|
return true;
|
|
@@ -2070,6 +2059,16 @@ const sinkListItem = typeOrName => ({ state, dispatch }) => {
|
|
|
2070
2059
|
return prosemirrorSchemaList.sinkListItem(type)(state, dispatch);
|
|
2071
2060
|
};
|
|
2072
2061
|
|
|
2062
|
+
function defaultBlockAt(match) {
|
|
2063
|
+
for (let i = 0; i < match.edgeCount; i += 1) {
|
|
2064
|
+
const { type } = match.edge(i);
|
|
2065
|
+
if (type.isTextblock && !type.hasRequiredAttrs()) {
|
|
2066
|
+
return type;
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
return null;
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2073
2072
|
function getSplittedAttributes(extensionAttributes, typeName, attributes) {
|
|
2074
2073
|
return Object.fromEntries(Object
|
|
2075
2074
|
.entries(attributes)
|
|
@@ -2084,15 +2083,6 @@ function getSplittedAttributes(extensionAttributes, typeName, attributes) {
|
|
|
2084
2083
|
}));
|
|
2085
2084
|
}
|
|
2086
2085
|
|
|
2087
|
-
function defaultBlockAt$1(match) {
|
|
2088
|
-
for (let i = 0; i < match.edgeCount; i += 1) {
|
|
2089
|
-
const { type } = match.edge(i);
|
|
2090
|
-
if (type.isTextblock && !type.hasRequiredAttrs()) {
|
|
2091
|
-
return type;
|
|
2092
|
-
}
|
|
2093
|
-
}
|
|
2094
|
-
return null;
|
|
2095
|
-
}
|
|
2096
2086
|
function ensureMarks(state, splittableMarks) {
|
|
2097
2087
|
const marks = state.storedMarks
|
|
2098
2088
|
|| (state.selection.$to.parentOffset && state.selection.$from.marks());
|
|
@@ -2128,7 +2118,7 @@ const splitBlock = ({ keepMarks = true } = {}) => ({ tr, state, dispatch, editor
|
|
|
2128
2118
|
}
|
|
2129
2119
|
const deflt = $from.depth === 0
|
|
2130
2120
|
? undefined
|
|
2131
|
-
: defaultBlockAt
|
|
2121
|
+
: defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)));
|
|
2132
2122
|
let types = atEnd && deflt
|
|
2133
2123
|
? [{
|
|
2134
2124
|
type: deflt,
|
|
@@ -3093,6 +3083,7 @@ class Editor extends EventEmitter {
|
|
|
3093
3083
|
*/
|
|
3094
3084
|
setEditable(editable) {
|
|
3095
3085
|
this.setOptions({ editable });
|
|
3086
|
+
this.emit('update', { editor: this, transaction: this.state.tr });
|
|
3096
3087
|
}
|
|
3097
3088
|
/**
|
|
3098
3089
|
* Returns whether the editor is editable.
|
|
@@ -3350,16 +3341,6 @@ function combineTransactionSteps(oldDoc, transactions) {
|
|
|
3350
3341
|
return transform;
|
|
3351
3342
|
}
|
|
3352
3343
|
|
|
3353
|
-
function defaultBlockAt(match) {
|
|
3354
|
-
for (let i = 0; i < match.edgeCount; i += 1) {
|
|
3355
|
-
const { type } = match.edge(i);
|
|
3356
|
-
if (type.isTextblock && !type.hasRequiredAttrs()) {
|
|
3357
|
-
return type;
|
|
3358
|
-
}
|
|
3359
|
-
}
|
|
3360
|
-
return null;
|
|
3361
|
-
}
|
|
3362
|
-
|
|
3363
3344
|
function findChildren(node, predicate) {
|
|
3364
3345
|
const nodesWithPos = [];
|
|
3365
3346
|
node.descendants((child, pos) => {
|
|
@@ -3577,7 +3558,7 @@ function getMarksBetween(from, to, doc) {
|
|
|
3577
3558
|
}
|
|
3578
3559
|
|
|
3579
3560
|
function isNodeSelection(value) {
|
|
3580
|
-
return
|
|
3561
|
+
return value instanceof prosemirrorState.NodeSelection;
|
|
3581
3562
|
}
|
|
3582
3563
|
|
|
3583
3564
|
function posToDOMRect(view, from, to) {
|
|
@@ -3838,6 +3819,26 @@ class Mark {
|
|
|
3838
3819
|
}));
|
|
3839
3820
|
return extension;
|
|
3840
3821
|
}
|
|
3822
|
+
static handleExit({ editor, mark, }) {
|
|
3823
|
+
const { tr } = editor.state;
|
|
3824
|
+
const currentPos = editor.state.selection.$from;
|
|
3825
|
+
const isAtEnd = currentPos.pos === currentPos.end();
|
|
3826
|
+
if (isAtEnd) {
|
|
3827
|
+
const currentMarks = currentPos.marks();
|
|
3828
|
+
const isInMark = !!currentMarks.find(m => (m === null || m === void 0 ? void 0 : m.type.name) === mark.name);
|
|
3829
|
+
if (!isInMark) {
|
|
3830
|
+
return false;
|
|
3831
|
+
}
|
|
3832
|
+
const removeMark = currentMarks.find(m => (m === null || m === void 0 ? void 0 : m.type.name) === mark.name);
|
|
3833
|
+
if (removeMark) {
|
|
3834
|
+
tr.removeStoredMark(removeMark);
|
|
3835
|
+
}
|
|
3836
|
+
tr.insertText(' ', currentPos.pos);
|
|
3837
|
+
editor.view.dispatch(tr);
|
|
3838
|
+
return true;
|
|
3839
|
+
}
|
|
3840
|
+
return false;
|
|
3841
|
+
}
|
|
3841
3842
|
}
|
|
3842
3843
|
|
|
3843
3844
|
class Node {
|
|
@@ -4136,6 +4137,35 @@ function markPasteRule(config) {
|
|
|
4136
4137
|
});
|
|
4137
4138
|
}
|
|
4138
4139
|
|
|
4140
|
+
// source: https://stackoverflow.com/a/6969486
|
|
4141
|
+
function escapeForRegEx(string) {
|
|
4142
|
+
return string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
4143
|
+
}
|
|
4144
|
+
|
|
4145
|
+
/**
|
|
4146
|
+
* Build an paste rule that adds a node when the
|
|
4147
|
+
* matched text is pasted into it.
|
|
4148
|
+
*/
|
|
4149
|
+
function nodePasteRule(config) {
|
|
4150
|
+
return new PasteRule({
|
|
4151
|
+
find: config.find,
|
|
4152
|
+
handler({ match, chain, range }) {
|
|
4153
|
+
const attributes = callOrReturn(config.getAttributes, undefined, match);
|
|
4154
|
+
if (attributes === false || attributes === null) {
|
|
4155
|
+
return null;
|
|
4156
|
+
}
|
|
4157
|
+
if (match.input) {
|
|
4158
|
+
chain()
|
|
4159
|
+
.deleteRange(range)
|
|
4160
|
+
.insertContent({
|
|
4161
|
+
type: config.type.name,
|
|
4162
|
+
attrs: attributes,
|
|
4163
|
+
});
|
|
4164
|
+
}
|
|
4165
|
+
},
|
|
4166
|
+
});
|
|
4167
|
+
}
|
|
4168
|
+
|
|
4139
4169
|
/**
|
|
4140
4170
|
* Build an paste rule that replaces text when the
|
|
4141
4171
|
* matched text is pasted into it.
|
|
@@ -4187,11 +4217,6 @@ class Tracker {
|
|
|
4187
4217
|
}
|
|
4188
4218
|
}
|
|
4189
4219
|
|
|
4190
|
-
// source: https://stackoverflow.com/a/6969486
|
|
4191
|
-
function escapeForRegEx(string) {
|
|
4192
|
-
return string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
4193
|
-
}
|
|
4194
|
-
|
|
4195
4220
|
exports.CommandManager = CommandManager;
|
|
4196
4221
|
exports.Editor = Editor;
|
|
4197
4222
|
exports.Extension = Extension;
|
|
@@ -4241,6 +4266,7 @@ exports.markInputRule = markInputRule;
|
|
|
4241
4266
|
exports.markPasteRule = markPasteRule;
|
|
4242
4267
|
exports.mergeAttributes = mergeAttributes;
|
|
4243
4268
|
exports.nodeInputRule = nodeInputRule;
|
|
4269
|
+
exports.nodePasteRule = nodePasteRule;
|
|
4244
4270
|
exports.pasteRulesPlugin = pasteRulesPlugin;
|
|
4245
4271
|
exports.posToDOMRect = posToDOMRect;
|
|
4246
4272
|
exports.textInputRule = textInputRule;
|