@tiptap/react 2.6.6 → 2.7.0-pre.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 +201 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +198 -20
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +1501 -1322
- package/dist/index.umd.js.map +1 -1
- package/dist/packages/core/src/NodeView.d.ts +20 -8
- package/dist/packages/core/src/index.d.ts +2 -0
- package/dist/packages/core/src/plugins/DropPlugin.d.ts +3 -0
- package/dist/packages/core/src/plugins/PastePlugin.d.ts +3 -0
- package/dist/packages/core/src/types.d.ts +35 -15
- package/dist/packages/react/src/ReactNodeViewRenderer.d.ts +86 -7
- package/dist/packages/react/src/ReactRenderer.d.ts +19 -10
- package/dist/packages/react/src/useEditorState.d.ts +23 -1
- package/package.json +8 -7
- package/src/ReactNodeViewRenderer.tsx +152 -41
- package/src/ReactRenderer.tsx +25 -18
- package/src/useEditor.ts +2 -0
- package/src/useEditorState.ts +43 -8
package/dist/index.cjs
CHANGED
|
@@ -11,6 +11,10 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
|
|
|
11
11
|
var React__default = /*#__PURE__*/_interopDefaultCompat(React);
|
|
12
12
|
var ReactDOM__default = /*#__PURE__*/_interopDefaultCompat(ReactDOM);
|
|
13
13
|
|
|
14
|
+
function getDefaultExportFromCjs (x) {
|
|
15
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
var shim = {exports: {}};
|
|
15
19
|
|
|
16
20
|
var useSyncExternalStoreShim_production_min = {};
|
|
@@ -446,6 +450,80 @@ const EditorContentWithKey = React.forwardRef((props, ref) => {
|
|
|
446
450
|
});
|
|
447
451
|
const EditorContent = React__default.default.memo(EditorContentWithKey);
|
|
448
452
|
|
|
453
|
+
var react = function equal(a, b) {
|
|
454
|
+
if (a === b) return true;
|
|
455
|
+
|
|
456
|
+
if (a && b && typeof a == 'object' && typeof b == 'object') {
|
|
457
|
+
if (a.constructor !== b.constructor) return false;
|
|
458
|
+
|
|
459
|
+
var length, i, keys;
|
|
460
|
+
if (Array.isArray(a)) {
|
|
461
|
+
length = a.length;
|
|
462
|
+
if (length != b.length) return false;
|
|
463
|
+
for (i = length; i-- !== 0;)
|
|
464
|
+
if (!equal(a[i], b[i])) return false;
|
|
465
|
+
return true;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
if ((a instanceof Map) && (b instanceof Map)) {
|
|
470
|
+
if (a.size !== b.size) return false;
|
|
471
|
+
for (i of a.entries())
|
|
472
|
+
if (!b.has(i[0])) return false;
|
|
473
|
+
for (i of a.entries())
|
|
474
|
+
if (!equal(i[1], b.get(i[0]))) return false;
|
|
475
|
+
return true;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if ((a instanceof Set) && (b instanceof Set)) {
|
|
479
|
+
if (a.size !== b.size) return false;
|
|
480
|
+
for (i of a.entries())
|
|
481
|
+
if (!b.has(i[0])) return false;
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
|
|
486
|
+
length = a.length;
|
|
487
|
+
if (length != b.length) return false;
|
|
488
|
+
for (i = length; i-- !== 0;)
|
|
489
|
+
if (a[i] !== b[i]) return false;
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
|
495
|
+
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
|
496
|
+
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
|
497
|
+
|
|
498
|
+
keys = Object.keys(a);
|
|
499
|
+
length = keys.length;
|
|
500
|
+
if (length !== Object.keys(b).length) return false;
|
|
501
|
+
|
|
502
|
+
for (i = length; i-- !== 0;)
|
|
503
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
|
504
|
+
|
|
505
|
+
for (i = length; i-- !== 0;) {
|
|
506
|
+
var key = keys[i];
|
|
507
|
+
|
|
508
|
+
if (key === '_owner' && a.$$typeof) {
|
|
509
|
+
// React-specific: avoid traversing React elements' _owner.
|
|
510
|
+
// _owner contains circular references
|
|
511
|
+
// and is not needed when comparing the actual elements (and not their owners)
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (!equal(a[key], b[key])) return false;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return true;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// true if both NaN, false otherwise
|
|
522
|
+
return a!==a && b!==b;
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
var deepEqual = /*@__PURE__*/getDefaultExportFromCjs(react);
|
|
526
|
+
|
|
449
527
|
var withSelector = {exports: {}};
|
|
450
528
|
|
|
451
529
|
var withSelector_production_min = {};
|
|
@@ -717,13 +795,25 @@ class EditorStateManager {
|
|
|
717
795
|
return undefined;
|
|
718
796
|
}
|
|
719
797
|
}
|
|
798
|
+
/**
|
|
799
|
+
* This hook allows you to watch for changes on the editor instance.
|
|
800
|
+
* It will allow you to select a part of the editor state and re-render the component when it changes.
|
|
801
|
+
* @example
|
|
802
|
+
* ```tsx
|
|
803
|
+
* const editor = useEditor({...options})
|
|
804
|
+
* const { currentSelection } = useEditorState({
|
|
805
|
+
* editor,
|
|
806
|
+
* selector: snapshot => ({ currentSelection: snapshot.editor.state.selection }),
|
|
807
|
+
* })
|
|
808
|
+
*/
|
|
720
809
|
function useEditorState(options) {
|
|
721
|
-
|
|
810
|
+
var _a;
|
|
811
|
+
const [editorStateManager] = React.useState(() => new EditorStateManager(options.editor));
|
|
722
812
|
// Using the `useSyncExternalStore` hook to sync the editor instance with the component state
|
|
723
|
-
const selectedState = withSelectorExports.useSyncExternalStoreWithSelector(
|
|
813
|
+
const selectedState = withSelectorExports.useSyncExternalStoreWithSelector(editorStateManager.subscribe, editorStateManager.getSnapshot, editorStateManager.getServerSnapshot, options.selector, (_a = options.equalityFn) !== null && _a !== void 0 ? _a : deepEqual);
|
|
724
814
|
React.useEffect(() => {
|
|
725
|
-
return
|
|
726
|
-
}, [options.editor,
|
|
815
|
+
return editorStateManager.watch(options.editor);
|
|
816
|
+
}, [options.editor, editorStateManager]);
|
|
727
817
|
React.useDebugValue(selectedState);
|
|
728
818
|
return selectedState;
|
|
729
819
|
}
|
|
@@ -817,6 +907,8 @@ class EditorInstanceManager {
|
|
|
817
907
|
onTransaction: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onTransaction) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
|
|
818
908
|
onUpdate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
|
|
819
909
|
onContentError: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onContentError) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
|
|
910
|
+
onDrop: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onDrop) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
|
|
911
|
+
onPaste: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onPaste) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
|
|
820
912
|
};
|
|
821
913
|
const editor = new core.Editor(optionsToApply);
|
|
822
914
|
// no need to keep track of the event listeners, they will be removed when the editor is destroyed
|
|
@@ -1105,7 +1197,10 @@ function isForwardRefComponent(Component) {
|
|
|
1105
1197
|
* })
|
|
1106
1198
|
*/
|
|
1107
1199
|
class ReactRenderer {
|
|
1108
|
-
|
|
1200
|
+
/**
|
|
1201
|
+
* Immediately creates element and renders the provided React component.
|
|
1202
|
+
*/
|
|
1203
|
+
constructor(component, { editor, props = {}, as = 'div', className = '', }) {
|
|
1109
1204
|
this.ref = null;
|
|
1110
1205
|
this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString();
|
|
1111
1206
|
this.component = component;
|
|
@@ -1116,11 +1211,6 @@ class ReactRenderer {
|
|
|
1116
1211
|
if (className) {
|
|
1117
1212
|
this.element.classList.add(...className.split(' '));
|
|
1118
1213
|
}
|
|
1119
|
-
if (attrs) {
|
|
1120
|
-
Object.keys(attrs).forEach(key => {
|
|
1121
|
-
this.element.setAttribute(key, attrs[key]);
|
|
1122
|
-
});
|
|
1123
|
-
}
|
|
1124
1214
|
if (this.editor.isInitialized) {
|
|
1125
1215
|
// On first render, we need to flush the render synchronously
|
|
1126
1216
|
// Renders afterwards can be async, but this fixes a cursor positioning issue
|
|
@@ -1132,12 +1222,16 @@ class ReactRenderer {
|
|
|
1132
1222
|
this.render();
|
|
1133
1223
|
}
|
|
1134
1224
|
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Render the React component.
|
|
1227
|
+
*/
|
|
1135
1228
|
render() {
|
|
1136
1229
|
var _a;
|
|
1137
1230
|
const Component = this.component;
|
|
1138
1231
|
const props = this.props;
|
|
1139
1232
|
const editor = this.editor;
|
|
1140
1233
|
if (isClassComponent(Component) || isForwardRefComponent(Component)) {
|
|
1234
|
+
// @ts-ignore This is a hack to make the ref work
|
|
1141
1235
|
props.ref = (ref) => {
|
|
1142
1236
|
this.ref = ref;
|
|
1143
1237
|
};
|
|
@@ -1145,6 +1239,9 @@ class ReactRenderer {
|
|
|
1145
1239
|
this.reactElement = React__default.default.createElement(Component, props);
|
|
1146
1240
|
(_a = editor === null || editor === void 0 ? void 0 : editor.contentComponent) === null || _a === void 0 ? void 0 : _a.setRenderer(this.id, this);
|
|
1147
1241
|
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Re-renders the React component with new props.
|
|
1244
|
+
*/
|
|
1148
1245
|
updateProps(props = {}) {
|
|
1149
1246
|
this.props = {
|
|
1150
1247
|
...this.props,
|
|
@@ -1152,21 +1249,39 @@ class ReactRenderer {
|
|
|
1152
1249
|
};
|
|
1153
1250
|
this.render();
|
|
1154
1251
|
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Destroy the React component.
|
|
1254
|
+
*/
|
|
1155
1255
|
destroy() {
|
|
1156
1256
|
var _a;
|
|
1157
1257
|
const editor = this.editor;
|
|
1158
1258
|
(_a = editor === null || editor === void 0 ? void 0 : editor.contentComponent) === null || _a === void 0 ? void 0 : _a.removeRenderer(this.id);
|
|
1159
1259
|
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Update the attributes of the element that holds the React component.
|
|
1262
|
+
*/
|
|
1263
|
+
updateAttributes(attributes) {
|
|
1264
|
+
Object.keys(attributes).forEach(key => {
|
|
1265
|
+
this.element.setAttribute(key, attributes[key]);
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1160
1268
|
}
|
|
1161
1269
|
|
|
1162
1270
|
class ReactNodeView extends core.NodeView {
|
|
1271
|
+
/**
|
|
1272
|
+
* Setup the React component.
|
|
1273
|
+
* Called on initialization.
|
|
1274
|
+
*/
|
|
1163
1275
|
mount() {
|
|
1164
1276
|
const props = {
|
|
1165
1277
|
editor: this.editor,
|
|
1166
1278
|
node: this.node,
|
|
1167
1279
|
decorations: this.decorations,
|
|
1280
|
+
innerDecorations: this.innerDecorations,
|
|
1281
|
+
view: this.view,
|
|
1168
1282
|
selected: false,
|
|
1169
1283
|
extension: this.extension,
|
|
1284
|
+
HTMLAttributes: this.HTMLAttributes,
|
|
1170
1285
|
getPos: () => this.getPos(),
|
|
1171
1286
|
updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
|
|
1172
1287
|
deleteNode: () => this.deleteNode(),
|
|
@@ -1201,6 +1316,7 @@ class ReactNodeView extends core.NodeView {
|
|
|
1201
1316
|
this.contentDOMElement = document.createElement(this.node.isInline ? 'span' : 'div');
|
|
1202
1317
|
}
|
|
1203
1318
|
if (this.contentDOMElement) {
|
|
1319
|
+
this.contentDOMElement.dataset.nodeViewContentReact = '';
|
|
1204
1320
|
// For some reason the whiteSpace prop is not inherited properly in Chrome and Safari
|
|
1205
1321
|
// With this fix it seems to work fine
|
|
1206
1322
|
// See: https://github.com/ueberdosis/tiptap/issues/1197
|
|
@@ -1218,9 +1334,13 @@ class ReactNodeView extends core.NodeView {
|
|
|
1218
1334
|
props,
|
|
1219
1335
|
as,
|
|
1220
1336
|
className: `node-${this.node.type.name} ${className}`.trim(),
|
|
1221
|
-
attrs: this.options.attrs,
|
|
1222
1337
|
});
|
|
1338
|
+
this.updateElementAttributes();
|
|
1223
1339
|
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Return the DOM element.
|
|
1342
|
+
* This is the element that will be used to display the node view.
|
|
1343
|
+
*/
|
|
1224
1344
|
get dom() {
|
|
1225
1345
|
var _a;
|
|
1226
1346
|
if (this.renderer.element.firstElementChild
|
|
@@ -1229,15 +1349,27 @@ class ReactNodeView extends core.NodeView {
|
|
|
1229
1349
|
}
|
|
1230
1350
|
return this.renderer.element;
|
|
1231
1351
|
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Return the content DOM element.
|
|
1354
|
+
* This is the element that will be used to display the rich-text content of the node.
|
|
1355
|
+
*/
|
|
1232
1356
|
get contentDOM() {
|
|
1233
1357
|
if (this.node.isLeaf) {
|
|
1234
1358
|
return null;
|
|
1235
1359
|
}
|
|
1236
1360
|
return this.contentDOMElement;
|
|
1237
1361
|
}
|
|
1362
|
+
/**
|
|
1363
|
+
* On editor selection update, check if the node is selected.
|
|
1364
|
+
* If it is, call `selectNode`, otherwise call `deselectNode`.
|
|
1365
|
+
*/
|
|
1238
1366
|
handleSelectionUpdate() {
|
|
1239
1367
|
const { from, to } = this.editor.state.selection;
|
|
1240
|
-
|
|
1368
|
+
const pos = this.getPos();
|
|
1369
|
+
if (typeof pos !== 'number') {
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
if (from <= pos && to >= pos + this.node.nodeSize) {
|
|
1241
1373
|
if (this.renderer.props.selected) {
|
|
1242
1374
|
return;
|
|
1243
1375
|
}
|
|
@@ -1250,9 +1382,16 @@ class ReactNodeView extends core.NodeView {
|
|
|
1250
1382
|
this.deselectNode();
|
|
1251
1383
|
}
|
|
1252
1384
|
}
|
|
1253
|
-
|
|
1254
|
-
|
|
1385
|
+
/**
|
|
1386
|
+
* On update, update the React component.
|
|
1387
|
+
* To prevent unnecessary updates, the `update` option can be used.
|
|
1388
|
+
*/
|
|
1389
|
+
update(node, decorations, innerDecorations) {
|
|
1390
|
+
const rerenderComponent = (props) => {
|
|
1255
1391
|
this.renderer.updateProps(props);
|
|
1392
|
+
if (typeof this.options.attrs === 'function') {
|
|
1393
|
+
this.updateElementAttributes();
|
|
1394
|
+
}
|
|
1256
1395
|
};
|
|
1257
1396
|
if (node.type !== this.node.type) {
|
|
1258
1397
|
return false;
|
|
@@ -1260,44 +1399,83 @@ class ReactNodeView extends core.NodeView {
|
|
|
1260
1399
|
if (typeof this.options.update === 'function') {
|
|
1261
1400
|
const oldNode = this.node;
|
|
1262
1401
|
const oldDecorations = this.decorations;
|
|
1402
|
+
const oldInnerDecorations = this.innerDecorations;
|
|
1263
1403
|
this.node = node;
|
|
1264
1404
|
this.decorations = decorations;
|
|
1405
|
+
this.innerDecorations = innerDecorations;
|
|
1265
1406
|
return this.options.update({
|
|
1266
1407
|
oldNode,
|
|
1267
1408
|
oldDecorations,
|
|
1268
1409
|
newNode: node,
|
|
1269
1410
|
newDecorations: decorations,
|
|
1270
|
-
|
|
1411
|
+
oldInnerDecorations,
|
|
1412
|
+
innerDecorations,
|
|
1413
|
+
updateProps: () => rerenderComponent({ node, decorations, innerDecorations }),
|
|
1271
1414
|
});
|
|
1272
1415
|
}
|
|
1273
|
-
if (node === this.node
|
|
1416
|
+
if (node === this.node
|
|
1417
|
+
&& this.decorations === decorations
|
|
1418
|
+
&& this.innerDecorations === innerDecorations) {
|
|
1274
1419
|
return true;
|
|
1275
1420
|
}
|
|
1276
1421
|
this.node = node;
|
|
1277
1422
|
this.decorations = decorations;
|
|
1278
|
-
|
|
1423
|
+
this.innerDecorations = innerDecorations;
|
|
1424
|
+
rerenderComponent({ node, decorations, innerDecorations });
|
|
1279
1425
|
return true;
|
|
1280
1426
|
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Select the node.
|
|
1429
|
+
* Add the `selected` prop and the `ProseMirror-selectednode` class.
|
|
1430
|
+
*/
|
|
1281
1431
|
selectNode() {
|
|
1282
1432
|
this.renderer.updateProps({
|
|
1283
1433
|
selected: true,
|
|
1284
1434
|
});
|
|
1285
1435
|
this.renderer.element.classList.add('ProseMirror-selectednode');
|
|
1286
1436
|
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Deselect the node.
|
|
1439
|
+
* Remove the `selected` prop and the `ProseMirror-selectednode` class.
|
|
1440
|
+
*/
|
|
1287
1441
|
deselectNode() {
|
|
1288
1442
|
this.renderer.updateProps({
|
|
1289
1443
|
selected: false,
|
|
1290
1444
|
});
|
|
1291
1445
|
this.renderer.element.classList.remove('ProseMirror-selectednode');
|
|
1292
1446
|
}
|
|
1447
|
+
/**
|
|
1448
|
+
* Destroy the React component instance.
|
|
1449
|
+
*/
|
|
1293
1450
|
destroy() {
|
|
1294
1451
|
this.renderer.destroy();
|
|
1295
1452
|
this.editor.off('selectionUpdate', this.handleSelectionUpdate);
|
|
1296
1453
|
this.contentDOMElement = null;
|
|
1297
1454
|
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Update the attributes of the top-level element that holds the React component.
|
|
1457
|
+
* Applying the attributes defined in the `attrs` option.
|
|
1458
|
+
*/
|
|
1459
|
+
updateElementAttributes() {
|
|
1460
|
+
if (this.options.attrs) {
|
|
1461
|
+
let attrsObj = {};
|
|
1462
|
+
if (typeof this.options.attrs === 'function') {
|
|
1463
|
+
const extensionAttributes = this.editor.extensionManager.attributes;
|
|
1464
|
+
const HTMLAttributes = core.getRenderedAttributes(this.node, extensionAttributes);
|
|
1465
|
+
attrsObj = this.options.attrs({ node: this.node, HTMLAttributes });
|
|
1466
|
+
}
|
|
1467
|
+
else {
|
|
1468
|
+
attrsObj = this.options.attrs;
|
|
1469
|
+
}
|
|
1470
|
+
this.renderer.updateAttributes(attrsObj);
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1298
1473
|
}
|
|
1474
|
+
/**
|
|
1475
|
+
* Create a React node view renderer.
|
|
1476
|
+
*/
|
|
1299
1477
|
function ReactNodeViewRenderer(component, options) {
|
|
1300
|
-
return
|
|
1478
|
+
return props => {
|
|
1301
1479
|
// try to get the parent component
|
|
1302
1480
|
// this is important for vue devtools to show the component hierarchy correctly
|
|
1303
1481
|
// maybe it’s `undefined` because <editor-content> isn’t rendered yet
|
|
@@ -1317,6 +1495,7 @@ exports.FloatingMenu = FloatingMenu;
|
|
|
1317
1495
|
exports.NodeViewContent = NodeViewContent;
|
|
1318
1496
|
exports.NodeViewWrapper = NodeViewWrapper;
|
|
1319
1497
|
exports.PureEditorContent = PureEditorContent;
|
|
1498
|
+
exports.ReactNodeView = ReactNodeView;
|
|
1320
1499
|
exports.ReactNodeViewContext = ReactNodeViewContext;
|
|
1321
1500
|
exports.ReactNodeViewRenderer = ReactNodeViewRenderer;
|
|
1322
1501
|
exports.ReactRenderer = ReactRenderer;
|
|
@@ -1325,9 +1504,9 @@ exports.useEditor = useEditor;
|
|
|
1325
1504
|
exports.useEditorState = useEditorState;
|
|
1326
1505
|
exports.useReactNodeView = useReactNodeView;
|
|
1327
1506
|
Object.keys(core).forEach(function (k) {
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1507
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
1508
|
+
enumerable: true,
|
|
1509
|
+
get: function () { return core[k]; }
|
|
1510
|
+
});
|
|
1332
1511
|
});
|
|
1333
1512
|
//# sourceMappingURL=index.cjs.map
|