@estiva-app/ui 0.72.0-widgets2.1 → 0.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/CommentHighlights.d.ts +100 -0
  2. package/dist/CommentHighlights.d.ts.map +1 -0
  3. package/dist/ComposeBox.d.ts +55 -0
  4. package/dist/ComposeBox.d.ts.map +1 -0
  5. package/dist/ComposerTriggers.d.ts.map +1 -1
  6. package/dist/SelectionToolbar.d.ts +17 -1
  7. package/dist/SelectionToolbar.d.ts.map +1 -1
  8. package/dist/editor.d.ts +3 -1
  9. package/dist/editor.d.ts.map +1 -1
  10. package/dist/editor.js +618 -217
  11. package/dist/editor.js.map +4 -4
  12. package/dist/index.js.map +1 -1
  13. package/dist/looks.d.ts +6 -0
  14. package/dist/looks.d.ts.map +1 -1
  15. package/package.json +1 -5
  16. package/registry.json +309 -3
  17. package/src/CommentHighlights.mdx +61 -0
  18. package/src/CommentHighlights.stories.tsx +72 -0
  19. package/src/CommentHighlights.test.ts +100 -0
  20. package/src/CommentHighlights.ts +413 -0
  21. package/src/ComposeBox.mdx +58 -0
  22. package/src/ComposeBox.stories.tsx +81 -0
  23. package/src/ComposeBox.tsx +183 -0
  24. package/src/ComposerTriggers.tsx +9 -3
  25. package/src/SelectionToolbar.actions.test.tsx +44 -0
  26. package/src/SelectionToolbar.mdx +1 -0
  27. package/src/SelectionToolbar.tsx +36 -2
  28. package/src/editor.ts +15 -1
  29. package/src/looks.ts +8 -0
  30. package/src/registry/app.test.ts +7 -1
  31. package/src/registry/registry.test.ts +6 -6
  32. package/stories/Choosing.mdx +2 -0
  33. package/dist/widgets-2/fixtures.d.ts +0 -102
  34. package/dist/widgets-2/fixtures.d.ts.map +0 -1
  35. package/dist/widgets-2/places.d.ts +0 -99
  36. package/dist/widgets-2/places.d.ts.map +0 -1
  37. package/dist/widgets-2/proposed.d.ts +0 -130
  38. package/dist/widgets-2/proposed.d.ts.map +0 -1
  39. package/dist/widgets-2.d.ts +0 -12
  40. package/dist/widgets-2.d.ts.map +0 -1
  41. package/dist/widgets-2.js +0 -584
  42. package/dist/widgets-2.js.map +0 -7
  43. package/src/widgets-2/fixtures.ts +0 -161
  44. package/src/widgets-2/places.tsx +0 -309
  45. package/src/widgets-2/proposed.tsx +0 -596
  46. package/src/widgets-2.ts +0 -11
  47. package/stories/widgets-2/ReadMe.mdx +0 -60
  48. package/stories/widgets-2/Widgets.stories.tsx +0 -504
  49. package/stories/widgets-2/today.tsx +0 -352
package/dist/editor.js CHANGED
@@ -7,7 +7,7 @@ import { IconBold, IconCode, IconItalic, IconLink, IconUnderline } from "@tabler
7
7
  import { Form } from "@estiva-app/ui";
8
8
  import { Popover } from "@estiva-app/ui";
9
9
  import { TextInput } from "@estiva-app/ui";
10
- import { Toolbar, ToolbarButton } from "@estiva-app/ui";
10
+ import { Toolbar, ToolbarButton, ToolbarSeparator } from "@estiva-app/ui";
11
11
  import { shortcutLabel } from "@estiva-app/ui";
12
12
  import { jsx, jsxs } from "react/jsx-runtime";
13
13
  var keptSelectionKey = new PluginKey("keptSelection");
@@ -83,7 +83,7 @@ var ICONS = {
83
83
  var SETTLE_MS = 250;
84
84
  var GAP = 8;
85
85
  var POPOVER_GAP = 4;
86
- function SelectionToolbar({ editor, marks = ["bold", "italic", "underline"], link = false, children }) {
86
+ function SelectionToolbar({ editor, marks = ["bold", "italic", "underline"], link = false, children, actions = [] }) {
87
87
  const [anchor, setAnchor] = useState(null);
88
88
  const [mode, setMode] = useState("marks");
89
89
  const [url, setUrl] = useState("");
@@ -274,131 +274,42 @@ function SelectionToolbar({ editor, marks = ["bold", "italic", "underline"], lin
274
274
  children: /* @__PURE__ */ jsx(IconLink, { size: 16, stroke: 1.5 })
275
275
  }
276
276
  ),
277
- children
277
+ children,
278
+ actions.length > 0 && /* @__PURE__ */ jsx(ToolbarSeparator, {}),
279
+ actions.map((action) => /* @__PURE__ */ jsx(
280
+ ToolbarButton,
281
+ {
282
+ "aria-label": action.label,
283
+ tooltip: action.label,
284
+ tooltipShortcut: action.keys ? shortcutLabel(action.keys) : void 0,
285
+ onMouseDown: (e) => e.preventDefault(),
286
+ onClick: () => {
287
+ hide();
288
+ action.run(editor);
289
+ },
290
+ children: action.icon
291
+ },
292
+ action.label
293
+ ))
278
294
  ] })
279
295
  )
280
296
  }
281
297
  );
282
298
  }
283
299
 
284
- // src/PastedImages.ts
300
+ // src/ComposeBox.tsx
301
+ import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
285
302
  import { Extension as Extension2 } from "@tiptap/core";
286
- import { Plugin as Plugin2, PluginKey as PluginKey2 } from "@tiptap/pm/state";
287
- var IMAGE_EXTENSIONS = {
288
- "image/png": "png",
289
- "image/jpeg": "jpg",
290
- "image/gif": "gif",
291
- "image/webp": "webp",
292
- "image/heic": "heic",
293
- "image/heif": "heif",
294
- "image/svg+xml": "svg"
295
- };
296
- var GENERIC_STEMS = /* @__PURE__ */ new Set(["image", "blob", "unknown", "untitled", "screenshot"]);
297
- function extensionFor(contentType) {
298
- const type = contentType.toLowerCase();
299
- return IMAGE_EXTENSIONS[type] ?? type.split("/")[1]?.split("+")[0] ?? "png";
300
- }
301
- function pastedImageName(contentType, at = /* @__PURE__ */ new Date(), index = 0) {
302
- const pad = (n) => String(n).padStart(2, "0");
303
- const stamp = `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())} ${pad(at.getHours())}-${pad(at.getMinutes())}-${pad(at.getSeconds())}`;
304
- const nth = index > 0 ? ` (${index + 1})` : "";
305
- return `Screenshot ${stamp}${nth}.${extensionFor(contentType)}`;
306
- }
307
- function hasUsableName(name) {
308
- const dot = name.lastIndexOf(".");
309
- if (dot <= 0 || dot === name.length - 1) return false;
310
- return !GENERIC_STEMS.has(name.slice(0, dot).toLowerCase());
311
- }
312
- function pastedImages(source, at = /* @__PURE__ */ new Date()) {
313
- if (!source) return [];
314
- if (source.getData("text/plain").trim() !== "") return [];
315
- const images = Array.from(source.files ?? []).filter((f) => f.type.toLowerCase().startsWith("image/"));
316
- let generated = 0;
317
- return images.map(
318
- (file) => hasUsableName(file.name) ? file : new File([file], pastedImageName(file.type, at, generated++), { type: file.type, lastModified: file.lastModified })
319
- );
320
- }
321
- var PastedImages = Extension2.create({
322
- name: "pastedImages",
323
- addOptions() {
324
- return { onImages: () => false };
325
- },
326
- addProseMirrorPlugins() {
327
- const options = this.options;
328
- return [
329
- new Plugin2({
330
- key: new PluginKey2("pastedImages"),
331
- props: {
332
- handlePaste: (_view, event) => {
333
- const files = pastedImages(event.clipboardData);
334
- return files.length > 0 && options.onImages(files);
335
- }
336
- }
337
- })
338
- ];
339
- }
340
- });
341
-
342
- // src/PastedMarkdown.ts
343
- import { Extension as Extension3 } from "@tiptap/core";
344
- import { Slice } from "@tiptap/pm/model";
345
- import { Plugin as Plugin3, PluginKey as PluginKey3 } from "@tiptap/pm/state";
346
- function inTableCell($context) {
347
- for (let depth = $context.depth; depth > 0; depth--) {
348
- const role = $context.node(depth).type.spec.tableRole;
349
- if (role === "cell" || role === "header_cell") return true;
350
- }
351
- return false;
352
- }
353
- var hasTable = (blocks) => blocks.some((block) => block.type === "table" || hasTable(block.content ?? []));
354
- var PastedMarkdown = Extension3.create({
355
- name: "pastedMarkdown",
356
- addOptions() {
357
- return { read: () => void 0 };
358
- },
359
- addProseMirrorPlugins() {
360
- const options = this.options;
361
- return [
362
- new Plugin3({
363
- key: new PluginKey3("pastedMarkdown"),
364
- props: {
365
- // Reached only for a text paste outside code; `plain` is the Shift paste.
366
- clipboardTextParser: (text, $context, plain, view) => {
367
- if (plain) return void 0;
368
- try {
369
- const blocks = options.read(text.replace(/\r\n?/g, "\n"))?.content ?? [];
370
- if (blocks.every((block) => block.type === "paragraph")) return void 0;
371
- if (inTableCell($context) && hasTable(blocks)) return void 0;
372
- return Slice.maxOpen(view.state.schema.nodeFromJSON({ type: "doc", content: blocks }).content);
373
- } catch {
374
- return void 0;
375
- }
376
- }
377
- }
378
- })
379
- ];
380
- }
381
- });
382
-
383
- // src/CodeBlockColours.ts
384
- import { CodeBlockLowlight } from "@tiptap/extension-code-block-lowlight";
385
-
386
- // src/codeColours.ts
387
- import { createElement } from "react";
388
- import { common, createLowlight } from "lowlight";
389
- var instance;
390
- function lowlight() {
391
- return instance ??= createLowlight(common);
392
- }
303
+ import { EditorContent } from "@tiptap/react";
304
+ import { IconArrowUp } from "@tabler/icons-react";
305
+ import { IconButton } from "@estiva-app/ui";
306
+ import { Toolbar as Toolbar2 } from "@estiva-app/ui";
307
+ import { cn } from "@estiva-app/ui";
308
+ import { richTextClassName } from "@estiva-app/ui";
393
309
 
394
- // src/CodeBlockColours.ts
395
- var namedOnly = {
396
- highlight: (language, value) => lowlight().highlight(language, value),
397
- highlightAuto: (value) => ({ type: "root", children: [{ type: "text", value }], data: { language: void 0, relevance: 0 } }),
398
- listLanguages: () => lowlight().listLanguages(),
399
- registered: (language) => lowlight().registered(language)
400
- };
401
- var CodeBlockColours = CodeBlockLowlight.configure({ lowlight: namedOnly });
310
+ // src/looks.ts
311
+ var FLOATING_SURFACE_CLASSES = "rounded-lg border border-border-default bg-bg-elevated shadow-lg";
312
+ var WRITING_BOX_CLASSES = "relative bg-bg-inset border border-border-default rounded-lg p-3 flex flex-col gap-4 signal:transition-shadow signal:focus-within:border-border-focus signal:focus-within:shadow-focus-ring";
402
313
 
403
314
  // src/suggestionPopup.tsx
404
315
  import { forwardRef, useRef as useRef2, useImperativeHandle } from "react";
@@ -512,6 +423,486 @@ function suggestionPopup(options) {
512
423
  };
513
424
  }
514
425
 
426
+ // src/ComposeBox.tsx
427
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
428
+ var COMPOSE_EDITOR_CLASSES = richTextClassName("default", "outline-none w-full bg-transparent min-h-[20px] [&>p+p]:-mt-1");
429
+ var ComposeKeys = Extension2.create({
430
+ name: "composeKeys",
431
+ addStorage() {
432
+ return { send: null };
433
+ },
434
+ addKeyboardShortcuts() {
435
+ return {
436
+ Enter: () => {
437
+ if (isSuggestionActive()) return false;
438
+ this.storage.send?.();
439
+ return true;
440
+ },
441
+ "Shift-Enter": ({ editor }) => {
442
+ const { $from } = editor.state.selection;
443
+ for (let d = $from.depth; d > 0; d--) {
444
+ const node = $from.node(d);
445
+ if (node.type.name === "listItem") {
446
+ return node.textContent.length === 0 ? editor.commands.liftListItem("listItem") : editor.commands.splitListItem("listItem");
447
+ }
448
+ if (node.type.name === "blockquote") {
449
+ if ($from.parent.textContent.length === 0) return editor.commands.lift("paragraph");
450
+ break;
451
+ }
452
+ }
453
+ return editor.commands.splitBlock();
454
+ }
455
+ };
456
+ }
457
+ });
458
+ function isEmptyDoc(editor) {
459
+ const doc = editor.state.doc;
460
+ if (doc.textContent.length > 0) return false;
461
+ let empty = true;
462
+ doc.descendants((node) => {
463
+ if (node.isAtom && node.type.name !== "hardBreak") empty = false;
464
+ });
465
+ return empty;
466
+ }
467
+ function ComposeBox({ editor, onSend, placeholder, tools, attachments, ready = false, holding = false, marked = false, selection, className }) {
468
+ const [empty, setEmpty] = useState2(true);
469
+ const canSend = (!empty || ready) && !holding;
470
+ const send = useCallback2(() => {
471
+ if (!editor || holding || isEmptyDoc(editor) && !ready) return true;
472
+ if (onSend(editor) === false) return true;
473
+ editor.commands.clearContent(true);
474
+ editor.commands.focus();
475
+ return true;
476
+ }, [editor, holding, ready, onSend]);
477
+ useEffect2(() => {
478
+ if (!editor) return;
479
+ const storage = editor.storage.composeKeys;
480
+ if (!storage) return;
481
+ storage.send = send;
482
+ return () => {
483
+ storage.send = null;
484
+ };
485
+ }, [editor, send]);
486
+ useEffect2(() => {
487
+ if (!editor) return;
488
+ const read = () => setEmpty(isEmptyDoc(editor));
489
+ read();
490
+ editor.on("update", read);
491
+ return () => {
492
+ editor.off("update", read);
493
+ };
494
+ }, [editor]);
495
+ return /* @__PURE__ */ jsx3("div", { className: cn("relative", className), children: /* @__PURE__ */ jsxs2("div", { className: cn(WRITING_BOX_CLASSES, "focus-within:border-border-strong transition-colors"), children: [
496
+ /* @__PURE__ */ jsxs2("div", { "data-composer-editor": true, className: cn("relative min-h-[20px] transition-all", marked && "border-l-4 border-border-strong pl-2"), children: [
497
+ /* @__PURE__ */ jsx3(EditorContent, { editor }),
498
+ /* @__PURE__ */ jsx3(SelectionToolbar, { editor, ...selection }),
499
+ empty && /* @__PURE__ */ jsx3("div", { className: "pointer-events-none absolute inset-0 flex flex-wrap items-center gap-1 text-body-2 text-text-muted", children: placeholder })
500
+ ] }),
501
+ attachments && /* @__PURE__ */ jsx3("div", { className: "flex flex-wrap gap-2", children: attachments }),
502
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between", children: [
503
+ tools ? /* @__PURE__ */ jsx3(Toolbar2, { "aria-label": "Compose tools", surface: false, className: "flex items-center gap-1", children: tools }) : /* @__PURE__ */ jsx3("span", {}),
504
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2.5", children: [
505
+ /* @__PURE__ */ jsx3("span", { className: "hidden select-none font-mono text-menu font-normal tracking-wider text-text-muted signal:inline", children: "Enter to send \xB7 Shift+Enter new line" }),
506
+ /* @__PURE__ */ jsx3(
507
+ IconButton,
508
+ {
509
+ variant: "primary",
510
+ onMouseDown: (e) => {
511
+ e.preventDefault();
512
+ send();
513
+ },
514
+ onClick: (e) => {
515
+ if (e.detail === 0) send();
516
+ },
517
+ disabled: !canSend,
518
+ "aria-label": "Send",
519
+ tooltip: "Send",
520
+ tooltipShortcut: "Enter",
521
+ glow: canSend,
522
+ children: /* @__PURE__ */ jsx3(IconArrowUp, { size: 16, stroke: 1.5 })
523
+ }
524
+ )
525
+ ] })
526
+ ] })
527
+ ] }) });
528
+ }
529
+
530
+ // src/CommentHighlights.ts
531
+ import { Extension as Extension3 } from "@tiptap/core";
532
+ import { Plugin as Plugin2, PluginKey as PluginKey2 } from "@tiptap/pm/state";
533
+ import { Decoration as Decoration2, DecorationSet as DecorationSet2 } from "@tiptap/pm/view";
534
+ var commentHighlightsKey = new PluginKey2("commentHighlights");
535
+ var COMMENT_HIGHLIGHT_CLASSES = {
536
+ rest: "cursor-pointer rounded-sm bg-warning-muted",
537
+ active: "cursor-pointer rounded-sm bg-warning-muted underline decoration-warning-default decoration-2 underline-offset-4"
538
+ };
539
+ var QUOTE_WHOLE_MAX = 1e3;
540
+ var QUOTE_END_LENGTH = 150;
541
+ var QUOTE_CONTEXT_LENGTH = 32;
542
+ function placesIn(doc) {
543
+ const places = /* @__PURE__ */ new Map();
544
+ const walk = (parent, parentPos) => {
545
+ parent.forEach((node, offset, index) => {
546
+ const pos = parentPos + offset;
547
+ const id = node.attrs.blockId;
548
+ if (typeof id === "string" && id && !places.has(id)) places.set(id, { node, pos, parent: parentPos, index });
549
+ if (!node.isTextblock && !node.isLeaf) walk(node, pos + 1);
550
+ });
551
+ };
552
+ walk(doc, 0);
553
+ return places;
554
+ }
555
+ function textOf(block) {
556
+ let text = "";
557
+ const starts = [];
558
+ const ends = [];
559
+ block.node.descendants((node, offset) => {
560
+ const at = block.pos + 1 + offset;
561
+ if (node.isText && node.text) {
562
+ for (let i = 0; i < node.text.length; i++) starts.push(at + i), ends.push(at + i + 1);
563
+ text += node.text;
564
+ } else if (node.isInline && node.isLeaf) {
565
+ const wire = typeof node.attrs.uri === "string" ? node.attrs.uri : "";
566
+ for (let i = 0; i < wire.length; i++) starts.push(at), ends.push(at + node.nodeSize);
567
+ text += wire;
568
+ }
569
+ return true;
570
+ });
571
+ return { text, starts, ends };
572
+ }
573
+ function find(text, words, from, context) {
574
+ let first = -1;
575
+ for (let at = text.indexOf(words, from); at !== -1; at = text.indexOf(words, at + 1)) {
576
+ if (first === -1) first = at;
577
+ if (context(at)) return at;
578
+ }
579
+ return first;
580
+ }
581
+ function runIn(doc, places, ids) {
582
+ const present = ids.map((id) => places.get(id)).filter((p) => !!p);
583
+ if (present.length === 0) return null;
584
+ const byParent = /* @__PURE__ */ new Map();
585
+ for (const p of present) byParent.set(p.parent, [...byParent.get(p.parent) ?? [], p]);
586
+ const group = [...byParent.values()].reduce((best, one) => one.length > best.length ? one : best);
587
+ const low = Math.min(...group.map((p) => p.index));
588
+ const high = Math.max(...group.map((p) => p.index));
589
+ const contentStart = group[0].parent;
590
+ const parent = contentStart === 0 ? doc : doc.nodeAt(contentStart - 1);
591
+ if (!parent) return group;
592
+ const run = [];
593
+ parent.forEach((node, offset, index) => {
594
+ if (index >= low && index <= high) run.push({ node, pos: contentStart + offset, parent: contentStart, index });
595
+ });
596
+ return run;
597
+ }
598
+ function placeOf(doc, anchor, places = placesIn(doc)) {
599
+ const run = runIn(doc, places, anchor.blocks);
600
+ if (!run) return { state: "detached" };
601
+ const from = run[0].pos;
602
+ const to = run[run.length - 1].pos + run[run.length - 1].node.nodeSize;
603
+ const { quote } = anchor;
604
+ if (!quote) return { state: "resolved", from, to, words: false };
605
+ const reworded = { state: "reworded", from, to };
606
+ const firstId = anchor.blocks[0];
607
+ const lastId = anchor.blocks[anchor.blocks.length - 1];
608
+ const first = run.findIndex((p) => p.node.attrs.blockId === firstId);
609
+ const last = run.findIndex((p) => p.node.attrs.blockId === lastId);
610
+ if (first === -1 || last === -1 || last < first) return reworded;
611
+ const a = textOf(run[first]);
612
+ const b = first === last ? a : textOf(run[last]);
613
+ const prefix = quote.prefix && quote.prefix.length <= QUOTE_CONTEXT_LENGTH ? quote.prefix : void 0;
614
+ const suffix = quote.suffix && quote.suffix.length <= QUOTE_CONTEXT_LENGTH ? quote.suffix : void 0;
615
+ const before = (text, i) => !prefix || text.slice(Math.max(0, i - prefix.length), i) === prefix;
616
+ const after = (text, i) => !suffix || text.slice(i, i + suffix.length) === suffix;
617
+ if (quote.end === void 0) {
618
+ const at = find(a.text, quote.start, 0, (i) => before(a.text, i) && after(a.text, i + quote.start.length));
619
+ if (at === -1 || quote.start === "") return reworded;
620
+ return { state: "resolved", from: a.starts[at], to: a.ends[at + quote.start.length - 1], words: true };
621
+ }
622
+ const startAt = find(a.text, quote.start, 0, (i) => before(a.text, i));
623
+ if (startAt === -1 || quote.start === "") return reworded;
624
+ const endFrom = first === last ? startAt + quote.start.length : 0;
625
+ const endAt = find(b.text, quote.end, endFrom, (i) => after(b.text, i + quote.end.length));
626
+ if (endAt === -1 || quote.end === "") return reworded;
627
+ return { state: "resolved", from: a.starts[startAt], to: b.ends[endAt + quote.end.length - 1], words: true };
628
+ }
629
+ var CommentHighlights = Extension3.create({
630
+ name: "commentHighlights",
631
+ addOptions() {
632
+ return { onSelect: null };
633
+ },
634
+ addProseMirrorPlugins() {
635
+ const options = this.options;
636
+ const editor = this.editor;
637
+ return [
638
+ new Plugin2({
639
+ key: commentHighlightsKey,
640
+ state: {
641
+ init: () => ({ anchors: [], active: null }),
642
+ apply(tr, previous) {
643
+ const meta = tr.getMeta(commentHighlightsKey);
644
+ return meta ?? previous;
645
+ }
646
+ },
647
+ props: {
648
+ decorations(state) {
649
+ const { anchors, active } = commentHighlightsKey.getState(state) ?? { anchors: [], active: null };
650
+ const places = placesIn(state.doc);
651
+ const drawn = anchors.flatMap((anchor) => {
652
+ const place2 = placeOf(state.doc, anchor, places);
653
+ if (place2.state !== "resolved") return [];
654
+ const attrs = { class: anchor.id === active ? COMMENT_HIGHLIGHT_CLASSES.active : COMMENT_HIGHLIGHT_CLASSES.rest, "data-comment-id": anchor.id };
655
+ if (place2.words) return [Decoration2.inline(place2.from, place2.to, attrs)];
656
+ const blocks = [];
657
+ state.doc.nodesBetween(place2.from, place2.to, (node, pos) => {
658
+ if (pos < place2.from || pos + node.nodeSize > place2.to) return true;
659
+ blocks.push(Decoration2.node(pos, pos + node.nodeSize, attrs));
660
+ return false;
661
+ });
662
+ return blocks;
663
+ });
664
+ return drawn.length ? DecorationSet2.create(state.doc, drawn) : null;
665
+ },
666
+ handleClick(view, pos) {
667
+ const { anchors } = commentHighlightsKey.getState(view.state) ?? { anchors: [] };
668
+ const places = placesIn(view.state.doc);
669
+ let hit = null;
670
+ for (const anchor of anchors) {
671
+ const place2 = placeOf(view.state.doc, anchor, places);
672
+ if (place2.state !== "resolved" || pos < place2.from || pos >= place2.to) continue;
673
+ const size = place2.to - place2.from;
674
+ if (!hit || size < hit.size) hit = { id: anchor.id, size };
675
+ }
676
+ if (hit) {
677
+ options.onSelect?.(hit.id);
678
+ editor.emit("commentSelect", { id: hit.id });
679
+ }
680
+ return false;
681
+ }
682
+ }
683
+ })
684
+ ];
685
+ }
686
+ });
687
+ function setCommentAnchors(editor, anchors, active = null) {
688
+ if (editor.isDestroyed) return;
689
+ editor.view.dispatch(editor.state.tr.setMeta(commentHighlightsKey, { anchors, active }));
690
+ }
691
+ function commentPlace(editor, anchor) {
692
+ return placeOf(editor.state.doc, anchor);
693
+ }
694
+ function commentElement(editor, anchor) {
695
+ const drawn = editor.view.dom.querySelector(`[data-comment-id="${CSS.escape(anchor.id)}"]`);
696
+ if (drawn) return drawn;
697
+ const place2 = placeOf(editor.state.doc, anchor);
698
+ if (place2.state === "detached") return null;
699
+ const dom = editor.view.nodeDOM(place2.from);
700
+ return dom instanceof HTMLElement ? dom : null;
701
+ }
702
+ function quoteText(quote) {
703
+ return quote.end ? `${quote.start} \u2026 ${quote.end}` : quote.start;
704
+ }
705
+ function headOf(text, length) {
706
+ if (text.length <= length) return text;
707
+ const cut = text.lastIndexOf(" ", length);
708
+ return text.slice(0, cut > length / 2 ? cut : length);
709
+ }
710
+ function tailOf(text, length) {
711
+ if (text.length <= length) return text;
712
+ const from = text.length - length;
713
+ const cut = text.indexOf(" ", from);
714
+ return text.slice(cut !== -1 && cut < from + length / 2 ? cut + 1 : from);
715
+ }
716
+ function occurrences(text, words) {
717
+ let count = 0;
718
+ for (let at = text.indexOf(words); words && at !== -1; at = text.indexOf(words, at + 1)) count++;
719
+ return count;
720
+ }
721
+ function offsetIn(block, pos) {
722
+ const at = block.starts.findIndex((start) => start >= pos);
723
+ return at === -1 ? block.starts.length : at;
724
+ }
725
+ function anchorOfSelection(editor) {
726
+ const { doc, selection } = editor.state;
727
+ if (selection.empty) return null;
728
+ const { $from, $to } = selection;
729
+ const places = placesIn(doc);
730
+ const around = (depth) => {
731
+ for (let d = depth; d > 0; d--) {
732
+ const id = $from.node(d).attrs.blockId;
733
+ if (typeof id === "string" && id && places.has(id)) return places.get(id);
734
+ }
735
+ return void 0;
736
+ };
737
+ let run;
738
+ if ($from.parent === $to.parent && $from.parent.isTextblock) {
739
+ const found = around($from.depth);
740
+ if (!found) return null;
741
+ run = [found];
742
+ } else {
743
+ const depth = $from.sharedDepth($to.pos);
744
+ const low = $from.index(depth);
745
+ const high = $to.pos >= $to.end(depth) ? $from.node(depth).childCount - 1 : $to.index(depth);
746
+ run = [];
747
+ for (let i = low; i <= high; i++) {
748
+ const id = $from.node(depth).child(i).attrs.blockId;
749
+ const place2 = typeof id === "string" ? places.get(id) : void 0;
750
+ if (!place2) {
751
+ const found = around(depth);
752
+ if (!found) return null;
753
+ run = [found];
754
+ break;
755
+ }
756
+ run.push(place2);
757
+ }
758
+ }
759
+ let firstText = textOf(run[0]);
760
+ let lastText = run.length === 1 ? firstText : textOf(run[run.length - 1]);
761
+ let start = offsetIn(firstText, selection.from);
762
+ let end = offsetIn(lastText, selection.to);
763
+ if (run.length > 1 && start >= firstText.text.length) run = run.slice(1), firstText = textOf(run[0]), start = 0;
764
+ if (run.length > 1 && end <= 0) run = run.slice(0, -1), lastText = textOf(run[run.length - 1]), end = lastText.text.length;
765
+ if (run.length === 1) lastText = firstText;
766
+ if (run.length === 1 && firstText.text && start >= end) return null;
767
+ const blocks = run.map((p) => p.node.attrs.blockId);
768
+ if (start === 0 && end >= lastText.text.length) return { blocks };
769
+ const single = run.length === 1;
770
+ const quote = { start: "" };
771
+ if (single && end - start <= QUOTE_WHOLE_MAX) {
772
+ quote.start = firstText.text.slice(start, end);
773
+ } else {
774
+ const startWords = single ? firstText.text.slice(start, end) : firstText.text.slice(start);
775
+ const endWords = single ? startWords : lastText.text.slice(0, end);
776
+ quote.start = headOf(startWords, QUOTE_END_LENGTH);
777
+ quote.end = tailOf(endWords, QUOTE_END_LENGTH);
778
+ }
779
+ if (!quote.start || quote.end === "") return { blocks };
780
+ const prefix = firstText.text.slice(Math.max(0, start - QUOTE_CONTEXT_LENGTH), start);
781
+ const suffix = lastText.text.slice(end, end + QUOTE_CONTEXT_LENGTH);
782
+ if (prefix && occurrences(firstText.text, quote.start) > 1) quote.prefix = prefix;
783
+ if (suffix && occurrences(lastText.text, quote.end ?? quote.start) > 1) quote.suffix = suffix;
784
+ return { blocks, quote };
785
+ }
786
+
787
+ // src/PastedImages.ts
788
+ import { Extension as Extension4 } from "@tiptap/core";
789
+ import { Plugin as Plugin3, PluginKey as PluginKey3 } from "@tiptap/pm/state";
790
+ var IMAGE_EXTENSIONS = {
791
+ "image/png": "png",
792
+ "image/jpeg": "jpg",
793
+ "image/gif": "gif",
794
+ "image/webp": "webp",
795
+ "image/heic": "heic",
796
+ "image/heif": "heif",
797
+ "image/svg+xml": "svg"
798
+ };
799
+ var GENERIC_STEMS = /* @__PURE__ */ new Set(["image", "blob", "unknown", "untitled", "screenshot"]);
800
+ function extensionFor(contentType) {
801
+ const type = contentType.toLowerCase();
802
+ return IMAGE_EXTENSIONS[type] ?? type.split("/")[1]?.split("+")[0] ?? "png";
803
+ }
804
+ function pastedImageName(contentType, at = /* @__PURE__ */ new Date(), index = 0) {
805
+ const pad = (n) => String(n).padStart(2, "0");
806
+ const stamp = `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())} ${pad(at.getHours())}-${pad(at.getMinutes())}-${pad(at.getSeconds())}`;
807
+ const nth = index > 0 ? ` (${index + 1})` : "";
808
+ return `Screenshot ${stamp}${nth}.${extensionFor(contentType)}`;
809
+ }
810
+ function hasUsableName(name) {
811
+ const dot = name.lastIndexOf(".");
812
+ if (dot <= 0 || dot === name.length - 1) return false;
813
+ return !GENERIC_STEMS.has(name.slice(0, dot).toLowerCase());
814
+ }
815
+ function pastedImages(source, at = /* @__PURE__ */ new Date()) {
816
+ if (!source) return [];
817
+ if (source.getData("text/plain").trim() !== "") return [];
818
+ const images = Array.from(source.files ?? []).filter((f) => f.type.toLowerCase().startsWith("image/"));
819
+ let generated = 0;
820
+ return images.map(
821
+ (file) => hasUsableName(file.name) ? file : new File([file], pastedImageName(file.type, at, generated++), { type: file.type, lastModified: file.lastModified })
822
+ );
823
+ }
824
+ var PastedImages = Extension4.create({
825
+ name: "pastedImages",
826
+ addOptions() {
827
+ return { onImages: () => false };
828
+ },
829
+ addProseMirrorPlugins() {
830
+ const options = this.options;
831
+ return [
832
+ new Plugin3({
833
+ key: new PluginKey3("pastedImages"),
834
+ props: {
835
+ handlePaste: (_view, event) => {
836
+ const files = pastedImages(event.clipboardData);
837
+ return files.length > 0 && options.onImages(files);
838
+ }
839
+ }
840
+ })
841
+ ];
842
+ }
843
+ });
844
+
845
+ // src/PastedMarkdown.ts
846
+ import { Extension as Extension5 } from "@tiptap/core";
847
+ import { Slice } from "@tiptap/pm/model";
848
+ import { Plugin as Plugin4, PluginKey as PluginKey4 } from "@tiptap/pm/state";
849
+ function inTableCell($context) {
850
+ for (let depth = $context.depth; depth > 0; depth--) {
851
+ const role = $context.node(depth).type.spec.tableRole;
852
+ if (role === "cell" || role === "header_cell") return true;
853
+ }
854
+ return false;
855
+ }
856
+ var hasTable = (blocks) => blocks.some((block) => block.type === "table" || hasTable(block.content ?? []));
857
+ var PastedMarkdown = Extension5.create({
858
+ name: "pastedMarkdown",
859
+ addOptions() {
860
+ return { read: () => void 0 };
861
+ },
862
+ addProseMirrorPlugins() {
863
+ const options = this.options;
864
+ return [
865
+ new Plugin4({
866
+ key: new PluginKey4("pastedMarkdown"),
867
+ props: {
868
+ // Reached only for a text paste outside code; `plain` is the Shift paste.
869
+ clipboardTextParser: (text, $context, plain, view) => {
870
+ if (plain) return void 0;
871
+ try {
872
+ const blocks = options.read(text.replace(/\r\n?/g, "\n"))?.content ?? [];
873
+ if (blocks.every((block) => block.type === "paragraph")) return void 0;
874
+ if (inTableCell($context) && hasTable(blocks)) return void 0;
875
+ return Slice.maxOpen(view.state.schema.nodeFromJSON({ type: "doc", content: blocks }).content);
876
+ } catch {
877
+ return void 0;
878
+ }
879
+ }
880
+ }
881
+ })
882
+ ];
883
+ }
884
+ });
885
+
886
+ // src/CodeBlockColours.ts
887
+ import { CodeBlockLowlight } from "@tiptap/extension-code-block-lowlight";
888
+
889
+ // src/codeColours.ts
890
+ import { createElement } from "react";
891
+ import { common, createLowlight } from "lowlight";
892
+ var instance;
893
+ function lowlight() {
894
+ return instance ??= createLowlight(common);
895
+ }
896
+
897
+ // src/CodeBlockColours.ts
898
+ var namedOnly = {
899
+ highlight: (language, value) => lowlight().highlight(language, value),
900
+ highlightAuto: (value) => ({ type: "root", children: [{ type: "text", value }], data: { language: void 0, relevance: 0 } }),
901
+ listLanguages: () => lowlight().listLanguages(),
902
+ registered: (language) => lowlight().registered(language)
903
+ };
904
+ var CodeBlockColours = CodeBlockLowlight.configure({ lowlight: namedOnly });
905
+
515
906
  // src/EditorBlockHandle.tsx
516
907
  import { useMemo } from "react";
517
908
  import { IconCopy, IconTrash } from "@tabler/icons-react";
@@ -520,15 +911,16 @@ import { Selection } from "@tiptap/pm/state";
520
911
  import { MenuItem, MenuSub } from "@estiva-app/ui";
521
912
 
522
913
  // src/ComposerTriggers.tsx
523
- import { Extension as Extension4 } from "@tiptap/core";
524
- import { PluginKey as PluginKey4 } from "@tiptap/pm/state";
914
+ import { Extension as Extension6 } from "@tiptap/core";
915
+ import { PluginKey as PluginKey5 } from "@tiptap/pm/state";
525
916
  import Mention from "@tiptap/extension-mention";
526
917
  import Suggestion from "@tiptap/suggestion";
527
918
  import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
528
919
  import { Avatar } from "@estiva-app/ui";
529
920
  import { EnterHint } from "@estiva-app/ui";
530
921
  import { inlineChipClassName } from "@estiva-app/ui";
531
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
922
+ import { WithTooltip } from "@estiva-app/ui";
923
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
532
924
  var PEOPLE_LIMIT = 6;
533
925
  function filterPeople(people, query) {
534
926
  const q = query.toLowerCase();
@@ -546,8 +938,8 @@ function peopleMenu(urgent) {
546
938
  row: (person) => ({
547
939
  label: person.name,
548
940
  description: person.description,
549
- leading: person.avatar ?? /* @__PURE__ */ jsx3(Avatar, { size: 32, alt: person.name }),
550
- hint: /* @__PURE__ */ jsx3(EnterHint, {}),
941
+ leading: person.avatar ?? /* @__PURE__ */ jsx4(Avatar, { size: 32, alt: person.name }),
942
+ hint: /* @__PURE__ */ jsx4(EnterHint, {}),
551
943
  size: "tall"
552
944
  })
553
945
  };
@@ -674,10 +1066,13 @@ var CaptionedReference = Mention.extend({
674
1066
  addNodeView() {
675
1067
  const { icon, iconFor } = this.options;
676
1068
  return ReactNodeViewRenderer(
677
- ({ node }) => /* @__PURE__ */ jsxs2(NodeViewWrapper, { as: "span", className: inlineChipClassName("neutral", "max-w-[24ch] cursor-default"), children: [
678
- /* @__PURE__ */ jsx3("span", { className: "flex items-center justify-center w-4 h-4 shrink-0 text-text-secondary", children: iconFor?.(node.attrs.uri ?? null) ?? icon }),
679
- /* @__PURE__ */ jsx3("span", { className: "truncate", children: captionOf(node.attrs.label, node.attrs.snippet) })
680
- ] }),
1069
+ ({ node }) => (
1070
+ // The caption is cut at 24ch, so the whole of it is on hover, in the package's tooltip (UIG-14) — as Peek's sent chip has it.
1071
+ /* @__PURE__ */ jsx4(NodeViewWrapper, { as: "span", children: /* @__PURE__ */ jsx4(WithTooltip, { inline: true, label: captionOf(node.attrs.label, node.attrs.snippet), children: /* @__PURE__ */ jsxs3("span", { className: inlineChipClassName("neutral", "max-w-[24ch] cursor-default"), children: [
1072
+ /* @__PURE__ */ jsx4("span", { className: "flex items-center justify-center w-4 h-4 shrink-0 text-text-secondary", children: iconFor?.(node.attrs.uri ?? null) ?? icon }),
1073
+ /* @__PURE__ */ jsx4("span", { className: "truncate", children: captionOf(node.attrs.label, node.attrs.snippet) })
1074
+ ] }) }) })
1075
+ ),
681
1076
  { as: "span" }
682
1077
  );
683
1078
  }
@@ -698,11 +1093,11 @@ function referenceMenu({ ariaLabel, sectionLabel, icon, iconFor }) {
698
1093
  return groups;
699
1094
  },
700
1095
  itemKey: (item) => `reference-${item.id}`,
701
- row: (item) => ({ leading: item.icon ?? iconFor?.(item.uri) ?? icon, label: captionOf(item.label, item.snippet), description: item.description, hint: /* @__PURE__ */ jsx3(EnterHint, {}) })
1096
+ row: (item) => ({ leading: item.icon ?? iconFor?.(item.uri) ?? icon, label: captionOf(item.label, item.snippet), description: item.description, hint: /* @__PURE__ */ jsx4(EnterHint, {}) })
702
1097
  };
703
1098
  }
704
1099
  var listed = (options, query) => options.sections ? options.sections(query).flatMap((section) => section.items.map((item) => ({ ...item, section: section.label }))) : filterReferences(options.items(), query);
705
- var ReferenceTrigger = Extension4.create({
1100
+ var ReferenceTrigger = Extension6.create({
706
1101
  name: "referenceTrigger",
707
1102
  addOptions() {
708
1103
  return { items: () => [], nodeName: "captionedReference", ariaLabel: "References", sectionLabel: "References", icon: null };
@@ -713,7 +1108,7 @@ var ReferenceTrigger = Extension4.create({
713
1108
  Suggestion({
714
1109
  editor: this.editor,
715
1110
  char: "[",
716
- pluginKey: new PluginKey4("referenceTrigger"),
1111
+ pluginKey: new PluginKey5("referenceTrigger"),
717
1112
  ...listening("]"),
718
1113
  // As a mention's: only where the chip may go.
719
1114
  allow: ({ state, range }) => {
@@ -818,7 +1213,7 @@ function filterSlashSections(sections, query) {
818
1213
  const q = query.toLowerCase();
819
1214
  return sections.map((section) => ({ ...section, commands: q ? section.commands.filter((command) => matches(command, q)) : section.commands }));
820
1215
  }
821
- var SlashCommands = Extension4.create({
1216
+ var SlashCommands = Extension6.create({
822
1217
  name: "slashCommands",
823
1218
  addOptions() {
824
1219
  return { sections: [formatSection()] };
@@ -830,7 +1225,7 @@ var SlashCommands = Extension4.create({
830
1225
  editor: this.editor,
831
1226
  char: "/",
832
1227
  startOfLine: false,
833
- pluginKey: new PluginKey4("slashCommands"),
1228
+ pluginKey: new PluginKey5("slashCommands"),
834
1229
  items: ({ query, editor }) => filterSlashSections(sections, query).flatMap(
835
1230
  (section, at) => section.commands.filter((command) => offers(editor, command)).map((command) => ({ ...command, section: at }))
836
1231
  ),
@@ -852,7 +1247,7 @@ var SlashCommands = Extension4.create({
852
1247
  });
853
1248
 
854
1249
  // src/EditorBlockHandle.tsx
855
- import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1250
+ import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
856
1251
  function editorBlocks(view) {
857
1252
  const out = [];
858
1253
  view.state.doc.forEach((node, pos) => {
@@ -919,8 +1314,8 @@ function EditorBlockHandle({ editor, turnInto = turnIntoRows, actions, children,
919
1314
  const node = pos === void 0 ? null : editor.state.doc.nodeAt(pos);
920
1315
  if (pos === void 0 || !node) return null;
921
1316
  const turnRows = typeof turnInto === "function" ? turnInto(node, editor) : node.isTextblock ? turnInto : [];
922
- return /* @__PURE__ */ jsxs3(Fragment, { children: [
923
- turnRows.length > 0 && /* @__PURE__ */ jsx4(MenuSub, { label: "Turn into", children: turnRows.map((row) => /* @__PURE__ */ jsx4(
1317
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
1318
+ turnRows.length > 0 && /* @__PURE__ */ jsx5(MenuSub, { label: "Turn into", children: turnRows.map((row) => /* @__PURE__ */ jsx5(
924
1319
  MenuItem,
925
1320
  {
926
1321
  label: row.label,
@@ -932,8 +1327,8 @@ function EditorBlockHandle({ editor, turnInto = turnIntoRows, actions, children,
932
1327
  },
933
1328
  row.label
934
1329
  )) }),
935
- /* @__PURE__ */ jsx4(MenuItem, { label: "Duplicate", leading: /* @__PURE__ */ jsx4(IconCopy, { size: 16, stroke: 1.5, className: "text-text-secondary" }), onClick: () => duplicateBlock(editor, pos) }),
936
- /* @__PURE__ */ jsx4(MenuItem, { label: "Delete", destructive: true, leading: /* @__PURE__ */ jsx4(IconTrash, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: () => deleteBlock(editor, pos) })
1330
+ /* @__PURE__ */ jsx5(MenuItem, { label: "Duplicate", leading: /* @__PURE__ */ jsx5(IconCopy, { size: 16, stroke: 1.5, className: "text-text-secondary" }), onClick: () => duplicateBlock(editor, pos) }),
1331
+ /* @__PURE__ */ jsx5(MenuItem, { label: "Delete", destructive: true, leading: /* @__PURE__ */ jsx5(IconTrash, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: () => deleteBlock(editor, pos) })
937
1332
  ] });
938
1333
  },
939
1334
  startDrag: (block, event) => {
@@ -955,7 +1350,7 @@ function EditorBlockHandle({ editor, turnInto = turnIntoRows, actions, children,
955
1350
  }
956
1351
  };
957
1352
  }, [editor, turnInto]);
958
- return /* @__PURE__ */ jsx4(BlockHandle, { editing, actions, className, children });
1353
+ return /* @__PURE__ */ jsx5(BlockHandle, { editing, actions, className, children });
959
1354
  }
960
1355
  var LISTS = ["bulletList", "orderedList"];
961
1356
  var isList = (node) => LISTS.includes(node.type.name);
@@ -1061,19 +1456,14 @@ function turnIntoRows(node, editor) {
1061
1456
  }
1062
1457
 
1063
1458
  // src/EditorTableControls.tsx
1064
- import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef3, useState as useState2 } from "react";
1459
+ import { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
1065
1460
  import { TextSelection } from "@tiptap/pm/state";
1066
1461
  import { addColumnAfter, addColumnBefore, addRowAfter, addRowBefore, deleteColumn, deleteRow, deleteTable, toggleHeader } from "@tiptap/pm/tables";
1067
1462
  import { IconColumnInsertLeft, IconColumnInsertRight, IconGripHorizontal, IconGripVertical, IconPlus, IconRowInsertBottom, IconRowInsertTop, IconTrash as IconTrash2 } from "@tabler/icons-react";
1068
- import { cn } from "@estiva-app/ui";
1069
- import { IconButton } from "@estiva-app/ui";
1070
-
1071
- // src/looks.ts
1072
- var FLOATING_SURFACE_CLASSES = "rounded-lg border border-border-default bg-bg-elevated shadow-lg";
1073
-
1074
- // src/EditorTableControls.tsx
1463
+ import { cn as cn2 } from "@estiva-app/ui";
1464
+ import { IconButton as IconButton2 } from "@estiva-app/ui";
1075
1465
  import { Menu, MenuItem as MenuItem2, MenuSeparator } from "@estiva-app/ui";
1076
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1466
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1077
1467
  function inCell(editor, cell, command) {
1078
1468
  const { view } = editor;
1079
1469
  if (!view.dom.contains(cell)) return false;
@@ -1119,13 +1509,13 @@ function place(frame, { table, row, cell }) {
1119
1509
  }
1120
1510
  var ICON = { size: 16, stroke: 1.5, className: "text-text-secondary" };
1121
1511
  var keepFocus = (e) => e.preventDefault();
1122
- var HANDLE_BOX = cn(FLOATING_SURFACE_CLASSES, "shadow-none");
1512
+ var HANDLE_BOX = cn2(FLOATING_SURFACE_CLASSES, "shadow-none");
1123
1513
  function EditorTableControls({ editor, children, className }) {
1124
1514
  const frame = useRef3(null);
1125
- const [hovered, setHovered] = useState2(null);
1126
- const [menu, setMenu] = useState2(null);
1515
+ const [hovered, setHovered] = useState3(null);
1516
+ const [menu, setMenu] = useState3(null);
1127
1517
  const editable = !!editor && editor.isEditable;
1128
- const follow = useCallback2(
1518
+ const follow = useCallback3(
1129
1519
  (target) => {
1130
1520
  if (!editor || !frame.current || !(target instanceof Element)) return;
1131
1521
  if (target.closest("[data-table-control]")) return;
@@ -1141,7 +1531,7 @@ function EditorTableControls({ editor, children, className }) {
1141
1531
  },
1142
1532
  [editor]
1143
1533
  );
1144
- useEffect2(() => {
1534
+ useEffect3(() => {
1145
1535
  if (!editor) return;
1146
1536
  const changed = ({ transaction }) => {
1147
1537
  if (transaction.docChanged && !menu) setHovered(null);
@@ -1157,11 +1547,11 @@ function EditorTableControls({ editor, children, className }) {
1157
1547
  setMenu(null);
1158
1548
  setHovered(null);
1159
1549
  };
1160
- return /* @__PURE__ */ jsxs4(
1550
+ return /* @__PURE__ */ jsxs5(
1161
1551
  "div",
1162
1552
  {
1163
1553
  ref: frame,
1164
- className: cn("relative", className),
1554
+ className: cn2("relative", className),
1165
1555
  onMouseMove: (e) => {
1166
1556
  if (!menu) follow(e.target);
1167
1557
  },
@@ -1170,39 +1560,39 @@ function EditorTableControls({ editor, children, className }) {
1170
1560
  },
1171
1561
  children: [
1172
1562
  children,
1173
- shown && editor && /* @__PURE__ */ jsxs4(Fragment2, { children: [
1174
- /* @__PURE__ */ jsx5("div", { "data-table-control": true, className: cn(HANDLE_BOX, "absolute -translate-x-1/2 -translate-y-1/2"), style: { left: shown.tableBox.left, top: shown.rowBox.top + shown.rowBox.height / 2 }, children: /* @__PURE__ */ jsxs4(
1563
+ shown && editor && /* @__PURE__ */ jsxs5(Fragment2, { children: [
1564
+ /* @__PURE__ */ jsx6("div", { "data-table-control": true, className: cn2(HANDLE_BOX, "absolute -translate-x-1/2 -translate-y-1/2"), style: { left: shown.tableBox.left, top: shown.rowBox.top + shown.rowBox.height / 2 }, children: /* @__PURE__ */ jsxs5(
1175
1565
  Menu,
1176
1566
  {
1177
1567
  open: menu === "row",
1178
1568
  onOpenChange: (open) => setMenu(open ? "row" : null),
1179
- trigger: /* @__PURE__ */ jsx5(IconButton, { "aria-label": "Row menu", tooltip: "Row", className: "h-6 w-4 p-0", children: /* @__PURE__ */ jsx5(IconGripVertical, { size: 16, stroke: 1.5 }) }),
1569
+ trigger: /* @__PURE__ */ jsx6(IconButton2, { "aria-label": "Row menu", tooltip: "Row", className: "h-6 w-4 p-0", children: /* @__PURE__ */ jsx6(IconGripVertical, { size: 16, stroke: 1.5 }) }),
1180
1570
  children: [
1181
- !isHeaderRow(shown.row) && /* @__PURE__ */ jsx5(MenuItem2, { label: "Insert above", leading: /* @__PURE__ */ jsx5(IconRowInsertTop, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addRowBefore)) }),
1182
- /* @__PURE__ */ jsx5(MenuItem2, { label: "Insert below", leading: /* @__PURE__ */ jsx5(IconRowInsertBottom, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addRowAfter)) }),
1183
- /* @__PURE__ */ jsx5(MenuSeparator, {}),
1184
- /* @__PURE__ */ jsx5(MenuItem2, { label: "Delete", destructive: true, leading: /* @__PURE__ */ jsx5(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => deleteTableRow(editor, shown.cell)) }),
1185
- /* @__PURE__ */ jsx5(MenuItem2, { label: "Delete table", destructive: true, leading: /* @__PURE__ */ jsx5(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => inCell(editor, shown.cell, deleteTable)) })
1571
+ !isHeaderRow(shown.row) && /* @__PURE__ */ jsx6(MenuItem2, { label: "Insert above", leading: /* @__PURE__ */ jsx6(IconRowInsertTop, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addRowBefore)) }),
1572
+ /* @__PURE__ */ jsx6(MenuItem2, { label: "Insert below", leading: /* @__PURE__ */ jsx6(IconRowInsertBottom, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addRowAfter)) }),
1573
+ /* @__PURE__ */ jsx6(MenuSeparator, {}),
1574
+ /* @__PURE__ */ jsx6(MenuItem2, { label: "Delete", destructive: true, leading: /* @__PURE__ */ jsx6(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => deleteTableRow(editor, shown.cell)) }),
1575
+ /* @__PURE__ */ jsx6(MenuItem2, { label: "Delete table", destructive: true, leading: /* @__PURE__ */ jsx6(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => inCell(editor, shown.cell, deleteTable)) })
1186
1576
  ]
1187
1577
  }
1188
1578
  ) }),
1189
- /* @__PURE__ */ jsx5("div", { "data-table-control": true, className: cn(HANDLE_BOX, "absolute -translate-x-1/2 -translate-y-1/2"), style: { left: shown.columnBox.left + shown.columnBox.width / 2, top: shown.tableBox.top }, children: /* @__PURE__ */ jsxs4(
1579
+ /* @__PURE__ */ jsx6("div", { "data-table-control": true, className: cn2(HANDLE_BOX, "absolute -translate-x-1/2 -translate-y-1/2"), style: { left: shown.columnBox.left + shown.columnBox.width / 2, top: shown.tableBox.top }, children: /* @__PURE__ */ jsxs5(
1190
1580
  Menu,
1191
1581
  {
1192
1582
  open: menu === "column",
1193
1583
  onOpenChange: (open) => setMenu(open ? "column" : null),
1194
- trigger: /* @__PURE__ */ jsx5(IconButton, { "aria-label": "Column menu", tooltip: "Column", className: "h-4 w-6 p-0", children: /* @__PURE__ */ jsx5(IconGripHorizontal, { size: 16, stroke: 1.5 }) }),
1584
+ trigger: /* @__PURE__ */ jsx6(IconButton2, { "aria-label": "Column menu", tooltip: "Column", className: "h-4 w-6 p-0", children: /* @__PURE__ */ jsx6(IconGripHorizontal, { size: 16, stroke: 1.5 }) }),
1195
1585
  children: [
1196
- /* @__PURE__ */ jsx5(MenuItem2, { label: "Insert left", leading: /* @__PURE__ */ jsx5(IconColumnInsertLeft, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addColumnBefore)) }),
1197
- /* @__PURE__ */ jsx5(MenuItem2, { label: "Insert right", leading: /* @__PURE__ */ jsx5(IconColumnInsertRight, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addColumnAfter)) }),
1198
- /* @__PURE__ */ jsx5(MenuSeparator, {}),
1199
- /* @__PURE__ */ jsx5(MenuItem2, { label: "Delete", destructive: true, leading: /* @__PURE__ */ jsx5(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => deleteTableColumn(editor, shown.cell)) }),
1200
- /* @__PURE__ */ jsx5(MenuItem2, { label: "Delete table", destructive: true, leading: /* @__PURE__ */ jsx5(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => inCell(editor, shown.cell, deleteTable)) })
1586
+ /* @__PURE__ */ jsx6(MenuItem2, { label: "Insert left", leading: /* @__PURE__ */ jsx6(IconColumnInsertLeft, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addColumnBefore)) }),
1587
+ /* @__PURE__ */ jsx6(MenuItem2, { label: "Insert right", leading: /* @__PURE__ */ jsx6(IconColumnInsertRight, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addColumnAfter)) }),
1588
+ /* @__PURE__ */ jsx6(MenuSeparator, {}),
1589
+ /* @__PURE__ */ jsx6(MenuItem2, { label: "Delete", destructive: true, leading: /* @__PURE__ */ jsx6(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => deleteTableColumn(editor, shown.cell)) }),
1590
+ /* @__PURE__ */ jsx6(MenuItem2, { label: "Delete table", destructive: true, leading: /* @__PURE__ */ jsx6(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => inCell(editor, shown.cell, deleteTable)) })
1201
1591
  ]
1202
1592
  }
1203
1593
  ) }),
1204
- shown.row === shown.table.rows[shown.table.rows.length - 1] && /* @__PURE__ */ jsx5("div", { "data-table-control": true, className: cn(HANDLE_BOX, "absolute flex h-4"), style: { left: shown.tableBox.left, top: shown.tableBox.top + shown.tableBox.height, width: shown.tableBox.width }, children: /* @__PURE__ */ jsx5(IconButton, { "aria-label": "Add row", tooltip: "Add row", className: "h-full w-full p-0", onMouseDown: keepFocus, onClick: run(() => appendTableRow(editor, shown.table)), children: /* @__PURE__ */ jsx5(IconPlus, { size: 12, stroke: 1.5 }) }) }),
1205
- shown.cell === shown.row.cells[shown.row.cells.length - 1] && /* @__PURE__ */ jsx5("div", { "data-table-control": true, className: cn(HANDLE_BOX, "absolute flex w-4"), style: { left: shown.tableBox.left + shown.tableBox.width, top: shown.tableBox.top, height: shown.tableBox.height }, children: /* @__PURE__ */ jsx5(IconButton, { "aria-label": "Add column", tooltip: "Add column", className: "h-full w-full p-0", onMouseDown: keepFocus, onClick: run(() => appendTableColumn(editor, shown.table)), children: /* @__PURE__ */ jsx5(IconPlus, { size: 12, stroke: 1.5 }) }) })
1594
+ shown.row === shown.table.rows[shown.table.rows.length - 1] && /* @__PURE__ */ jsx6("div", { "data-table-control": true, className: cn2(HANDLE_BOX, "absolute flex h-4"), style: { left: shown.tableBox.left, top: shown.tableBox.top + shown.tableBox.height, width: shown.tableBox.width }, children: /* @__PURE__ */ jsx6(IconButton2, { "aria-label": "Add row", tooltip: "Add row", className: "h-full w-full p-0", onMouseDown: keepFocus, onClick: run(() => appendTableRow(editor, shown.table)), children: /* @__PURE__ */ jsx6(IconPlus, { size: 12, stroke: 1.5 }) }) }),
1595
+ shown.cell === shown.row.cells[shown.row.cells.length - 1] && /* @__PURE__ */ jsx6("div", { "data-table-control": true, className: cn2(HANDLE_BOX, "absolute flex w-4"), style: { left: shown.tableBox.left + shown.tableBox.width, top: shown.tableBox.top, height: shown.tableBox.height }, children: /* @__PURE__ */ jsx6(IconButton2, { "aria-label": "Add column", tooltip: "Add column", className: "h-full w-full p-0", onMouseDown: keepFocus, onClick: run(() => appendTableColumn(editor, shown.table)), children: /* @__PURE__ */ jsx6(IconPlus, { size: 12, stroke: 1.5 }) }) })
1206
1596
  ] })
1207
1597
  ]
1208
1598
  }
@@ -1210,27 +1600,27 @@ function EditorTableControls({ editor, children, className }) {
1210
1600
  }
1211
1601
 
1212
1602
  // src/BlockNodes.tsx
1213
- import { Extension as Extension8, InputRule, Node as Node2 } from "@tiptap/core";
1603
+ import { Extension as Extension10, InputRule, Node as Node2 } from "@tiptap/core";
1214
1604
  import { DOMSerializer } from "@tiptap/pm/model";
1215
- import { Plugin as Plugin7, PluginKey as PluginKey8 } from "@tiptap/pm/state";
1605
+ import { Plugin as Plugin8, PluginKey as PluginKey9 } from "@tiptap/pm/state";
1216
1606
  import { Mapping, ReplaceAroundStep } from "@tiptap/pm/transform";
1217
1607
  import { NodeViewWrapper as NodeViewWrapper2, ReactNodeViewRenderer as ReactNodeViewRenderer2, ReactRenderer as ReactRenderer2 } from "@tiptap/react";
1218
1608
  import { Checkbox } from "@estiva-app/ui";
1219
1609
  import { calloutLook } from "@estiva-app/ui";
1220
1610
 
1221
1611
  // src/ReferenceMenu.tsx
1222
- import { useCallback as useCallback3 } from "react";
1223
- import { Extension as Extension7 } from "@tiptap/core";
1612
+ import { useCallback as useCallback4 } from "react";
1613
+ import { Extension as Extension9 } from "@tiptap/core";
1224
1614
  import { useEditorState } from "@tiptap/react";
1225
- import { NodeSelection as NodeSelection2, Plugin as Plugin6, PluginKey as PluginKey7, TextSelection as TextSelection2 } from "@tiptap/pm/state";
1615
+ import { NodeSelection as NodeSelection2, Plugin as Plugin7, PluginKey as PluginKey8, TextSelection as TextSelection2 } from "@tiptap/pm/state";
1226
1616
  import { ReplaceStep } from "@tiptap/pm/transform";
1227
1617
  import { IconCheck } from "@tabler/icons-react";
1228
1618
 
1229
1619
  // src/LinkChips.ts
1230
- import { Extension as Extension5 } from "@tiptap/core";
1620
+ import { Extension as Extension7 } from "@tiptap/core";
1231
1621
  import { closeHistory } from "@tiptap/pm/history";
1232
- import { Plugin as Plugin4, PluginKey as PluginKey5 } from "@tiptap/pm/state";
1233
- var key = new PluginKey5("linkChips");
1622
+ import { Plugin as Plugin5, PluginKey as PluginKey6 } from "@tiptap/pm/state";
1623
+ var key = new PluginKey6("linkChips");
1234
1624
  var CHIPS_MADE = "linkChipsMade";
1235
1625
  var PASTES_KEPT = 8;
1236
1626
  var LINK_OR_URL = /(\[[^[\]\n]+\]\((?:https?:\/\/|mailto:)[^\s)]+\))|(https?:\/\/[^\s<>"'`]+)/g;
@@ -1305,7 +1695,7 @@ function refreshLinkChips(editor) {
1305
1695
  const tr = apply(editor.state, findLinkChips(editor.state.doc, editor.state.selection, chips.options.referenceOf, chips.pasted));
1306
1696
  if (tr) editor.view.dispatch(tr);
1307
1697
  }
1308
- var LinkChips = Extension5.create({
1698
+ var LinkChips = Extension7.create({
1309
1699
  name: "linkChips",
1310
1700
  addOptions() {
1311
1701
  return { referenceOf: null, ask: null, limit: 24 };
@@ -1314,7 +1704,7 @@ var LinkChips = Extension5.create({
1314
1704
  const options = this.options;
1315
1705
  const editor = this.editor;
1316
1706
  return [
1317
- new Plugin4({
1707
+ new Plugin5({
1318
1708
  key,
1319
1709
  // The options, where `refreshLinkChips` can read them from the state alone, and where the last pastes landed.
1320
1710
  state: {
@@ -1378,10 +1768,10 @@ import { MenuItem as MenuItem3, MenuSection, MenuSeparator as MenuSeparator2 } f
1378
1768
  import { Popover as Popover2 } from "@estiva-app/ui";
1379
1769
 
1380
1770
  // src/ReferenceCards.ts
1381
- import { Extension as Extension6 } from "@tiptap/core";
1382
- import { NodeSelection, Plugin as Plugin5, PluginKey as PluginKey6 } from "@tiptap/pm/state";
1383
- import { Decoration as Decoration2, DecorationSet as DecorationSet2 } from "@tiptap/pm/view";
1384
- import { useEffect as useEffect3, useState as useState3 } from "react";
1771
+ import { Extension as Extension8 } from "@tiptap/core";
1772
+ import { NodeSelection, Plugin as Plugin6, PluginKey as PluginKey7 } from "@tiptap/pm/state";
1773
+ import { Decoration as Decoration3, DecorationSet as DecorationSet3 } from "@tiptap/pm/view";
1774
+ import { useEffect as useEffect4, useState as useState4 } from "react";
1385
1775
  function layoutOf(raw) {
1386
1776
  if (typeof raw !== "string" || raw === "" || raw === "none") return void 0;
1387
1777
  return raw === "detailed" ? "detailed" : "compact";
@@ -1408,7 +1798,7 @@ function referenceCardPlacements(doc) {
1408
1798
  });
1409
1799
  return out;
1410
1800
  }
1411
- var key2 = new PluginKey6("referenceCards");
1801
+ var key2 = new PluginKey7("referenceCards");
1412
1802
  function elementFor(storage, slotKey) {
1413
1803
  let element = storage.elements.get(slotKey);
1414
1804
  if (!element) {
@@ -1422,17 +1812,17 @@ function elementFor(storage, slotKey) {
1422
1812
  function storageOf(editor) {
1423
1813
  return editor.storage.referenceCards;
1424
1814
  }
1425
- var ReferenceCards = Extension6.create({
1815
+ var ReferenceCards = Extension8.create({
1426
1816
  name: "referenceCards",
1427
1817
  addStorage() {
1428
1818
  return { elements: /* @__PURE__ */ new Map() };
1429
1819
  },
1430
1820
  addProseMirrorPlugins() {
1431
1821
  const storage = this.storage;
1432
- const decorate = (doc) => DecorationSet2.create(
1822
+ const decorate = (doc) => DecorationSet3.create(
1433
1823
  doc,
1434
1824
  referenceCardPlacements(doc).map(
1435
- (p) => Decoration2.widget(p.pos, () => elementFor(storage, p.key), {
1825
+ (p) => Decoration3.widget(p.pos, () => elementFor(storage, p.key), {
1436
1826
  key: p.key,
1437
1827
  side: 1,
1438
1828
  ignoreSelection: true,
@@ -1442,7 +1832,7 @@ var ReferenceCards = Extension6.create({
1442
1832
  )
1443
1833
  );
1444
1834
  return [
1445
- new Plugin5({
1835
+ new Plugin6({
1446
1836
  key: key2,
1447
1837
  state: {
1448
1838
  init: (_, state) => decorate(state.doc),
@@ -1454,8 +1844,8 @@ var ReferenceCards = Extension6.create({
1454
1844
  }
1455
1845
  });
1456
1846
  function useReferenceCards(editor) {
1457
- const [slots, setSlots] = useState3([]);
1458
- useEffect3(() => {
1847
+ const [slots, setSlots] = useState4([]);
1848
+ useEffect4(() => {
1459
1849
  if (!editor) return;
1460
1850
  const storage = storageOf(editor);
1461
1851
  if (!storage) return;
@@ -1520,8 +1910,8 @@ function setReferenceCardAt(editor, pos, layout) {
1520
1910
  }
1521
1911
 
1522
1912
  // src/ReferenceMenu.tsx
1523
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1524
- var key3 = new PluginKey7("referenceMenu");
1913
+ import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1914
+ var key3 = new PluginKey8("referenceMenu");
1525
1915
  var LAYOUTS = [
1526
1916
  { layout: "none", label: "None" },
1527
1917
  { layout: "compact", label: "Compact" },
@@ -1600,14 +1990,14 @@ function caretAfter(state, pos) {
1600
1990
  const node = state.doc.nodeAt(pos);
1601
1991
  return state.tr.setSelection(TextSelection2.create(state.doc, pos + (node?.nodeSize ?? 1)));
1602
1992
  }
1603
- var ReferenceMenu = Extension7.create({
1993
+ var ReferenceMenu = Extension9.create({
1604
1994
  name: "referenceMenu",
1605
1995
  // Before the editor's own keys, so Enter on a highlighted row is the row's, not a new line.
1606
1996
  priority: 1e3,
1607
1997
  addProseMirrorPlugins() {
1608
1998
  const editor = this.editor;
1609
1999
  return [
1610
- new Plugin6({
2000
+ new Plugin7({
1611
2001
  key: key3,
1612
2002
  state: {
1613
2003
  init: () => null,
@@ -1682,7 +2072,7 @@ function ReferenceMenuView({ editor }) {
1682
2072
  return { pos: open.pos, active: open.active, named: !!node.attrs.uri, layout };
1683
2073
  }
1684
2074
  });
1685
- const keepFocus2 = useCallback3((list) => {
2075
+ const keepFocus2 = useCallback4((list) => {
1686
2076
  const panel = list?.closest('[role="dialog"]');
1687
2077
  if (!panel) return;
1688
2078
  const keep = (event) => event.preventDefault();
@@ -1699,7 +2089,7 @@ function ReferenceMenuView({ editor }) {
1699
2089
  };
1700
2090
  return (
1701
2091
  // finalFocus={false}: focus never left the text.
1702
- /* @__PURE__ */ jsx6(
2092
+ /* @__PURE__ */ jsx7(
1703
2093
  Popover2,
1704
2094
  {
1705
2095
  anchor,
@@ -1711,8 +2101,8 @@ function ReferenceMenuView({ editor }) {
1711
2101
  align: "left",
1712
2102
  ariaLabel: "Link",
1713
2103
  finalFocus: false,
1714
- children: shown && /* @__PURE__ */ jsxs5("div", { ref: keepFocus2, role: "menu", "aria-label": "Link", className: "flex flex-col gap-0.5", children: [
1715
- opens && /* @__PURE__ */ jsx6(
2104
+ children: shown && /* @__PURE__ */ jsxs6("div", { ref: keepFocus2, role: "menu", "aria-label": "Link", className: "flex flex-col gap-0.5", children: [
2105
+ opens && /* @__PURE__ */ jsx7(
1716
2106
  MenuItem3,
1717
2107
  {
1718
2108
  role: "menuitem",
@@ -1725,9 +2115,9 @@ function ReferenceMenuView({ editor }) {
1725
2115
  }
1726
2116
  }
1727
2117
  ),
1728
- shown.named && /* @__PURE__ */ jsxs5(Fragment3, { children: [
1729
- opens && /* @__PURE__ */ jsx6(MenuSeparator2, {}),
1730
- /* @__PURE__ */ jsx6("div", { role: "group", "aria-label": "Card", children: /* @__PURE__ */ jsx6(MenuSection, { label: "Card", children: LAYOUTS.map(({ layout, label }, i) => /* @__PURE__ */ jsx6(
2118
+ shown.named && /* @__PURE__ */ jsxs6(Fragment3, { children: [
2119
+ opens && /* @__PURE__ */ jsx7(MenuSeparator2, {}),
2120
+ /* @__PURE__ */ jsx7("div", { role: "group", "aria-label": "Card", children: /* @__PURE__ */ jsx7(MenuSection, { label: "Card", children: LAYOUTS.map(({ layout, label }, i) => /* @__PURE__ */ jsx7(
1731
2121
  MenuItem3,
1732
2122
  {
1733
2123
  role: "menuitemradio",
@@ -1735,7 +2125,7 @@ function ReferenceMenuView({ editor }) {
1735
2125
  tabIndex: -1,
1736
2126
  label,
1737
2127
  selected: shown.active === i + (opens ? 1 : 0),
1738
- trailing: shown.layout === layout ? /* @__PURE__ */ jsx6(IconCheck, { size: 16, "aria-hidden": true }) : void 0,
2128
+ trailing: shown.layout === layout ? /* @__PURE__ */ jsx7(IconCheck, { size: 16, "aria-hidden": true }) : void 0,
1739
2129
  onMouseDown: (event) => {
1740
2130
  event.preventDefault();
1741
2131
  run(layout);
@@ -1751,7 +2141,7 @@ function ReferenceMenuView({ editor }) {
1751
2141
  }
1752
2142
 
1753
2143
  // src/BlockNodes.tsx
1754
- import { jsx as jsx7 } from "react/jsx-runtime";
2144
+ import { jsx as jsx8 } from "react/jsx-runtime";
1755
2145
  var BLOCK_TYPES = [
1756
2146
  "paragraph",
1757
2147
  "heading",
@@ -1909,7 +2299,7 @@ function bringsInBlocks(transactions) {
1909
2299
  })
1910
2300
  );
1911
2301
  }
1912
- var BlockId = Extension8.create({
2302
+ var BlockId = Extension10.create({
1913
2303
  name: "blockId",
1914
2304
  onCreate() {
1915
2305
  const { state, view } = this.editor;
@@ -1921,8 +2311,8 @@ var BlockId = Extension8.create({
1921
2311
  },
1922
2312
  addProseMirrorPlugins() {
1923
2313
  return [
1924
- new Plugin7({
1925
- key: new PluginKey8("blockIdSplit"),
2314
+ new Plugin8({
2315
+ key: new PluginKey9("blockIdSplit"),
1926
2316
  appendTransaction: (transactions, old, state) => {
1927
2317
  if (!bringsInBlocks(transactions)) return null;
1928
2318
  const mapping = new Mapping();
@@ -1996,7 +2386,7 @@ var ReferenceNode = Node2.create({
1996
2386
  return ReactNodeViewRenderer2(({ node, editor, getPos }) => {
1997
2387
  const uri = String(node.attrs.uri ?? "");
1998
2388
  const href = typeof node.attrs.href === "string" && node.attrs.href ? node.attrs.href : void 0;
1999
- return /* @__PURE__ */ jsx7(
2389
+ return /* @__PURE__ */ jsx8(
2000
2390
  NodeViewWrapper2,
2001
2391
  {
2002
2392
  as: "span",
@@ -2007,7 +2397,7 @@ var ReferenceNode = Node2.create({
2007
2397
  event.preventDefault();
2008
2398
  event.stopPropagation();
2009
2399
  },
2010
- children: uri ? /* @__PURE__ */ jsx7(View, { uri, ...href ? { href } : {} }) : /* @__PURE__ */ jsx7("span", { children: href })
2400
+ children: uri ? /* @__PURE__ */ jsx8(View, { uri, ...href ? { href } : {} }) : /* @__PURE__ */ jsx8("span", { children: href })
2011
2401
  }
2012
2402
  );
2013
2403
  });
@@ -2038,7 +2428,7 @@ var UnknownBlock = Node2.create({
2038
2428
  function UnknownBlockView({ node }) {
2039
2429
  const source = node.attrs.source;
2040
2430
  const text = String(node.attrs.text ?? "");
2041
- return /* @__PURE__ */ jsx7(
2431
+ return /* @__PURE__ */ jsx8(
2042
2432
  NodeViewWrapper2,
2043
2433
  {
2044
2434
  "data-block-id": source?.id,
@@ -2078,7 +2468,7 @@ var AttachmentNode = Node2.create({
2078
2468
  addNodeView() {
2079
2469
  const View = this.options.view;
2080
2470
  if (!View) return null;
2081
- return ReactNodeViewRenderer2(({ node }) => /* @__PURE__ */ jsx7(NodeViewWrapper2, { className: "my-2", children: /* @__PURE__ */ jsx7(View, { attrs: node.attrs }) }));
2471
+ return ReactNodeViewRenderer2(({ node }) => /* @__PURE__ */ jsx8(NodeViewWrapper2, { className: "my-2", children: /* @__PURE__ */ jsx8(View, { attrs: node.attrs }) }));
2082
2472
  }
2083
2473
  });
2084
2474
  var TICK = "checklistTick";
@@ -2147,7 +2537,7 @@ function listItemView(editor, node, view, getPos) {
2147
2537
  }
2148
2538
  };
2149
2539
  }
2150
- var Checklist = Extension8.create({
2540
+ var Checklist = Extension10.create({
2151
2541
  name: "checklist",
2152
2542
  // Before the list item's own Enter and Backspace.
2153
2543
  priority: 101,
@@ -2212,14 +2602,14 @@ var Checklist = Extension8.create({
2212
2602
  addProseMirrorPlugins() {
2213
2603
  const editor = this.editor;
2214
2604
  return [
2215
- new Plugin7({
2216
- key: new PluginKey8("checklist"),
2605
+ new Plugin8({
2606
+ key: new PluginKey9("checklist"),
2217
2607
  props: { nodeViews: { listItem: (node, view, getPos) => listItemView(editor, node, view, getPos) } }
2218
2608
  })
2219
2609
  ];
2220
2610
  }
2221
2611
  });
2222
- var Callout = Extension8.create({
2612
+ var Callout = Extension10.create({
2223
2613
  name: "callout",
2224
2614
  addGlobalAttributes() {
2225
2615
  return [
@@ -2240,10 +2630,14 @@ var Callout = Extension8.create({
2240
2630
  export {
2241
2631
  AttachmentNode,
2242
2632
  BlockId,
2633
+ COMPOSE_EDITOR_CLASSES,
2243
2634
  Callout,
2244
2635
  CaptionedReference,
2245
2636
  Checklist,
2246
2637
  CodeBlockColours,
2638
+ CommentHighlights,
2639
+ ComposeBox,
2640
+ ComposeKeys,
2247
2641
  EditorBlockHandle,
2248
2642
  EditorTableControls,
2249
2643
  FORMATS,
@@ -2261,10 +2655,13 @@ export {
2261
2655
  SlashCommands,
2262
2656
  UnknownBlock,
2263
2657
  UrgentPersonMention,
2658
+ anchorOfSelection,
2264
2659
  appendTableColumn,
2265
2660
  appendTableRow,
2266
2661
  applyFormat,
2267
2662
  blockDropCursor,
2663
+ commentElement,
2664
+ commentPlace,
2268
2665
  deleteBlock,
2269
2666
  deleteTableColumn,
2270
2667
  deleteTableRow,
@@ -2278,16 +2675,20 @@ export {
2278
2675
  isReferenceMenuOpen,
2279
2676
  isSuggestionActive,
2280
2677
  isSuggestionOpen,
2678
+ keepSelection,
2281
2679
  moveBlock,
2282
2680
  normalizeHref,
2283
2681
  pastedImageName,
2284
2682
  pastedImages,
2285
2683
  peopleMenu,
2684
+ quoteText,
2286
2685
  referenceAtSelection,
2287
2686
  referenceCardPlacements,
2288
2687
  referenceMenu,
2289
2688
  referenceMenuClick,
2290
2689
  refreshLinkChips,
2690
+ releaseSelection,
2691
+ setCommentAnchors,
2291
2692
  setReferenceCard,
2292
2693
  setReferenceCardAt,
2293
2694
  startBlockDrag,