rte-builder 1.0.0 → 2.0.2

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.js CHANGED
@@ -34,2151 +34,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
34
34
  ));
35
35
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
36
 
37
- // node_modules/@tiptap/core/dist/index.js
38
- function createChainableState(config) {
39
- const { state, transaction } = config;
40
- let { selection } = transaction;
41
- let { doc } = transaction;
42
- let { storedMarks } = transaction;
43
- return {
44
- ...state,
45
- apply: state.apply.bind(state),
46
- applyTransaction: state.applyTransaction.bind(state),
47
- plugins: state.plugins,
48
- schema: state.schema,
49
- reconfigure: state.reconfigure.bind(state),
50
- toJSON: state.toJSON.bind(state),
51
- get storedMarks() {
52
- return storedMarks;
53
- },
54
- get selection() {
55
- return selection;
56
- },
57
- get doc() {
58
- return doc;
59
- },
60
- get tr() {
61
- selection = transaction.selection;
62
- doc = transaction.doc;
63
- storedMarks = transaction.storedMarks;
64
- return transaction;
65
- }
66
- };
67
- }
68
- function getExtensionField(extension, field, context) {
69
- if (extension.config[field] === void 0 && extension.parent) {
70
- return getExtensionField(extension.parent, field, context);
71
- }
72
- if (typeof extension.config[field] === "function") {
73
- const value = extension.config[field].bind({
74
- ...context,
75
- parent: extension.parent ? getExtensionField(extension.parent, field, context) : null
76
- });
77
- return value;
78
- }
79
- return extension.config[field];
80
- }
81
- function splitExtensions(extensions) {
82
- const baseExtensions = extensions.filter((extension) => extension.type === "extension");
83
- const nodeExtensions = extensions.filter((extension) => extension.type === "node");
84
- const markExtensions = extensions.filter((extension) => extension.type === "mark");
85
- return {
86
- baseExtensions,
87
- nodeExtensions,
88
- markExtensions
89
- };
90
- }
91
- function getNodeType(nameOrType, schema) {
92
- if (typeof nameOrType === "string") {
93
- if (!schema.nodes[nameOrType]) {
94
- throw Error(`There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`);
95
- }
96
- return schema.nodes[nameOrType];
97
- }
98
- return nameOrType;
99
- }
100
- function mergeAttributes(...objects) {
101
- return objects.filter((item) => !!item).reduce((items, item) => {
102
- const mergedAttributes = { ...items };
103
- Object.entries(item).forEach(([key, value]) => {
104
- const exists = mergedAttributes[key];
105
- if (!exists) {
106
- mergedAttributes[key] = value;
107
- return;
108
- }
109
- if (key === "class") {
110
- const valueClasses = value ? String(value).split(" ") : [];
111
- const existingClasses = mergedAttributes[key] ? mergedAttributes[key].split(" ") : [];
112
- const insertClasses = valueClasses.filter((valueClass) => !existingClasses.includes(valueClass));
113
- mergedAttributes[key] = [...existingClasses, ...insertClasses].join(" ");
114
- } else if (key === "style") {
115
- const newStyles = value ? value.split(";").map((style) => style.trim()).filter(Boolean) : [];
116
- const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(";").map((style) => style.trim()).filter(Boolean) : [];
117
- const styleMap = /* @__PURE__ */ new Map();
118
- existingStyles.forEach((style) => {
119
- const [property, val] = style.split(":").map((part) => part.trim());
120
- styleMap.set(property, val);
121
- });
122
- newStyles.forEach((style) => {
123
- const [property, val] = style.split(":").map((part) => part.trim());
124
- styleMap.set(property, val);
125
- });
126
- mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join("; ");
127
- } else {
128
- mergedAttributes[key] = value;
129
- }
130
- });
131
- return mergedAttributes;
132
- }, {});
133
- }
134
- function isFunction(value) {
135
- return typeof value === "function";
136
- }
137
- function callOrReturn(value, context = void 0, ...props) {
138
- if (isFunction(value)) {
139
- if (context) {
140
- return value.bind(context)(...props);
141
- }
142
- return value(...props);
143
- }
144
- return value;
145
- }
146
- function isRegExp(value) {
147
- return Object.prototype.toString.call(value) === "[object RegExp]";
148
- }
149
- function getType(value) {
150
- return Object.prototype.toString.call(value).slice(8, -1);
151
- }
152
- function isPlainObject(value) {
153
- if (getType(value) !== "Object") {
154
- return false;
155
- }
156
- return value.constructor === Object && Object.getPrototypeOf(value) === Object.prototype;
157
- }
158
- function mergeDeep(target, source) {
159
- const output = { ...target };
160
- if (isPlainObject(target) && isPlainObject(source)) {
161
- Object.keys(source).forEach((key) => {
162
- if (isPlainObject(source[key]) && isPlainObject(target[key])) {
163
- output[key] = mergeDeep(target[key], source[key]);
164
- } else {
165
- output[key] = source[key];
166
- }
167
- });
168
- }
169
- return output;
170
- }
171
- function getTextBetween(startNode, range, options) {
172
- const { from, to } = range;
173
- const { blockSeparator = "\n\n", textSerializers = {} } = options || {};
174
- let text = "";
175
- startNode.nodesBetween(from, to, (node, pos, parent, index) => {
176
- var _a;
177
- if (node.isBlock && pos > from) {
178
- text += blockSeparator;
179
- }
180
- const textSerializer = textSerializers === null || textSerializers === void 0 ? void 0 : textSerializers[node.type.name];
181
- if (textSerializer) {
182
- if (parent) {
183
- text += textSerializer({
184
- node,
185
- pos,
186
- parent,
187
- index,
188
- range
189
- });
190
- }
191
- return false;
192
- }
193
- if (node.isText) {
194
- text += (_a = node === null || node === void 0 ? void 0 : node.text) === null || _a === void 0 ? void 0 : _a.slice(Math.max(from, pos) - pos, to - pos);
195
- }
196
- });
197
- return text;
198
- }
199
- function getTextSerializersFromSchema(schema) {
200
- return Object.fromEntries(Object.entries(schema.nodes).filter(([, node]) => node.spec.toText).map(([name, node]) => [name, node.spec.toText]));
201
- }
202
- function objectIncludes(object1, object2, options = { strict: true }) {
203
- const keys = Object.keys(object2);
204
- if (!keys.length) {
205
- return true;
206
- }
207
- return keys.every((key) => {
208
- if (options.strict) {
209
- return object2[key] === object1[key];
210
- }
211
- if (isRegExp(object2[key])) {
212
- return object2[key].test(object1[key]);
213
- }
214
- return object2[key] === object1[key];
215
- });
216
- }
217
- function findMarkInSet(marks, type, attributes = {}) {
218
- return marks.find((item) => {
219
- return item.type === type && objectIncludes(
220
- // Only check equality for the attributes that are provided
221
- Object.fromEntries(Object.keys(attributes).map((k) => [k, item.attrs[k]])),
222
- attributes
223
- );
224
- });
225
- }
226
- function isMarkInSet(marks, type, attributes = {}) {
227
- return !!findMarkInSet(marks, type, attributes);
228
- }
229
- function getMarkRange($pos, type, attributes) {
230
- var _a;
231
- if (!$pos || !type) {
232
- return;
233
- }
234
- let start = $pos.parent.childAfter($pos.parentOffset);
235
- if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
236
- start = $pos.parent.childBefore($pos.parentOffset);
237
- }
238
- if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
239
- return;
240
- }
241
- attributes = attributes || ((_a = start.node.marks[0]) === null || _a === void 0 ? void 0 : _a.attrs);
242
- const mark = findMarkInSet([...start.node.marks], type, attributes);
243
- if (!mark) {
244
- return;
245
- }
246
- let startIndex = start.index;
247
- let startPos = $pos.start() + start.offset;
248
- let endIndex = startIndex + 1;
249
- let endPos = startPos + start.node.nodeSize;
250
- while (startIndex > 0 && isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes)) {
251
- startIndex -= 1;
252
- startPos -= $pos.parent.child(startIndex).nodeSize;
253
- }
254
- while (endIndex < $pos.parent.childCount && isMarkInSet([...$pos.parent.child(endIndex).marks], type, attributes)) {
255
- endPos += $pos.parent.child(endIndex).nodeSize;
256
- endIndex += 1;
257
- }
258
- return {
259
- from: startPos,
260
- to: endPos
261
- };
262
- }
263
- function getMarkType(nameOrType, schema) {
264
- if (typeof nameOrType === "string") {
265
- if (!schema.marks[nameOrType]) {
266
- throw Error(`There is no mark type named '${nameOrType}'. Maybe you forgot to add the extension?`);
267
- }
268
- return schema.marks[nameOrType];
269
- }
270
- return nameOrType;
271
- }
272
- function isTextSelection(value) {
273
- return value instanceof import_state.TextSelection;
274
- }
275
- function minMax(value = 0, min = 0, max = 0) {
276
- return Math.min(Math.max(value, min), max);
277
- }
278
- function resolveFocusPosition(doc, position = null) {
279
- if (!position) {
280
- return null;
281
- }
282
- const selectionAtStart = import_state.Selection.atStart(doc);
283
- const selectionAtEnd = import_state.Selection.atEnd(doc);
284
- if (position === "start" || position === true) {
285
- return selectionAtStart;
286
- }
287
- if (position === "end") {
288
- return selectionAtEnd;
289
- }
290
- const minPos = selectionAtStart.from;
291
- const maxPos = selectionAtEnd.to;
292
- if (position === "all") {
293
- return import_state.TextSelection.create(doc, minMax(0, minPos, maxPos), minMax(doc.content.size, minPos, maxPos));
294
- }
295
- return import_state.TextSelection.create(doc, minMax(position, minPos, maxPos), minMax(position, minPos, maxPos));
296
- }
297
- function isAndroid() {
298
- return navigator.platform === "Android" || /android/i.test(navigator.userAgent);
299
- }
300
- function isiOS() {
301
- return [
302
- "iPad Simulator",
303
- "iPhone Simulator",
304
- "iPod Simulator",
305
- "iPad",
306
- "iPhone",
307
- "iPod"
308
- ].includes(navigator.platform) || navigator.userAgent.includes("Mac") && "ontouchend" in document;
309
- }
310
- function isSafari() {
311
- return typeof navigator !== "undefined" ? /^((?!chrome|android).)*safari/i.test(navigator.userAgent) : false;
312
- }
313
- function elementFromString(value) {
314
- const wrappedValue = `<body>${value}</body>`;
315
- const html = new window.DOMParser().parseFromString(wrappedValue, "text/html").body;
316
- return removeWhitespaces(html);
317
- }
318
- function createNodeFromContent(content, schema, options) {
319
- if (content instanceof import_model.Node || content instanceof import_model.Fragment) {
320
- return content;
321
- }
322
- options = {
323
- slice: true,
324
- parseOptions: {},
325
- ...options
326
- };
327
- const isJSONContent = typeof content === "object" && content !== null;
328
- const isTextContent = typeof content === "string";
329
- if (isJSONContent) {
330
- try {
331
- const isArrayContent = Array.isArray(content) && content.length > 0;
332
- if (isArrayContent) {
333
- return import_model.Fragment.fromArray(content.map((item) => schema.nodeFromJSON(item)));
334
- }
335
- const node = schema.nodeFromJSON(content);
336
- if (options.errorOnInvalidContent) {
337
- node.check();
338
- }
339
- return node;
340
- } catch (error) {
341
- if (options.errorOnInvalidContent) {
342
- throw new Error("[tiptap error]: Invalid JSON content", { cause: error });
343
- }
344
- console.warn("[tiptap warn]: Invalid content.", "Passed value:", content, "Error:", error);
345
- return createNodeFromContent("", schema, options);
346
- }
347
- }
348
- if (isTextContent) {
349
- if (options.errorOnInvalidContent) {
350
- let hasInvalidContent = false;
351
- let invalidContent = "";
352
- const contentCheckSchema = new import_model.Schema({
353
- topNode: schema.spec.topNode,
354
- marks: schema.spec.marks,
355
- // Prosemirror's schemas are executed such that: the last to execute, matches last
356
- // This means that we can add a catch-all node at the end of the schema to catch any content that we don't know how to handle
357
- nodes: schema.spec.nodes.append({
358
- __tiptap__private__unknown__catch__all__node: {
359
- content: "inline*",
360
- group: "block",
361
- parseDOM: [
362
- {
363
- tag: "*",
364
- getAttrs: (e) => {
365
- hasInvalidContent = true;
366
- invalidContent = typeof e === "string" ? e : e.outerHTML;
367
- return null;
368
- }
369
- }
370
- ]
371
- }
372
- })
373
- });
374
- if (options.slice) {
375
- import_model.DOMParser.fromSchema(contentCheckSchema).parseSlice(elementFromString(content), options.parseOptions);
376
- } else {
377
- import_model.DOMParser.fromSchema(contentCheckSchema).parse(elementFromString(content), options.parseOptions);
378
- }
379
- if (options.errorOnInvalidContent && hasInvalidContent) {
380
- throw new Error("[tiptap error]: Invalid HTML content", { cause: new Error(`Invalid element found: ${invalidContent}`) });
381
- }
382
- }
383
- const parser = import_model.DOMParser.fromSchema(schema);
384
- if (options.slice) {
385
- return parser.parseSlice(elementFromString(content), options.parseOptions).content;
386
- }
387
- return parser.parse(elementFromString(content), options.parseOptions);
388
- }
389
- return createNodeFromContent("", schema, options);
390
- }
391
- function selectionToInsertionEnd(tr, startLen, bias) {
392
- const last = tr.steps.length - 1;
393
- if (last < startLen) {
394
- return;
395
- }
396
- const step = tr.steps[last];
397
- if (!(step instanceof import_transform.ReplaceStep || step instanceof import_transform.ReplaceAroundStep)) {
398
- return;
399
- }
400
- const map = tr.mapping.maps[last];
401
- let end = 0;
402
- map.forEach((_from, _to, _newFrom, newTo) => {
403
- if (end === 0) {
404
- end = newTo;
405
- }
406
- });
407
- tr.setSelection(import_state.Selection.near(tr.doc.resolve(end), bias));
408
- }
409
- function isMacOS() {
410
- return typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
411
- }
412
- function normalizeKeyName(name) {
413
- const parts = name.split(/-(?!$)/);
414
- let result = parts[parts.length - 1];
415
- if (result === "Space") {
416
- result = " ";
417
- }
418
- let alt;
419
- let ctrl;
420
- let shift;
421
- let meta;
422
- for (let i = 0; i < parts.length - 1; i += 1) {
423
- const mod = parts[i];
424
- if (/^(cmd|meta|m)$/i.test(mod)) {
425
- meta = true;
426
- } else if (/^a(lt)?$/i.test(mod)) {
427
- alt = true;
428
- } else if (/^(c|ctrl|control)$/i.test(mod)) {
429
- ctrl = true;
430
- } else if (/^s(hift)?$/i.test(mod)) {
431
- shift = true;
432
- } else if (/^mod$/i.test(mod)) {
433
- if (isiOS() || isMacOS()) {
434
- meta = true;
435
- } else {
436
- ctrl = true;
437
- }
438
- } else {
439
- throw new Error(`Unrecognized modifier name: ${mod}`);
440
- }
441
- }
442
- if (alt) {
443
- result = `Alt-${result}`;
444
- }
445
- if (ctrl) {
446
- result = `Ctrl-${result}`;
447
- }
448
- if (meta) {
449
- result = `Meta-${result}`;
450
- }
451
- if (shift) {
452
- result = `Shift-${result}`;
453
- }
454
- return result;
455
- }
456
- function isNodeActive(state, typeOrName, attributes = {}) {
457
- const { from, to, empty } = state.selection;
458
- const type = typeOrName ? getNodeType(typeOrName, state.schema) : null;
459
- const nodeRanges = [];
460
- state.doc.nodesBetween(from, to, (node, pos) => {
461
- if (node.isText) {
462
- return;
463
- }
464
- const relativeFrom = Math.max(from, pos);
465
- const relativeTo = Math.min(to, pos + node.nodeSize);
466
- nodeRanges.push({
467
- node,
468
- from: relativeFrom,
469
- to: relativeTo
470
- });
471
- });
472
- const selectionRange = to - from;
473
- const matchedNodeRanges = nodeRanges.filter((nodeRange) => {
474
- if (!type) {
475
- return true;
476
- }
477
- return type.name === nodeRange.node.type.name;
478
- }).filter((nodeRange) => objectIncludes(nodeRange.node.attrs, attributes, { strict: false }));
479
- if (empty) {
480
- return !!matchedNodeRanges.length;
481
- }
482
- const range = matchedNodeRanges.reduce((sum, nodeRange) => sum + nodeRange.to - nodeRange.from, 0);
483
- return range >= selectionRange;
484
- }
485
- function getSchemaTypeNameByName(name, schema) {
486
- if (schema.nodes[name]) {
487
- return "node";
488
- }
489
- if (schema.marks[name]) {
490
- return "mark";
491
- }
492
- return null;
493
- }
494
- function deleteProps(obj, propOrProps) {
495
- const props = typeof propOrProps === "string" ? [propOrProps] : propOrProps;
496
- return Object.keys(obj).reduce((newObj, prop) => {
497
- if (!props.includes(prop)) {
498
- newObj[prop] = obj[prop];
499
- }
500
- return newObj;
501
- }, {});
502
- }
503
- function createDocument(content, schema, parseOptions = {}, options = {}) {
504
- return createNodeFromContent(content, schema, {
505
- slice: false,
506
- parseOptions,
507
- errorOnInvalidContent: options.errorOnInvalidContent
508
- });
509
- }
510
- function getMarkAttributes(state, typeOrName) {
511
- const type = getMarkType(typeOrName, state.schema);
512
- const { from, to, empty } = state.selection;
513
- const marks = [];
514
- if (empty) {
515
- if (state.storedMarks) {
516
- marks.push(...state.storedMarks);
517
- }
518
- marks.push(...state.selection.$head.marks());
519
- } else {
520
- state.doc.nodesBetween(from, to, (node) => {
521
- marks.push(...node.marks);
522
- });
523
- }
524
- const mark = marks.find((markItem) => markItem.type.name === type.name);
525
- if (!mark) {
526
- return {};
527
- }
528
- return { ...mark.attrs };
529
- }
530
- function defaultBlockAt(match) {
531
- for (let i = 0; i < match.edgeCount; i += 1) {
532
- const { type } = match.edge(i);
533
- if (type.isTextblock && !type.hasRequiredAttrs()) {
534
- return type;
535
- }
536
- }
537
- return null;
538
- }
539
- function findParentNodeClosestToPos($pos, predicate) {
540
- for (let i = $pos.depth; i > 0; i -= 1) {
541
- const node = $pos.node(i);
542
- if (predicate(node)) {
543
- return {
544
- pos: i > 0 ? $pos.before(i) : 0,
545
- start: $pos.start(i),
546
- depth: i,
547
- node
548
- };
549
- }
550
- }
551
- }
552
- function findParentNode(predicate) {
553
- return (selection) => findParentNodeClosestToPos(selection.$from, predicate);
554
- }
555
- function getSplittedAttributes(extensionAttributes, typeName, attributes) {
556
- return Object.fromEntries(Object.entries(attributes).filter(([name]) => {
557
- const extensionAttribute = extensionAttributes.find((item) => {
558
- return item.type === typeName && item.name === name;
559
- });
560
- if (!extensionAttribute) {
561
- return false;
562
- }
563
- return extensionAttribute.attribute.keepOnSplit;
564
- }));
565
- }
566
- function isMarkActive(state, typeOrName, attributes = {}) {
567
- const { empty, ranges } = state.selection;
568
- const type = typeOrName ? getMarkType(typeOrName, state.schema) : null;
569
- if (empty) {
570
- return !!(state.storedMarks || state.selection.$from.marks()).filter((mark) => {
571
- if (!type) {
572
- return true;
573
- }
574
- return type.name === mark.type.name;
575
- }).find((mark) => objectIncludes(mark.attrs, attributes, { strict: false }));
576
- }
577
- let selectionRange = 0;
578
- const markRanges = [];
579
- ranges.forEach(({ $from, $to }) => {
580
- const from = $from.pos;
581
- const to = $to.pos;
582
- state.doc.nodesBetween(from, to, (node, pos) => {
583
- if (!node.isText && !node.marks.length) {
584
- return;
585
- }
586
- const relativeFrom = Math.max(from, pos);
587
- const relativeTo = Math.min(to, pos + node.nodeSize);
588
- const range2 = relativeTo - relativeFrom;
589
- selectionRange += range2;
590
- markRanges.push(...node.marks.map((mark) => ({
591
- mark,
592
- from: relativeFrom,
593
- to: relativeTo
594
- })));
595
- });
596
- });
597
- if (selectionRange === 0) {
598
- return false;
599
- }
600
- const matchedRange = markRanges.filter((markRange) => {
601
- if (!type) {
602
- return true;
603
- }
604
- return type.name === markRange.mark.type.name;
605
- }).filter((markRange) => objectIncludes(markRange.mark.attrs, attributes, { strict: false })).reduce((sum, markRange) => sum + markRange.to - markRange.from, 0);
606
- const excludedRange = markRanges.filter((markRange) => {
607
- if (!type) {
608
- return true;
609
- }
610
- return markRange.mark.type !== type && markRange.mark.type.excludes(type);
611
- }).reduce((sum, markRange) => sum + markRange.to - markRange.from, 0);
612
- const range = matchedRange > 0 ? matchedRange + excludedRange : matchedRange;
613
- return range >= selectionRange;
614
- }
615
- function isList(name, extensions) {
616
- const { nodeExtensions } = splitExtensions(extensions);
617
- const extension = nodeExtensions.find((item) => item.name === name);
618
- if (!extension) {
619
- return false;
620
- }
621
- const context = {
622
- name: extension.name,
623
- options: extension.options,
624
- storage: extension.storage
625
- };
626
- const group = callOrReturn(getExtensionField(extension, "group", context));
627
- if (typeof group !== "string") {
628
- return false;
629
- }
630
- return group.split(" ").includes("list");
631
- }
632
- function isNodeEmpty(node, { checkChildren = true, ignoreWhitespace = false } = {}) {
633
- var _a;
634
- if (ignoreWhitespace) {
635
- if (node.type.name === "hardBreak") {
636
- return true;
637
- }
638
- if (node.isText) {
639
- return /^\s*$/m.test((_a = node.text) !== null && _a !== void 0 ? _a : "");
640
- }
641
- }
642
- if (node.isText) {
643
- return !node.text;
644
- }
645
- if (node.isAtom || node.isLeaf) {
646
- return false;
647
- }
648
- if (node.content.childCount === 0) {
649
- return true;
650
- }
651
- if (checkChildren) {
652
- let isContentEmpty = true;
653
- node.content.forEach((childNode) => {
654
- if (isContentEmpty === false) {
655
- return;
656
- }
657
- if (!isNodeEmpty(childNode, { ignoreWhitespace, checkChildren })) {
658
- isContentEmpty = false;
659
- }
660
- });
661
- return isContentEmpty;
662
- }
663
- return false;
664
- }
665
- function canSetMark(state, tr, newMarkType) {
666
- var _a;
667
- const { selection } = tr;
668
- let cursor = null;
669
- if (isTextSelection(selection)) {
670
- cursor = selection.$cursor;
671
- }
672
- if (cursor) {
673
- const currentMarks = (_a = state.storedMarks) !== null && _a !== void 0 ? _a : cursor.marks();
674
- return !!newMarkType.isInSet(currentMarks) || !currentMarks.some((mark) => mark.type.excludes(newMarkType));
675
- }
676
- const { ranges } = selection;
677
- return ranges.some(({ $from, $to }) => {
678
- let someNodeSupportsMark = $from.depth === 0 ? state.doc.inlineContent && state.doc.type.allowsMarkType(newMarkType) : false;
679
- state.doc.nodesBetween($from.pos, $to.pos, (node, _pos, parent) => {
680
- if (someNodeSupportsMark) {
681
- return false;
682
- }
683
- if (node.isInline) {
684
- const parentAllowsMarkType = !parent || parent.type.allowsMarkType(newMarkType);
685
- const currentMarksAllowMarkType = !!newMarkType.isInSet(node.marks) || !node.marks.some((otherMark) => otherMark.type.excludes(newMarkType));
686
- someNodeSupportsMark = parentAllowsMarkType && currentMarksAllowMarkType;
687
- }
688
- return !someNodeSupportsMark;
689
- });
690
- return someNodeSupportsMark;
691
- });
692
- }
693
- function ensureMarks(state, splittableMarks) {
694
- const marks = state.storedMarks || state.selection.$to.parentOffset && state.selection.$from.marks();
695
- if (marks) {
696
- const filteredMarks = marks.filter((mark) => splittableMarks === null || splittableMarks === void 0 ? void 0 : splittableMarks.includes(mark.type.name));
697
- state.tr.ensureMarks(filteredMarks);
698
- }
699
- }
700
- var import_state, import_view, import_keymap, import_model, import_transform, import_commands, import_schema_list, CommandManager, Extension, ClipboardTextSerializer, blur, clearContent, clearNodes, command, createParagraphNear, cut, deleteCurrentNode, deleteNode, deleteRange, deleteSelection, enter, exitCode, extendMarkRange, first, focus, forEach, insertContent, removeWhitespaces, isFragment, insertContentAt, joinUp, joinDown, joinBackward, joinForward, joinItemBackward, joinItemForward, joinTextblockBackward, joinTextblockForward, keyboardShortcut, lift, liftEmptyBlock, liftListItem, newlineInCode, resetAttributes, scrollIntoView, selectAll, selectNodeBackward, selectNodeForward, selectParentNode, selectTextblockEnd, selectTextblockStart, setContent, setMark, setMeta, setNode, setNodeSelection, setTextSelection, sinkListItem, splitBlock, splitListItem, joinListBackwards, joinListForwards, toggleList, toggleMark, toggleNode, toggleWrap, undoInputRule, unsetAllMarks, unsetMark, updateAttributes, wrapIn, wrapInList, commands, Commands, Drop, Editable, focusEventsPluginKey, FocusEvents, Keymap, Paste, Tabindex, Node;
701
- var init_dist = __esm({
702
- "node_modules/@tiptap/core/dist/index.js"() {
703
- "use strict";
704
- import_state = require("@tiptap/pm/state");
705
- import_view = require("@tiptap/pm/view");
706
- import_keymap = require("@tiptap/pm/keymap");
707
- import_model = require("@tiptap/pm/model");
708
- import_transform = require("@tiptap/pm/transform");
709
- import_commands = require("@tiptap/pm/commands");
710
- import_schema_list = require("@tiptap/pm/schema-list");
711
- CommandManager = class {
712
- constructor(props) {
713
- this.editor = props.editor;
714
- this.rawCommands = this.editor.extensionManager.commands;
715
- this.customState = props.state;
716
- }
717
- get hasCustomState() {
718
- return !!this.customState;
719
- }
720
- get state() {
721
- return this.customState || this.editor.state;
722
- }
723
- get commands() {
724
- const { rawCommands, editor, state } = this;
725
- const { view } = editor;
726
- const { tr } = state;
727
- const props = this.buildProps(tr);
728
- return Object.fromEntries(Object.entries(rawCommands).map(([name, command2]) => {
729
- const method = (...args) => {
730
- const callback = command2(...args)(props);
731
- if (!tr.getMeta("preventDispatch") && !this.hasCustomState) {
732
- view.dispatch(tr);
733
- }
734
- return callback;
735
- };
736
- return [name, method];
737
- }));
738
- }
739
- get chain() {
740
- return () => this.createChain();
741
- }
742
- get can() {
743
- return () => this.createCan();
744
- }
745
- createChain(startTr, shouldDispatch = true) {
746
- const { rawCommands, editor, state } = this;
747
- const { view } = editor;
748
- const callbacks = [];
749
- const hasStartTransaction = !!startTr;
750
- const tr = startTr || state.tr;
751
- const run = () => {
752
- if (!hasStartTransaction && shouldDispatch && !tr.getMeta("preventDispatch") && !this.hasCustomState) {
753
- view.dispatch(tr);
754
- }
755
- return callbacks.every((callback) => callback === true);
756
- };
757
- const chain = {
758
- ...Object.fromEntries(Object.entries(rawCommands).map(([name, command2]) => {
759
- const chainedCommand = (...args) => {
760
- const props = this.buildProps(tr, shouldDispatch);
761
- const callback = command2(...args)(props);
762
- callbacks.push(callback);
763
- return chain;
764
- };
765
- return [name, chainedCommand];
766
- })),
767
- run
768
- };
769
- return chain;
770
- }
771
- createCan(startTr) {
772
- const { rawCommands, state } = this;
773
- const dispatch = false;
774
- const tr = startTr || state.tr;
775
- const props = this.buildProps(tr, dispatch);
776
- const formattedCommands = Object.fromEntries(Object.entries(rawCommands).map(([name, command2]) => {
777
- return [name, (...args) => command2(...args)({ ...props, dispatch: void 0 })];
778
- }));
779
- return {
780
- ...formattedCommands,
781
- chain: () => this.createChain(tr, dispatch)
782
- };
783
- }
784
- buildProps(tr, shouldDispatch = true) {
785
- const { rawCommands, editor, state } = this;
786
- const { view } = editor;
787
- const props = {
788
- tr,
789
- editor,
790
- view,
791
- state: createChainableState({
792
- state,
793
- transaction: tr
794
- }),
795
- dispatch: shouldDispatch ? () => void 0 : void 0,
796
- chain: () => this.createChain(tr, shouldDispatch),
797
- can: () => this.createCan(tr),
798
- get commands() {
799
- return Object.fromEntries(Object.entries(rawCommands).map(([name, command2]) => {
800
- return [name, (...args) => command2(...args)(props)];
801
- }));
802
- }
803
- };
804
- return props;
805
- }
806
- };
807
- Extension = class _Extension {
808
- constructor(config = {}) {
809
- this.type = "extension";
810
- this.name = "extension";
811
- this.parent = null;
812
- this.child = null;
813
- this.config = {
814
- name: this.name,
815
- defaultOptions: {}
816
- };
817
- this.config = {
818
- ...this.config,
819
- ...config
820
- };
821
- this.name = this.config.name;
822
- if (config.defaultOptions && Object.keys(config.defaultOptions).length > 0) {
823
- console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${this.name}".`);
824
- }
825
- this.options = this.config.defaultOptions;
826
- if (this.config.addOptions) {
827
- this.options = callOrReturn(getExtensionField(this, "addOptions", {
828
- name: this.name
829
- }));
830
- }
831
- this.storage = callOrReturn(getExtensionField(this, "addStorage", {
832
- name: this.name,
833
- options: this.options
834
- })) || {};
835
- }
836
- static create(config = {}) {
837
- return new _Extension(config);
838
- }
839
- configure(options = {}) {
840
- const extension = this.extend({
841
- ...this.config,
842
- addOptions: () => {
843
- return mergeDeep(this.options, options);
844
- }
845
- });
846
- extension.name = this.name;
847
- extension.parent = this.parent;
848
- return extension;
849
- }
850
- extend(extendedConfig = {}) {
851
- const extension = new _Extension({ ...this.config, ...extendedConfig });
852
- extension.parent = this;
853
- this.child = extension;
854
- extension.name = extendedConfig.name ? extendedConfig.name : extension.parent.name;
855
- if (extendedConfig.defaultOptions && Object.keys(extendedConfig.defaultOptions).length > 0) {
856
- console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${extension.name}".`);
857
- }
858
- extension.options = callOrReturn(getExtensionField(extension, "addOptions", {
859
- name: extension.name
860
- }));
861
- extension.storage = callOrReturn(getExtensionField(extension, "addStorage", {
862
- name: extension.name,
863
- options: extension.options
864
- }));
865
- return extension;
866
- }
867
- };
868
- ClipboardTextSerializer = Extension.create({
869
- name: "clipboardTextSerializer",
870
- addOptions() {
871
- return {
872
- blockSeparator: void 0
873
- };
874
- },
875
- addProseMirrorPlugins() {
876
- return [
877
- new import_state.Plugin({
878
- key: new import_state.PluginKey("clipboardTextSerializer"),
879
- props: {
880
- clipboardTextSerializer: () => {
881
- const { editor } = this;
882
- const { state, schema } = editor;
883
- const { doc, selection } = state;
884
- const { ranges } = selection;
885
- const from = Math.min(...ranges.map((range2) => range2.$from.pos));
886
- const to = Math.max(...ranges.map((range2) => range2.$to.pos));
887
- const textSerializers = getTextSerializersFromSchema(schema);
888
- const range = { from, to };
889
- return getTextBetween(doc, range, {
890
- ...this.options.blockSeparator !== void 0 ? { blockSeparator: this.options.blockSeparator } : {},
891
- textSerializers
892
- });
893
- }
894
- }
895
- })
896
- ];
897
- }
898
- });
899
- blur = () => ({ editor, view }) => {
900
- requestAnimationFrame(() => {
901
- var _a;
902
- if (!editor.isDestroyed) {
903
- view.dom.blur();
904
- (_a = window === null || window === void 0 ? void 0 : window.getSelection()) === null || _a === void 0 ? void 0 : _a.removeAllRanges();
905
- }
906
- });
907
- return true;
908
- };
909
- clearContent = (emitUpdate = false) => ({ commands: commands2 }) => {
910
- return commands2.setContent("", emitUpdate);
911
- };
912
- clearNodes = () => ({ state, tr, dispatch }) => {
913
- const { selection } = tr;
914
- const { ranges } = selection;
915
- if (!dispatch) {
916
- return true;
917
- }
918
- ranges.forEach(({ $from, $to }) => {
919
- state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
920
- if (node.type.isText) {
921
- return;
922
- }
923
- const { doc, mapping } = tr;
924
- const $mappedFrom = doc.resolve(mapping.map(pos));
925
- const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize));
926
- const nodeRange = $mappedFrom.blockRange($mappedTo);
927
- if (!nodeRange) {
928
- return;
929
- }
930
- const targetLiftDepth = (0, import_transform.liftTarget)(nodeRange);
931
- if (node.type.isTextblock) {
932
- const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index());
933
- tr.setNodeMarkup(nodeRange.start, defaultType);
934
- }
935
- if (targetLiftDepth || targetLiftDepth === 0) {
936
- tr.lift(nodeRange, targetLiftDepth);
937
- }
938
- });
939
- });
940
- return true;
941
- };
942
- command = (fn) => (props) => {
943
- return fn(props);
944
- };
945
- createParagraphNear = () => ({ state, dispatch }) => {
946
- return (0, import_commands.createParagraphNear)(state, dispatch);
947
- };
948
- cut = (originRange, targetPos) => ({ editor, tr }) => {
949
- const { state } = editor;
950
- const contentSlice = state.doc.slice(originRange.from, originRange.to);
951
- tr.deleteRange(originRange.from, originRange.to);
952
- const newPos = tr.mapping.map(targetPos);
953
- tr.insert(newPos, contentSlice.content);
954
- tr.setSelection(new import_state.TextSelection(tr.doc.resolve(Math.max(newPos - 1, 0))));
955
- return true;
956
- };
957
- deleteCurrentNode = () => ({ tr, dispatch }) => {
958
- const { selection } = tr;
959
- const currentNode = selection.$anchor.node();
960
- if (currentNode.content.size > 0) {
961
- return false;
962
- }
963
- const $pos = tr.selection.$anchor;
964
- for (let depth = $pos.depth; depth > 0; depth -= 1) {
965
- const node = $pos.node(depth);
966
- if (node.type === currentNode.type) {
967
- if (dispatch) {
968
- const from = $pos.before(depth);
969
- const to = $pos.after(depth);
970
- tr.delete(from, to).scrollIntoView();
971
- }
972
- return true;
973
- }
974
- }
975
- return false;
976
- };
977
- deleteNode = (typeOrName) => ({ tr, state, dispatch }) => {
978
- const type = getNodeType(typeOrName, state.schema);
979
- const $pos = tr.selection.$anchor;
980
- for (let depth = $pos.depth; depth > 0; depth -= 1) {
981
- const node = $pos.node(depth);
982
- if (node.type === type) {
983
- if (dispatch) {
984
- const from = $pos.before(depth);
985
- const to = $pos.after(depth);
986
- tr.delete(from, to).scrollIntoView();
987
- }
988
- return true;
989
- }
990
- }
991
- return false;
992
- };
993
- deleteRange = (range) => ({ tr, dispatch }) => {
994
- const { from, to } = range;
995
- if (dispatch) {
996
- tr.delete(from, to);
997
- }
998
- return true;
999
- };
1000
- deleteSelection = () => ({ state, dispatch }) => {
1001
- return (0, import_commands.deleteSelection)(state, dispatch);
1002
- };
1003
- enter = () => ({ commands: commands2 }) => {
1004
- return commands2.keyboardShortcut("Enter");
1005
- };
1006
- exitCode = () => ({ state, dispatch }) => {
1007
- return (0, import_commands.exitCode)(state, dispatch);
1008
- };
1009
- extendMarkRange = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
1010
- const type = getMarkType(typeOrName, state.schema);
1011
- const { doc, selection } = tr;
1012
- const { $from, from, to } = selection;
1013
- if (dispatch) {
1014
- const range = getMarkRange($from, type, attributes);
1015
- if (range && range.from <= from && range.to >= to) {
1016
- const newSelection = import_state.TextSelection.create(doc, range.from, range.to);
1017
- tr.setSelection(newSelection);
1018
- }
1019
- }
1020
- return true;
1021
- };
1022
- first = (commands2) => (props) => {
1023
- const items = typeof commands2 === "function" ? commands2(props) : commands2;
1024
- for (let i = 0; i < items.length; i += 1) {
1025
- if (items[i](props)) {
1026
- return true;
1027
- }
1028
- }
1029
- return false;
1030
- };
1031
- focus = (position = null, options = {}) => ({ editor, view, tr, dispatch }) => {
1032
- options = {
1033
- scrollIntoView: true,
1034
- ...options
1035
- };
1036
- const delayedFocus = () => {
1037
- if (isiOS() || isAndroid()) {
1038
- view.dom.focus();
1039
- }
1040
- requestAnimationFrame(() => {
1041
- if (!editor.isDestroyed) {
1042
- view.focus();
1043
- if (isSafari() && !isiOS() && !isAndroid()) {
1044
- view.dom.focus({ preventScroll: true });
1045
- }
1046
- }
1047
- });
1048
- };
1049
- if (view.hasFocus() && position === null || position === false) {
1050
- return true;
1051
- }
1052
- if (dispatch && position === null && !isTextSelection(editor.state.selection)) {
1053
- delayedFocus();
1054
- return true;
1055
- }
1056
- const selection = resolveFocusPosition(tr.doc, position) || editor.state.selection;
1057
- const isSameSelection = editor.state.selection.eq(selection);
1058
- if (dispatch) {
1059
- if (!isSameSelection) {
1060
- tr.setSelection(selection);
1061
- }
1062
- if (isSameSelection && tr.storedMarks) {
1063
- tr.setStoredMarks(tr.storedMarks);
1064
- }
1065
- delayedFocus();
1066
- }
1067
- return true;
1068
- };
1069
- forEach = (items, fn) => (props) => {
1070
- return items.every((item, index) => fn(item, { ...props, index }));
1071
- };
1072
- insertContent = (value, options) => ({ tr, commands: commands2 }) => {
1073
- return commands2.insertContentAt({ from: tr.selection.from, to: tr.selection.to }, value, options);
1074
- };
1075
- removeWhitespaces = (node) => {
1076
- const children = node.childNodes;
1077
- for (let i = children.length - 1; i >= 0; i -= 1) {
1078
- const child = children[i];
1079
- if (child.nodeType === 3 && child.nodeValue && /^(\n\s\s|\n)$/.test(child.nodeValue)) {
1080
- node.removeChild(child);
1081
- } else if (child.nodeType === 1) {
1082
- removeWhitespaces(child);
1083
- }
1084
- }
1085
- return node;
1086
- };
1087
- isFragment = (nodeOrFragment) => {
1088
- return !("type" in nodeOrFragment);
1089
- };
1090
- insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) => {
1091
- var _a;
1092
- if (dispatch) {
1093
- options = {
1094
- parseOptions: editor.options.parseOptions,
1095
- updateSelection: true,
1096
- applyInputRules: false,
1097
- applyPasteRules: false,
1098
- ...options
1099
- };
1100
- let content;
1101
- const emitContentError = (error) => {
1102
- editor.emit("contentError", {
1103
- editor,
1104
- error,
1105
- disableCollaboration: () => {
1106
- if (editor.storage.collaboration) {
1107
- editor.storage.collaboration.isDisabled = true;
1108
- }
1109
- }
1110
- });
1111
- };
1112
- const parseOptions = {
1113
- preserveWhitespace: "full",
1114
- ...options.parseOptions
1115
- };
1116
- if (!options.errorOnInvalidContent && !editor.options.enableContentCheck && editor.options.emitContentError) {
1117
- try {
1118
- createNodeFromContent(value, editor.schema, {
1119
- parseOptions,
1120
- errorOnInvalidContent: true
1121
- });
1122
- } catch (e) {
1123
- emitContentError(e);
1124
- }
1125
- }
1126
- try {
1127
- content = createNodeFromContent(value, editor.schema, {
1128
- parseOptions,
1129
- errorOnInvalidContent: (_a = options.errorOnInvalidContent) !== null && _a !== void 0 ? _a : editor.options.enableContentCheck
1130
- });
1131
- } catch (e) {
1132
- emitContentError(e);
1133
- return false;
1134
- }
1135
- let { from, to } = typeof position === "number" ? { from: position, to: position } : { from: position.from, to: position.to };
1136
- let isOnlyTextContent = true;
1137
- let isOnlyBlockContent = true;
1138
- const nodes = isFragment(content) ? content : [content];
1139
- nodes.forEach((node) => {
1140
- node.check();
1141
- isOnlyTextContent = isOnlyTextContent ? node.isText && node.marks.length === 0 : false;
1142
- isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false;
1143
- });
1144
- if (from === to && isOnlyBlockContent) {
1145
- const { parent } = tr.doc.resolve(from);
1146
- const isEmptyTextBlock = parent.isTextblock && !parent.type.spec.code && !parent.childCount;
1147
- if (isEmptyTextBlock) {
1148
- from -= 1;
1149
- to += 1;
1150
- }
1151
- }
1152
- let newContent;
1153
- if (isOnlyTextContent) {
1154
- if (Array.isArray(value)) {
1155
- newContent = value.map((v) => v.text || "").join("");
1156
- } else if (value instanceof import_model.Fragment) {
1157
- let text = "";
1158
- value.forEach((node) => {
1159
- if (node.text) {
1160
- text += node.text;
1161
- }
1162
- });
1163
- newContent = text;
1164
- } else if (typeof value === "object" && !!value && !!value.text) {
1165
- newContent = value.text;
1166
- } else {
1167
- newContent = value;
1168
- }
1169
- tr.insertText(newContent, from, to);
1170
- } else {
1171
- newContent = content;
1172
- tr.replaceWith(from, to, newContent);
1173
- }
1174
- if (options.updateSelection) {
1175
- selectionToInsertionEnd(tr, tr.steps.length - 1, -1);
1176
- }
1177
- if (options.applyInputRules) {
1178
- tr.setMeta("applyInputRules", { from, text: newContent });
1179
- }
1180
- if (options.applyPasteRules) {
1181
- tr.setMeta("applyPasteRules", { from, text: newContent });
1182
- }
1183
- }
1184
- return true;
1185
- };
1186
- joinUp = () => ({ state, dispatch }) => {
1187
- return (0, import_commands.joinUp)(state, dispatch);
1188
- };
1189
- joinDown = () => ({ state, dispatch }) => {
1190
- return (0, import_commands.joinDown)(state, dispatch);
1191
- };
1192
- joinBackward = () => ({ state, dispatch }) => {
1193
- return (0, import_commands.joinBackward)(state, dispatch);
1194
- };
1195
- joinForward = () => ({ state, dispatch }) => {
1196
- return (0, import_commands.joinForward)(state, dispatch);
1197
- };
1198
- joinItemBackward = () => ({ state, dispatch, tr }) => {
1199
- try {
1200
- const point = (0, import_transform.joinPoint)(state.doc, state.selection.$from.pos, -1);
1201
- if (point === null || point === void 0) {
1202
- return false;
1203
- }
1204
- tr.join(point, 2);
1205
- if (dispatch) {
1206
- dispatch(tr);
1207
- }
1208
- return true;
1209
- } catch {
1210
- return false;
1211
- }
1212
- };
1213
- joinItemForward = () => ({ state, dispatch, tr }) => {
1214
- try {
1215
- const point = (0, import_transform.joinPoint)(state.doc, state.selection.$from.pos, 1);
1216
- if (point === null || point === void 0) {
1217
- return false;
1218
- }
1219
- tr.join(point, 2);
1220
- if (dispatch) {
1221
- dispatch(tr);
1222
- }
1223
- return true;
1224
- } catch {
1225
- return false;
1226
- }
1227
- };
1228
- joinTextblockBackward = () => ({ state, dispatch }) => {
1229
- return (0, import_commands.joinTextblockBackward)(state, dispatch);
1230
- };
1231
- joinTextblockForward = () => ({ state, dispatch }) => {
1232
- return (0, import_commands.joinTextblockForward)(state, dispatch);
1233
- };
1234
- keyboardShortcut = (name) => ({ editor, view, tr, dispatch }) => {
1235
- const keys = normalizeKeyName(name).split(/-(?!$)/);
1236
- const key = keys.find((item) => !["Alt", "Ctrl", "Meta", "Shift"].includes(item));
1237
- const event = new KeyboardEvent("keydown", {
1238
- key: key === "Space" ? " " : key,
1239
- altKey: keys.includes("Alt"),
1240
- ctrlKey: keys.includes("Ctrl"),
1241
- metaKey: keys.includes("Meta"),
1242
- shiftKey: keys.includes("Shift"),
1243
- bubbles: true,
1244
- cancelable: true
1245
- });
1246
- const capturedTransaction = editor.captureTransaction(() => {
1247
- view.someProp("handleKeyDown", (f) => f(view, event));
1248
- });
1249
- capturedTransaction === null || capturedTransaction === void 0 ? void 0 : capturedTransaction.steps.forEach((step) => {
1250
- const newStep = step.map(tr.mapping);
1251
- if (newStep && dispatch) {
1252
- tr.maybeStep(newStep);
1253
- }
1254
- });
1255
- return true;
1256
- };
1257
- lift = (typeOrName, attributes = {}) => ({ state, dispatch }) => {
1258
- const type = getNodeType(typeOrName, state.schema);
1259
- const isActive = isNodeActive(state, type, attributes);
1260
- if (!isActive) {
1261
- return false;
1262
- }
1263
- return (0, import_commands.lift)(state, dispatch);
1264
- };
1265
- liftEmptyBlock = () => ({ state, dispatch }) => {
1266
- return (0, import_commands.liftEmptyBlock)(state, dispatch);
1267
- };
1268
- liftListItem = (typeOrName) => ({ state, dispatch }) => {
1269
- const type = getNodeType(typeOrName, state.schema);
1270
- return (0, import_schema_list.liftListItem)(type)(state, dispatch);
1271
- };
1272
- newlineInCode = () => ({ state, dispatch }) => {
1273
- return (0, import_commands.newlineInCode)(state, dispatch);
1274
- };
1275
- resetAttributes = (typeOrName, attributes) => ({ tr, state, dispatch }) => {
1276
- let nodeType = null;
1277
- let markType = null;
1278
- const schemaType = getSchemaTypeNameByName(typeof typeOrName === "string" ? typeOrName : typeOrName.name, state.schema);
1279
- if (!schemaType) {
1280
- return false;
1281
- }
1282
- if (schemaType === "node") {
1283
- nodeType = getNodeType(typeOrName, state.schema);
1284
- }
1285
- if (schemaType === "mark") {
1286
- markType = getMarkType(typeOrName, state.schema);
1287
- }
1288
- if (dispatch) {
1289
- tr.selection.ranges.forEach((range) => {
1290
- state.doc.nodesBetween(range.$from.pos, range.$to.pos, (node, pos) => {
1291
- if (nodeType && nodeType === node.type) {
1292
- tr.setNodeMarkup(pos, void 0, deleteProps(node.attrs, attributes));
1293
- }
1294
- if (markType && node.marks.length) {
1295
- node.marks.forEach((mark) => {
1296
- if (markType === mark.type) {
1297
- tr.addMark(pos, pos + node.nodeSize, markType.create(deleteProps(mark.attrs, attributes)));
1298
- }
1299
- });
1300
- }
1301
- });
1302
- });
1303
- }
1304
- return true;
1305
- };
1306
- scrollIntoView = () => ({ tr, dispatch }) => {
1307
- if (dispatch) {
1308
- tr.scrollIntoView();
1309
- }
1310
- return true;
1311
- };
1312
- selectAll = () => ({ tr, dispatch }) => {
1313
- if (dispatch) {
1314
- const selection = new import_state.AllSelection(tr.doc);
1315
- tr.setSelection(selection);
1316
- }
1317
- return true;
1318
- };
1319
- selectNodeBackward = () => ({ state, dispatch }) => {
1320
- return (0, import_commands.selectNodeBackward)(state, dispatch);
1321
- };
1322
- selectNodeForward = () => ({ state, dispatch }) => {
1323
- return (0, import_commands.selectNodeForward)(state, dispatch);
1324
- };
1325
- selectParentNode = () => ({ state, dispatch }) => {
1326
- return (0, import_commands.selectParentNode)(state, dispatch);
1327
- };
1328
- selectTextblockEnd = () => ({ state, dispatch }) => {
1329
- return (0, import_commands.selectTextblockEnd)(state, dispatch);
1330
- };
1331
- selectTextblockStart = () => ({ state, dispatch }) => {
1332
- return (0, import_commands.selectTextblockStart)(state, dispatch);
1333
- };
1334
- setContent = (content, emitUpdate = false, parseOptions = {}, options = {}) => ({ editor, tr, dispatch, commands: commands2 }) => {
1335
- var _a, _b;
1336
- const { doc } = tr;
1337
- if (parseOptions.preserveWhitespace !== "full") {
1338
- const document2 = createDocument(content, editor.schema, parseOptions, {
1339
- errorOnInvalidContent: (_a = options.errorOnInvalidContent) !== null && _a !== void 0 ? _a : editor.options.enableContentCheck
1340
- });
1341
- if (dispatch) {
1342
- tr.replaceWith(0, doc.content.size, document2).setMeta("preventUpdate", !emitUpdate);
1343
- }
1344
- return true;
1345
- }
1346
- if (dispatch) {
1347
- tr.setMeta("preventUpdate", !emitUpdate);
1348
- }
1349
- return commands2.insertContentAt({ from: 0, to: doc.content.size }, content, {
1350
- parseOptions,
1351
- errorOnInvalidContent: (_b = options.errorOnInvalidContent) !== null && _b !== void 0 ? _b : editor.options.enableContentCheck
1352
- });
1353
- };
1354
- setMark = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
1355
- const { selection } = tr;
1356
- const { empty, ranges } = selection;
1357
- const type = getMarkType(typeOrName, state.schema);
1358
- if (dispatch) {
1359
- if (empty) {
1360
- const oldAttributes = getMarkAttributes(state, type);
1361
- tr.addStoredMark(type.create({
1362
- ...oldAttributes,
1363
- ...attributes
1364
- }));
1365
- } else {
1366
- ranges.forEach((range) => {
1367
- const from = range.$from.pos;
1368
- const to = range.$to.pos;
1369
- state.doc.nodesBetween(from, to, (node, pos) => {
1370
- const trimmedFrom = Math.max(pos, from);
1371
- const trimmedTo = Math.min(pos + node.nodeSize, to);
1372
- const someHasMark = node.marks.find((mark) => mark.type === type);
1373
- if (someHasMark) {
1374
- node.marks.forEach((mark) => {
1375
- if (type === mark.type) {
1376
- tr.addMark(trimmedFrom, trimmedTo, type.create({
1377
- ...mark.attrs,
1378
- ...attributes
1379
- }));
1380
- }
1381
- });
1382
- } else {
1383
- tr.addMark(trimmedFrom, trimmedTo, type.create(attributes));
1384
- }
1385
- });
1386
- });
1387
- }
1388
- }
1389
- return canSetMark(state, tr, type);
1390
- };
1391
- setMeta = (key, value) => ({ tr }) => {
1392
- tr.setMeta(key, value);
1393
- return true;
1394
- };
1395
- setNode = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) => {
1396
- const type = getNodeType(typeOrName, state.schema);
1397
- let attributesToCopy;
1398
- if (state.selection.$anchor.sameParent(state.selection.$head)) {
1399
- attributesToCopy = state.selection.$anchor.parent.attrs;
1400
- }
1401
- if (!type.isTextblock) {
1402
- console.warn('[tiptap warn]: Currently "setNode()" only supports text block nodes.');
1403
- return false;
1404
- }
1405
- return chain().command(({ commands: commands2 }) => {
1406
- const canSetBlock = (0, import_commands.setBlockType)(type, { ...attributesToCopy, ...attributes })(state);
1407
- if (canSetBlock) {
1408
- return true;
1409
- }
1410
- return commands2.clearNodes();
1411
- }).command(({ state: updatedState }) => {
1412
- return (0, import_commands.setBlockType)(type, { ...attributesToCopy, ...attributes })(updatedState, dispatch);
1413
- }).run();
1414
- };
1415
- setNodeSelection = (position) => ({ tr, dispatch }) => {
1416
- if (dispatch) {
1417
- const { doc } = tr;
1418
- const from = minMax(position, 0, doc.content.size);
1419
- const selection = import_state.NodeSelection.create(doc, from);
1420
- tr.setSelection(selection);
1421
- }
1422
- return true;
1423
- };
1424
- setTextSelection = (position) => ({ tr, dispatch }) => {
1425
- if (dispatch) {
1426
- const { doc } = tr;
1427
- const { from, to } = typeof position === "number" ? { from: position, to: position } : position;
1428
- const minPos = import_state.TextSelection.atStart(doc).from;
1429
- const maxPos = import_state.TextSelection.atEnd(doc).to;
1430
- const resolvedFrom = minMax(from, minPos, maxPos);
1431
- const resolvedEnd = minMax(to, minPos, maxPos);
1432
- const selection = import_state.TextSelection.create(doc, resolvedFrom, resolvedEnd);
1433
- tr.setSelection(selection);
1434
- }
1435
- return true;
1436
- };
1437
- sinkListItem = (typeOrName) => ({ state, dispatch }) => {
1438
- const type = getNodeType(typeOrName, state.schema);
1439
- return (0, import_schema_list.sinkListItem)(type)(state, dispatch);
1440
- };
1441
- splitBlock = ({ keepMarks = true } = {}) => ({ tr, state, dispatch, editor }) => {
1442
- const { selection, doc } = tr;
1443
- const { $from, $to } = selection;
1444
- const extensionAttributes = editor.extensionManager.attributes;
1445
- const newAttributes = getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs);
1446
- if (selection instanceof import_state.NodeSelection && selection.node.isBlock) {
1447
- if (!$from.parentOffset || !(0, import_transform.canSplit)(doc, $from.pos)) {
1448
- return false;
1449
- }
1450
- if (dispatch) {
1451
- if (keepMarks) {
1452
- ensureMarks(state, editor.extensionManager.splittableMarks);
1453
- }
1454
- tr.split($from.pos).scrollIntoView();
1455
- }
1456
- return true;
1457
- }
1458
- if (!$from.parent.isBlock) {
1459
- return false;
1460
- }
1461
- const atEnd = $to.parentOffset === $to.parent.content.size;
1462
- const deflt = $from.depth === 0 ? void 0 : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)));
1463
- let types = atEnd && deflt ? [
1464
- {
1465
- type: deflt,
1466
- attrs: newAttributes
1467
- }
1468
- ] : void 0;
1469
- let can = (0, import_transform.canSplit)(tr.doc, tr.mapping.map($from.pos), 1, types);
1470
- if (!types && !can && (0, import_transform.canSplit)(tr.doc, tr.mapping.map($from.pos), 1, deflt ? [{ type: deflt }] : void 0)) {
1471
- can = true;
1472
- types = deflt ? [
1473
- {
1474
- type: deflt,
1475
- attrs: newAttributes
1476
- }
1477
- ] : void 0;
1478
- }
1479
- if (dispatch) {
1480
- if (can) {
1481
- if (selection instanceof import_state.TextSelection) {
1482
- tr.deleteSelection();
1483
- }
1484
- tr.split(tr.mapping.map($from.pos), 1, types);
1485
- if (deflt && !atEnd && !$from.parentOffset && $from.parent.type !== deflt) {
1486
- const first2 = tr.mapping.map($from.before());
1487
- const $first = tr.doc.resolve(first2);
1488
- if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) {
1489
- tr.setNodeMarkup(tr.mapping.map($from.before()), deflt);
1490
- }
1491
- }
1492
- }
1493
- if (keepMarks) {
1494
- ensureMarks(state, editor.extensionManager.splittableMarks);
1495
- }
1496
- tr.scrollIntoView();
1497
- }
1498
- return can;
1499
- };
1500
- splitListItem = (typeOrName, overrideAttrs = {}) => ({ tr, state, dispatch, editor }) => {
1501
- var _a;
1502
- const type = getNodeType(typeOrName, state.schema);
1503
- const { $from, $to } = state.selection;
1504
- const node = state.selection.node;
1505
- if (node && node.isBlock || $from.depth < 2 || !$from.sameParent($to)) {
1506
- return false;
1507
- }
1508
- const grandParent = $from.node(-1);
1509
- if (grandParent.type !== type) {
1510
- return false;
1511
- }
1512
- const extensionAttributes = editor.extensionManager.attributes;
1513
- if ($from.parent.content.size === 0 && $from.node(-1).childCount === $from.indexAfter(-1)) {
1514
- if ($from.depth === 2 || $from.node(-3).type !== type || $from.index(-2) !== $from.node(-2).childCount - 1) {
1515
- return false;
1516
- }
1517
- if (dispatch) {
1518
- let wrap = import_model.Fragment.empty;
1519
- const depthBefore = $from.index(-1) ? 1 : $from.index(-2) ? 2 : 3;
1520
- for (let d = $from.depth - depthBefore; d >= $from.depth - 3; d -= 1) {
1521
- wrap = import_model.Fragment.from($from.node(d).copy(wrap));
1522
- }
1523
- const depthAfter = $from.indexAfter(-1) < $from.node(-2).childCount ? 1 : $from.indexAfter(-2) < $from.node(-3).childCount ? 2 : 3;
1524
- const newNextTypeAttributes2 = {
1525
- ...getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs),
1526
- ...overrideAttrs
1527
- };
1528
- const nextType2 = ((_a = type.contentMatch.defaultType) === null || _a === void 0 ? void 0 : _a.createAndFill(newNextTypeAttributes2)) || void 0;
1529
- wrap = wrap.append(import_model.Fragment.from(type.createAndFill(null, nextType2) || void 0));
1530
- const start = $from.before($from.depth - (depthBefore - 1));
1531
- tr.replace(start, $from.after(-depthAfter), new import_model.Slice(wrap, 4 - depthBefore, 0));
1532
- let sel = -1;
1533
- tr.doc.nodesBetween(start, tr.doc.content.size, (n, pos) => {
1534
- if (sel > -1) {
1535
- return false;
1536
- }
1537
- if (n.isTextblock && n.content.size === 0) {
1538
- sel = pos + 1;
1539
- }
1540
- });
1541
- if (sel > -1) {
1542
- tr.setSelection(import_state.TextSelection.near(tr.doc.resolve(sel)));
1543
- }
1544
- tr.scrollIntoView();
1545
- }
1546
- return true;
1547
- }
1548
- const nextType = $to.pos === $from.end() ? grandParent.contentMatchAt(0).defaultType : null;
1549
- const newTypeAttributes = {
1550
- ...getSplittedAttributes(extensionAttributes, grandParent.type.name, grandParent.attrs),
1551
- ...overrideAttrs
1552
- };
1553
- const newNextTypeAttributes = {
1554
- ...getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs),
1555
- ...overrideAttrs
1556
- };
1557
- tr.delete($from.pos, $to.pos);
1558
- const types = nextType ? [
1559
- { type, attrs: newTypeAttributes },
1560
- { type: nextType, attrs: newNextTypeAttributes }
1561
- ] : [{ type, attrs: newTypeAttributes }];
1562
- if (!(0, import_transform.canSplit)(tr.doc, $from.pos, 2)) {
1563
- return false;
1564
- }
1565
- if (dispatch) {
1566
- const { selection, storedMarks } = state;
1567
- const { splittableMarks } = editor.extensionManager;
1568
- const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks();
1569
- tr.split($from.pos, 2, types).scrollIntoView();
1570
- if (!marks || !dispatch) {
1571
- return true;
1572
- }
1573
- const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name));
1574
- tr.ensureMarks(filteredMarks);
1575
- }
1576
- return true;
1577
- };
1578
- joinListBackwards = (tr, listType) => {
1579
- const list = findParentNode((node) => node.type === listType)(tr.selection);
1580
- if (!list) {
1581
- return true;
1582
- }
1583
- const before = tr.doc.resolve(Math.max(0, list.pos - 1)).before(list.depth);
1584
- if (before === void 0) {
1585
- return true;
1586
- }
1587
- const nodeBefore = tr.doc.nodeAt(before);
1588
- const canJoinBackwards = list.node.type === (nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.type) && (0, import_transform.canJoin)(tr.doc, list.pos);
1589
- if (!canJoinBackwards) {
1590
- return true;
1591
- }
1592
- tr.join(list.pos);
1593
- return true;
1594
- };
1595
- joinListForwards = (tr, listType) => {
1596
- const list = findParentNode((node) => node.type === listType)(tr.selection);
1597
- if (!list) {
1598
- return true;
1599
- }
1600
- const after = tr.doc.resolve(list.start).after(list.depth);
1601
- if (after === void 0) {
1602
- return true;
1603
- }
1604
- const nodeAfter = tr.doc.nodeAt(after);
1605
- const canJoinForwards = list.node.type === (nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.type) && (0, import_transform.canJoin)(tr.doc, after);
1606
- if (!canJoinForwards) {
1607
- return true;
1608
- }
1609
- tr.join(after);
1610
- return true;
1611
- };
1612
- toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) => ({ editor, tr, state, dispatch, chain, commands: commands2, can }) => {
1613
- const { extensions, splittableMarks } = editor.extensionManager;
1614
- const listType = getNodeType(listTypeOrName, state.schema);
1615
- const itemType = getNodeType(itemTypeOrName, state.schema);
1616
- const { selection, storedMarks } = state;
1617
- const { $from, $to } = selection;
1618
- const range = $from.blockRange($to);
1619
- const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks();
1620
- if (!range) {
1621
- return false;
1622
- }
1623
- const parentList = findParentNode((node) => isList(node.type.name, extensions))(selection);
1624
- if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) {
1625
- if (parentList.node.type === listType) {
1626
- return commands2.liftListItem(itemType);
1627
- }
1628
- if (isList(parentList.node.type.name, extensions) && listType.validContent(parentList.node.content) && dispatch) {
1629
- return chain().command(() => {
1630
- tr.setNodeMarkup(parentList.pos, listType);
1631
- return true;
1632
- }).command(() => joinListBackwards(tr, listType)).command(() => joinListForwards(tr, listType)).run();
1633
- }
1634
- }
1635
- if (!keepMarks || !marks || !dispatch) {
1636
- return chain().command(() => {
1637
- const canWrapInList = can().wrapInList(listType, attributes);
1638
- if (canWrapInList) {
1639
- return true;
1640
- }
1641
- return commands2.clearNodes();
1642
- }).wrapInList(listType, attributes).command(() => joinListBackwards(tr, listType)).command(() => joinListForwards(tr, listType)).run();
1643
- }
1644
- return chain().command(() => {
1645
- const canWrapInList = can().wrapInList(listType, attributes);
1646
- const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name));
1647
- tr.ensureMarks(filteredMarks);
1648
- if (canWrapInList) {
1649
- return true;
1650
- }
1651
- return commands2.clearNodes();
1652
- }).wrapInList(listType, attributes).command(() => joinListBackwards(tr, listType)).command(() => joinListForwards(tr, listType)).run();
1653
- };
1654
- toggleMark = (typeOrName, attributes = {}, options = {}) => ({ state, commands: commands2 }) => {
1655
- const { extendEmptyMarkRange = false } = options;
1656
- const type = getMarkType(typeOrName, state.schema);
1657
- const isActive = isMarkActive(state, type, attributes);
1658
- if (isActive) {
1659
- return commands2.unsetMark(type, { extendEmptyMarkRange });
1660
- }
1661
- return commands2.setMark(type, attributes);
1662
- };
1663
- toggleNode = (typeOrName, toggleTypeOrName, attributes = {}) => ({ state, commands: commands2 }) => {
1664
- const type = getNodeType(typeOrName, state.schema);
1665
- const toggleType = getNodeType(toggleTypeOrName, state.schema);
1666
- const isActive = isNodeActive(state, type, attributes);
1667
- let attributesToCopy;
1668
- if (state.selection.$anchor.sameParent(state.selection.$head)) {
1669
- attributesToCopy = state.selection.$anchor.parent.attrs;
1670
- }
1671
- if (isActive) {
1672
- return commands2.setNode(toggleType, attributesToCopy);
1673
- }
1674
- return commands2.setNode(type, { ...attributesToCopy, ...attributes });
1675
- };
1676
- toggleWrap = (typeOrName, attributes = {}) => ({ state, commands: commands2 }) => {
1677
- const type = getNodeType(typeOrName, state.schema);
1678
- const isActive = isNodeActive(state, type, attributes);
1679
- if (isActive) {
1680
- return commands2.lift(type);
1681
- }
1682
- return commands2.wrapIn(type, attributes);
1683
- };
1684
- undoInputRule = () => ({ state, dispatch }) => {
1685
- const plugins = state.plugins;
1686
- for (let i = 0; i < plugins.length; i += 1) {
1687
- const plugin = plugins[i];
1688
- let undoable;
1689
- if (plugin.spec.isInputRules && (undoable = plugin.getState(state))) {
1690
- if (dispatch) {
1691
- const tr = state.tr;
1692
- const toUndo = undoable.transform;
1693
- for (let j = toUndo.steps.length - 1; j >= 0; j -= 1) {
1694
- tr.step(toUndo.steps[j].invert(toUndo.docs[j]));
1695
- }
1696
- if (undoable.text) {
1697
- const marks = tr.doc.resolve(undoable.from).marks();
1698
- tr.replaceWith(undoable.from, undoable.to, state.schema.text(undoable.text, marks));
1699
- } else {
1700
- tr.delete(undoable.from, undoable.to);
1701
- }
1702
- }
1703
- return true;
1704
- }
1705
- }
1706
- return false;
1707
- };
1708
- unsetAllMarks = () => ({ tr, dispatch }) => {
1709
- const { selection } = tr;
1710
- const { empty, ranges } = selection;
1711
- if (empty) {
1712
- return true;
1713
- }
1714
- if (dispatch) {
1715
- ranges.forEach((range) => {
1716
- tr.removeMark(range.$from.pos, range.$to.pos);
1717
- });
1718
- }
1719
- return true;
1720
- };
1721
- unsetMark = (typeOrName, options = {}) => ({ tr, state, dispatch }) => {
1722
- var _a;
1723
- const { extendEmptyMarkRange = false } = options;
1724
- const { selection } = tr;
1725
- const type = getMarkType(typeOrName, state.schema);
1726
- const { $from, empty, ranges } = selection;
1727
- if (!dispatch) {
1728
- return true;
1729
- }
1730
- if (empty && extendEmptyMarkRange) {
1731
- let { from, to } = selection;
1732
- const attrs = (_a = $from.marks().find((mark) => mark.type === type)) === null || _a === void 0 ? void 0 : _a.attrs;
1733
- const range = getMarkRange($from, type, attrs);
1734
- if (range) {
1735
- from = range.from;
1736
- to = range.to;
1737
- }
1738
- tr.removeMark(from, to, type);
1739
- } else {
1740
- ranges.forEach((range) => {
1741
- tr.removeMark(range.$from.pos, range.$to.pos, type);
1742
- });
1743
- }
1744
- tr.removeStoredMark(type);
1745
- return true;
1746
- };
1747
- updateAttributes = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
1748
- let nodeType = null;
1749
- let markType = null;
1750
- const schemaType = getSchemaTypeNameByName(typeof typeOrName === "string" ? typeOrName : typeOrName.name, state.schema);
1751
- if (!schemaType) {
1752
- return false;
1753
- }
1754
- if (schemaType === "node") {
1755
- nodeType = getNodeType(typeOrName, state.schema);
1756
- }
1757
- if (schemaType === "mark") {
1758
- markType = getMarkType(typeOrName, state.schema);
1759
- }
1760
- if (dispatch) {
1761
- tr.selection.ranges.forEach((range) => {
1762
- const from = range.$from.pos;
1763
- const to = range.$to.pos;
1764
- let lastPos;
1765
- let lastNode;
1766
- let trimmedFrom;
1767
- let trimmedTo;
1768
- if (tr.selection.empty) {
1769
- state.doc.nodesBetween(from, to, (node, pos) => {
1770
- if (nodeType && nodeType === node.type) {
1771
- trimmedFrom = Math.max(pos, from);
1772
- trimmedTo = Math.min(pos + node.nodeSize, to);
1773
- lastPos = pos;
1774
- lastNode = node;
1775
- }
1776
- });
1777
- } else {
1778
- state.doc.nodesBetween(from, to, (node, pos) => {
1779
- if (pos < from && nodeType && nodeType === node.type) {
1780
- trimmedFrom = Math.max(pos, from);
1781
- trimmedTo = Math.min(pos + node.nodeSize, to);
1782
- lastPos = pos;
1783
- lastNode = node;
1784
- }
1785
- if (pos >= from && pos <= to) {
1786
- if (nodeType && nodeType === node.type) {
1787
- tr.setNodeMarkup(pos, void 0, {
1788
- ...node.attrs,
1789
- ...attributes
1790
- });
1791
- }
1792
- if (markType && node.marks.length) {
1793
- node.marks.forEach((mark) => {
1794
- if (markType === mark.type) {
1795
- const trimmedFrom2 = Math.max(pos, from);
1796
- const trimmedTo2 = Math.min(pos + node.nodeSize, to);
1797
- tr.addMark(trimmedFrom2, trimmedTo2, markType.create({
1798
- ...mark.attrs,
1799
- ...attributes
1800
- }));
1801
- }
1802
- });
1803
- }
1804
- }
1805
- });
1806
- }
1807
- if (lastNode) {
1808
- if (lastPos !== void 0) {
1809
- tr.setNodeMarkup(lastPos, void 0, {
1810
- ...lastNode.attrs,
1811
- ...attributes
1812
- });
1813
- }
1814
- if (markType && lastNode.marks.length) {
1815
- lastNode.marks.forEach((mark) => {
1816
- if (markType === mark.type) {
1817
- tr.addMark(trimmedFrom, trimmedTo, markType.create({
1818
- ...mark.attrs,
1819
- ...attributes
1820
- }));
1821
- }
1822
- });
1823
- }
1824
- }
1825
- });
1826
- }
1827
- return true;
1828
- };
1829
- wrapIn = (typeOrName, attributes = {}) => ({ state, dispatch }) => {
1830
- const type = getNodeType(typeOrName, state.schema);
1831
- return (0, import_commands.wrapIn)(type, attributes)(state, dispatch);
1832
- };
1833
- wrapInList = (typeOrName, attributes = {}) => ({ state, dispatch }) => {
1834
- const type = getNodeType(typeOrName, state.schema);
1835
- return (0, import_schema_list.wrapInList)(type, attributes)(state, dispatch);
1836
- };
1837
- commands = /* @__PURE__ */ Object.freeze({
1838
- __proto__: null,
1839
- blur,
1840
- clearContent,
1841
- clearNodes,
1842
- command,
1843
- createParagraphNear,
1844
- cut,
1845
- deleteCurrentNode,
1846
- deleteNode,
1847
- deleteRange,
1848
- deleteSelection,
1849
- enter,
1850
- exitCode,
1851
- extendMarkRange,
1852
- first,
1853
- focus,
1854
- forEach,
1855
- insertContent,
1856
- insertContentAt,
1857
- joinBackward,
1858
- joinDown,
1859
- joinForward,
1860
- joinItemBackward,
1861
- joinItemForward,
1862
- joinTextblockBackward,
1863
- joinTextblockForward,
1864
- joinUp,
1865
- keyboardShortcut,
1866
- lift,
1867
- liftEmptyBlock,
1868
- liftListItem,
1869
- newlineInCode,
1870
- resetAttributes,
1871
- scrollIntoView,
1872
- selectAll,
1873
- selectNodeBackward,
1874
- selectNodeForward,
1875
- selectParentNode,
1876
- selectTextblockEnd,
1877
- selectTextblockStart,
1878
- setContent,
1879
- setMark,
1880
- setMeta,
1881
- setNode,
1882
- setNodeSelection,
1883
- setTextSelection,
1884
- sinkListItem,
1885
- splitBlock,
1886
- splitListItem,
1887
- toggleList,
1888
- toggleMark,
1889
- toggleNode,
1890
- toggleWrap,
1891
- undoInputRule,
1892
- unsetAllMarks,
1893
- unsetMark,
1894
- updateAttributes,
1895
- wrapIn,
1896
- wrapInList
1897
- });
1898
- Commands = Extension.create({
1899
- name: "commands",
1900
- addCommands() {
1901
- return {
1902
- ...commands
1903
- };
1904
- }
1905
- });
1906
- Drop = Extension.create({
1907
- name: "drop",
1908
- addProseMirrorPlugins() {
1909
- return [
1910
- new import_state.Plugin({
1911
- key: new import_state.PluginKey("tiptapDrop"),
1912
- props: {
1913
- handleDrop: (_, e, slice, moved) => {
1914
- this.editor.emit("drop", {
1915
- editor: this.editor,
1916
- event: e,
1917
- slice,
1918
- moved
1919
- });
1920
- }
1921
- }
1922
- })
1923
- ];
1924
- }
1925
- });
1926
- Editable = Extension.create({
1927
- name: "editable",
1928
- addProseMirrorPlugins() {
1929
- return [
1930
- new import_state.Plugin({
1931
- key: new import_state.PluginKey("editable"),
1932
- props: {
1933
- editable: () => this.editor.options.editable
1934
- }
1935
- })
1936
- ];
1937
- }
1938
- });
1939
- focusEventsPluginKey = new import_state.PluginKey("focusEvents");
1940
- FocusEvents = Extension.create({
1941
- name: "focusEvents",
1942
- addProseMirrorPlugins() {
1943
- const { editor } = this;
1944
- return [
1945
- new import_state.Plugin({
1946
- key: focusEventsPluginKey,
1947
- props: {
1948
- handleDOMEvents: {
1949
- focus: (view, event) => {
1950
- editor.isFocused = true;
1951
- const transaction = editor.state.tr.setMeta("focus", { event }).setMeta("addToHistory", false);
1952
- view.dispatch(transaction);
1953
- return false;
1954
- },
1955
- blur: (view, event) => {
1956
- editor.isFocused = false;
1957
- const transaction = editor.state.tr.setMeta("blur", { event }).setMeta("addToHistory", false);
1958
- view.dispatch(transaction);
1959
- return false;
1960
- }
1961
- }
1962
- }
1963
- })
1964
- ];
1965
- }
1966
- });
1967
- Keymap = Extension.create({
1968
- name: "keymap",
1969
- addKeyboardShortcuts() {
1970
- const handleBackspace = () => this.editor.commands.first(({ commands: commands2 }) => [
1971
- () => commands2.undoInputRule(),
1972
- // maybe convert first text block node to default node
1973
- () => commands2.command(({ tr }) => {
1974
- const { selection, doc } = tr;
1975
- const { empty, $anchor } = selection;
1976
- const { pos, parent } = $anchor;
1977
- const $parentPos = $anchor.parent.isTextblock && pos > 0 ? tr.doc.resolve(pos - 1) : $anchor;
1978
- const parentIsIsolating = $parentPos.parent.type.spec.isolating;
1979
- const parentPos = $anchor.pos - $anchor.parentOffset;
1980
- const isAtStart = parentIsIsolating && $parentPos.parent.childCount === 1 ? parentPos === $anchor.pos : import_state.Selection.atStart(doc).from === pos;
1981
- if (!empty || !parent.type.isTextblock || parent.textContent.length || !isAtStart || isAtStart && $anchor.parent.type.name === "paragraph") {
1982
- return false;
1983
- }
1984
- return commands2.clearNodes();
1985
- }),
1986
- () => commands2.deleteSelection(),
1987
- () => commands2.joinBackward(),
1988
- () => commands2.selectNodeBackward()
1989
- ]);
1990
- const handleDelete = () => this.editor.commands.first(({ commands: commands2 }) => [
1991
- () => commands2.deleteSelection(),
1992
- () => commands2.deleteCurrentNode(),
1993
- () => commands2.joinForward(),
1994
- () => commands2.selectNodeForward()
1995
- ]);
1996
- const handleEnter = () => this.editor.commands.first(({ commands: commands2 }) => [
1997
- () => commands2.newlineInCode(),
1998
- () => commands2.createParagraphNear(),
1999
- () => commands2.liftEmptyBlock(),
2000
- () => commands2.splitBlock()
2001
- ]);
2002
- const baseKeymap = {
2003
- Enter: handleEnter,
2004
- "Mod-Enter": () => this.editor.commands.exitCode(),
2005
- Backspace: handleBackspace,
2006
- "Mod-Backspace": handleBackspace,
2007
- "Shift-Backspace": handleBackspace,
2008
- Delete: handleDelete,
2009
- "Mod-Delete": handleDelete,
2010
- "Mod-a": () => this.editor.commands.selectAll()
2011
- };
2012
- const pcKeymap = {
2013
- ...baseKeymap
2014
- };
2015
- const macKeymap = {
2016
- ...baseKeymap,
2017
- "Ctrl-h": handleBackspace,
2018
- "Alt-Backspace": handleBackspace,
2019
- "Ctrl-d": handleDelete,
2020
- "Ctrl-Alt-Backspace": handleDelete,
2021
- "Alt-Delete": handleDelete,
2022
- "Alt-d": handleDelete,
2023
- "Ctrl-a": () => this.editor.commands.selectTextblockStart(),
2024
- "Ctrl-e": () => this.editor.commands.selectTextblockEnd()
2025
- };
2026
- if (isiOS() || isMacOS()) {
2027
- return macKeymap;
2028
- }
2029
- return pcKeymap;
2030
- },
2031
- addProseMirrorPlugins() {
2032
- return [
2033
- // With this plugin we check if the whole document was selected and deleted.
2034
- // In this case we will additionally call `clearNodes()` to convert e.g. a heading
2035
- // to a paragraph if necessary.
2036
- // This is an alternative to ProseMirror's `AllSelection`, which doesn’t work well
2037
- // with many other commands.
2038
- new import_state.Plugin({
2039
- key: new import_state.PluginKey("clearDocument"),
2040
- appendTransaction: (transactions, oldState, newState) => {
2041
- if (transactions.some((tr2) => tr2.getMeta("composition"))) {
2042
- return;
2043
- }
2044
- const docChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
2045
- const ignoreTr = transactions.some((transaction) => transaction.getMeta("preventClearDocument"));
2046
- if (!docChanges || ignoreTr) {
2047
- return;
2048
- }
2049
- const { empty, from, to } = oldState.selection;
2050
- const allFrom = import_state.Selection.atStart(oldState.doc).from;
2051
- const allEnd = import_state.Selection.atEnd(oldState.doc).to;
2052
- const allWasSelected = from === allFrom && to === allEnd;
2053
- if (empty || !allWasSelected) {
2054
- return;
2055
- }
2056
- const isEmpty = isNodeEmpty(newState.doc);
2057
- if (!isEmpty) {
2058
- return;
2059
- }
2060
- const tr = newState.tr;
2061
- const state = createChainableState({
2062
- state: newState,
2063
- transaction: tr
2064
- });
2065
- const { commands: commands2 } = new CommandManager({
2066
- editor: this.editor,
2067
- state
2068
- });
2069
- commands2.clearNodes();
2070
- if (!tr.steps.length) {
2071
- return;
2072
- }
2073
- return tr;
2074
- }
2075
- })
2076
- ];
2077
- }
2078
- });
2079
- Paste = Extension.create({
2080
- name: "paste",
2081
- addProseMirrorPlugins() {
2082
- return [
2083
- new import_state.Plugin({
2084
- key: new import_state.PluginKey("tiptapPaste"),
2085
- props: {
2086
- handlePaste: (_view, e, slice) => {
2087
- this.editor.emit("paste", {
2088
- editor: this.editor,
2089
- event: e,
2090
- slice
2091
- });
2092
- }
2093
- }
2094
- })
2095
- ];
2096
- }
2097
- });
2098
- Tabindex = Extension.create({
2099
- name: "tabindex",
2100
- addProseMirrorPlugins() {
2101
- return [
2102
- new import_state.Plugin({
2103
- key: new import_state.PluginKey("tabindex"),
2104
- props: {
2105
- attributes: () => this.editor.isEditable ? { tabindex: "0" } : {}
2106
- }
2107
- })
2108
- ];
2109
- }
2110
- });
2111
- Node = class _Node {
2112
- constructor(config = {}) {
2113
- this.type = "node";
2114
- this.name = "node";
2115
- this.parent = null;
2116
- this.child = null;
2117
- this.config = {
2118
- name: this.name,
2119
- defaultOptions: {}
2120
- };
2121
- this.config = {
2122
- ...this.config,
2123
- ...config
2124
- };
2125
- this.name = this.config.name;
2126
- if (config.defaultOptions && Object.keys(config.defaultOptions).length > 0) {
2127
- console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${this.name}".`);
2128
- }
2129
- this.options = this.config.defaultOptions;
2130
- if (this.config.addOptions) {
2131
- this.options = callOrReturn(getExtensionField(this, "addOptions", {
2132
- name: this.name
2133
- }));
2134
- }
2135
- this.storage = callOrReturn(getExtensionField(this, "addStorage", {
2136
- name: this.name,
2137
- options: this.options
2138
- })) || {};
2139
- }
2140
- static create(config = {}) {
2141
- return new _Node(config);
2142
- }
2143
- configure(options = {}) {
2144
- const extension = this.extend({
2145
- ...this.config,
2146
- addOptions: () => {
2147
- return mergeDeep(this.options, options);
2148
- }
2149
- });
2150
- extension.name = this.name;
2151
- extension.parent = this.parent;
2152
- return extension;
2153
- }
2154
- extend(extendedConfig = {}) {
2155
- const extension = new _Node(extendedConfig);
2156
- extension.parent = this;
2157
- this.child = extension;
2158
- extension.name = extendedConfig.name ? extendedConfig.name : extension.parent.name;
2159
- if (extendedConfig.defaultOptions && Object.keys(extendedConfig.defaultOptions).length > 0) {
2160
- console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${extension.name}".`);
2161
- }
2162
- extension.options = callOrReturn(getExtensionField(extension, "addOptions", {
2163
- name: extension.name
2164
- }));
2165
- extension.storage = callOrReturn(getExtensionField(extension, "addStorage", {
2166
- name: extension.name,
2167
- options: extension.options
2168
- }));
2169
- return extension;
2170
- }
2171
- };
2172
- }
2173
- });
2174
-
2175
37
  // src/extensions/FontSize.ts
2176
- var FontSize;
38
+ var import_core, FontSize;
2177
39
  var init_FontSize = __esm({
2178
40
  "src/extensions/FontSize.ts"() {
2179
41
  "use strict";
2180
- init_dist();
2181
- FontSize = Extension.create({
42
+ import_core = require("@tiptap/core");
43
+ FontSize = import_core.Extension.create({
2182
44
  name: "fontSize",
2183
45
  addOptions() {
2184
46
  return {
@@ -2221,12 +83,12 @@ var init_FontSize = __esm({
2221
83
  });
2222
84
 
2223
85
  // src/extensions/LineHeight.ts
2224
- var LineHeight;
86
+ var import_core2, LineHeight;
2225
87
  var init_LineHeight = __esm({
2226
88
  "src/extensions/LineHeight.ts"() {
2227
89
  "use strict";
2228
- init_dist();
2229
- LineHeight = Extension.create({
90
+ import_core2 = require("@tiptap/core");
91
+ LineHeight = import_core2.Extension.create({
2230
92
  name: "lineHeight",
2231
93
  addOptions() {
2232
94
  return {
@@ -2257,14 +119,14 @@ var init_LineHeight = __esm({
2257
119
  },
2258
120
  addCommands() {
2259
121
  return {
2260
- setLineHeight: (lineHeight) => ({ commands: commands2 }) => {
122
+ setLineHeight: (lineHeight) => ({ commands }) => {
2261
123
  return this.options.types.every(
2262
- (type) => commands2.updateAttributes(type, { lineHeight })
124
+ (type) => commands.updateAttributes(type, { lineHeight })
2263
125
  );
2264
126
  },
2265
- unsetLineHeight: () => ({ commands: commands2 }) => {
127
+ unsetLineHeight: () => ({ commands }) => {
2266
128
  return this.options.types.every(
2267
- (type) => commands2.resetAttributes(type, "lineHeight")
129
+ (type) => commands.resetAttributes(type, "lineHeight")
2268
130
  );
2269
131
  }
2270
132
  };
@@ -2274,12 +136,12 @@ var init_LineHeight = __esm({
2274
136
  });
2275
137
 
2276
138
  // src/extensions/Video.ts
2277
- var Video;
139
+ var import_core3, Video;
2278
140
  var init_Video = __esm({
2279
141
  "src/extensions/Video.ts"() {
2280
142
  "use strict";
2281
- init_dist();
2282
- Video = Node.create({
143
+ import_core3 = require("@tiptap/core");
144
+ Video = import_core3.Node.create({
2283
145
  name: "video",
2284
146
  addOptions() {
2285
147
  return {
@@ -2327,14 +189,14 @@ var init_Video = __esm({
2327
189
  renderHTML({ HTMLAttributes }) {
2328
190
  return [
2329
191
  "video",
2330
- mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
192
+ (0, import_core3.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
2331
193
  ["source", { src: HTMLAttributes.src }]
2332
194
  ];
2333
195
  },
2334
196
  addCommands() {
2335
197
  return {
2336
- setVideo: (options) => ({ commands: commands2 }) => {
2337
- return commands2.insertContent({
198
+ setVideo: (options) => ({ commands }) => {
199
+ return commands.insertContent({
2338
200
  type: this.name,
2339
201
  attrs: options
2340
202
  });
@@ -2346,11 +208,11 @@ var init_Video = __esm({
2346
208
  });
2347
209
 
2348
210
  // src/extensions/Emoji.ts
2349
- var EMOJI_CATEGORIES, Emoji;
211
+ var import_core4, EMOJI_CATEGORIES, Emoji;
2350
212
  var init_Emoji = __esm({
2351
213
  "src/extensions/Emoji.ts"() {
2352
214
  "use strict";
2353
- init_dist();
215
+ import_core4 = require("@tiptap/core");
2354
216
  EMOJI_CATEGORIES = {
2355
217
  smileys: {
2356
218
  label: "Smileys & People",
@@ -3359,7 +1221,7 @@ var init_Emoji = __esm({
3359
1221
  ]
3360
1222
  }
3361
1223
  };
3362
- Emoji = Extension.create({
1224
+ Emoji = import_core4.Extension.create({
3363
1225
  name: "emoji",
3364
1226
  addOptions() {
3365
1227
  return {
@@ -3368,8 +1230,8 @@ var init_Emoji = __esm({
3368
1230
  },
3369
1231
  addCommands() {
3370
1232
  return {
3371
- insertEmoji: (emoji) => ({ commands: commands2 }) => {
3372
- return commands2.insertContent(emoji);
1233
+ insertEmoji: (emoji) => ({ commands }) => {
1234
+ return commands.insertContent(emoji);
3373
1235
  }
3374
1236
  };
3375
1237
  }
@@ -3378,12 +1240,12 @@ var init_Emoji = __esm({
3378
1240
  });
3379
1241
 
3380
1242
  // src/extensions/Fullscreen.ts
3381
- var Fullscreen;
1243
+ var import_core5, Fullscreen;
3382
1244
  var init_Fullscreen = __esm({
3383
1245
  "src/extensions/Fullscreen.ts"() {
3384
1246
  "use strict";
3385
- init_dist();
3386
- Fullscreen = Extension.create({
1247
+ import_core5 = require("@tiptap/core");
1248
+ Fullscreen = import_core5.Extension.create({
3387
1249
  name: "fullscreen",
3388
1250
  addOptions() {
3389
1251
  return {
@@ -3449,11 +1311,11 @@ var init_Fullscreen = __esm({
3449
1311
  });
3450
1312
 
3451
1313
  // src/extensions/Print.ts
3452
- var defaultPrintStyles, Print;
1314
+ var import_core6, defaultPrintStyles, Print;
3453
1315
  var init_Print = __esm({
3454
1316
  "src/extensions/Print.ts"() {
3455
1317
  "use strict";
3456
- init_dist();
1318
+ import_core6 = require("@tiptap/core");
3457
1319
  defaultPrintStyles = `
3458
1320
  body {
3459
1321
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
@@ -3569,7 +1431,7 @@ var init_Print = __esm({
3569
1431
  }
3570
1432
  }
3571
1433
  `;
3572
- Print = Extension.create({
1434
+ Print = import_core6.Extension.create({
3573
1435
  name: "print",
3574
1436
  addOptions() {
3575
1437
  return {
@@ -3627,12 +1489,12 @@ var init_Print = __esm({
3627
1489
  });
3628
1490
 
3629
1491
  // src/extensions/Indent.ts
3630
- var Indent;
1492
+ var import_core7, Indent;
3631
1493
  var init_Indent = __esm({
3632
1494
  "src/extensions/Indent.ts"() {
3633
1495
  "use strict";
3634
- init_dist();
3635
- Indent = Extension.create({
1496
+ import_core7 = require("@tiptap/core");
1497
+ Indent = import_core7.Extension.create({
3636
1498
  name: "indent",
3637
1499
  addOptions() {
3638
1500
  return {
@@ -4879,9 +2741,9 @@ var init_SlateToolbar = __esm({
4879
2741
  onToggleFullscreen,
4880
2742
  onPrint,
4881
2743
  isFullscreen = false,
4882
- toggleMark: toggleMark3,
2744
+ toggleMark: toggleMark2,
4883
2745
  toggleBlock: toggleBlock2,
4884
- isMarkActive: isMarkActive3,
2746
+ isMarkActive: isMarkActive2,
4885
2747
  isBlockActive: isBlockActive2
4886
2748
  }) => {
4887
2749
  const [showEmojiPicker, setShowEmojiPicker] = (0, import_react4.useState)(false);
@@ -5015,8 +2877,8 @@ var init_SlateToolbar = __esm({
5015
2877
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
5016
2878
  ToolbarButton,
5017
2879
  {
5018
- active: isMarkActive3(editor, "bold"),
5019
- onClick: () => toggleMark3(editor, "bold"),
2880
+ active: isMarkActive2(editor, "bold"),
2881
+ onClick: () => toggleMark2(editor, "bold"),
5020
2882
  title: "Bold (Ctrl+B)",
5021
2883
  children: icons.bold
5022
2884
  },
@@ -5026,8 +2888,8 @@ var init_SlateToolbar = __esm({
5026
2888
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
5027
2889
  ToolbarButton,
5028
2890
  {
5029
- active: isMarkActive3(editor, "italic"),
5030
- onClick: () => toggleMark3(editor, "italic"),
2891
+ active: isMarkActive2(editor, "italic"),
2892
+ onClick: () => toggleMark2(editor, "italic"),
5031
2893
  title: "Italic (Ctrl+I)",
5032
2894
  children: icons.italic
5033
2895
  },
@@ -5037,8 +2899,8 @@ var init_SlateToolbar = __esm({
5037
2899
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
5038
2900
  ToolbarButton,
5039
2901
  {
5040
- active: isMarkActive3(editor, "underline"),
5041
- onClick: () => toggleMark3(editor, "underline"),
2902
+ active: isMarkActive2(editor, "underline"),
2903
+ onClick: () => toggleMark2(editor, "underline"),
5042
2904
  title: "Underline (Ctrl+U)",
5043
2905
  children: icons.underline
5044
2906
  },
@@ -5048,8 +2910,8 @@ var init_SlateToolbar = __esm({
5048
2910
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
5049
2911
  ToolbarButton,
5050
2912
  {
5051
- active: isMarkActive3(editor, "strikethrough"),
5052
- onClick: () => toggleMark3(editor, "strikethrough"),
2913
+ active: isMarkActive2(editor, "strikethrough"),
2914
+ onClick: () => toggleMark2(editor, "strikethrough"),
5053
2915
  title: "Strikethrough",
5054
2916
  children: icons.strike
5055
2917
  },
@@ -5059,8 +2921,8 @@ var init_SlateToolbar = __esm({
5059
2921
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
5060
2922
  ToolbarButton,
5061
2923
  {
5062
- active: isMarkActive3(editor, "code"),
5063
- onClick: () => toggleMark3(editor, "code"),
2924
+ active: isMarkActive2(editor, "code"),
2925
+ onClick: () => toggleMark2(editor, "code"),
5064
2926
  title: "Code",
5065
2927
  children: icons.code
5066
2928
  },
@@ -5081,8 +2943,8 @@ var init_SlateToolbar = __esm({
5081
2943
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
5082
2944
  ToolbarButton,
5083
2945
  {
5084
- active: isMarkActive3(editor, "subscript"),
5085
- onClick: () => toggleMark3(editor, "subscript"),
2946
+ active: isMarkActive2(editor, "subscript"),
2947
+ onClick: () => toggleMark2(editor, "subscript"),
5086
2948
  title: "Subscript",
5087
2949
  children: icons.subscript
5088
2950
  },
@@ -5092,8 +2954,8 @@ var init_SlateToolbar = __esm({
5092
2954
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
5093
2955
  ToolbarButton,
5094
2956
  {
5095
- active: isMarkActive3(editor, "superscript"),
5096
- onClick: () => toggleMark3(editor, "superscript"),
2957
+ active: isMarkActive2(editor, "superscript"),
2958
+ onClick: () => toggleMark2(editor, "superscript"),
5097
2959
  title: "Superscript",
5098
2960
  children: icons.superscript
5099
2961
  },
@@ -5464,7 +3326,7 @@ __export(SlateEditorComponent_exports, {
5464
3326
  SlateEditorComponent: () => SlateEditorComponent,
5465
3327
  default: () => SlateEditorComponent_default
5466
3328
  });
5467
- var import_react5, import_slate2, import_slate_react2, import_slate_history, import_is_hotkey, import_jsx_runtime4, HOTKEYS, LIST_TYPES, TEXT_ALIGN_TYPES, isMarkActive2, isBlockActive, toggleMark2, toggleBlock, serializeToHtml, serializeNode, escapeHtml, deserializeFromHtml, deserializeElement, renderElement, renderLeaf, withInlines, SlateEditorComponent, SlateEditorComponent_default;
3329
+ var import_react5, import_slate2, import_slate_react2, import_slate_history, import_is_hotkey, import_jsx_runtime4, HOTKEYS, LIST_TYPES, TEXT_ALIGN_TYPES, isMarkActive, isBlockActive, toggleMark, toggleBlock, serializeToHtml, serializeNode, escapeHtml, deserializeFromHtml, deserializeElement, renderElement, renderLeaf, withInlines, SlateEditorComponent, SlateEditorComponent_default;
5468
3330
  var init_SlateEditorComponent = __esm({
5469
3331
  "src/adapters/slate/SlateEditorComponent.tsx"() {
5470
3332
  "use strict";
@@ -5484,7 +3346,7 @@ var init_SlateEditorComponent = __esm({
5484
3346
  };
5485
3347
  LIST_TYPES = ["numbered-list", "bulleted-list"];
5486
3348
  TEXT_ALIGN_TYPES = ["left", "center", "right", "justify"];
5487
- isMarkActive2 = (editor, format) => {
3349
+ isMarkActive = (editor, format) => {
5488
3350
  const marks = import_slate2.Editor.marks(editor);
5489
3351
  return marks ? marks[format] === true : false;
5490
3352
  };
@@ -5499,8 +3361,8 @@ var init_SlateEditorComponent = __esm({
5499
3361
  );
5500
3362
  return !!match;
5501
3363
  };
5502
- toggleMark2 = (editor, format) => {
5503
- const isActive = isMarkActive2(editor, format);
3364
+ toggleMark = (editor, format) => {
3365
+ const isActive = isMarkActive(editor, format);
5504
3366
  if (isActive) {
5505
3367
  import_slate2.Editor.removeMark(editor, format);
5506
3368
  } else {
@@ -5513,7 +3375,7 @@ var init_SlateEditorComponent = __esm({
5513
3375
  format,
5514
3376
  TEXT_ALIGN_TYPES.includes(format) ? "align" : "type"
5515
3377
  );
5516
- const isList2 = LIST_TYPES.includes(format);
3378
+ const isList = LIST_TYPES.includes(format);
5517
3379
  import_slate2.Transforms.unwrapNodes(editor, {
5518
3380
  match: (n) => !import_slate2.Editor.isEditor(n) && import_slate2.Element.isElement(n) && LIST_TYPES.includes(n.type) && !TEXT_ALIGN_TYPES.includes(format),
5519
3381
  split: true
@@ -5525,11 +3387,11 @@ var init_SlateEditorComponent = __esm({
5525
3387
  };
5526
3388
  } else {
5527
3389
  newProperties = {
5528
- type: isActive ? "paragraph" : isList2 ? "list-item" : format
3390
+ type: isActive ? "paragraph" : isList ? "list-item" : format
5529
3391
  };
5530
3392
  }
5531
3393
  import_slate2.Transforms.setNodes(editor, newProperties);
5532
- if (!isActive && isList2) {
3394
+ if (!isActive && isList) {
5533
3395
  const block = { type: format, children: [] };
5534
3396
  import_slate2.Transforms.wrapNodes(editor, block);
5535
3397
  }
@@ -5816,7 +3678,7 @@ var init_SlateEditorComponent = __esm({
5816
3678
  if ((0, import_is_hotkey.default)(hotkey, event)) {
5817
3679
  event.preventDefault();
5818
3680
  const mark = HOTKEYS[hotkey];
5819
- toggleMark2(editor, mark);
3681
+ toggleMark(editor, mark);
5820
3682
  }
5821
3683
  }
5822
3684
  },
@@ -5950,9 +3812,9 @@ var init_SlateEditorComponent = __esm({
5950
3812
  onToggleFullscreen: handleToggleFullscreen,
5951
3813
  onPrint: handlePrint,
5952
3814
  isFullscreen,
5953
- toggleMark: toggleMark2,
3815
+ toggleMark,
5954
3816
  toggleBlock,
5955
- isMarkActive: isMarkActive2,
3817
+ isMarkActive,
5956
3818
  isBlockActive
5957
3819
  }
5958
3820
  ),
@@ -6971,7 +4833,11 @@ var init_LexicalEditorComponent = __esm({
6971
4833
  // src/index.tsx
6972
4834
  var index_exports = {};
6973
4835
  __export(index_exports, {
4836
+ CollaborationProvider: () => CollaborationProvider,
4837
+ CommentsPanel: () => CommentsPanel,
4838
+ CommentsProvider: () => CommentsProvider,
6974
4839
  DEFAULT_FEATURES: () => DEFAULT_FEATURES,
4840
+ DEFAULT_REACTION_EMOJIS: () => DEFAULT_REACTION_EMOJIS,
6975
4841
  EMOJI_CATEGORIES: () => EMOJI_CATEGORIES,
6976
4842
  EditorRegistry: () => EditorRegistry,
6977
4843
  Emoji: () => Emoji,
@@ -6979,12 +4845,15 @@ __export(index_exports, {
6979
4845
  Fullscreen: () => Fullscreen,
6980
4846
  Indent: () => Indent,
6981
4847
  LineHeight: () => LineHeight,
4848
+ PresenceIndicator: () => PresenceIndicator,
6982
4849
  Print: () => Print,
6983
4850
  RichTextEditor: () => RichTextEditor,
6984
4851
  TipTapAdapter: () => TipTapAdapter,
6985
4852
  TipTapEditorComponent: () => TipTapEditorComponent,
6986
4853
  TipTapToolbar: () => TipTapToolbar,
6987
4854
  UnifiedEditor: () => UnifiedEditor,
4855
+ VersionHistoryPanel: () => VersionHistoryPanel,
4856
+ VersionHistoryProvider: () => VersionHistoryProvider,
6988
4857
  Video: () => Video,
6989
4858
  blogToolbar: () => blogToolbar,
6990
4859
  codeToolbar: () => codeToolbar,
@@ -7006,7 +4875,13 @@ __export(index_exports, {
7006
4875
  registerAdapter: () => registerAdapter,
7007
4876
  simpleToolbar: () => simpleToolbar,
7008
4877
  toolbarPresets: () => toolbarPresets,
7009
- unregisterAdapter: () => unregisterAdapter
4878
+ unregisterAdapter: () => unregisterAdapter,
4879
+ useCollaboration: () => useCollaboration,
4880
+ useCollaborationOptional: () => useCollaborationOptional,
4881
+ useComments: () => useComments,
4882
+ useCommentsOptional: () => useCommentsOptional,
4883
+ useVersionHistory: () => useVersionHistory,
4884
+ useVersionHistoryOptional: () => useVersionHistoryOptional
7010
4885
  });
7011
4886
  module.exports = __toCommonJS(index_exports);
7012
4887
 
@@ -8675,9 +6550,1382 @@ init_Emoji();
8675
6550
  init_Fullscreen();
8676
6551
  init_Print();
8677
6552
  init_Indent();
6553
+
6554
+ // src/collaboration/CollaborationContext.tsx
6555
+ var import_react12 = require("react");
6556
+ var import_jsx_runtime10 = require("react/jsx-runtime");
6557
+ var initialState = {
6558
+ status: "disconnected",
6559
+ users: [],
6560
+ error: void 0,
6561
+ isHost: false
6562
+ };
6563
+ function collaborationReducer(state, action) {
6564
+ switch (action.type) {
6565
+ case "SET_STATUS":
6566
+ return { ...state, status: action.status, error: action.status === "error" ? state.error : void 0 };
6567
+ case "SET_USERS":
6568
+ return { ...state, users: action.users };
6569
+ case "ADD_USER":
6570
+ if (state.users.find((u) => u.id === action.user.id)) {
6571
+ return {
6572
+ ...state,
6573
+ users: state.users.map((u) => u.id === action.user.id ? action.user : u)
6574
+ };
6575
+ }
6576
+ return { ...state, users: [...state.users, action.user] };
6577
+ case "REMOVE_USER":
6578
+ return { ...state, users: state.users.filter((u) => u.id !== action.userId) };
6579
+ case "UPDATE_CURSOR":
6580
+ return {
6581
+ ...state,
6582
+ users: state.users.map(
6583
+ (u) => u.id === action.userId ? { ...u, cursor: action.cursor, lastActive: Date.now() } : u
6584
+ )
6585
+ };
6586
+ case "SET_ERROR":
6587
+ return { ...state, status: "error", error: action.error };
6588
+ case "CLEAR_ERROR":
6589
+ return { ...state, error: void 0 };
6590
+ case "SET_HOST":
6591
+ return { ...state, isHost: action.isHost };
6592
+ default:
6593
+ return state;
6594
+ }
6595
+ }
6596
+ var CollaborationContext = (0, import_react12.createContext)(null);
6597
+ function generateUserColor() {
6598
+ const colors = [
6599
+ "#f87171",
6600
+ "#fb923c",
6601
+ "#fbbf24",
6602
+ "#a3e635",
6603
+ "#4ade80",
6604
+ "#2dd4bf",
6605
+ "#22d3ee",
6606
+ "#60a5fa",
6607
+ "#a78bfa",
6608
+ "#e879f9"
6609
+ ];
6610
+ return colors[Math.floor(Math.random() * colors.length)];
6611
+ }
6612
+ function CollaborationProvider({
6613
+ children,
6614
+ config,
6615
+ onStatusChange,
6616
+ onUsersChange
6617
+ }) {
6618
+ const [state, dispatch] = (0, import_react12.useReducer)(collaborationReducer, initialState);
6619
+ const wsRef = (0, import_react12.useRef)(null);
6620
+ const reconnectTimeoutRef = (0, import_react12.useRef)(null);
6621
+ const reconnectAttemptsRef = (0, import_react12.useRef)(0);
6622
+ (0, import_react12.useEffect)(() => {
6623
+ onStatusChange?.(state.status);
6624
+ }, [state.status, onStatusChange]);
6625
+ (0, import_react12.useEffect)(() => {
6626
+ onUsersChange?.(state.users);
6627
+ }, [state.users, onUsersChange]);
6628
+ const connect = (0, import_react12.useCallback)(async () => {
6629
+ if (!config) return;
6630
+ dispatch({ type: "SET_STATUS", status: "connecting" });
6631
+ try {
6632
+ if (config.provider === "websocket" && config.serverUrl) {
6633
+ const url = new URL(config.serverUrl);
6634
+ url.searchParams.set("room", config.roomId);
6635
+ if (config.token) {
6636
+ url.searchParams.set("token", config.token);
6637
+ }
6638
+ const ws = new WebSocket(url.toString());
6639
+ wsRef.current = ws;
6640
+ ws.onopen = () => {
6641
+ dispatch({ type: "SET_STATUS", status: "connected" });
6642
+ reconnectAttemptsRef.current = 0;
6643
+ ws.send(JSON.stringify({
6644
+ type: "join",
6645
+ user: {
6646
+ id: config.user.id,
6647
+ name: config.user.name,
6648
+ avatar: config.user.avatar,
6649
+ color: config.user.color || generateUserColor()
6650
+ }
6651
+ }));
6652
+ };
6653
+ ws.onmessage = (event) => {
6654
+ try {
6655
+ const message = JSON.parse(event.data);
6656
+ handleCollaborationEvent(message);
6657
+ } catch {
6658
+ console.error("Failed to parse collaboration message");
6659
+ }
6660
+ };
6661
+ ws.onclose = () => {
6662
+ dispatch({ type: "SET_STATUS", status: "disconnected" });
6663
+ handleReconnect();
6664
+ };
6665
+ ws.onerror = () => {
6666
+ dispatch({ type: "SET_ERROR", error: "Connection error" });
6667
+ };
6668
+ } else if (config.provider === "webrtc") {
6669
+ dispatch({ type: "SET_ERROR", error: "WebRTC provider not yet implemented" });
6670
+ } else if (config.provider === "custom") {
6671
+ dispatch({ type: "SET_STATUS", status: "connected" });
6672
+ }
6673
+ } catch (error) {
6674
+ dispatch({ type: "SET_ERROR", error: error instanceof Error ? error.message : "Connection failed" });
6675
+ }
6676
+ }, [config]);
6677
+ const handleCollaborationEvent = (0, import_react12.useCallback)((event) => {
6678
+ switch (event.type) {
6679
+ case "user-joined":
6680
+ dispatch({ type: "ADD_USER", user: event.user });
6681
+ break;
6682
+ case "user-left":
6683
+ dispatch({ type: "REMOVE_USER", userId: event.userId });
6684
+ break;
6685
+ case "cursor-moved":
6686
+ dispatch({ type: "UPDATE_CURSOR", userId: event.userId, cursor: event.cursor });
6687
+ break;
6688
+ case "status-changed":
6689
+ dispatch({ type: "SET_STATUS", status: event.status });
6690
+ break;
6691
+ case "error":
6692
+ dispatch({ type: "SET_ERROR", error: event.message });
6693
+ break;
6694
+ }
6695
+ }, []);
6696
+ const handleReconnect = (0, import_react12.useCallback)(() => {
6697
+ if (!config?.autoReconnect) return;
6698
+ const maxAttempts = config.maxReconnectAttempts ?? 5;
6699
+ const interval = config.reconnectInterval ?? 3e3;
6700
+ if (reconnectAttemptsRef.current >= maxAttempts) {
6701
+ dispatch({ type: "SET_ERROR", error: "Max reconnection attempts reached" });
6702
+ return;
6703
+ }
6704
+ dispatch({ type: "SET_STATUS", status: "reconnecting" });
6705
+ reconnectAttemptsRef.current++;
6706
+ reconnectTimeoutRef.current = setTimeout(() => {
6707
+ connect();
6708
+ }, interval);
6709
+ }, [config, connect]);
6710
+ const disconnect = (0, import_react12.useCallback)(() => {
6711
+ if (reconnectTimeoutRef.current) {
6712
+ clearTimeout(reconnectTimeoutRef.current);
6713
+ }
6714
+ if (wsRef.current) {
6715
+ wsRef.current.close();
6716
+ wsRef.current = null;
6717
+ }
6718
+ dispatch({ type: "SET_STATUS", status: "disconnected" });
6719
+ dispatch({ type: "SET_USERS", users: [] });
6720
+ }, []);
6721
+ const updateCursor = (0, import_react12.useCallback)((cursor) => {
6722
+ if (!config || !wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) return;
6723
+ wsRef.current.send(JSON.stringify({
6724
+ type: "cursor",
6725
+ userId: config.user.id,
6726
+ cursor
6727
+ }));
6728
+ }, [config]);
6729
+ (0, import_react12.useEffect)(() => {
6730
+ return () => {
6731
+ disconnect();
6732
+ };
6733
+ }, [disconnect]);
6734
+ const value = {
6735
+ state,
6736
+ config: config ?? null,
6737
+ connect,
6738
+ disconnect,
6739
+ updateCursor,
6740
+ isEnabled: !!config
6741
+ };
6742
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CollaborationContext.Provider, { value, children });
6743
+ }
6744
+ function useCollaboration() {
6745
+ const context = (0, import_react12.useContext)(CollaborationContext);
6746
+ if (!context) {
6747
+ throw new Error("useCollaboration must be used within a CollaborationProvider");
6748
+ }
6749
+ return context;
6750
+ }
6751
+ function useCollaborationOptional() {
6752
+ return (0, import_react12.useContext)(CollaborationContext);
6753
+ }
6754
+
6755
+ // src/collaboration/PresenceIndicator.tsx
6756
+ var import_jsx_runtime11 = require("react/jsx-runtime");
6757
+ function getInitials(name) {
6758
+ return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
6759
+ }
6760
+ function UserAvatar({ user, showName }) {
6761
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
6762
+ "div",
6763
+ {
6764
+ className: "rte-presence-avatar",
6765
+ style: { borderColor: user.color },
6766
+ title: user.name,
6767
+ children: [
6768
+ user.avatar ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { src: user.avatar, alt: user.name }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { backgroundColor: user.color }, children: getInitials(user.name) }),
6769
+ user.isActive && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rte-presence-active-dot" }),
6770
+ showName && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rte-presence-name", children: user.name })
6771
+ ]
6772
+ }
6773
+ );
6774
+ }
6775
+ function StatusBadge({ status }) {
6776
+ const statusConfig = {
6777
+ connected: { label: "Connected", color: "#22c55e" },
6778
+ connecting: { label: "Connecting...", color: "#eab308" },
6779
+ reconnecting: { label: "Reconnecting...", color: "#f97316" },
6780
+ disconnected: { label: "Disconnected", color: "#6b7280" },
6781
+ error: { label: "Error", color: "#ef4444" }
6782
+ };
6783
+ const config = statusConfig[status] || statusConfig.disconnected;
6784
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rte-presence-status", style: { color: config.color }, children: [
6785
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rte-presence-status-dot", style: { backgroundColor: config.color } }),
6786
+ config.label
6787
+ ] });
6788
+ }
6789
+ function PresenceIndicator({
6790
+ maxAvatars = 5,
6791
+ showNames = false,
6792
+ className = ""
6793
+ }) {
6794
+ const collaboration = useCollaborationOptional();
6795
+ if (!collaboration?.isEnabled) {
6796
+ return null;
6797
+ }
6798
+ const { state } = collaboration;
6799
+ const visibleUsers = state.users.slice(0, maxAvatars);
6800
+ const remainingCount = Math.max(0, state.users.length - maxAvatars);
6801
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `rte-presence-indicator ${className}`, children: [
6802
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StatusBadge, { status: state.status }),
6803
+ state.users.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rte-presence-avatars", children: [
6804
+ visibleUsers.map((user) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(UserAvatar, { user, showName: showNames }, user.id)),
6805
+ remainingCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rte-presence-avatar rte-presence-more", children: [
6806
+ "+",
6807
+ remainingCount
6808
+ ] })
6809
+ ] }),
6810
+ state.error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rte-presence-error", title: state.error, children: "!" })
6811
+ ] });
6812
+ }
6813
+
6814
+ // src/comments/types.ts
6815
+ var DEFAULT_REACTION_EMOJIS = ["\u{1F44D}", "\u{1F44E}", "\u2764\uFE0F", "\u{1F389}", "\u{1F604}", "\u{1F615}", "\u{1F440}", "\u{1F680}"];
6816
+
6817
+ // src/comments/CommentsContext.tsx
6818
+ var import_react13 = require("react");
6819
+ var import_jsx_runtime12 = require("react/jsx-runtime");
6820
+ var initialState2 = {
6821
+ threads: [],
6822
+ activeThreadId: null,
6823
+ isPanelOpen: false,
6824
+ filter: "all",
6825
+ currentUser: null
6826
+ };
6827
+ function generateId() {
6828
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
6829
+ }
6830
+ function commentsReducer(state, action) {
6831
+ switch (action.type) {
6832
+ case "SET_THREADS":
6833
+ return { ...state, threads: action.threads };
6834
+ case "ADD_THREAD":
6835
+ return { ...state, threads: [...state.threads, action.thread] };
6836
+ case "DELETE_THREAD":
6837
+ return {
6838
+ ...state,
6839
+ threads: state.threads.filter((t) => t.id !== action.threadId),
6840
+ activeThreadId: state.activeThreadId === action.threadId ? null : state.activeThreadId
6841
+ };
6842
+ case "RESOLVE_THREAD":
6843
+ return {
6844
+ ...state,
6845
+ threads: state.threads.map(
6846
+ (t) => t.id === action.threadId ? { ...t, status: "resolved", resolvedAt: Date.now(), resolvedBy: action.resolvedBy } : t
6847
+ )
6848
+ };
6849
+ case "REOPEN_THREAD":
6850
+ return {
6851
+ ...state,
6852
+ threads: state.threads.map(
6853
+ (t) => t.id === action.threadId ? { ...t, status: "open", resolvedAt: void 0, resolvedBy: void 0 } : t
6854
+ )
6855
+ };
6856
+ case "ADD_COMMENT":
6857
+ return {
6858
+ ...state,
6859
+ threads: state.threads.map(
6860
+ (t) => t.id === action.threadId ? { ...t, comments: [...t.comments, action.comment] } : t
6861
+ )
6862
+ };
6863
+ case "UPDATE_COMMENT":
6864
+ return {
6865
+ ...state,
6866
+ threads: state.threads.map(
6867
+ (t) => t.id === action.threadId ? {
6868
+ ...t,
6869
+ comments: t.comments.map(
6870
+ (c) => c.id === action.comment.id ? action.comment : c
6871
+ )
6872
+ } : t
6873
+ )
6874
+ };
6875
+ case "DELETE_COMMENT":
6876
+ return {
6877
+ ...state,
6878
+ threads: state.threads.map(
6879
+ (t) => t.id === action.threadId ? { ...t, comments: t.comments.filter((c) => c.id !== action.commentId) } : t
6880
+ )
6881
+ };
6882
+ case "ADD_REACTION":
6883
+ return {
6884
+ ...state,
6885
+ threads: state.threads.map(
6886
+ (t) => t.id === action.threadId ? {
6887
+ ...t,
6888
+ comments: t.comments.map((c) => {
6889
+ if (c.id !== action.commentId) return c;
6890
+ const reactions = c.reactions || [];
6891
+ const existingReaction = reactions.find((r) => r.emoji === action.emoji);
6892
+ if (existingReaction) {
6893
+ return {
6894
+ ...c,
6895
+ reactions: reactions.map(
6896
+ (r) => r.emoji === action.emoji ? { ...r, users: [...r.users, action.user] } : r
6897
+ )
6898
+ };
6899
+ }
6900
+ return {
6901
+ ...c,
6902
+ reactions: [...reactions, { emoji: action.emoji, users: [action.user] }]
6903
+ };
6904
+ })
6905
+ } : t
6906
+ )
6907
+ };
6908
+ case "REMOVE_REACTION":
6909
+ return {
6910
+ ...state,
6911
+ threads: state.threads.map(
6912
+ (t) => t.id === action.threadId ? {
6913
+ ...t,
6914
+ comments: t.comments.map((c) => {
6915
+ if (c.id !== action.commentId) return c;
6916
+ return {
6917
+ ...c,
6918
+ reactions: (c.reactions || []).map(
6919
+ (r) => r.emoji === action.emoji ? { ...r, users: r.users.filter((u) => u.id !== action.userId) } : r
6920
+ ).filter((r) => r.users.length > 0)
6921
+ };
6922
+ })
6923
+ } : t
6924
+ )
6925
+ };
6926
+ case "SET_ACTIVE_THREAD":
6927
+ return { ...state, activeThreadId: action.threadId };
6928
+ case "TOGGLE_PANEL":
6929
+ return { ...state, isPanelOpen: action.isOpen ?? !state.isPanelOpen };
6930
+ case "SET_FILTER":
6931
+ return { ...state, filter: action.filter };
6932
+ case "SET_CURRENT_USER":
6933
+ return { ...state, currentUser: action.user };
6934
+ default:
6935
+ return state;
6936
+ }
6937
+ }
6938
+ var CommentsContext = (0, import_react13.createContext)(null);
6939
+ function CommentsProvider({
6940
+ children,
6941
+ config,
6942
+ initialThreads = [],
6943
+ onThreadsChange
6944
+ }) {
6945
+ const [state, dispatch] = (0, import_react13.useReducer)(commentsReducer, {
6946
+ ...initialState2,
6947
+ threads: initialThreads,
6948
+ currentUser: config?.currentUser ?? null
6949
+ });
6950
+ const subscribersRef = { current: /* @__PURE__ */ new Set() };
6951
+ (0, import_react13.useEffect)(() => {
6952
+ if (config?.onLoad) {
6953
+ config.onLoad().then((threads) => {
6954
+ dispatch({ type: "SET_THREADS", threads });
6955
+ });
6956
+ }
6957
+ }, [config]);
6958
+ (0, import_react13.useEffect)(() => {
6959
+ onThreadsChange?.(state.threads);
6960
+ if (config?.onSave) {
6961
+ config.onSave(state.threads);
6962
+ }
6963
+ }, [state.threads, onThreadsChange, config]);
6964
+ (0, import_react13.useEffect)(() => {
6965
+ if (config?.currentUser) {
6966
+ dispatch({ type: "SET_CURRENT_USER", user: config.currentUser });
6967
+ }
6968
+ }, [config?.currentUser]);
6969
+ const emitEvent = (0, import_react13.useCallback)((event) => {
6970
+ subscribersRef.current.forEach((callback) => callback(event));
6971
+ }, []);
6972
+ const createThread = (0, import_react13.useCallback)((range, initialComment) => {
6973
+ if (!state.currentUser) return null;
6974
+ const threadId = generateId();
6975
+ const commentId = generateId();
6976
+ const now = Date.now();
6977
+ const comment = {
6978
+ id: commentId,
6979
+ threadId,
6980
+ content: initialComment,
6981
+ author: state.currentUser,
6982
+ createdAt: now,
6983
+ isEdited: false
6984
+ };
6985
+ const thread = {
6986
+ id: threadId,
6987
+ range,
6988
+ comments: [comment],
6989
+ status: "open",
6990
+ createdAt: now
6991
+ };
6992
+ dispatch({ type: "ADD_THREAD", thread });
6993
+ emitEvent({ type: "thread-created", thread });
6994
+ return thread;
6995
+ }, [state.currentUser, emitEvent]);
6996
+ const deleteThread = (0, import_react13.useCallback)((threadId) => {
6997
+ if (config?.allowDelete === false) return;
6998
+ dispatch({ type: "DELETE_THREAD", threadId });
6999
+ emitEvent({ type: "thread-deleted", threadId });
7000
+ }, [config, emitEvent]);
7001
+ const resolveThread = (0, import_react13.useCallback)((threadId) => {
7002
+ if (!state.currentUser || config?.allowResolve === false) return;
7003
+ dispatch({ type: "RESOLVE_THREAD", threadId, resolvedBy: state.currentUser });
7004
+ emitEvent({ type: "thread-resolved", threadId, resolvedBy: state.currentUser });
7005
+ }, [state.currentUser, config, emitEvent]);
7006
+ const reopenThread = (0, import_react13.useCallback)((threadId) => {
7007
+ dispatch({ type: "REOPEN_THREAD", threadId });
7008
+ emitEvent({ type: "thread-reopened", threadId });
7009
+ }, [emitEvent]);
7010
+ const addComment = (0, import_react13.useCallback)((threadId, content) => {
7011
+ if (!state.currentUser) return null;
7012
+ const comment = {
7013
+ id: generateId(),
7014
+ threadId,
7015
+ content,
7016
+ author: state.currentUser,
7017
+ createdAt: Date.now(),
7018
+ isEdited: false
7019
+ };
7020
+ dispatch({ type: "ADD_COMMENT", threadId, comment });
7021
+ emitEvent({ type: "comment-added", threadId, comment });
7022
+ return comment;
7023
+ }, [state.currentUser, emitEvent]);
7024
+ const updateComment = (0, import_react13.useCallback)((threadId, commentId, content) => {
7025
+ if (config?.allowEdit === false) return;
7026
+ const thread = state.threads.find((t) => t.id === threadId);
7027
+ const existingComment = thread?.comments.find((c) => c.id === commentId);
7028
+ if (!existingComment) return;
7029
+ const updatedComment = {
7030
+ ...existingComment,
7031
+ content,
7032
+ updatedAt: Date.now(),
7033
+ isEdited: true
7034
+ };
7035
+ dispatch({ type: "UPDATE_COMMENT", threadId, comment: updatedComment });
7036
+ emitEvent({ type: "comment-updated", threadId, comment: updatedComment });
7037
+ }, [state.threads, config, emitEvent]);
7038
+ const deleteComment = (0, import_react13.useCallback)((threadId, commentId) => {
7039
+ if (config?.allowDelete === false) return;
7040
+ dispatch({ type: "DELETE_COMMENT", threadId, commentId });
7041
+ emitEvent({ type: "comment-deleted", threadId, commentId });
7042
+ }, [config, emitEvent]);
7043
+ const addReaction = (0, import_react13.useCallback)((threadId, commentId, emoji) => {
7044
+ if (!state.currentUser || config?.allowReactions === false) return;
7045
+ const allowedEmojis = config?.reactionEmojis ?? DEFAULT_REACTION_EMOJIS;
7046
+ if (!allowedEmojis.includes(emoji)) return;
7047
+ dispatch({ type: "ADD_REACTION", threadId, commentId, emoji, user: state.currentUser });
7048
+ emitEvent({ type: "reaction-added", threadId, commentId, emoji, user: state.currentUser });
7049
+ }, [state.currentUser, config, emitEvent]);
7050
+ const removeReaction = (0, import_react13.useCallback)((threadId, commentId, emoji) => {
7051
+ if (!state.currentUser) return;
7052
+ dispatch({ type: "REMOVE_REACTION", threadId, commentId, emoji, userId: state.currentUser.id });
7053
+ emitEvent({ type: "reaction-removed", threadId, commentId, emoji, userId: state.currentUser.id });
7054
+ }, [state.currentUser, emitEvent]);
7055
+ const setActiveThread = (0, import_react13.useCallback)((threadId) => {
7056
+ dispatch({ type: "SET_ACTIVE_THREAD", threadId });
7057
+ }, []);
7058
+ const togglePanel = (0, import_react13.useCallback)((isOpen) => {
7059
+ dispatch({ type: "TOGGLE_PANEL", isOpen });
7060
+ }, []);
7061
+ const setFilter = (0, import_react13.useCallback)((filter) => {
7062
+ dispatch({ type: "SET_FILTER", filter });
7063
+ }, []);
7064
+ const getThreadByRange = (0, import_react13.useCallback)((from, to) => {
7065
+ return state.threads.find((t) => t.range.from === from && t.range.to === to);
7066
+ }, [state.threads]);
7067
+ const getFilteredThreads = (0, import_react13.useCallback)(() => {
7068
+ if (state.filter === "all") return state.threads;
7069
+ return state.threads.filter((t) => t.status === state.filter);
7070
+ }, [state.threads, state.filter]);
7071
+ const subscribe = (0, import_react13.useCallback)((callback) => {
7072
+ subscribersRef.current.add(callback);
7073
+ return () => {
7074
+ subscribersRef.current.delete(callback);
7075
+ };
7076
+ }, []);
7077
+ const value = {
7078
+ state,
7079
+ config: config ?? null,
7080
+ createThread,
7081
+ deleteThread,
7082
+ resolveThread,
7083
+ reopenThread,
7084
+ addComment,
7085
+ updateComment,
7086
+ deleteComment,
7087
+ addReaction,
7088
+ removeReaction,
7089
+ setActiveThread,
7090
+ togglePanel,
7091
+ setFilter,
7092
+ getThreadByRange,
7093
+ getFilteredThreads,
7094
+ subscribe,
7095
+ isEnabled: !!config
7096
+ };
7097
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CommentsContext.Provider, { value, children });
7098
+ }
7099
+ function useComments() {
7100
+ const context = (0, import_react13.useContext)(CommentsContext);
7101
+ if (!context) {
7102
+ throw new Error("useComments must be used within a CommentsProvider");
7103
+ }
7104
+ return context;
7105
+ }
7106
+ function useCommentsOptional() {
7107
+ return (0, import_react13.useContext)(CommentsContext);
7108
+ }
7109
+
7110
+ // src/comments/CommentsPanel.tsx
7111
+ var import_react14 = require("react");
7112
+ var import_jsx_runtime13 = require("react/jsx-runtime");
7113
+ function formatRelativeTime(timestamp) {
7114
+ const now = Date.now();
7115
+ const diff = now - timestamp;
7116
+ const minutes = Math.floor(diff / 6e4);
7117
+ const hours = Math.floor(diff / 36e5);
7118
+ const days = Math.floor(diff / 864e5);
7119
+ if (minutes < 1) return "Just now";
7120
+ if (minutes < 60) return `${minutes}m ago`;
7121
+ if (hours < 24) return `${hours}h ago`;
7122
+ if (days < 7) return `${days}d ago`;
7123
+ return new Date(timestamp).toLocaleDateString();
7124
+ }
7125
+ function CommentItem({
7126
+ comment,
7127
+ threadId,
7128
+ isFirst
7129
+ }) {
7130
+ const comments = useCommentsOptional();
7131
+ const [isEditing, setIsEditing] = (0, import_react14.useState)(false);
7132
+ const [editContent, setEditContent] = (0, import_react14.useState)(comment.content);
7133
+ const [showReactions, setShowReactions] = (0, import_react14.useState)(false);
7134
+ if (!comments) return null;
7135
+ const { config, updateComment, deleteComment, addReaction, removeReaction, state } = comments;
7136
+ const canEdit = config?.allowEdit !== false && comment.author.id === state.currentUser?.id;
7137
+ const canDelete = config?.allowDelete !== false && comment.author.id === state.currentUser?.id;
7138
+ const canReact = config?.allowReactions !== false;
7139
+ const reactionEmojis = config?.reactionEmojis ?? DEFAULT_REACTION_EMOJIS;
7140
+ const handleSaveEdit = () => {
7141
+ updateComment(threadId, comment.id, editContent);
7142
+ setIsEditing(false);
7143
+ };
7144
+ const handleToggleReaction = (emoji) => {
7145
+ const reaction = comment.reactions?.find((r) => r.emoji === emoji);
7146
+ const hasReacted = reaction?.users.some((u) => u.id === state.currentUser?.id);
7147
+ if (hasReacted) {
7148
+ removeReaction(threadId, comment.id, emoji);
7149
+ } else {
7150
+ addReaction(threadId, comment.id, emoji);
7151
+ }
7152
+ setShowReactions(false);
7153
+ };
7154
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `rte-comment ${isFirst ? "rte-comment-first" : ""}`, children: [
7155
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-comment-header", children: [
7156
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-comment-author", children: [
7157
+ comment.author.avatar ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: comment.author.avatar, alt: comment.author.name, className: "rte-comment-avatar" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rte-comment-avatar-placeholder", children: comment.author.name.charAt(0).toUpperCase() }),
7158
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "rte-comment-author-name", children: comment.author.name })
7159
+ ] }),
7160
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "rte-comment-time", children: [
7161
+ formatRelativeTime(comment.createdAt),
7162
+ comment.isEdited && " (edited)"
7163
+ ] })
7164
+ ] }),
7165
+ isEditing ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-comment-edit", children: [
7166
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7167
+ "textarea",
7168
+ {
7169
+ value: editContent,
7170
+ onChange: (e) => setEditContent(e.target.value),
7171
+ className: "rte-comment-edit-input"
7172
+ }
7173
+ ),
7174
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-comment-edit-actions", children: [
7175
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: handleSaveEdit, className: "rte-comment-btn-save", children: "Save" }),
7176
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setIsEditing(false), className: "rte-comment-btn-cancel", children: "Cancel" })
7177
+ ] })
7178
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rte-comment-content", dangerouslySetInnerHTML: { __html: comment.content } }),
7179
+ comment.reactions && comment.reactions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rte-comment-reactions", children: comment.reactions.map((reaction) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7180
+ "button",
7181
+ {
7182
+ className: `rte-comment-reaction ${reaction.users.some((u) => u.id === state.currentUser?.id) ? "active" : ""}`,
7183
+ onClick: () => handleToggleReaction(reaction.emoji),
7184
+ title: reaction.users.map((u) => u.name).join(", "),
7185
+ children: [
7186
+ reaction.emoji,
7187
+ " ",
7188
+ reaction.users.length
7189
+ ]
7190
+ },
7191
+ reaction.emoji
7192
+ )) }),
7193
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-comment-actions", children: [
7194
+ canReact && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-comment-reaction-picker", children: [
7195
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7196
+ "button",
7197
+ {
7198
+ className: "rte-comment-action-btn",
7199
+ onClick: () => setShowReactions(!showReactions),
7200
+ children: "\u{1F60A}"
7201
+ }
7202
+ ),
7203
+ showReactions && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rte-comment-reaction-dropdown", children: reactionEmojis.map((emoji) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => handleToggleReaction(emoji), children: emoji }, emoji)) })
7204
+ ] }),
7205
+ canEdit && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { className: "rte-comment-action-btn", onClick: () => setIsEditing(true), children: "Edit" }),
7206
+ canDelete && !isFirst && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7207
+ "button",
7208
+ {
7209
+ className: "rte-comment-action-btn rte-comment-action-delete",
7210
+ onClick: () => deleteComment(threadId, comment.id),
7211
+ children: "Delete"
7212
+ }
7213
+ )
7214
+ ] })
7215
+ ] });
7216
+ }
7217
+ function ThreadItem({ thread }) {
7218
+ const comments = useCommentsOptional();
7219
+ const [replyContent, setReplyContent] = (0, import_react14.useState)("");
7220
+ const [showReply, setShowReply] = (0, import_react14.useState)(false);
7221
+ if (!comments) return null;
7222
+ const { state, setActiveThread, addComment, resolveThread, reopenThread, deleteThread, config } = comments;
7223
+ const isActive = state.activeThreadId === thread.id;
7224
+ const canResolve = config?.allowResolve !== false;
7225
+ const handleReply = () => {
7226
+ if (replyContent.trim()) {
7227
+ addComment(thread.id, replyContent);
7228
+ setReplyContent("");
7229
+ setShowReply(false);
7230
+ }
7231
+ };
7232
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7233
+ "div",
7234
+ {
7235
+ className: `rte-thread ${isActive ? "rte-thread-active" : ""} ${thread.status === "resolved" ? "rte-thread-resolved" : ""}`,
7236
+ onClick: () => setActiveThread(thread.id),
7237
+ children: [
7238
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-thread-header", children: [
7239
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-thread-quote", children: [
7240
+ '"',
7241
+ thread.range.text.slice(0, 50),
7242
+ '..."'
7243
+ ] }),
7244
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-thread-meta", children: [
7245
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: `rte-thread-status rte-thread-status-${thread.status}`, children: thread.status }),
7246
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "rte-thread-count", children: [
7247
+ thread.comments.length,
7248
+ " comment",
7249
+ thread.comments.length !== 1 ? "s" : ""
7250
+ ] })
7251
+ ] })
7252
+ ] }),
7253
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rte-thread-comments", children: thread.comments.map((comment, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7254
+ CommentItem,
7255
+ {
7256
+ comment,
7257
+ threadId: thread.id,
7258
+ isFirst: index === 0
7259
+ },
7260
+ comment.id
7261
+ )) }),
7262
+ thread.status === "open" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rte-thread-reply", children: showReply ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
7263
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7264
+ "textarea",
7265
+ {
7266
+ value: replyContent,
7267
+ onChange: (e) => setReplyContent(e.target.value),
7268
+ placeholder: "Write a reply...",
7269
+ className: "rte-thread-reply-input"
7270
+ }
7271
+ ),
7272
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-thread-reply-actions", children: [
7273
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: handleReply, className: "rte-btn-primary", disabled: !replyContent.trim(), children: "Reply" }),
7274
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setShowReply(false), className: "rte-btn-secondary", children: "Cancel" })
7275
+ ] })
7276
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setShowReply(true), className: "rte-thread-reply-btn", children: "Reply" }) }),
7277
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-thread-actions", children: [
7278
+ canResolve && thread.status === "open" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => resolveThread(thread.id), className: "rte-btn-resolve", children: "\u2713 Resolve" }),
7279
+ thread.status === "resolved" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => reopenThread(thread.id), className: "rte-btn-reopen", children: "Reopen" }),
7280
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7281
+ "button",
7282
+ {
7283
+ onClick: (e) => {
7284
+ e.stopPropagation();
7285
+ deleteThread(thread.id);
7286
+ },
7287
+ className: "rte-btn-delete-thread",
7288
+ children: "Delete"
7289
+ }
7290
+ )
7291
+ ] })
7292
+ ]
7293
+ }
7294
+ );
7295
+ }
7296
+ function CommentsPanel({ position = "right", className = "" }) {
7297
+ const comments = useCommentsOptional();
7298
+ if (!comments?.isEnabled || !comments.state.isPanelOpen) {
7299
+ return null;
7300
+ }
7301
+ const { state, togglePanel, setFilter, getFilteredThreads } = comments;
7302
+ const filteredThreads = getFilteredThreads();
7303
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `rte-comments-panel rte-comments-panel-${position} ${className}`, children: [
7304
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rte-comments-panel-header", children: [
7305
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { children: "Comments" }),
7306
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => togglePanel(false), className: "rte-comments-close-btn", children: "\xD7" })
7307
+ ] }),
7308
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rte-comments-filters", children: ["all", "open", "resolved"].map((filter) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7309
+ "button",
7310
+ {
7311
+ className: `rte-comments-filter ${state.filter === filter ? "active" : ""}`,
7312
+ onClick: () => setFilter(filter),
7313
+ children: [
7314
+ filter.charAt(0).toUpperCase() + filter.slice(1),
7315
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "rte-comments-filter-count", children: filter === "all" ? state.threads.length : state.threads.filter((t) => t.status === filter).length })
7316
+ ]
7317
+ },
7318
+ filter
7319
+ )) }),
7320
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rte-comments-list", children: filteredThreads.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rte-comments-empty", children: state.filter === "all" ? "No comments yet. Select text and add a comment." : `No ${state.filter} comments.` }) : filteredThreads.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ThreadItem, { thread }, thread.id)) })
7321
+ ] });
7322
+ }
7323
+
7324
+ // src/history/VersionHistoryContext.tsx
7325
+ var import_react15 = require("react");
7326
+ var import_jsx_runtime14 = require("react/jsx-runtime");
7327
+ var initialState3 = {
7328
+ versions: [],
7329
+ viewingVersionId: null,
7330
+ isPanelOpen: false,
7331
+ isComparing: false,
7332
+ compareFromId: null,
7333
+ compareToId: null,
7334
+ autoSaveEnabled: true,
7335
+ autoSaveInterval: 6e4
7336
+ };
7337
+ function generateId2() {
7338
+ return `v-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
7339
+ }
7340
+ function versionHistoryReducer(state, action) {
7341
+ switch (action.type) {
7342
+ case "SET_VERSIONS":
7343
+ return { ...state, versions: action.versions };
7344
+ case "ADD_VERSION":
7345
+ return {
7346
+ ...state,
7347
+ versions: [action.version, ...state.versions]
7348
+ };
7349
+ case "DELETE_VERSION":
7350
+ return {
7351
+ ...state,
7352
+ versions: state.versions.filter((v) => v.id !== action.versionId),
7353
+ viewingVersionId: state.viewingVersionId === action.versionId ? null : state.viewingVersionId
7354
+ };
7355
+ case "PIN_VERSION":
7356
+ return {
7357
+ ...state,
7358
+ versions: state.versions.map(
7359
+ (v) => v.id === action.versionId ? { ...v, isPinned: true } : v
7360
+ )
7361
+ };
7362
+ case "UNPIN_VERSION":
7363
+ return {
7364
+ ...state,
7365
+ versions: state.versions.map(
7366
+ (v) => v.id === action.versionId ? { ...v, isPinned: false } : v
7367
+ )
7368
+ };
7369
+ case "RENAME_VERSION":
7370
+ return {
7371
+ ...state,
7372
+ versions: state.versions.map(
7373
+ (v) => v.id === action.versionId ? { ...v, title: action.title } : v
7374
+ )
7375
+ };
7376
+ case "SET_VIEWING_VERSION":
7377
+ return { ...state, viewingVersionId: action.versionId };
7378
+ case "TOGGLE_PANEL":
7379
+ return { ...state, isPanelOpen: action.isOpen ?? !state.isPanelOpen };
7380
+ case "START_COMPARE":
7381
+ return {
7382
+ ...state,
7383
+ isComparing: true,
7384
+ compareFromId: action.fromId,
7385
+ compareToId: action.toId
7386
+ };
7387
+ case "STOP_COMPARE":
7388
+ return {
7389
+ ...state,
7390
+ isComparing: false,
7391
+ compareFromId: null,
7392
+ compareToId: null
7393
+ };
7394
+ case "SET_AUTO_SAVE":
7395
+ return { ...state, autoSaveEnabled: action.enabled };
7396
+ case "SET_AUTO_SAVE_INTERVAL":
7397
+ return { ...state, autoSaveInterval: action.interval };
7398
+ default:
7399
+ return state;
7400
+ }
7401
+ }
7402
+ function countWords(text) {
7403
+ return text.trim().split(/\s+/).filter(Boolean).length;
7404
+ }
7405
+ function computeDiff(oldText, newText) {
7406
+ const changes = [];
7407
+ const oldLines = oldText.split("\n");
7408
+ const newLines = newText.split("\n");
7409
+ let i = 0;
7410
+ let j = 0;
7411
+ while (i < oldLines.length || j < newLines.length) {
7412
+ if (i >= oldLines.length) {
7413
+ changes.push({
7414
+ type: "addition",
7415
+ content: newLines[j],
7416
+ position: j
7417
+ });
7418
+ j++;
7419
+ } else if (j >= newLines.length) {
7420
+ changes.push({
7421
+ type: "deletion",
7422
+ content: oldLines[i],
7423
+ position: i
7424
+ });
7425
+ i++;
7426
+ } else if (oldLines[i] === newLines[j]) {
7427
+ i++;
7428
+ j++;
7429
+ } else {
7430
+ const oldLineInNew = newLines.indexOf(oldLines[i], j);
7431
+ const newLineInOld = oldLines.indexOf(newLines[j], i);
7432
+ if (oldLineInNew === -1 && newLineInOld === -1) {
7433
+ changes.push({
7434
+ type: "modification",
7435
+ content: `${oldLines[i]} -> ${newLines[j]}`,
7436
+ position: i
7437
+ });
7438
+ i++;
7439
+ j++;
7440
+ } else if (oldLineInNew === -1) {
7441
+ changes.push({
7442
+ type: "deletion",
7443
+ content: oldLines[i],
7444
+ position: i
7445
+ });
7446
+ i++;
7447
+ } else {
7448
+ changes.push({
7449
+ type: "addition",
7450
+ content: newLines[j],
7451
+ position: j
7452
+ });
7453
+ j++;
7454
+ }
7455
+ }
7456
+ }
7457
+ return changes;
7458
+ }
7459
+ var VersionHistoryContext = (0, import_react15.createContext)(null);
7460
+ function VersionHistoryProvider({
7461
+ children,
7462
+ config,
7463
+ initialVersions = [],
7464
+ onVersionsChange,
7465
+ getCurrentContent
7466
+ }) {
7467
+ const [state, dispatch] = (0, import_react15.useReducer)(versionHistoryReducer, {
7468
+ ...initialState3,
7469
+ versions: initialVersions,
7470
+ autoSaveEnabled: config?.autoSave ?? true,
7471
+ autoSaveInterval: config?.autoSaveInterval ?? 6e4
7472
+ });
7473
+ const subscribersRef = (0, import_react15.useRef)(/* @__PURE__ */ new Set());
7474
+ const autoSaveTimerRef = (0, import_react15.useRef)(null);
7475
+ const lastContentRef = (0, import_react15.useRef)("");
7476
+ const versionNumberRef = (0, import_react15.useRef)(initialVersions.length);
7477
+ (0, import_react15.useEffect)(() => {
7478
+ if (config?.onLoad) {
7479
+ config.onLoad().then((versions) => {
7480
+ dispatch({ type: "SET_VERSIONS", versions });
7481
+ versionNumberRef.current = versions.length;
7482
+ });
7483
+ }
7484
+ }, [config]);
7485
+ (0, import_react15.useEffect)(() => {
7486
+ onVersionsChange?.(state.versions);
7487
+ if (config?.onSave) {
7488
+ config.onSave(state.versions);
7489
+ }
7490
+ }, [state.versions, onVersionsChange, config]);
7491
+ (0, import_react15.useEffect)(() => {
7492
+ if (!state.autoSaveEnabled || !config || !getCurrentContent) return;
7493
+ autoSaveTimerRef.current = setInterval(() => {
7494
+ const { html, json } = getCurrentContent();
7495
+ if (html !== lastContentRef.current) {
7496
+ lastContentRef.current = html;
7497
+ createVersion(html, json, { isAutoSave: true });
7498
+ }
7499
+ }, state.autoSaveInterval);
7500
+ return () => {
7501
+ if (autoSaveTimerRef.current) {
7502
+ clearInterval(autoSaveTimerRef.current);
7503
+ }
7504
+ };
7505
+ }, [state.autoSaveEnabled, state.autoSaveInterval, config, getCurrentContent]);
7506
+ const emitEvent = (0, import_react15.useCallback)((event) => {
7507
+ subscribersRef.current.forEach((callback) => callback(event));
7508
+ }, []);
7509
+ const createVersion = (0, import_react15.useCallback)((content, jsonContent, options) => {
7510
+ if (!config?.currentUser) return null;
7511
+ const maxVersions = config.maxVersions ?? 100;
7512
+ let versions = state.versions;
7513
+ if (versions.length >= maxVersions) {
7514
+ const oldestUnpinned = [...versions].reverse().find((v) => !v.isPinned);
7515
+ if (oldestUnpinned) {
7516
+ versions = versions.filter((v) => v.id !== oldestUnpinned.id);
7517
+ }
7518
+ }
7519
+ versionNumberRef.current++;
7520
+ const textContent = content.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
7521
+ const version = {
7522
+ id: generateId2(),
7523
+ number: versionNumberRef.current,
7524
+ title: options?.title,
7525
+ content,
7526
+ jsonContent,
7527
+ textContent,
7528
+ author: config.currentUser,
7529
+ createdAt: Date.now(),
7530
+ wordCount: countWords(textContent),
7531
+ characterCount: textContent.length,
7532
+ isAutoSave: options?.isAutoSave ?? false,
7533
+ isPinned: false
7534
+ };
7535
+ dispatch({ type: "ADD_VERSION", version });
7536
+ emitEvent({ type: "version-created", version });
7537
+ return version;
7538
+ }, [config, state.versions, emitEvent]);
7539
+ const deleteVersion = (0, import_react15.useCallback)((versionId) => {
7540
+ dispatch({ type: "DELETE_VERSION", versionId });
7541
+ emitEvent({ type: "version-deleted", versionId });
7542
+ }, [emitEvent]);
7543
+ const restoreVersion = (0, import_react15.useCallback)((versionId) => {
7544
+ const version = state.versions.find((v) => v.id === versionId);
7545
+ if (!version) return null;
7546
+ config?.onRestore?.(version);
7547
+ emitEvent({ type: "version-restored", versionId });
7548
+ return version.content;
7549
+ }, [state.versions, config, emitEvent]);
7550
+ const pinVersion = (0, import_react15.useCallback)((versionId) => {
7551
+ dispatch({ type: "PIN_VERSION", versionId });
7552
+ emitEvent({ type: "version-pinned", versionId });
7553
+ }, [emitEvent]);
7554
+ const unpinVersion = (0, import_react15.useCallback)((versionId) => {
7555
+ dispatch({ type: "UNPIN_VERSION", versionId });
7556
+ emitEvent({ type: "version-unpinned", versionId });
7557
+ }, [emitEvent]);
7558
+ const renameVersion = (0, import_react15.useCallback)((versionId, title) => {
7559
+ dispatch({ type: "RENAME_VERSION", versionId, title });
7560
+ emitEvent({ type: "version-renamed", versionId, title });
7561
+ }, [emitEvent]);
7562
+ const viewVersion = (0, import_react15.useCallback)((versionId) => {
7563
+ dispatch({ type: "SET_VIEWING_VERSION", versionId });
7564
+ }, []);
7565
+ const getVersionContent = (0, import_react15.useCallback)((versionId) => {
7566
+ const version = state.versions.find((v) => v.id === versionId);
7567
+ return version?.content ?? null;
7568
+ }, [state.versions]);
7569
+ const compareVersions = (0, import_react15.useCallback)((fromId, toId) => {
7570
+ const fromVersion = state.versions.find((v) => v.id === fromId);
7571
+ const toVersion = state.versions.find((v) => v.id === toId);
7572
+ if (!fromVersion || !toVersion) return null;
7573
+ const changes = computeDiff(fromVersion.textContent, toVersion.textContent);
7574
+ return {
7575
+ fromVersionId: fromId,
7576
+ toVersionId: toId,
7577
+ changes,
7578
+ stats: {
7579
+ additions: changes.filter((c) => c.type === "addition").length,
7580
+ deletions: changes.filter((c) => c.type === "deletion").length,
7581
+ modifications: changes.filter((c) => c.type === "modification").length
7582
+ }
7583
+ };
7584
+ }, [state.versions]);
7585
+ const startCompare = (0, import_react15.useCallback)((fromId, toId) => {
7586
+ dispatch({ type: "START_COMPARE", fromId, toId });
7587
+ }, []);
7588
+ const stopCompare = (0, import_react15.useCallback)(() => {
7589
+ dispatch({ type: "STOP_COMPARE" });
7590
+ }, []);
7591
+ const togglePanel = (0, import_react15.useCallback)((isOpen) => {
7592
+ dispatch({ type: "TOGGLE_PANEL", isOpen });
7593
+ }, []);
7594
+ const setAutoSave = (0, import_react15.useCallback)((enabled) => {
7595
+ dispatch({ type: "SET_AUTO_SAVE", enabled });
7596
+ emitEvent({ type: "auto-save-toggled", enabled });
7597
+ }, [emitEvent]);
7598
+ const getVersion = (0, import_react15.useCallback)((versionId) => {
7599
+ return state.versions.find((v) => v.id === versionId);
7600
+ }, [state.versions]);
7601
+ const getLatestVersion = (0, import_react15.useCallback)(() => {
7602
+ return state.versions[0];
7603
+ }, [state.versions]);
7604
+ const getPinnedVersions = (0, import_react15.useCallback)(() => {
7605
+ return state.versions.filter((v) => v.isPinned);
7606
+ }, [state.versions]);
7607
+ const subscribe = (0, import_react15.useCallback)((callback) => {
7608
+ subscribersRef.current.add(callback);
7609
+ return () => {
7610
+ subscribersRef.current.delete(callback);
7611
+ };
7612
+ }, []);
7613
+ const value = {
7614
+ state,
7615
+ config: config ?? null,
7616
+ createVersion,
7617
+ deleteVersion,
7618
+ restoreVersion,
7619
+ pinVersion,
7620
+ unpinVersion,
7621
+ renameVersion,
7622
+ viewVersion,
7623
+ getVersionContent,
7624
+ compareVersions,
7625
+ startCompare,
7626
+ stopCompare,
7627
+ togglePanel,
7628
+ setAutoSave,
7629
+ getVersion,
7630
+ getLatestVersion,
7631
+ getPinnedVersions,
7632
+ subscribe,
7633
+ isEnabled: !!config
7634
+ };
7635
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VersionHistoryContext.Provider, { value, children });
7636
+ }
7637
+ function useVersionHistory() {
7638
+ const context = (0, import_react15.useContext)(VersionHistoryContext);
7639
+ if (!context) {
7640
+ throw new Error("useVersionHistory must be used within a VersionHistoryProvider");
7641
+ }
7642
+ return context;
7643
+ }
7644
+ function useVersionHistoryOptional() {
7645
+ return (0, import_react15.useContext)(VersionHistoryContext);
7646
+ }
7647
+
7648
+ // src/history/VersionHistoryPanel.tsx
7649
+ var import_react16 = require("react");
7650
+ var import_jsx_runtime15 = require("react/jsx-runtime");
7651
+ function formatDate(timestamp) {
7652
+ const date = new Date(timestamp);
7653
+ const now = /* @__PURE__ */ new Date();
7654
+ const isToday = date.toDateString() === now.toDateString();
7655
+ if (isToday) {
7656
+ return `Today at ${date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}`;
7657
+ }
7658
+ const yesterday = new Date(now);
7659
+ yesterday.setDate(yesterday.getDate() - 1);
7660
+ if (date.toDateString() === yesterday.toDateString()) {
7661
+ return `Yesterday at ${date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}`;
7662
+ }
7663
+ return date.toLocaleDateString([], {
7664
+ month: "short",
7665
+ day: "numeric",
7666
+ hour: "2-digit",
7667
+ minute: "2-digit"
7668
+ });
7669
+ }
7670
+ function VersionItem({
7671
+ version,
7672
+ isViewing,
7673
+ isCompareFrom,
7674
+ isCompareTo,
7675
+ onView,
7676
+ onRestore,
7677
+ onPin,
7678
+ onRename,
7679
+ onDelete,
7680
+ onCompareSelect
7681
+ }) {
7682
+ const [isRenaming, setIsRenaming] = (0, import_react16.useState)(false);
7683
+ const [newTitle, setNewTitle] = (0, import_react16.useState)(version.title || "");
7684
+ const handleRename = () => {
7685
+ onRename(newTitle);
7686
+ setIsRenaming(false);
7687
+ };
7688
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7689
+ "div",
7690
+ {
7691
+ className: `rte-version-item ${isViewing ? "rte-version-viewing" : ""} ${isCompareFrom ? "rte-version-compare-from" : ""} ${isCompareTo ? "rte-version-compare-to" : ""}`,
7692
+ children: [
7693
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-header", onClick: onView, children: [
7694
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-info", children: [
7695
+ isRenaming ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7696
+ "input",
7697
+ {
7698
+ type: "text",
7699
+ value: newTitle,
7700
+ onChange: (e) => setNewTitle(e.target.value),
7701
+ onBlur: handleRename,
7702
+ onKeyDown: (e) => e.key === "Enter" && handleRename(),
7703
+ className: "rte-version-rename-input",
7704
+ onClick: (e) => e.stopPropagation(),
7705
+ autoFocus: true
7706
+ }
7707
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "rte-version-title", children: [
7708
+ version.title || `Version ${version.number}`,
7709
+ version.isPinned && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rte-version-pin-icon", children: "\u{1F4CC}" }),
7710
+ version.isAutoSave && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rte-version-auto-badge", children: "Auto" })
7711
+ ] }),
7712
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rte-version-time", children: formatDate(version.createdAt) })
7713
+ ] }),
7714
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-author", children: [
7715
+ version.author.avatar ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("img", { src: version.author.avatar, alt: version.author.name, className: "rte-version-avatar" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rte-version-avatar-placeholder", children: version.author.name.charAt(0).toUpperCase() }),
7716
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: version.author.name })
7717
+ ] })
7718
+ ] }),
7719
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-stats", children: [
7720
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { children: [
7721
+ version.wordCount,
7722
+ " words"
7723
+ ] }),
7724
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { children: [
7725
+ version.characterCount,
7726
+ " chars"
7727
+ ] })
7728
+ ] }),
7729
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-actions", children: [
7730
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { onClick: onRestore, className: "rte-version-btn", title: "Restore this version", children: "\u21BA Restore" }),
7731
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { onClick: onCompareSelect, className: "rte-version-btn", title: "Compare with another version", children: "\u21C4 Compare" }),
7732
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { onClick: onPin, className: "rte-version-btn", title: version.isPinned ? "Unpin" : "Pin", children: version.isPinned ? "\u{1F4CC} Unpin" : "\u{1F4CC} Pin" }),
7733
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7734
+ "button",
7735
+ {
7736
+ onClick: () => setIsRenaming(true),
7737
+ className: "rte-version-btn",
7738
+ title: "Rename version",
7739
+ children: "\u270F\uFE0F"
7740
+ }
7741
+ ),
7742
+ !version.isPinned && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { onClick: onDelete, className: "rte-version-btn rte-version-btn-delete", title: "Delete", children: "\u{1F5D1}\uFE0F" })
7743
+ ] })
7744
+ ]
7745
+ }
7746
+ );
7747
+ }
7748
+ function ComparisonView({
7749
+ fromVersion,
7750
+ toVersion,
7751
+ onClose
7752
+ }) {
7753
+ const versionHistory = useVersionHistoryOptional();
7754
+ if (!versionHistory) return null;
7755
+ const comparison = versionHistory.compareVersions(fromVersion.id, toVersion.id);
7756
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-comparison", children: [
7757
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-comparison-header", children: [
7758
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h4", { children: "Comparing Versions" }),
7759
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { onClick: onClose, className: "rte-version-comparison-close", children: "\xD7" })
7760
+ ] }),
7761
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-comparison-info", children: [
7762
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-comparison-from", children: [
7763
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rte-version-comparison-label", children: "From:" }),
7764
+ fromVersion.title || `Version ${fromVersion.number}`
7765
+ ] }),
7766
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rte-version-comparison-arrow", children: "\u2192" }),
7767
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-comparison-to", children: [
7768
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rte-version-comparison-label", children: "To:" }),
7769
+ toVersion.title || `Version ${toVersion.number}`
7770
+ ] })
7771
+ ] }),
7772
+ comparison && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-comparison-stats", children: [
7773
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "rte-comparison-stat rte-comparison-additions", children: [
7774
+ "+",
7775
+ comparison.stats.additions,
7776
+ " additions"
7777
+ ] }),
7778
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "rte-comparison-stat rte-comparison-deletions", children: [
7779
+ "-",
7780
+ comparison.stats.deletions,
7781
+ " deletions"
7782
+ ] }),
7783
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "rte-comparison-stat rte-comparison-modifications", children: [
7784
+ "~",
7785
+ comparison.stats.modifications,
7786
+ " modifications"
7787
+ ] })
7788
+ ] }),
7789
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rte-version-comparison-diff", children: comparison?.changes.map((change, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `rte-diff-line rte-diff-${change.type}`, children: [
7790
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rte-diff-indicator", children: change.type === "addition" ? "+" : change.type === "deletion" ? "-" : "~" }),
7791
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rte-diff-content", children: change.content })
7792
+ ] }, index)) })
7793
+ ] });
7794
+ }
7795
+ function VersionHistoryPanel({ position = "right", className = "" }) {
7796
+ const versionHistory = useVersionHistoryOptional();
7797
+ const [compareFromId, setCompareFromId] = (0, import_react16.useState)(null);
7798
+ if (!versionHistory?.isEnabled || !versionHistory.state.isPanelOpen) {
7799
+ return null;
7800
+ }
7801
+ const {
7802
+ state,
7803
+ togglePanel,
7804
+ viewVersion,
7805
+ restoreVersion,
7806
+ pinVersion,
7807
+ unpinVersion,
7808
+ renameVersion,
7809
+ deleteVersion,
7810
+ setAutoSave,
7811
+ getVersion,
7812
+ createVersion,
7813
+ stopCompare
7814
+ } = versionHistory;
7815
+ const handleRestore = (versionId) => {
7816
+ const content = restoreVersion(versionId);
7817
+ if (content) {
7818
+ viewVersion(null);
7819
+ }
7820
+ };
7821
+ const handleCompareSelect = (versionId) => {
7822
+ if (!compareFromId) {
7823
+ setCompareFromId(versionId);
7824
+ } else {
7825
+ versionHistory.startCompare(compareFromId, versionId);
7826
+ setCompareFromId(null);
7827
+ }
7828
+ };
7829
+ const handleCancelCompare = () => {
7830
+ setCompareFromId(null);
7831
+ stopCompare();
7832
+ };
7833
+ const compareFromVersion = state.compareFromId ? getVersion(state.compareFromId) : void 0;
7834
+ const compareToVersion = state.compareToId ? getVersion(state.compareToId) : void 0;
7835
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `rte-version-panel rte-version-panel-${position} ${className}`, children: [
7836
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-panel-header", children: [
7837
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { children: "Version History" }),
7838
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { onClick: () => togglePanel(false), className: "rte-version-close-btn", children: "\xD7" })
7839
+ ] }),
7840
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-autosave", children: [
7841
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "rte-version-autosave-label", children: [
7842
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7843
+ "input",
7844
+ {
7845
+ type: "checkbox",
7846
+ checked: state.autoSaveEnabled,
7847
+ onChange: (e) => setAutoSave(e.target.checked)
7848
+ }
7849
+ ),
7850
+ "Auto-save versions"
7851
+ ] }),
7852
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7853
+ "button",
7854
+ {
7855
+ onClick: () => createVersion("", void 0, { isAutoSave: false }),
7856
+ className: "rte-version-save-btn",
7857
+ children: "Save Now"
7858
+ }
7859
+ )
7860
+ ] }),
7861
+ compareFromId && !state.isComparing && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-compare-mode", children: [
7862
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Select another version to compare" }),
7863
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { onClick: handleCancelCompare, children: "Cancel" })
7864
+ ] }),
7865
+ state.isComparing && compareFromVersion && compareToVersion && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7866
+ ComparisonView,
7867
+ {
7868
+ fromVersion: compareFromVersion,
7869
+ toVersion: compareToVersion,
7870
+ onClose: handleCancelCompare
7871
+ }
7872
+ ),
7873
+ !state.isComparing && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rte-version-list", children: state.versions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rte-version-empty", children: "No versions saved yet. Changes will be auto-saved periodically." }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
7874
+ state.versions.some((v) => v.isPinned) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-section", children: [
7875
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rte-version-section-title", children: "\u{1F4CC} Pinned" }),
7876
+ state.versions.filter((v) => v.isPinned).map((version) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7877
+ VersionItem,
7878
+ {
7879
+ version,
7880
+ isViewing: state.viewingVersionId === version.id,
7881
+ isCompareFrom: compareFromId === version.id,
7882
+ isCompareTo: false,
7883
+ onView: () => viewVersion(version.id),
7884
+ onRestore: () => handleRestore(version.id),
7885
+ onPin: () => unpinVersion(version.id),
7886
+ onRename: (title) => renameVersion(version.id, title),
7887
+ onDelete: () => deleteVersion(version.id),
7888
+ onCompareSelect: () => handleCompareSelect(version.id)
7889
+ },
7890
+ version.id
7891
+ ))
7892
+ ] }),
7893
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-section", children: [
7894
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rte-version-section-title", children: "Recent" }),
7895
+ state.versions.filter((v) => !v.isPinned).map((version) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7896
+ VersionItem,
7897
+ {
7898
+ version,
7899
+ isViewing: state.viewingVersionId === version.id,
7900
+ isCompareFrom: compareFromId === version.id,
7901
+ isCompareTo: false,
7902
+ onView: () => viewVersion(version.id),
7903
+ onRestore: () => handleRestore(version.id),
7904
+ onPin: () => pinVersion(version.id),
7905
+ onRename: (title) => renameVersion(version.id, title),
7906
+ onDelete: () => deleteVersion(version.id),
7907
+ onCompareSelect: () => handleCompareSelect(version.id)
7908
+ },
7909
+ version.id
7910
+ ))
7911
+ ] })
7912
+ ] }) }),
7913
+ state.viewingVersionId && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rte-version-viewing-indicator", children: [
7914
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { children: [
7915
+ "Viewing: ",
7916
+ getVersion(state.viewingVersionId)?.title || `Version ${getVersion(state.viewingVersionId)?.number}`
7917
+ ] }),
7918
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { onClick: () => viewVersion(null), className: "rte-version-back-btn", children: "\u2190 Back to current" })
7919
+ ] })
7920
+ ] });
7921
+ }
8678
7922
  // Annotate the CommonJS export names for ESM import in node:
8679
7923
  0 && (module.exports = {
7924
+ CollaborationProvider,
7925
+ CommentsPanel,
7926
+ CommentsProvider,
8680
7927
  DEFAULT_FEATURES,
7928
+ DEFAULT_REACTION_EMOJIS,
8681
7929
  EMOJI_CATEGORIES,
8682
7930
  EditorRegistry,
8683
7931
  Emoji,
@@ -8685,12 +7933,15 @@ init_Indent();
8685
7933
  Fullscreen,
8686
7934
  Indent,
8687
7935
  LineHeight,
7936
+ PresenceIndicator,
8688
7937
  Print,
8689
7938
  RichTextEditor,
8690
7939
  TipTapAdapter,
8691
7940
  TipTapEditorComponent,
8692
7941
  TipTapToolbar,
8693
7942
  UnifiedEditor,
7943
+ VersionHistoryPanel,
7944
+ VersionHistoryProvider,
8694
7945
  Video,
8695
7946
  blogToolbar,
8696
7947
  codeToolbar,
@@ -8712,6 +7963,12 @@ init_Indent();
8712
7963
  registerAdapter,
8713
7964
  simpleToolbar,
8714
7965
  toolbarPresets,
8715
- unregisterAdapter
7966
+ unregisterAdapter,
7967
+ useCollaboration,
7968
+ useCollaborationOptional,
7969
+ useComments,
7970
+ useCommentsOptional,
7971
+ useVersionHistory,
7972
+ useVersionHistoryOptional
8716
7973
  });
8717
7974
  //# sourceMappingURL=index.js.map