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