@tiptap/react 2.6.5 → 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 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
- const [editorInstance] = React.useState(() => new EditorStateManager(options.editor));
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(editorInstance.subscribe, editorInstance.getSnapshot, editorInstance.getServerSnapshot, options.selector, options.equalityFn);
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 editorInstance.watch(options.editor);
726
- }, [options.editor, editorInstance]);
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
- constructor(component, { editor, props = {}, as = 'div', className = '', attrs, }) {
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
- if (from <= this.getPos() && to >= this.getPos() + this.node.nodeSize) {
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
- update(node, decorations) {
1254
- const updateProps = (props) => {
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
- updateProps: () => updateProps({ node, decorations }),
1411
+ oldInnerDecorations,
1412
+ innerDecorations,
1413
+ updateProps: () => rerenderComponent({ node, decorations, innerDecorations }),
1271
1414
  });
1272
1415
  }
1273
- if (node === this.node && this.decorations === decorations) {
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
- updateProps({ node, decorations });
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 (props) => {
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
- if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
1329
- enumerable: true,
1330
- get: function () { return core[k]; }
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