@tiptap/react 2.5.9 → 2.6.1

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.umd.js CHANGED
@@ -4,127 +4,6 @@
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["@tiptap/react"] = {}, global.extensionBubbleMenu, global.React, global.ReactDOM, global.core, global.extensionFloatingMenu));
5
5
  })(this, (function (exports, extensionBubbleMenu, React, ReactDOM, core, extensionFloatingMenu) { 'use strict';
6
6
 
7
- const mergeRefs = (...refs) => {
8
- return (node) => {
9
- refs.forEach(ref => {
10
- if (typeof ref === 'function') {
11
- ref(node);
12
- }
13
- else if (ref) {
14
- ref.current = node;
15
- }
16
- });
17
- };
18
- };
19
- const Portals = ({ renderers }) => {
20
- return (React.createElement(React.Fragment, null, Object.entries(renderers).map(([key, renderer]) => {
21
- return ReactDOM.createPortal(renderer.reactElement, renderer.element, key);
22
- })));
23
- };
24
- class PureEditorContent extends React.Component {
25
- constructor(props) {
26
- super(props);
27
- this.editorContentRef = React.createRef();
28
- this.initialized = false;
29
- this.state = {
30
- renderers: {},
31
- };
32
- }
33
- componentDidMount() {
34
- this.init();
35
- }
36
- componentDidUpdate() {
37
- this.init();
38
- }
39
- init() {
40
- const { editor } = this.props;
41
- if (editor && !editor.isDestroyed && editor.options.element) {
42
- if (editor.contentComponent) {
43
- return;
44
- }
45
- const element = this.editorContentRef.current;
46
- element.append(...editor.options.element.childNodes);
47
- editor.setOptions({
48
- element,
49
- });
50
- editor.contentComponent = this;
51
- editor.createNodeViews();
52
- this.initialized = true;
53
- }
54
- }
55
- maybeFlushSync(fn) {
56
- // Avoid calling flushSync until the editor is initialized.
57
- // Initialization happens during the componentDidMount or componentDidUpdate
58
- // lifecycle methods, and React doesn't allow calling flushSync from inside
59
- // a lifecycle method.
60
- if (this.initialized) {
61
- ReactDOM.flushSync(fn);
62
- }
63
- else {
64
- fn();
65
- }
66
- }
67
- setRenderer(id, renderer) {
68
- this.maybeFlushSync(() => {
69
- this.setState(({ renderers }) => ({
70
- renderers: {
71
- ...renderers,
72
- [id]: renderer,
73
- },
74
- }));
75
- });
76
- }
77
- removeRenderer(id) {
78
- this.maybeFlushSync(() => {
79
- this.setState(({ renderers }) => {
80
- const nextRenderers = { ...renderers };
81
- delete nextRenderers[id];
82
- return { renderers: nextRenderers };
83
- });
84
- });
85
- }
86
- componentWillUnmount() {
87
- const { editor } = this.props;
88
- if (!editor) {
89
- return;
90
- }
91
- this.initialized = false;
92
- if (!editor.isDestroyed) {
93
- editor.view.setProps({
94
- nodeViews: {},
95
- });
96
- }
97
- editor.contentComponent = null;
98
- if (!editor.options.element.firstChild) {
99
- return;
100
- }
101
- const newElement = document.createElement('div');
102
- newElement.append(...editor.options.element.childNodes);
103
- editor.setOptions({
104
- element: newElement,
105
- });
106
- }
107
- render() {
108
- const { editor, innerRef, ...rest } = this.props;
109
- return (React.createElement(React.Fragment, null,
110
- React.createElement("div", { ref: mergeRefs(innerRef, this.editorContentRef), ...rest }),
111
- React.createElement(Portals, { renderers: this.state.renderers })));
112
- }
113
- }
114
- // EditorContent should be re-created whenever the Editor instance changes
115
- const EditorContentWithKey = React.forwardRef((props, ref) => {
116
- const key = React.useMemo(() => {
117
- return Math.floor(Math.random() * 0xFFFFFFFF).toString();
118
- }, [props.editor]);
119
- // Can't use JSX here because it conflicts with the type definition of Vue's JSX, so use createElement
120
- return React.createElement(PureEditorContent, {
121
- key,
122
- innerRef: ref,
123
- ...props,
124
- });
125
- });
126
- const EditorContent = React.memo(EditorContentWithKey);
127
-
128
7
  var shim = {exports: {}};
129
8
 
130
9
  var useSyncExternalStoreShim_production_min = {};
@@ -403,12 +282,161 @@
403
282
 
404
283
  var shimExports = shim.exports;
405
284
 
406
- class Editor extends core.Editor {
407
- constructor() {
408
- super(...arguments);
409
- this.contentComponent = null;
285
+ const mergeRefs = (...refs) => {
286
+ return (node) => {
287
+ refs.forEach(ref => {
288
+ if (typeof ref === 'function') {
289
+ ref(node);
290
+ }
291
+ else if (ref) {
292
+ ref.current = node;
293
+ }
294
+ });
295
+ };
296
+ };
297
+ /**
298
+ * This component renders all of the editor's node views.
299
+ */
300
+ const Portals = ({ contentComponent, }) => {
301
+ // For performance reasons, we render the node view portals on state changes only
302
+ const renderers = shimExports.useSyncExternalStore(contentComponent.subscribe, contentComponent.getSnapshot, contentComponent.getServerSnapshot);
303
+ // This allows us to directly render the portals without any additional wrapper
304
+ return (React.createElement(React.Fragment, null, Object.values(renderers)));
305
+ };
306
+ function getInstance() {
307
+ const subscribers = new Set();
308
+ let renderers = {};
309
+ return {
310
+ /**
311
+ * Subscribe to the editor instance's changes.
312
+ */
313
+ subscribe(callback) {
314
+ subscribers.add(callback);
315
+ return () => {
316
+ subscribers.delete(callback);
317
+ };
318
+ },
319
+ getSnapshot() {
320
+ return renderers;
321
+ },
322
+ getServerSnapshot() {
323
+ return renderers;
324
+ },
325
+ /**
326
+ * Adds a new NodeView Renderer to the editor.
327
+ */
328
+ setRenderer(id, renderer) {
329
+ renderers = {
330
+ ...renderers,
331
+ [id]: ReactDOM.createPortal(renderer.reactElement, renderer.element, id),
332
+ };
333
+ subscribers.forEach(subscriber => subscriber());
334
+ },
335
+ /**
336
+ * Removes a NodeView Renderer from the editor.
337
+ */
338
+ removeRenderer(id) {
339
+ const nextRenderers = { ...renderers };
340
+ delete nextRenderers[id];
341
+ renderers = nextRenderers;
342
+ subscribers.forEach(subscriber => subscriber());
343
+ },
344
+ };
345
+ }
346
+ class PureEditorContent extends React.Component {
347
+ constructor(props) {
348
+ super(props);
349
+ this.editorContentRef = React.createRef();
350
+ this.initialized = false;
351
+ this.state = {
352
+ hasContentComponentInitialized: Boolean(props.editor.contentComponent),
353
+ };
354
+ }
355
+ componentDidMount() {
356
+ this.init();
357
+ }
358
+ componentDidUpdate() {
359
+ this.init();
360
+ }
361
+ init() {
362
+ const editor = this.props.editor;
363
+ if (editor && !editor.isDestroyed && editor.options.element) {
364
+ if (editor.contentComponent) {
365
+ return;
366
+ }
367
+ const element = this.editorContentRef.current;
368
+ element.append(...editor.options.element.childNodes);
369
+ editor.setOptions({
370
+ element,
371
+ });
372
+ editor.contentComponent = getInstance();
373
+ // Has the content component been initialized?
374
+ if (!this.state.hasContentComponentInitialized) {
375
+ // Subscribe to the content component
376
+ this.unsubscribeToContentComponent = editor.contentComponent.subscribe(() => {
377
+ this.setState(prevState => {
378
+ if (!prevState.hasContentComponentInitialized) {
379
+ return {
380
+ hasContentComponentInitialized: true,
381
+ };
382
+ }
383
+ return prevState;
384
+ });
385
+ // Unsubscribe to previous content component
386
+ if (this.unsubscribeToContentComponent) {
387
+ this.unsubscribeToContentComponent();
388
+ }
389
+ });
390
+ }
391
+ editor.createNodeViews();
392
+ this.initialized = true;
393
+ }
394
+ }
395
+ componentWillUnmount() {
396
+ const editor = this.props.editor;
397
+ if (!editor) {
398
+ return;
399
+ }
400
+ this.initialized = false;
401
+ if (!editor.isDestroyed) {
402
+ editor.view.setProps({
403
+ nodeViews: {},
404
+ });
405
+ }
406
+ if (this.unsubscribeToContentComponent) {
407
+ this.unsubscribeToContentComponent();
408
+ }
409
+ editor.contentComponent = null;
410
+ if (!editor.options.element.firstChild) {
411
+ return;
412
+ }
413
+ const newElement = document.createElement('div');
414
+ newElement.append(...editor.options.element.childNodes);
415
+ editor.setOptions({
416
+ element: newElement,
417
+ });
418
+ }
419
+ render() {
420
+ const { editor, innerRef, ...rest } = this.props;
421
+ return (React.createElement(React.Fragment, null,
422
+ React.createElement("div", { ref: mergeRefs(innerRef, this.editorContentRef), ...rest }),
423
+ (editor === null || editor === void 0 ? void 0 : editor.contentComponent) && React.createElement(Portals, { contentComponent: editor.contentComponent })));
410
424
  }
411
425
  }
426
+ // EditorContent should be re-created whenever the Editor instance changes
427
+ const EditorContentWithKey = React.forwardRef((props, ref) => {
428
+ const key = React.useMemo(() => {
429
+ return Math.floor(Math.random() * 0xffffffff).toString();
430
+ // eslint-disable-next-line react-hooks/exhaustive-deps
431
+ }, [props.editor]);
432
+ // Can't use JSX here because it conflicts with the type definition of Vue's JSX, so use createElement
433
+ return React.createElement(PureEditorContent, {
434
+ key,
435
+ innerRef: ref,
436
+ ...props,
437
+ });
438
+ });
439
+ const EditorContent = React.memo(EditorContentWithKey);
412
440
 
413
441
  var withSelector = {exports: {}};
414
442
 
@@ -768,17 +796,20 @@
768
796
  * Create a new editor instance. And attach event listeners.
769
797
  */
770
798
  createEditor() {
771
- const editor = new Editor(this.options.current);
772
- // Always call the most recent version of the callback function by default
773
- editor.on('beforeCreate', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onBeforeCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
774
- editor.on('blur', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
775
- editor.on('create', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
776
- editor.on('destroy', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onDestroy) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
777
- editor.on('focus', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
778
- editor.on('selectionUpdate', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onSelectionUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
779
- editor.on('transaction', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onTransaction) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
780
- editor.on('update', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
781
- editor.on('contentError', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onContentError) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
799
+ const optionsToApply = {
800
+ ...this.options.current,
801
+ // Always call the most recent version of the callback function by default
802
+ onBeforeCreate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onBeforeCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
803
+ onBlur: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
804
+ onCreate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
805
+ onDestroy: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onDestroy) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
806
+ onFocus: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
807
+ onSelectionUpdate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onSelectionUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
808
+ onTransaction: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onTransaction) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
809
+ onUpdate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
810
+ onContentError: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onContentError) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
811
+ };
812
+ const editor = new core.Editor(optionsToApply);
782
813
  // no need to keep track of the event listeners, they will be removed when the editor is destroyed
783
814
  return editor;
784
815
  }
@@ -1012,7 +1043,9 @@
1012
1043
  const NodeViewContent = props => {
1013
1044
  const Tag = props.as || 'div';
1014
1045
  const { nodeViewContentRef } = useReactNodeView();
1015
- return (React.createElement(Tag, { ...props, ref: nodeViewContentRef, "data-node-view-content": "", style: {
1046
+ return (
1047
+ // @ts-ignore
1048
+ React.createElement(Tag, { ...props, ref: nodeViewContentRef, "data-node-view-content": "", style: {
1016
1049
  whiteSpace: 'pre-wrap',
1017
1050
  ...props.style,
1018
1051
  } }));
@@ -1021,7 +1054,9 @@
1021
1054
  const NodeViewWrapper = React.forwardRef((props, ref) => {
1022
1055
  const { onDragStart } = useReactNodeView();
1023
1056
  const Tag = props.as || 'div';
1024
- return (React.createElement(Tag, { ...props, ref: ref, "data-node-view-wrapper": "", onDragStart: onDragStart, style: {
1057
+ return (
1058
+ // @ts-ignore
1059
+ React.createElement(Tag, { ...props, ref: ref, "data-node-view-wrapper": "", onDragStart: onDragStart, style: {
1025
1060
  whiteSpace: 'normal',
1026
1061
  ...props.style,
1027
1062
  } }));
@@ -1075,19 +1110,29 @@
1075
1110
  this.element.setAttribute(key, attrs[key]);
1076
1111
  });
1077
1112
  }
1078
- this.render();
1113
+ if (this.editor.isInitialized) {
1114
+ // On first render, we need to flush the render synchronously
1115
+ // Renders afterwards can be async, but this fixes a cursor positioning issue
1116
+ ReactDOM.flushSync(() => {
1117
+ this.render();
1118
+ });
1119
+ }
1120
+ else {
1121
+ this.render();
1122
+ }
1079
1123
  }
1080
1124
  render() {
1081
- var _a, _b;
1125
+ var _a;
1082
1126
  const Component = this.component;
1083
1127
  const props = this.props;
1128
+ const editor = this.editor;
1084
1129
  if (isClassComponent(Component) || isForwardRefComponent(Component)) {
1085
1130
  props.ref = (ref) => {
1086
1131
  this.ref = ref;
1087
1132
  };
1088
1133
  }
1089
- this.reactElement = React.createElement(Component, { ...props });
1090
- (_b = (_a = this.editor) === null || _a === void 0 ? void 0 : _a.contentComponent) === null || _b === void 0 ? void 0 : _b.setRenderer(this.id, this);
1134
+ this.reactElement = React.createElement(Component, props);
1135
+ (_a = editor === null || editor === void 0 ? void 0 : editor.contentComponent) === null || _a === void 0 ? void 0 : _a.setRenderer(this.id, this);
1091
1136
  }
1092
1137
  updateProps(props = {}) {
1093
1138
  this.props = {
@@ -1097,8 +1142,9 @@
1097
1142
  this.render();
1098
1143
  }
1099
1144
  destroy() {
1100
- var _a, _b;
1101
- (_b = (_a = this.editor) === null || _a === void 0 ? void 0 : _a.contentComponent) === null || _b === void 0 ? void 0 : _b.removeRenderer(this.id);
1145
+ var _a;
1146
+ const editor = this.editor;
1147
+ (_a = editor === null || editor === void 0 ? void 0 : editor.contentComponent) === null || _a === void 0 ? void 0 : _a.removeRenderer(this.id);
1102
1148
  }
1103
1149
  }
1104
1150
 
@@ -1120,18 +1166,19 @@
1120
1166
  };
1121
1167
  this.component.displayName = capitalizeFirstChar(this.extension.name);
1122
1168
  }
1123
- const ReactNodeViewProvider = componentProps => {
1124
- const Component = this.component;
1125
- const onDragStart = this.onDragStart.bind(this);
1126
- const nodeViewContentRef = element => {
1127
- if (element && this.contentDOMElement && element.firstChild !== this.contentDOMElement) {
1128
- element.appendChild(this.contentDOMElement);
1129
- }
1130
- };
1131
- return (React.createElement(React.Fragment, null,
1132
- React.createElement(ReactNodeViewContext.Provider, { value: { onDragStart, nodeViewContentRef } },
1133
- React.createElement(Component, { ...componentProps }))));
1169
+ const onDragStart = this.onDragStart.bind(this);
1170
+ const nodeViewContentRef = element => {
1171
+ if (element && this.contentDOMElement && element.firstChild !== this.contentDOMElement) {
1172
+ element.appendChild(this.contentDOMElement);
1173
+ }
1134
1174
  };
1175
+ const context = { onDragStart, nodeViewContentRef };
1176
+ const Component = this.component;
1177
+ // For performance reasons, we memoize the provider component
1178
+ // And all of the things it requires are declared outside of the component, so it doesn't need to re-render
1179
+ const ReactNodeViewProvider = React.memo(componentProps => {
1180
+ return (React.createElement(ReactNodeViewContext.Provider, { value: context }, React.createElement(Component, componentProps)));
1181
+ });
1135
1182
  ReactNodeViewProvider.displayName = 'ReactNodeView';
1136
1183
  if (this.node.isLeaf) {
1137
1184
  this.contentDOMElement = null;
@@ -1250,8 +1297,11 @@
1250
1297
  };
1251
1298
  }
1252
1299
 
1300
+ Object.defineProperty(exports, "Editor", {
1301
+ enumerable: true,
1302
+ get: function () { return core.Editor; }
1303
+ });
1253
1304
  exports.BubbleMenu = BubbleMenu;
1254
- exports.Editor = Editor;
1255
1305
  exports.EditorConsumer = EditorConsumer;
1256
1306
  exports.EditorContent = EditorContent;
1257
1307
  exports.EditorContext = EditorContext;