@tiptap/core 2.0.0-beta.153 → 2.0.0-beta.157
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/tiptap-core.cjs.js +219 -151
- package/dist/tiptap-core.cjs.js.map +1 -1
- package/dist/tiptap-core.esm.js +219 -151
- package/dist/tiptap-core.esm.js.map +1 -1
- package/dist/tiptap-core.umd.js +219 -151
- package/dist/tiptap-core.umd.js.map +1 -1
- package/package.json +3 -3
- package/src/commands/clearNodes.ts +13 -8
- package/src/commands/setNode.ts +9 -6
- package/src/commands/toggleList.ts +10 -0
- package/src/extensions/keymap.ts +70 -0
package/dist/tiptap-core.esm.js
CHANGED
|
@@ -230,23 +230,27 @@ var clearContent$1 = /*#__PURE__*/Object.freeze({
|
|
|
230
230
|
const clearNodes = () => ({ state, tr, dispatch }) => {
|
|
231
231
|
const { selection } = tr;
|
|
232
232
|
const { ranges } = selection;
|
|
233
|
-
|
|
234
|
-
|
|
233
|
+
if (!dispatch) {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
ranges.forEach(({ $from, $to }) => {
|
|
237
|
+
state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
|
|
235
238
|
if (node.type.isText) {
|
|
236
239
|
return;
|
|
237
240
|
}
|
|
238
|
-
const
|
|
239
|
-
const $
|
|
240
|
-
const
|
|
241
|
+
const { doc, mapping } = tr;
|
|
242
|
+
const $mappedFrom = doc.resolve(mapping.map(pos));
|
|
243
|
+
const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize));
|
|
244
|
+
const nodeRange = $mappedFrom.blockRange($mappedTo);
|
|
241
245
|
if (!nodeRange) {
|
|
242
246
|
return;
|
|
243
247
|
}
|
|
244
248
|
const targetLiftDepth = liftTarget(nodeRange);
|
|
245
|
-
if (node.type.isTextblock
|
|
246
|
-
const { defaultType } = $
|
|
249
|
+
if (node.type.isTextblock) {
|
|
250
|
+
const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index());
|
|
247
251
|
tr.setNodeMarkup(nodeRange.start, defaultType);
|
|
248
252
|
}
|
|
249
|
-
if (
|
|
253
|
+
if (targetLiftDepth || targetLiftDepth === 0) {
|
|
250
254
|
tr.lift(nodeRange, targetLiftDepth);
|
|
251
255
|
}
|
|
252
256
|
});
|
|
@@ -1106,12 +1110,15 @@ const setNode = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) =>
|
|
|
1106
1110
|
console.warn('[tiptap warn]: Currently "setNode()" only supports text block nodes.');
|
|
1107
1111
|
return false;
|
|
1108
1112
|
}
|
|
1109
|
-
const canSetBlock = setBlockType(type, attributes)(state);
|
|
1110
|
-
if (canSetBlock) {
|
|
1111
|
-
return setBlockType(type, attributes)(state, dispatch);
|
|
1112
|
-
}
|
|
1113
1113
|
return chain()
|
|
1114
|
-
|
|
1114
|
+
// try to convert node to default node if needed
|
|
1115
|
+
.command(({ commands }) => {
|
|
1116
|
+
const canSetBlock = setBlockType(type, attributes)(state);
|
|
1117
|
+
if (canSetBlock) {
|
|
1118
|
+
return true;
|
|
1119
|
+
}
|
|
1120
|
+
return commands.clearNodes();
|
|
1121
|
+
})
|
|
1115
1122
|
.command(({ state: updatedState }) => {
|
|
1116
1123
|
return setBlockType(type, attributes)(updatedState, dispatch);
|
|
1117
1124
|
})
|
|
@@ -1415,6 +1422,9 @@ const joinListBackwards = (tr, listType) => {
|
|
|
1415
1422
|
return true;
|
|
1416
1423
|
}
|
|
1417
1424
|
const before = tr.doc.resolve(Math.max(0, list.pos - 1)).before(list.depth);
|
|
1425
|
+
if (before === undefined) {
|
|
1426
|
+
return true;
|
|
1427
|
+
}
|
|
1418
1428
|
const nodeBefore = tr.doc.nodeAt(before);
|
|
1419
1429
|
const canJoinBackwards = list.node.type === (nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.type)
|
|
1420
1430
|
&& canJoin(tr.doc, list.pos);
|
|
@@ -1430,6 +1440,9 @@ const joinListForwards = (tr, listType) => {
|
|
|
1430
1440
|
return true;
|
|
1431
1441
|
}
|
|
1432
1442
|
const after = tr.doc.resolve(list.start).after(list.depth);
|
|
1443
|
+
if (after === undefined) {
|
|
1444
|
+
return true;
|
|
1445
|
+
}
|
|
1433
1446
|
const nodeAfter = tr.doc.nodeAt(after);
|
|
1434
1447
|
const canJoinForwards = list.node.type === (nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.type)
|
|
1435
1448
|
&& canJoin(tr.doc, after);
|
|
@@ -1856,144 +1869,6 @@ const FocusEvents = Extension.create({
|
|
|
1856
1869
|
},
|
|
1857
1870
|
});
|
|
1858
1871
|
|
|
1859
|
-
const Keymap = Extension.create({
|
|
1860
|
-
name: 'keymap',
|
|
1861
|
-
addKeyboardShortcuts() {
|
|
1862
|
-
const handleBackspace = () => this.editor.commands.first(({ commands }) => [
|
|
1863
|
-
() => commands.undoInputRule(),
|
|
1864
|
-
() => commands.deleteSelection(),
|
|
1865
|
-
() => commands.joinBackward(),
|
|
1866
|
-
() => commands.selectNodeBackward(),
|
|
1867
|
-
]);
|
|
1868
|
-
const handleDelete = () => this.editor.commands.first(({ commands }) => [
|
|
1869
|
-
() => commands.deleteSelection(),
|
|
1870
|
-
() => commands.joinForward(),
|
|
1871
|
-
() => commands.selectNodeForward(),
|
|
1872
|
-
]);
|
|
1873
|
-
return {
|
|
1874
|
-
Enter: () => this.editor.commands.first(({ commands }) => [
|
|
1875
|
-
() => commands.newlineInCode(),
|
|
1876
|
-
() => commands.createParagraphNear(),
|
|
1877
|
-
() => commands.liftEmptyBlock(),
|
|
1878
|
-
() => commands.splitBlock(),
|
|
1879
|
-
]),
|
|
1880
|
-
'Mod-Enter': () => this.editor.commands.exitCode(),
|
|
1881
|
-
Backspace: handleBackspace,
|
|
1882
|
-
'Mod-Backspace': handleBackspace,
|
|
1883
|
-
'Shift-Backspace': handleBackspace,
|
|
1884
|
-
Delete: handleDelete,
|
|
1885
|
-
'Mod-Delete': handleDelete,
|
|
1886
|
-
'Mod-a': () => this.editor.commands.selectAll(),
|
|
1887
|
-
};
|
|
1888
|
-
},
|
|
1889
|
-
});
|
|
1890
|
-
|
|
1891
|
-
const Tabindex = Extension.create({
|
|
1892
|
-
name: 'tabindex',
|
|
1893
|
-
addProseMirrorPlugins() {
|
|
1894
|
-
return [
|
|
1895
|
-
new Plugin({
|
|
1896
|
-
key: new PluginKey('tabindex'),
|
|
1897
|
-
props: {
|
|
1898
|
-
attributes: {
|
|
1899
|
-
tabindex: '0',
|
|
1900
|
-
},
|
|
1901
|
-
},
|
|
1902
|
-
}),
|
|
1903
|
-
];
|
|
1904
|
-
},
|
|
1905
|
-
});
|
|
1906
|
-
|
|
1907
|
-
var extensions = /*#__PURE__*/Object.freeze({
|
|
1908
|
-
__proto__: null,
|
|
1909
|
-
ClipboardTextSerializer: ClipboardTextSerializer,
|
|
1910
|
-
Commands: Commands,
|
|
1911
|
-
Editable: Editable,
|
|
1912
|
-
FocusEvents: FocusEvents,
|
|
1913
|
-
Keymap: Keymap,
|
|
1914
|
-
Tabindex: Tabindex
|
|
1915
|
-
});
|
|
1916
|
-
|
|
1917
|
-
function getNodeAttributes(state, typeOrName) {
|
|
1918
|
-
const type = getNodeType(typeOrName, state.schema);
|
|
1919
|
-
const { from, to } = state.selection;
|
|
1920
|
-
const nodes = [];
|
|
1921
|
-
state.doc.nodesBetween(from, to, node => {
|
|
1922
|
-
nodes.push(node);
|
|
1923
|
-
});
|
|
1924
|
-
const node = nodes
|
|
1925
|
-
.reverse()
|
|
1926
|
-
.find(nodeItem => nodeItem.type.name === type.name);
|
|
1927
|
-
if (!node) {
|
|
1928
|
-
return {};
|
|
1929
|
-
}
|
|
1930
|
-
return { ...node.attrs };
|
|
1931
|
-
}
|
|
1932
|
-
|
|
1933
|
-
function getAttributes(state, typeOrName) {
|
|
1934
|
-
const schemaType = getSchemaTypeNameByName(typeof typeOrName === 'string'
|
|
1935
|
-
? typeOrName
|
|
1936
|
-
: typeOrName.name, state.schema);
|
|
1937
|
-
if (schemaType === 'node') {
|
|
1938
|
-
return getNodeAttributes(state, typeOrName);
|
|
1939
|
-
}
|
|
1940
|
-
if (schemaType === 'mark') {
|
|
1941
|
-
return getMarkAttributes(state, typeOrName);
|
|
1942
|
-
}
|
|
1943
|
-
return {};
|
|
1944
|
-
}
|
|
1945
|
-
|
|
1946
|
-
function isActive(state, name, attributes = {}) {
|
|
1947
|
-
if (!name) {
|
|
1948
|
-
return isNodeActive(state, null, attributes) || isMarkActive(state, null, attributes);
|
|
1949
|
-
}
|
|
1950
|
-
const schemaType = getSchemaTypeNameByName(name, state.schema);
|
|
1951
|
-
if (schemaType === 'node') {
|
|
1952
|
-
return isNodeActive(state, name, attributes);
|
|
1953
|
-
}
|
|
1954
|
-
if (schemaType === 'mark') {
|
|
1955
|
-
return isMarkActive(state, name, attributes);
|
|
1956
|
-
}
|
|
1957
|
-
return false;
|
|
1958
|
-
}
|
|
1959
|
-
|
|
1960
|
-
function getHTMLFromFragment(fragment, schema) {
|
|
1961
|
-
const documentFragment = DOMSerializer
|
|
1962
|
-
.fromSchema(schema)
|
|
1963
|
-
.serializeFragment(fragment);
|
|
1964
|
-
const temporaryDocument = document.implementation.createHTMLDocument();
|
|
1965
|
-
const container = temporaryDocument.createElement('div');
|
|
1966
|
-
container.appendChild(documentFragment);
|
|
1967
|
-
return container.innerHTML;
|
|
1968
|
-
}
|
|
1969
|
-
|
|
1970
|
-
function getText(node, options) {
|
|
1971
|
-
const range = {
|
|
1972
|
-
from: 0,
|
|
1973
|
-
to: node.content.size,
|
|
1974
|
-
};
|
|
1975
|
-
return getTextBetween(node, range, options);
|
|
1976
|
-
}
|
|
1977
|
-
|
|
1978
|
-
function isNodeEmpty(node) {
|
|
1979
|
-
var _a;
|
|
1980
|
-
const defaultContent = (_a = node.type.createAndFill()) === null || _a === void 0 ? void 0 : _a.toJSON();
|
|
1981
|
-
const content = node.toJSON();
|
|
1982
|
-
return JSON.stringify(defaultContent) === JSON.stringify(content);
|
|
1983
|
-
}
|
|
1984
|
-
|
|
1985
|
-
function createStyleTag(style) {
|
|
1986
|
-
const tipTapStyleTag = document.querySelector('style[data-tiptap-style]');
|
|
1987
|
-
if (tipTapStyleTag !== null) {
|
|
1988
|
-
return tipTapStyleTag;
|
|
1989
|
-
}
|
|
1990
|
-
const styleNode = document.createElement('style');
|
|
1991
|
-
styleNode.setAttribute('data-tiptap-style', '');
|
|
1992
|
-
styleNode.innerHTML = style;
|
|
1993
|
-
document.getElementsByTagName('head')[0].appendChild(styleNode);
|
|
1994
|
-
return styleNode;
|
|
1995
|
-
}
|
|
1996
|
-
|
|
1997
1872
|
function createChainableState(config) {
|
|
1998
1873
|
const { state, transaction } = config;
|
|
1999
1874
|
let { selection } = transaction;
|
|
@@ -2136,6 +2011,199 @@ class CommandManager {
|
|
|
2136
2011
|
}
|
|
2137
2012
|
}
|
|
2138
2013
|
|
|
2014
|
+
const Keymap = Extension.create({
|
|
2015
|
+
name: 'keymap',
|
|
2016
|
+
addKeyboardShortcuts() {
|
|
2017
|
+
const handleBackspace = () => this.editor.commands.first(({ commands }) => [
|
|
2018
|
+
() => commands.undoInputRule(),
|
|
2019
|
+
// maybe convert first text block node to default node
|
|
2020
|
+
() => commands.command(({ tr }) => {
|
|
2021
|
+
const { selection, doc } = tr;
|
|
2022
|
+
const { empty, $anchor } = selection;
|
|
2023
|
+
const { pos, parent } = $anchor;
|
|
2024
|
+
const isAtStart = Selection.atStart(doc).from === pos;
|
|
2025
|
+
if (!empty
|
|
2026
|
+
|| !isAtStart
|
|
2027
|
+
|| !parent.type.isTextblock
|
|
2028
|
+
|| parent.textContent.length) {
|
|
2029
|
+
return false;
|
|
2030
|
+
}
|
|
2031
|
+
return commands.clearNodes();
|
|
2032
|
+
}),
|
|
2033
|
+
() => commands.deleteSelection(),
|
|
2034
|
+
() => commands.joinBackward(),
|
|
2035
|
+
() => commands.selectNodeBackward(),
|
|
2036
|
+
]);
|
|
2037
|
+
const handleDelete = () => this.editor.commands.first(({ commands }) => [
|
|
2038
|
+
() => commands.deleteSelection(),
|
|
2039
|
+
() => commands.joinForward(),
|
|
2040
|
+
() => commands.selectNodeForward(),
|
|
2041
|
+
]);
|
|
2042
|
+
return {
|
|
2043
|
+
Enter: () => this.editor.commands.first(({ commands }) => [
|
|
2044
|
+
() => commands.newlineInCode(),
|
|
2045
|
+
() => commands.createParagraphNear(),
|
|
2046
|
+
() => commands.liftEmptyBlock(),
|
|
2047
|
+
() => commands.splitBlock(),
|
|
2048
|
+
]),
|
|
2049
|
+
'Mod-Enter': () => this.editor.commands.exitCode(),
|
|
2050
|
+
Backspace: handleBackspace,
|
|
2051
|
+
'Mod-Backspace': handleBackspace,
|
|
2052
|
+
'Shift-Backspace': handleBackspace,
|
|
2053
|
+
Delete: handleDelete,
|
|
2054
|
+
'Mod-Delete': handleDelete,
|
|
2055
|
+
'Mod-a': () => this.editor.commands.selectAll(),
|
|
2056
|
+
};
|
|
2057
|
+
},
|
|
2058
|
+
addProseMirrorPlugins() {
|
|
2059
|
+
return [
|
|
2060
|
+
// With this plugin we check if the whole document was selected and deleted.
|
|
2061
|
+
// In this case we will additionally call `clearNodes()` to convert e.g. a heading
|
|
2062
|
+
// to a paragraph if necessary.
|
|
2063
|
+
// This is an alternative to ProseMirror's `AllSelection`, which doesn’t work well
|
|
2064
|
+
// with many other commands.
|
|
2065
|
+
new Plugin({
|
|
2066
|
+
key: new PluginKey('clearDocument'),
|
|
2067
|
+
appendTransaction: (transactions, oldState, newState) => {
|
|
2068
|
+
const docChanges = transactions.some(transaction => transaction.docChanged)
|
|
2069
|
+
&& !oldState.doc.eq(newState.doc);
|
|
2070
|
+
if (!docChanges) {
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
const { empty, from, to } = oldState.selection;
|
|
2074
|
+
const allFrom = Selection.atStart(oldState.doc).from;
|
|
2075
|
+
const allEnd = Selection.atEnd(oldState.doc).to;
|
|
2076
|
+
const allWasSelected = from === allFrom && to === allEnd;
|
|
2077
|
+
const isEmpty = newState.doc.textBetween(0, newState.doc.content.size, ' ', ' ').length === 0;
|
|
2078
|
+
if (empty || !allWasSelected || !isEmpty) {
|
|
2079
|
+
return;
|
|
2080
|
+
}
|
|
2081
|
+
const tr = newState.tr;
|
|
2082
|
+
const state = createChainableState({
|
|
2083
|
+
state: newState,
|
|
2084
|
+
transaction: tr,
|
|
2085
|
+
});
|
|
2086
|
+
const { commands } = new CommandManager({
|
|
2087
|
+
editor: this.editor,
|
|
2088
|
+
state,
|
|
2089
|
+
});
|
|
2090
|
+
commands.clearNodes();
|
|
2091
|
+
if (!tr.steps.length) {
|
|
2092
|
+
return;
|
|
2093
|
+
}
|
|
2094
|
+
return tr;
|
|
2095
|
+
},
|
|
2096
|
+
}),
|
|
2097
|
+
];
|
|
2098
|
+
},
|
|
2099
|
+
});
|
|
2100
|
+
|
|
2101
|
+
const Tabindex = Extension.create({
|
|
2102
|
+
name: 'tabindex',
|
|
2103
|
+
addProseMirrorPlugins() {
|
|
2104
|
+
return [
|
|
2105
|
+
new Plugin({
|
|
2106
|
+
key: new PluginKey('tabindex'),
|
|
2107
|
+
props: {
|
|
2108
|
+
attributes: {
|
|
2109
|
+
tabindex: '0',
|
|
2110
|
+
},
|
|
2111
|
+
},
|
|
2112
|
+
}),
|
|
2113
|
+
];
|
|
2114
|
+
},
|
|
2115
|
+
});
|
|
2116
|
+
|
|
2117
|
+
var extensions = /*#__PURE__*/Object.freeze({
|
|
2118
|
+
__proto__: null,
|
|
2119
|
+
ClipboardTextSerializer: ClipboardTextSerializer,
|
|
2120
|
+
Commands: Commands,
|
|
2121
|
+
Editable: Editable,
|
|
2122
|
+
FocusEvents: FocusEvents,
|
|
2123
|
+
Keymap: Keymap,
|
|
2124
|
+
Tabindex: Tabindex
|
|
2125
|
+
});
|
|
2126
|
+
|
|
2127
|
+
function getNodeAttributes(state, typeOrName) {
|
|
2128
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2129
|
+
const { from, to } = state.selection;
|
|
2130
|
+
const nodes = [];
|
|
2131
|
+
state.doc.nodesBetween(from, to, node => {
|
|
2132
|
+
nodes.push(node);
|
|
2133
|
+
});
|
|
2134
|
+
const node = nodes
|
|
2135
|
+
.reverse()
|
|
2136
|
+
.find(nodeItem => nodeItem.type.name === type.name);
|
|
2137
|
+
if (!node) {
|
|
2138
|
+
return {};
|
|
2139
|
+
}
|
|
2140
|
+
return { ...node.attrs };
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
function getAttributes(state, typeOrName) {
|
|
2144
|
+
const schemaType = getSchemaTypeNameByName(typeof typeOrName === 'string'
|
|
2145
|
+
? typeOrName
|
|
2146
|
+
: typeOrName.name, state.schema);
|
|
2147
|
+
if (schemaType === 'node') {
|
|
2148
|
+
return getNodeAttributes(state, typeOrName);
|
|
2149
|
+
}
|
|
2150
|
+
if (schemaType === 'mark') {
|
|
2151
|
+
return getMarkAttributes(state, typeOrName);
|
|
2152
|
+
}
|
|
2153
|
+
return {};
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
function isActive(state, name, attributes = {}) {
|
|
2157
|
+
if (!name) {
|
|
2158
|
+
return isNodeActive(state, null, attributes) || isMarkActive(state, null, attributes);
|
|
2159
|
+
}
|
|
2160
|
+
const schemaType = getSchemaTypeNameByName(name, state.schema);
|
|
2161
|
+
if (schemaType === 'node') {
|
|
2162
|
+
return isNodeActive(state, name, attributes);
|
|
2163
|
+
}
|
|
2164
|
+
if (schemaType === 'mark') {
|
|
2165
|
+
return isMarkActive(state, name, attributes);
|
|
2166
|
+
}
|
|
2167
|
+
return false;
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
function getHTMLFromFragment(fragment, schema) {
|
|
2171
|
+
const documentFragment = DOMSerializer
|
|
2172
|
+
.fromSchema(schema)
|
|
2173
|
+
.serializeFragment(fragment);
|
|
2174
|
+
const temporaryDocument = document.implementation.createHTMLDocument();
|
|
2175
|
+
const container = temporaryDocument.createElement('div');
|
|
2176
|
+
container.appendChild(documentFragment);
|
|
2177
|
+
return container.innerHTML;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
function getText(node, options) {
|
|
2181
|
+
const range = {
|
|
2182
|
+
from: 0,
|
|
2183
|
+
to: node.content.size,
|
|
2184
|
+
};
|
|
2185
|
+
return getTextBetween(node, range, options);
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
function isNodeEmpty(node) {
|
|
2189
|
+
var _a;
|
|
2190
|
+
const defaultContent = (_a = node.type.createAndFill()) === null || _a === void 0 ? void 0 : _a.toJSON();
|
|
2191
|
+
const content = node.toJSON();
|
|
2192
|
+
return JSON.stringify(defaultContent) === JSON.stringify(content);
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
function createStyleTag(style) {
|
|
2196
|
+
const tipTapStyleTag = document.querySelector('style[data-tiptap-style]');
|
|
2197
|
+
if (tipTapStyleTag !== null) {
|
|
2198
|
+
return tipTapStyleTag;
|
|
2199
|
+
}
|
|
2200
|
+
const styleNode = document.createElement('style');
|
|
2201
|
+
styleNode.setAttribute('data-tiptap-style', '');
|
|
2202
|
+
styleNode.innerHTML = style;
|
|
2203
|
+
document.getElementsByTagName('head')[0].appendChild(styleNode);
|
|
2204
|
+
return styleNode;
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2139
2207
|
class InputRule {
|
|
2140
2208
|
constructor(config) {
|
|
2141
2209
|
this.find = config.find;
|