@tiptap/react 3.20.3 → 3.20.4

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 ADDED
@@ -0,0 +1,1195 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/index.ts
32
+ var index_exports = {};
33
+ __export(index_exports, {
34
+ EditorConsumer: () => EditorConsumer,
35
+ EditorContent: () => EditorContent,
36
+ EditorContext: () => EditorContext,
37
+ EditorProvider: () => EditorProvider,
38
+ MarkViewContent: () => MarkViewContent,
39
+ NodeViewContent: () => NodeViewContent,
40
+ NodeViewWrapper: () => NodeViewWrapper,
41
+ PureEditorContent: () => PureEditorContent,
42
+ ReactMarkView: () => ReactMarkView,
43
+ ReactMarkViewContext: () => ReactMarkViewContext,
44
+ ReactMarkViewRenderer: () => ReactMarkViewRenderer,
45
+ ReactNodeView: () => ReactNodeView,
46
+ ReactNodeViewContentProvider: () => ReactNodeViewContentProvider,
47
+ ReactNodeViewContext: () => ReactNodeViewContext,
48
+ ReactNodeViewRenderer: () => ReactNodeViewRenderer,
49
+ ReactRenderer: () => ReactRenderer,
50
+ Tiptap: () => Tiptap,
51
+ TiptapContent: () => TiptapContent,
52
+ TiptapContext: () => TiptapContext,
53
+ TiptapWrapper: () => TiptapWrapper,
54
+ useCurrentEditor: () => useCurrentEditor,
55
+ useEditor: () => useEditor,
56
+ useEditorState: () => useEditorState,
57
+ useReactNodeView: () => useReactNodeView,
58
+ useTiptap: () => useTiptap,
59
+ useTiptapState: () => useTiptapState
60
+ });
61
+ module.exports = __toCommonJS(index_exports);
62
+
63
+ // src/Context.tsx
64
+ var import_react4 = require("react");
65
+
66
+ // src/EditorContent.tsx
67
+ var import_react = __toESM(require("react"), 1);
68
+ var import_react_dom = __toESM(require("react-dom"), 1);
69
+ var import_shim = require("use-sync-external-store/shim/index.js");
70
+ var import_jsx_runtime = require("react/jsx-runtime");
71
+ var mergeRefs = (...refs) => {
72
+ return (node) => {
73
+ refs.forEach((ref) => {
74
+ if (typeof ref === "function") {
75
+ ref(node);
76
+ } else if (ref) {
77
+ ;
78
+ ref.current = node;
79
+ }
80
+ });
81
+ };
82
+ };
83
+ var Portals = ({ contentComponent }) => {
84
+ const renderers = (0, import_shim.useSyncExternalStore)(
85
+ contentComponent.subscribe,
86
+ contentComponent.getSnapshot,
87
+ contentComponent.getServerSnapshot
88
+ );
89
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: Object.values(renderers) });
90
+ };
91
+ function getInstance() {
92
+ const subscribers = /* @__PURE__ */ new Set();
93
+ let renderers = {};
94
+ return {
95
+ /**
96
+ * Subscribe to the editor instance's changes.
97
+ */
98
+ subscribe(callback) {
99
+ subscribers.add(callback);
100
+ return () => {
101
+ subscribers.delete(callback);
102
+ };
103
+ },
104
+ getSnapshot() {
105
+ return renderers;
106
+ },
107
+ getServerSnapshot() {
108
+ return renderers;
109
+ },
110
+ /**
111
+ * Adds a new NodeView Renderer to the editor.
112
+ */
113
+ setRenderer(id, renderer) {
114
+ renderers = {
115
+ ...renderers,
116
+ [id]: import_react_dom.default.createPortal(renderer.reactElement, renderer.element, id)
117
+ };
118
+ subscribers.forEach((subscriber) => subscriber());
119
+ },
120
+ /**
121
+ * Removes a NodeView Renderer from the editor.
122
+ */
123
+ removeRenderer(id) {
124
+ const nextRenderers = { ...renderers };
125
+ delete nextRenderers[id];
126
+ renderers = nextRenderers;
127
+ subscribers.forEach((subscriber) => subscriber());
128
+ }
129
+ };
130
+ }
131
+ var PureEditorContent = class extends import_react.default.Component {
132
+ constructor(props) {
133
+ var _a;
134
+ super(props);
135
+ this.editorContentRef = import_react.default.createRef();
136
+ this.initialized = false;
137
+ this.state = {
138
+ hasContentComponentInitialized: Boolean((_a = props.editor) == null ? void 0 : _a.contentComponent)
139
+ };
140
+ }
141
+ componentDidMount() {
142
+ this.init();
143
+ }
144
+ componentDidUpdate() {
145
+ this.init();
146
+ }
147
+ init() {
148
+ var _a;
149
+ const editor = this.props.editor;
150
+ if (editor && !editor.isDestroyed && ((_a = editor.view.dom) == null ? void 0 : _a.parentNode)) {
151
+ if (editor.contentComponent) {
152
+ return;
153
+ }
154
+ const element = this.editorContentRef.current;
155
+ element.append(...editor.view.dom.parentNode.childNodes);
156
+ editor.setOptions({
157
+ element
158
+ });
159
+ editor.contentComponent = getInstance();
160
+ if (!this.state.hasContentComponentInitialized) {
161
+ this.unsubscribeToContentComponent = editor.contentComponent.subscribe(() => {
162
+ this.setState((prevState) => {
163
+ if (!prevState.hasContentComponentInitialized) {
164
+ return {
165
+ hasContentComponentInitialized: true
166
+ };
167
+ }
168
+ return prevState;
169
+ });
170
+ if (this.unsubscribeToContentComponent) {
171
+ this.unsubscribeToContentComponent();
172
+ }
173
+ });
174
+ }
175
+ editor.createNodeViews();
176
+ this.initialized = true;
177
+ }
178
+ }
179
+ componentWillUnmount() {
180
+ var _a;
181
+ const editor = this.props.editor;
182
+ if (!editor) {
183
+ return;
184
+ }
185
+ this.initialized = false;
186
+ if (!editor.isDestroyed) {
187
+ editor.view.setProps({
188
+ nodeViews: {}
189
+ });
190
+ }
191
+ if (this.unsubscribeToContentComponent) {
192
+ this.unsubscribeToContentComponent();
193
+ }
194
+ editor.contentComponent = null;
195
+ try {
196
+ if (!((_a = editor.view.dom) == null ? void 0 : _a.parentNode)) {
197
+ return;
198
+ }
199
+ const newElement = document.createElement("div");
200
+ newElement.append(...editor.view.dom.parentNode.childNodes);
201
+ editor.setOptions({
202
+ element: newElement
203
+ });
204
+ } catch {
205
+ }
206
+ }
207
+ render() {
208
+ const { editor, innerRef, ...rest } = this.props;
209
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
210
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: mergeRefs(innerRef, this.editorContentRef), ...rest }),
211
+ (editor == null ? void 0 : editor.contentComponent) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Portals, { contentComponent: editor.contentComponent })
212
+ ] });
213
+ }
214
+ };
215
+ var EditorContentWithKey = (0, import_react.forwardRef)(
216
+ (props, ref) => {
217
+ const key = import_react.default.useMemo(() => {
218
+ return Math.floor(Math.random() * 4294967295).toString();
219
+ }, [props.editor]);
220
+ return import_react.default.createElement(PureEditorContent, {
221
+ key,
222
+ innerRef: ref,
223
+ ...props
224
+ });
225
+ }
226
+ );
227
+ var EditorContent = import_react.default.memo(EditorContentWithKey);
228
+
229
+ // src/useEditor.ts
230
+ var import_core = require("@tiptap/core");
231
+ var import_react3 = require("react");
232
+ var import_shim2 = require("use-sync-external-store/shim/index.js");
233
+
234
+ // src/useEditorState.ts
235
+ var import_fast_equals = require("fast-equals");
236
+ var import_react2 = require("react");
237
+ var import_with_selector = require("use-sync-external-store/shim/with-selector.js");
238
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? import_react2.useLayoutEffect : import_react2.useEffect;
239
+ var EditorStateManager = class {
240
+ constructor(initialEditor) {
241
+ this.transactionNumber = 0;
242
+ this.lastTransactionNumber = 0;
243
+ this.subscribers = /* @__PURE__ */ new Set();
244
+ this.editor = initialEditor;
245
+ this.lastSnapshot = { editor: initialEditor, transactionNumber: 0 };
246
+ this.getSnapshot = this.getSnapshot.bind(this);
247
+ this.getServerSnapshot = this.getServerSnapshot.bind(this);
248
+ this.watch = this.watch.bind(this);
249
+ this.subscribe = this.subscribe.bind(this);
250
+ }
251
+ /**
252
+ * Get the current editor instance.
253
+ */
254
+ getSnapshot() {
255
+ if (this.transactionNumber === this.lastTransactionNumber) {
256
+ return this.lastSnapshot;
257
+ }
258
+ this.lastTransactionNumber = this.transactionNumber;
259
+ this.lastSnapshot = { editor: this.editor, transactionNumber: this.transactionNumber };
260
+ return this.lastSnapshot;
261
+ }
262
+ /**
263
+ * Always disable the editor on the server-side.
264
+ */
265
+ getServerSnapshot() {
266
+ return { editor: null, transactionNumber: 0 };
267
+ }
268
+ /**
269
+ * Subscribe to the editor instance's changes.
270
+ */
271
+ subscribe(callback) {
272
+ this.subscribers.add(callback);
273
+ return () => {
274
+ this.subscribers.delete(callback);
275
+ };
276
+ }
277
+ /**
278
+ * Watch the editor instance for changes.
279
+ */
280
+ watch(nextEditor) {
281
+ this.editor = nextEditor;
282
+ if (this.editor) {
283
+ const fn = () => {
284
+ this.transactionNumber += 1;
285
+ this.subscribers.forEach((callback) => callback());
286
+ };
287
+ const currentEditor = this.editor;
288
+ currentEditor.on("transaction", fn);
289
+ return () => {
290
+ currentEditor.off("transaction", fn);
291
+ };
292
+ }
293
+ return void 0;
294
+ }
295
+ };
296
+ function useEditorState(options) {
297
+ var _a;
298
+ const [editorStateManager] = (0, import_react2.useState)(() => new EditorStateManager(options.editor));
299
+ const selectedState = (0, import_with_selector.useSyncExternalStoreWithSelector)(
300
+ editorStateManager.subscribe,
301
+ editorStateManager.getSnapshot,
302
+ editorStateManager.getServerSnapshot,
303
+ options.selector,
304
+ (_a = options.equalityFn) != null ? _a : import_fast_equals.deepEqual
305
+ );
306
+ useIsomorphicLayoutEffect(() => {
307
+ return editorStateManager.watch(options.editor);
308
+ }, [options.editor, editorStateManager]);
309
+ (0, import_react2.useDebugValue)(selectedState);
310
+ return selectedState;
311
+ }
312
+
313
+ // src/useEditor.ts
314
+ var isDev = process.env.NODE_ENV !== "production";
315
+ var isSSR = typeof window === "undefined";
316
+ var isNext = isSSR || Boolean(typeof window !== "undefined" && window.next);
317
+ var EditorInstanceManager = class _EditorInstanceManager {
318
+ constructor(options) {
319
+ /**
320
+ * The current editor instance.
321
+ */
322
+ this.editor = null;
323
+ /**
324
+ * The subscriptions to notify when the editor instance
325
+ * has been created or destroyed.
326
+ */
327
+ this.subscriptions = /* @__PURE__ */ new Set();
328
+ /**
329
+ * Whether the editor has been mounted.
330
+ */
331
+ this.isComponentMounted = false;
332
+ /**
333
+ * The most recent dependencies array.
334
+ */
335
+ this.previousDeps = null;
336
+ /**
337
+ * The unique instance ID. This is used to identify the editor instance. And will be re-generated for each new instance.
338
+ */
339
+ this.instanceId = "";
340
+ this.options = options;
341
+ this.subscriptions = /* @__PURE__ */ new Set();
342
+ this.setEditor(this.getInitialEditor());
343
+ this.scheduleDestroy();
344
+ this.getEditor = this.getEditor.bind(this);
345
+ this.getServerSnapshot = this.getServerSnapshot.bind(this);
346
+ this.subscribe = this.subscribe.bind(this);
347
+ this.refreshEditorInstance = this.refreshEditorInstance.bind(this);
348
+ this.scheduleDestroy = this.scheduleDestroy.bind(this);
349
+ this.onRender = this.onRender.bind(this);
350
+ this.createEditor = this.createEditor.bind(this);
351
+ }
352
+ setEditor(editor) {
353
+ this.editor = editor;
354
+ this.instanceId = Math.random().toString(36).slice(2, 9);
355
+ this.subscriptions.forEach((cb) => cb());
356
+ }
357
+ getInitialEditor() {
358
+ if (this.options.current.immediatelyRender === void 0) {
359
+ if (isSSR || isNext) {
360
+ if (isDev) {
361
+ throw new Error(
362
+ "Tiptap Error: SSR has been detected, please set `immediatelyRender` explicitly to `false` to avoid hydration mismatches."
363
+ );
364
+ }
365
+ return null;
366
+ }
367
+ return this.createEditor();
368
+ }
369
+ if (this.options.current.immediatelyRender && isSSR && isDev) {
370
+ throw new Error(
371
+ "Tiptap Error: SSR has been detected, and `immediatelyRender` has been set to `true` this is an unsupported configuration that may result in errors, explicitly set `immediatelyRender` to `false` to avoid hydration mismatches."
372
+ );
373
+ }
374
+ if (this.options.current.immediatelyRender) {
375
+ return this.createEditor();
376
+ }
377
+ return null;
378
+ }
379
+ /**
380
+ * Create a new editor instance. And attach event listeners.
381
+ */
382
+ createEditor() {
383
+ const optionsToApply = {
384
+ ...this.options.current,
385
+ // Always call the most recent version of the callback function by default
386
+ onBeforeCreate: (...args) => {
387
+ var _a, _b;
388
+ return (_b = (_a = this.options.current).onBeforeCreate) == null ? void 0 : _b.call(_a, ...args);
389
+ },
390
+ onBlur: (...args) => {
391
+ var _a, _b;
392
+ return (_b = (_a = this.options.current).onBlur) == null ? void 0 : _b.call(_a, ...args);
393
+ },
394
+ onCreate: (...args) => {
395
+ var _a, _b;
396
+ return (_b = (_a = this.options.current).onCreate) == null ? void 0 : _b.call(_a, ...args);
397
+ },
398
+ onDestroy: (...args) => {
399
+ var _a, _b;
400
+ return (_b = (_a = this.options.current).onDestroy) == null ? void 0 : _b.call(_a, ...args);
401
+ },
402
+ onFocus: (...args) => {
403
+ var _a, _b;
404
+ return (_b = (_a = this.options.current).onFocus) == null ? void 0 : _b.call(_a, ...args);
405
+ },
406
+ onSelectionUpdate: (...args) => {
407
+ var _a, _b;
408
+ return (_b = (_a = this.options.current).onSelectionUpdate) == null ? void 0 : _b.call(_a, ...args);
409
+ },
410
+ onTransaction: (...args) => {
411
+ var _a, _b;
412
+ return (_b = (_a = this.options.current).onTransaction) == null ? void 0 : _b.call(_a, ...args);
413
+ },
414
+ onUpdate: (...args) => {
415
+ var _a, _b;
416
+ return (_b = (_a = this.options.current).onUpdate) == null ? void 0 : _b.call(_a, ...args);
417
+ },
418
+ onContentError: (...args) => {
419
+ var _a, _b;
420
+ return (_b = (_a = this.options.current).onContentError) == null ? void 0 : _b.call(_a, ...args);
421
+ },
422
+ onDrop: (...args) => {
423
+ var _a, _b;
424
+ return (_b = (_a = this.options.current).onDrop) == null ? void 0 : _b.call(_a, ...args);
425
+ },
426
+ onPaste: (...args) => {
427
+ var _a, _b;
428
+ return (_b = (_a = this.options.current).onPaste) == null ? void 0 : _b.call(_a, ...args);
429
+ },
430
+ onDelete: (...args) => {
431
+ var _a, _b;
432
+ return (_b = (_a = this.options.current).onDelete) == null ? void 0 : _b.call(_a, ...args);
433
+ }
434
+ };
435
+ const editor = new import_core.Editor(optionsToApply);
436
+ return editor;
437
+ }
438
+ /**
439
+ * Get the current editor instance.
440
+ */
441
+ getEditor() {
442
+ return this.editor;
443
+ }
444
+ /**
445
+ * Always disable the editor on the server-side.
446
+ */
447
+ getServerSnapshot() {
448
+ return null;
449
+ }
450
+ /**
451
+ * Subscribe to the editor instance's changes.
452
+ */
453
+ subscribe(onStoreChange) {
454
+ this.subscriptions.add(onStoreChange);
455
+ return () => {
456
+ this.subscriptions.delete(onStoreChange);
457
+ };
458
+ }
459
+ static compareOptions(a, b) {
460
+ return Object.keys(a).every((key) => {
461
+ if ([
462
+ "onCreate",
463
+ "onBeforeCreate",
464
+ "onDestroy",
465
+ "onUpdate",
466
+ "onTransaction",
467
+ "onFocus",
468
+ "onBlur",
469
+ "onSelectionUpdate",
470
+ "onContentError",
471
+ "onDrop",
472
+ "onPaste"
473
+ ].includes(key)) {
474
+ return true;
475
+ }
476
+ if (key === "extensions" && a.extensions && b.extensions) {
477
+ if (a.extensions.length !== b.extensions.length) {
478
+ return false;
479
+ }
480
+ return a.extensions.every((extension, index) => {
481
+ var _a;
482
+ if (extension !== ((_a = b.extensions) == null ? void 0 : _a[index])) {
483
+ return false;
484
+ }
485
+ return true;
486
+ });
487
+ }
488
+ if (a[key] !== b[key]) {
489
+ return false;
490
+ }
491
+ return true;
492
+ });
493
+ }
494
+ /**
495
+ * On each render, we will create, update, or destroy the editor instance.
496
+ * @param deps The dependencies to watch for changes
497
+ * @returns A cleanup function
498
+ */
499
+ onRender(deps) {
500
+ return () => {
501
+ this.isComponentMounted = true;
502
+ clearTimeout(this.scheduledDestructionTimeout);
503
+ if (this.editor && !this.editor.isDestroyed && deps.length === 0) {
504
+ if (!_EditorInstanceManager.compareOptions(this.options.current, this.editor.options)) {
505
+ this.editor.setOptions({
506
+ ...this.options.current,
507
+ editable: this.editor.isEditable
508
+ });
509
+ }
510
+ } else {
511
+ this.refreshEditorInstance(deps);
512
+ }
513
+ return () => {
514
+ this.isComponentMounted = false;
515
+ this.scheduleDestroy();
516
+ };
517
+ };
518
+ }
519
+ /**
520
+ * Recreate the editor instance if the dependencies have changed.
521
+ */
522
+ refreshEditorInstance(deps) {
523
+ if (this.editor && !this.editor.isDestroyed) {
524
+ if (this.previousDeps === null) {
525
+ this.previousDeps = deps;
526
+ return;
527
+ }
528
+ const depsAreEqual = this.previousDeps.length === deps.length && this.previousDeps.every((dep, index) => dep === deps[index]);
529
+ if (depsAreEqual) {
530
+ return;
531
+ }
532
+ }
533
+ if (this.editor && !this.editor.isDestroyed) {
534
+ this.editor.destroy();
535
+ }
536
+ this.setEditor(this.createEditor());
537
+ this.previousDeps = deps;
538
+ }
539
+ /**
540
+ * Schedule the destruction of the editor instance.
541
+ * This will only destroy the editor if it was not mounted on the next tick.
542
+ * This is to avoid destroying the editor instance when it's actually still mounted.
543
+ */
544
+ scheduleDestroy() {
545
+ const currentInstanceId = this.instanceId;
546
+ const currentEditor = this.editor;
547
+ this.scheduledDestructionTimeout = setTimeout(() => {
548
+ if (this.isComponentMounted && this.instanceId === currentInstanceId) {
549
+ if (currentEditor) {
550
+ currentEditor.setOptions(this.options.current);
551
+ }
552
+ return;
553
+ }
554
+ if (currentEditor && !currentEditor.isDestroyed) {
555
+ currentEditor.destroy();
556
+ if (this.instanceId === currentInstanceId) {
557
+ this.setEditor(null);
558
+ }
559
+ }
560
+ }, 1);
561
+ }
562
+ };
563
+ function useEditor(options = {}, deps = []) {
564
+ const mostRecentOptions = (0, import_react3.useRef)(options);
565
+ mostRecentOptions.current = options;
566
+ const [instanceManager] = (0, import_react3.useState)(() => new EditorInstanceManager(mostRecentOptions));
567
+ const editor = (0, import_shim2.useSyncExternalStore)(
568
+ instanceManager.subscribe,
569
+ instanceManager.getEditor,
570
+ instanceManager.getServerSnapshot
571
+ );
572
+ (0, import_react3.useDebugValue)(editor);
573
+ (0, import_react3.useEffect)(instanceManager.onRender(deps));
574
+ useEditorState({
575
+ editor,
576
+ selector: ({ transactionNumber }) => {
577
+ if (options.shouldRerenderOnTransaction === false || options.shouldRerenderOnTransaction === void 0) {
578
+ return null;
579
+ }
580
+ if (options.immediatelyRender && transactionNumber === 0) {
581
+ return 0;
582
+ }
583
+ return transactionNumber + 1;
584
+ }
585
+ });
586
+ return editor;
587
+ }
588
+
589
+ // src/Context.tsx
590
+ var import_jsx_runtime2 = require("react/jsx-runtime");
591
+ var EditorContext = (0, import_react4.createContext)({
592
+ editor: null
593
+ });
594
+ var EditorConsumer = EditorContext.Consumer;
595
+ var useCurrentEditor = () => (0, import_react4.useContext)(EditorContext);
596
+ function EditorProvider({
597
+ children,
598
+ slotAfter,
599
+ slotBefore,
600
+ editorContainerProps = {},
601
+ ...editorOptions
602
+ }) {
603
+ const editor = useEditor(editorOptions);
604
+ const contextValue = (0, import_react4.useMemo)(() => ({ editor }), [editor]);
605
+ if (!editor) {
606
+ return null;
607
+ }
608
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(EditorContext.Provider, { value: contextValue, children: [
609
+ slotBefore,
610
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EditorConsumer, { children: ({ editor: currentEditor }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EditorContent, { editor: currentEditor, ...editorContainerProps }) }),
611
+ children,
612
+ slotAfter
613
+ ] });
614
+ }
615
+
616
+ // src/useReactNodeView.ts
617
+ var import_react5 = require("react");
618
+ var ReactNodeViewContext = (0, import_react5.createContext)({
619
+ onDragStart: () => {
620
+ },
621
+ nodeViewContentChildren: void 0,
622
+ nodeViewContentRef: () => {
623
+ }
624
+ });
625
+ var ReactNodeViewContentProvider = ({ children, content }) => {
626
+ return (0, import_react5.createElement)(ReactNodeViewContext.Provider, { value: { nodeViewContentChildren: content } }, children);
627
+ };
628
+ var useReactNodeView = () => (0, import_react5.useContext)(ReactNodeViewContext);
629
+
630
+ // src/NodeViewContent.tsx
631
+ var import_jsx_runtime3 = (
632
+ // @ts-ignore
633
+ require("react/jsx-runtime")
634
+ );
635
+ function NodeViewContent({
636
+ as: Tag = "div",
637
+ ...props
638
+ }) {
639
+ const { nodeViewContentRef, nodeViewContentChildren } = useReactNodeView();
640
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
641
+ Tag,
642
+ {
643
+ ...props,
644
+ ref: nodeViewContentRef,
645
+ "data-node-view-content": "",
646
+ style: {
647
+ whiteSpace: "pre-wrap",
648
+ ...props.style
649
+ },
650
+ children: nodeViewContentChildren
651
+ }
652
+ );
653
+ }
654
+
655
+ // src/NodeViewWrapper.tsx
656
+ var import_react6 = __toESM(require("react"), 1);
657
+ var import_jsx_runtime4 = (
658
+ // @ts-ignore
659
+ require("react/jsx-runtime")
660
+ );
661
+ var NodeViewWrapper = import_react6.default.forwardRef((props, ref) => {
662
+ const { onDragStart } = useReactNodeView();
663
+ const Tag = props.as || "div";
664
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
665
+ Tag,
666
+ {
667
+ ...props,
668
+ ref,
669
+ "data-node-view-wrapper": "",
670
+ onDragStart,
671
+ style: {
672
+ whiteSpace: "normal",
673
+ ...props.style
674
+ }
675
+ }
676
+ );
677
+ });
678
+
679
+ // src/ReactMarkViewRenderer.tsx
680
+ var import_core2 = require("@tiptap/core");
681
+ var import_react8 = __toESM(require("react"), 1);
682
+
683
+ // src/ReactRenderer.tsx
684
+ var import_react7 = require("react");
685
+ var import_react_dom2 = require("react-dom");
686
+ var import_jsx_runtime5 = require("react/jsx-runtime");
687
+ function isClassComponent(Component) {
688
+ return !!(typeof Component === "function" && Component.prototype && Component.prototype.isReactComponent);
689
+ }
690
+ function isForwardRefComponent(Component) {
691
+ return !!(typeof Component === "object" && Component.$$typeof && (Component.$$typeof.toString() === "Symbol(react.forward_ref)" || Component.$$typeof.description === "react.forward_ref"));
692
+ }
693
+ function isMemoComponent(Component) {
694
+ return !!(typeof Component === "object" && Component.$$typeof && (Component.$$typeof.toString() === "Symbol(react.memo)" || Component.$$typeof.description === "react.memo"));
695
+ }
696
+ function canReceiveRef(Component) {
697
+ if (isClassComponent(Component)) {
698
+ return true;
699
+ }
700
+ if (isForwardRefComponent(Component)) {
701
+ return true;
702
+ }
703
+ if (isMemoComponent(Component)) {
704
+ const wrappedComponent = Component.type;
705
+ if (wrappedComponent) {
706
+ return isClassComponent(wrappedComponent) || isForwardRefComponent(wrappedComponent);
707
+ }
708
+ }
709
+ return false;
710
+ }
711
+ function isReact19Plus() {
712
+ try {
713
+ if (import_react7.version) {
714
+ const majorVersion = parseInt(import_react7.version.split(".")[0], 10);
715
+ return majorVersion >= 19;
716
+ }
717
+ } catch {
718
+ }
719
+ return false;
720
+ }
721
+ var ReactRenderer = class {
722
+ /**
723
+ * Immediately creates element and renders the provided React component.
724
+ */
725
+ constructor(component, { editor, props = {}, as = "div", className = "" }) {
726
+ this.ref = null;
727
+ /**
728
+ * Flag to track if the renderer has been destroyed, preventing queued or asynchronous renders from executing after teardown.
729
+ */
730
+ this.destroyed = false;
731
+ this.id = Math.floor(Math.random() * 4294967295).toString();
732
+ this.component = component;
733
+ this.editor = editor;
734
+ this.props = props;
735
+ this.element = document.createElement(as);
736
+ this.element.classList.add("react-renderer");
737
+ if (className) {
738
+ this.element.classList.add(...className.split(" "));
739
+ }
740
+ if (this.editor.isInitialized) {
741
+ (0, import_react_dom2.flushSync)(() => {
742
+ this.render();
743
+ });
744
+ } else {
745
+ queueMicrotask(() => {
746
+ if (this.destroyed) {
747
+ return;
748
+ }
749
+ this.render();
750
+ });
751
+ }
752
+ }
753
+ /**
754
+ * Render the React component.
755
+ */
756
+ render() {
757
+ var _a;
758
+ if (this.destroyed) {
759
+ return;
760
+ }
761
+ const Component = this.component;
762
+ const props = this.props;
763
+ const editor = this.editor;
764
+ const isReact19 = isReact19Plus();
765
+ const componentCanReceiveRef = canReceiveRef(Component);
766
+ const elementProps = { ...props };
767
+ if (elementProps.ref && !(isReact19 || componentCanReceiveRef)) {
768
+ delete elementProps.ref;
769
+ }
770
+ if (!elementProps.ref && (isReact19 || componentCanReceiveRef)) {
771
+ elementProps.ref = (ref) => {
772
+ this.ref = ref;
773
+ };
774
+ }
775
+ this.reactElement = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Component, { ...elementProps });
776
+ (_a = editor == null ? void 0 : editor.contentComponent) == null ? void 0 : _a.setRenderer(this.id, this);
777
+ }
778
+ /**
779
+ * Re-renders the React component with new props.
780
+ */
781
+ updateProps(props = {}) {
782
+ if (this.destroyed) {
783
+ return;
784
+ }
785
+ this.props = {
786
+ ...this.props,
787
+ ...props
788
+ };
789
+ this.render();
790
+ }
791
+ /**
792
+ * Destroy the React component.
793
+ */
794
+ destroy() {
795
+ var _a;
796
+ this.destroyed = true;
797
+ const editor = this.editor;
798
+ (_a = editor == null ? void 0 : editor.contentComponent) == null ? void 0 : _a.removeRenderer(this.id);
799
+ try {
800
+ if (this.element && this.element.parentNode) {
801
+ this.element.parentNode.removeChild(this.element);
802
+ }
803
+ } catch {
804
+ }
805
+ }
806
+ /**
807
+ * Update the attributes of the element that holds the React component.
808
+ */
809
+ updateAttributes(attributes) {
810
+ Object.keys(attributes).forEach((key) => {
811
+ this.element.setAttribute(key, attributes[key]);
812
+ });
813
+ }
814
+ };
815
+
816
+ // src/ReactMarkViewRenderer.tsx
817
+ var import_jsx_runtime6 = (
818
+ // @ts-ignore
819
+ require("react/jsx-runtime")
820
+ );
821
+ var ReactMarkViewContext = import_react8.default.createContext({
822
+ markViewContentRef: () => {
823
+ }
824
+ });
825
+ var MarkViewContent = (props) => {
826
+ const { as: Tag = "span", ...rest } = props;
827
+ const { markViewContentRef } = import_react8.default.useContext(ReactMarkViewContext);
828
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Tag, { ...rest, ref: markViewContentRef, "data-mark-view-content": "" });
829
+ };
830
+ var ReactMarkView = class extends import_core2.MarkView {
831
+ constructor(component, props, options) {
832
+ super(component, props, options);
833
+ const { as = "span", attrs, className = "" } = options || {};
834
+ const componentProps = { ...props, updateAttributes: this.updateAttributes.bind(this) };
835
+ this.contentDOMElement = document.createElement("span");
836
+ const markViewContentRef = (el) => {
837
+ if (el && !el.contains(this.contentDOMElement)) {
838
+ el.appendChild(this.contentDOMElement);
839
+ }
840
+ };
841
+ const context = {
842
+ markViewContentRef
843
+ };
844
+ const ReactMarkViewProvider = import_react8.default.memo((componentProps2) => {
845
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ReactMarkViewContext.Provider, { value: context, children: import_react8.default.createElement(component, componentProps2) });
846
+ });
847
+ ReactMarkViewProvider.displayName = "ReactMarkView";
848
+ this.renderer = new ReactRenderer(ReactMarkViewProvider, {
849
+ editor: props.editor,
850
+ props: componentProps,
851
+ as,
852
+ className: `mark-${props.mark.type.name} ${className}`.trim()
853
+ });
854
+ if (attrs) {
855
+ this.renderer.updateAttributes(attrs);
856
+ }
857
+ }
858
+ get dom() {
859
+ return this.renderer.element;
860
+ }
861
+ get contentDOM() {
862
+ return this.contentDOMElement;
863
+ }
864
+ };
865
+ function ReactMarkViewRenderer(component, options = {}) {
866
+ return (props) => new ReactMarkView(component, props, options);
867
+ }
868
+
869
+ // src/ReactNodeViewRenderer.tsx
870
+ var import_core3 = require("@tiptap/core");
871
+ var import_react9 = require("react");
872
+ var import_jsx_runtime7 = require("react/jsx-runtime");
873
+ var ReactNodeView = class extends import_core3.NodeView {
874
+ constructor(component, props, options) {
875
+ super(component, props, options);
876
+ /**
877
+ * The requestAnimationFrame ID used for selection updates.
878
+ */
879
+ this.selectionRafId = null;
880
+ this.cachedExtensionWithSyncedStorage = null;
881
+ if (!this.node.isLeaf) {
882
+ if (this.options.contentDOMElementTag) {
883
+ this.contentDOMElement = document.createElement(this.options.contentDOMElementTag);
884
+ } else {
885
+ this.contentDOMElement = document.createElement(this.node.isInline ? "span" : "div");
886
+ }
887
+ this.contentDOMElement.dataset.nodeViewContentReact = "";
888
+ this.contentDOMElement.dataset.nodeViewWrapper = "";
889
+ this.contentDOMElement.style.whiteSpace = "inherit";
890
+ const contentTarget = this.dom.querySelector("[data-node-view-content]");
891
+ if (!contentTarget) {
892
+ return;
893
+ }
894
+ contentTarget.appendChild(this.contentDOMElement);
895
+ }
896
+ }
897
+ /**
898
+ * Returns a proxy of the extension that redirects storage access to the editor's mutable storage.
899
+ * This preserves the original prototype chain (instanceof checks, methods like configure/extend work).
900
+ * Cached to avoid proxy creation on every update.
901
+ */
902
+ get extensionWithSyncedStorage() {
903
+ if (!this.cachedExtensionWithSyncedStorage) {
904
+ const editor = this.editor;
905
+ const extension = this.extension;
906
+ this.cachedExtensionWithSyncedStorage = new Proxy(extension, {
907
+ get(target, prop, receiver) {
908
+ var _a;
909
+ if (prop === "storage") {
910
+ return (_a = editor.storage[extension.name]) != null ? _a : {};
911
+ }
912
+ return Reflect.get(target, prop, receiver);
913
+ }
914
+ });
915
+ }
916
+ return this.cachedExtensionWithSyncedStorage;
917
+ }
918
+ /**
919
+ * Setup the React component.
920
+ * Called on initialization.
921
+ */
922
+ mount() {
923
+ const props = {
924
+ editor: this.editor,
925
+ node: this.node,
926
+ decorations: this.decorations,
927
+ innerDecorations: this.innerDecorations,
928
+ view: this.view,
929
+ selected: false,
930
+ extension: this.extensionWithSyncedStorage,
931
+ HTMLAttributes: this.HTMLAttributes,
932
+ getPos: () => this.getPos(),
933
+ updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
934
+ deleteNode: () => this.deleteNode(),
935
+ ref: (0, import_react9.createRef)()
936
+ };
937
+ if (!this.component.displayName) {
938
+ const capitalizeFirstChar = (string) => {
939
+ return string.charAt(0).toUpperCase() + string.substring(1);
940
+ };
941
+ this.component.displayName = capitalizeFirstChar(this.extension.name);
942
+ }
943
+ const onDragStart = this.onDragStart.bind(this);
944
+ const nodeViewContentRef = (element) => {
945
+ if (element && this.contentDOMElement && element.firstChild !== this.contentDOMElement) {
946
+ if (element.hasAttribute("data-node-view-wrapper")) {
947
+ element.removeAttribute("data-node-view-wrapper");
948
+ }
949
+ element.appendChild(this.contentDOMElement);
950
+ }
951
+ };
952
+ const context = { onDragStart, nodeViewContentRef };
953
+ const Component = this.component;
954
+ const ReactNodeViewProvider = (0, import_react9.memo)((componentProps) => {
955
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ReactNodeViewContext.Provider, { value: context, children: (0, import_react9.createElement)(Component, componentProps) });
956
+ });
957
+ ReactNodeViewProvider.displayName = "ReactNodeView";
958
+ let as = this.node.isInline ? "span" : "div";
959
+ if (this.options.as) {
960
+ as = this.options.as;
961
+ }
962
+ const { className = "" } = this.options;
963
+ this.handleSelectionUpdate = this.handleSelectionUpdate.bind(this);
964
+ this.renderer = new ReactRenderer(ReactNodeViewProvider, {
965
+ editor: this.editor,
966
+ props,
967
+ as,
968
+ className: `node-${this.node.type.name} ${className}`.trim()
969
+ });
970
+ this.editor.on("selectionUpdate", this.handleSelectionUpdate);
971
+ this.updateElementAttributes();
972
+ }
973
+ /**
974
+ * Return the DOM element.
975
+ * This is the element that will be used to display the node view.
976
+ */
977
+ get dom() {
978
+ var _a;
979
+ if (this.renderer.element.firstElementChild && !((_a = this.renderer.element.firstElementChild) == null ? void 0 : _a.hasAttribute("data-node-view-wrapper"))) {
980
+ throw Error("Please use the NodeViewWrapper component for your node view.");
981
+ }
982
+ return this.renderer.element;
983
+ }
984
+ /**
985
+ * Return the content DOM element.
986
+ * This is the element that will be used to display the rich-text content of the node.
987
+ */
988
+ get contentDOM() {
989
+ if (this.node.isLeaf) {
990
+ return null;
991
+ }
992
+ return this.contentDOMElement;
993
+ }
994
+ /**
995
+ * On editor selection update, check if the node is selected.
996
+ * If it is, call `selectNode`, otherwise call `deselectNode`.
997
+ */
998
+ handleSelectionUpdate() {
999
+ if (this.selectionRafId) {
1000
+ cancelAnimationFrame(this.selectionRafId);
1001
+ this.selectionRafId = null;
1002
+ }
1003
+ this.selectionRafId = requestAnimationFrame(() => {
1004
+ this.selectionRafId = null;
1005
+ const { from, to } = this.editor.state.selection;
1006
+ const pos = this.getPos();
1007
+ if (typeof pos !== "number") {
1008
+ return;
1009
+ }
1010
+ if (from <= pos && to >= pos + this.node.nodeSize) {
1011
+ if (this.renderer.props.selected) {
1012
+ return;
1013
+ }
1014
+ this.selectNode();
1015
+ } else {
1016
+ if (!this.renderer.props.selected) {
1017
+ return;
1018
+ }
1019
+ this.deselectNode();
1020
+ }
1021
+ });
1022
+ }
1023
+ /**
1024
+ * On update, update the React component.
1025
+ * To prevent unnecessary updates, the `update` option can be used.
1026
+ */
1027
+ update(node, decorations, innerDecorations) {
1028
+ const rerenderComponent = (props) => {
1029
+ this.renderer.updateProps(props);
1030
+ if (typeof this.options.attrs === "function") {
1031
+ this.updateElementAttributes();
1032
+ }
1033
+ };
1034
+ if (node.type !== this.node.type) {
1035
+ return false;
1036
+ }
1037
+ if (typeof this.options.update === "function") {
1038
+ const oldNode = this.node;
1039
+ const oldDecorations = this.decorations;
1040
+ const oldInnerDecorations = this.innerDecorations;
1041
+ this.node = node;
1042
+ this.decorations = decorations;
1043
+ this.innerDecorations = innerDecorations;
1044
+ return this.options.update({
1045
+ oldNode,
1046
+ oldDecorations,
1047
+ newNode: node,
1048
+ newDecorations: decorations,
1049
+ oldInnerDecorations,
1050
+ innerDecorations,
1051
+ updateProps: () => rerenderComponent({ node, decorations, innerDecorations, extension: this.extensionWithSyncedStorage })
1052
+ });
1053
+ }
1054
+ if (node === this.node && this.decorations === decorations && this.innerDecorations === innerDecorations) {
1055
+ return true;
1056
+ }
1057
+ this.node = node;
1058
+ this.decorations = decorations;
1059
+ this.innerDecorations = innerDecorations;
1060
+ rerenderComponent({ node, decorations, innerDecorations, extension: this.extensionWithSyncedStorage });
1061
+ return true;
1062
+ }
1063
+ /**
1064
+ * Select the node.
1065
+ * Add the `selected` prop and the `ProseMirror-selectednode` class.
1066
+ */
1067
+ selectNode() {
1068
+ this.renderer.updateProps({
1069
+ selected: true
1070
+ });
1071
+ this.renderer.element.classList.add("ProseMirror-selectednode");
1072
+ }
1073
+ /**
1074
+ * Deselect the node.
1075
+ * Remove the `selected` prop and the `ProseMirror-selectednode` class.
1076
+ */
1077
+ deselectNode() {
1078
+ this.renderer.updateProps({
1079
+ selected: false
1080
+ });
1081
+ this.renderer.element.classList.remove("ProseMirror-selectednode");
1082
+ }
1083
+ /**
1084
+ * Destroy the React component instance.
1085
+ */
1086
+ destroy() {
1087
+ this.renderer.destroy();
1088
+ this.editor.off("selectionUpdate", this.handleSelectionUpdate);
1089
+ this.contentDOMElement = null;
1090
+ if (this.selectionRafId) {
1091
+ cancelAnimationFrame(this.selectionRafId);
1092
+ this.selectionRafId = null;
1093
+ }
1094
+ }
1095
+ /**
1096
+ * Update the attributes of the top-level element that holds the React component.
1097
+ * Applying the attributes defined in the `attrs` option.
1098
+ */
1099
+ updateElementAttributes() {
1100
+ if (this.options.attrs) {
1101
+ let attrsObj = {};
1102
+ if (typeof this.options.attrs === "function") {
1103
+ const extensionAttributes = this.editor.extensionManager.attributes;
1104
+ const HTMLAttributes = (0, import_core3.getRenderedAttributes)(this.node, extensionAttributes);
1105
+ attrsObj = this.options.attrs({ node: this.node, HTMLAttributes });
1106
+ } else {
1107
+ attrsObj = this.options.attrs;
1108
+ }
1109
+ this.renderer.updateAttributes(attrsObj);
1110
+ }
1111
+ }
1112
+ };
1113
+ function ReactNodeViewRenderer(component, options) {
1114
+ return (props) => {
1115
+ if (!props.editor.contentComponent) {
1116
+ return {};
1117
+ }
1118
+ return new ReactNodeView(component, props, options);
1119
+ };
1120
+ }
1121
+
1122
+ // src/Tiptap.tsx
1123
+ var import_react10 = require("react");
1124
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1125
+ var TiptapContext = (0, import_react10.createContext)({
1126
+ get editor() {
1127
+ throw new Error("useTiptap must be used within a <Tiptap> provider");
1128
+ }
1129
+ });
1130
+ TiptapContext.displayName = "TiptapContext";
1131
+ var useTiptap = () => (0, import_react10.useContext)(TiptapContext);
1132
+ function useTiptapState(selector, equalityFn) {
1133
+ const { editor } = useTiptap();
1134
+ return useEditorState({
1135
+ editor,
1136
+ selector,
1137
+ equalityFn
1138
+ });
1139
+ }
1140
+ function TiptapWrapper({ editor, instance, children }) {
1141
+ const resolvedEditor = editor != null ? editor : instance;
1142
+ if (!resolvedEditor) {
1143
+ throw new Error("Tiptap: An editor instance is required. Pass a non-null `editor` prop.");
1144
+ }
1145
+ const tiptapContextValue = (0, import_react10.useMemo)(() => ({ editor: resolvedEditor }), [resolvedEditor]);
1146
+ const legacyContextValue = (0, import_react10.useMemo)(() => ({ editor: resolvedEditor }), [resolvedEditor]);
1147
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(EditorContext.Provider, { value: legacyContextValue, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TiptapContext.Provider, { value: tiptapContextValue, children }) });
1148
+ }
1149
+ TiptapWrapper.displayName = "Tiptap";
1150
+ function TiptapContent({ ...rest }) {
1151
+ const { editor } = useTiptap();
1152
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(EditorContent, { editor, ...rest });
1153
+ }
1154
+ TiptapContent.displayName = "Tiptap.Content";
1155
+ var Tiptap = Object.assign(TiptapWrapper, {
1156
+ /**
1157
+ * The Tiptap Content component that renders the EditorContent with the editor instance from the context.
1158
+ * @see TiptapContent
1159
+ */
1160
+ Content: TiptapContent
1161
+ });
1162
+
1163
+ // src/index.ts
1164
+ __reExport(index_exports, require("@tiptap/core"), module.exports);
1165
+ // Annotate the CommonJS export names for ESM import in node:
1166
+ 0 && (module.exports = {
1167
+ EditorConsumer,
1168
+ EditorContent,
1169
+ EditorContext,
1170
+ EditorProvider,
1171
+ MarkViewContent,
1172
+ NodeViewContent,
1173
+ NodeViewWrapper,
1174
+ PureEditorContent,
1175
+ ReactMarkView,
1176
+ ReactMarkViewContext,
1177
+ ReactMarkViewRenderer,
1178
+ ReactNodeView,
1179
+ ReactNodeViewContentProvider,
1180
+ ReactNodeViewContext,
1181
+ ReactNodeViewRenderer,
1182
+ ReactRenderer,
1183
+ Tiptap,
1184
+ TiptapContent,
1185
+ TiptapContext,
1186
+ TiptapWrapper,
1187
+ useCurrentEditor,
1188
+ useEditor,
1189
+ useEditorState,
1190
+ useReactNodeView,
1191
+ useTiptap,
1192
+ useTiptapState,
1193
+ ...require("@tiptap/core")
1194
+ });
1195
+ //# sourceMappingURL=index.cjs.map