@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.
- package/dist/CommentHighlights.d.ts +100 -0
- package/dist/CommentHighlights.d.ts.map +1 -0
- package/dist/ComposeBox.d.ts +55 -0
- package/dist/ComposeBox.d.ts.map +1 -0
- package/dist/ComposerTriggers.d.ts.map +1 -1
- package/dist/SelectionToolbar.d.ts +17 -1
- package/dist/SelectionToolbar.d.ts.map +1 -1
- package/dist/editor.d.ts +3 -1
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +618 -217
- package/dist/editor.js.map +4 -4
- package/dist/index.js.map +1 -1
- package/dist/looks.d.ts +6 -0
- package/dist/looks.d.ts.map +1 -1
- package/package.json +1 -5
- package/registry.json +309 -3
- package/src/CommentHighlights.mdx +61 -0
- package/src/CommentHighlights.stories.tsx +72 -0
- package/src/CommentHighlights.test.ts +100 -0
- package/src/CommentHighlights.ts +413 -0
- package/src/ComposeBox.mdx +58 -0
- package/src/ComposeBox.stories.tsx +81 -0
- package/src/ComposeBox.tsx +183 -0
- package/src/ComposerTriggers.tsx +9 -3
- package/src/SelectionToolbar.actions.test.tsx +44 -0
- package/src/SelectionToolbar.mdx +1 -0
- package/src/SelectionToolbar.tsx +36 -2
- package/src/editor.ts +15 -1
- package/src/looks.ts +8 -0
- package/src/registry/app.test.ts +7 -1
- package/src/registry/registry.test.ts +6 -6
- package/stories/Choosing.mdx +2 -0
- package/dist/widgets-2/fixtures.d.ts +0 -102
- package/dist/widgets-2/fixtures.d.ts.map +0 -1
- package/dist/widgets-2/places.d.ts +0 -99
- package/dist/widgets-2/places.d.ts.map +0 -1
- package/dist/widgets-2/proposed.d.ts +0 -130
- package/dist/widgets-2/proposed.d.ts.map +0 -1
- package/dist/widgets-2.d.ts +0 -12
- package/dist/widgets-2.d.ts.map +0 -1
- package/dist/widgets-2.js +0 -584
- package/dist/widgets-2.js.map +0 -7
- package/src/widgets-2/fixtures.ts +0 -161
- package/src/widgets-2/places.tsx +0 -309
- package/src/widgets-2/proposed.tsx +0 -596
- package/src/widgets-2.ts +0 -11
- package/stories/widgets-2/ReadMe.mdx +0 -60
- package/stories/widgets-2/Widgets.stories.tsx +0 -504
- 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/
|
|
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 {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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/
|
|
395
|
-
var
|
|
396
|
-
|
|
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
|
|
524
|
-
import { PluginKey as
|
|
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 {
|
|
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__ */
|
|
550
|
-
hint: /* @__PURE__ */
|
|
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 }) =>
|
|
678
|
-
|
|
679
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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__ */
|
|
923
|
-
turnRows.length > 0 && /* @__PURE__ */
|
|
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__ */
|
|
936
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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
|
|
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 =
|
|
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] =
|
|
1126
|
-
const [menu, setMenu] =
|
|
1515
|
+
const [hovered, setHovered] = useState3(null);
|
|
1516
|
+
const [menu, setMenu] = useState3(null);
|
|
1127
1517
|
const editable = !!editor && editor.isEditable;
|
|
1128
|
-
const follow =
|
|
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
|
-
|
|
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__ */
|
|
1550
|
+
return /* @__PURE__ */ jsxs5(
|
|
1161
1551
|
"div",
|
|
1162
1552
|
{
|
|
1163
1553
|
ref: frame,
|
|
1164
|
-
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__ */
|
|
1174
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1182
|
-
/* @__PURE__ */
|
|
1183
|
-
/* @__PURE__ */
|
|
1184
|
-
/* @__PURE__ */
|
|
1185
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1197
|
-
/* @__PURE__ */
|
|
1198
|
-
/* @__PURE__ */
|
|
1199
|
-
/* @__PURE__ */
|
|
1200
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1205
|
-
shown.cell === shown.row.cells[shown.row.cells.length - 1] && /* @__PURE__ */
|
|
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
|
|
1603
|
+
import { Extension as Extension10, InputRule, Node as Node2 } from "@tiptap/core";
|
|
1214
1604
|
import { DOMSerializer } from "@tiptap/pm/model";
|
|
1215
|
-
import { Plugin as
|
|
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
|
|
1223
|
-
import { Extension as
|
|
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
|
|
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
|
|
1620
|
+
import { Extension as Extension7 } from "@tiptap/core";
|
|
1231
1621
|
import { closeHistory } from "@tiptap/pm/history";
|
|
1232
|
-
import { Plugin as
|
|
1233
|
-
var key = new
|
|
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 =
|
|
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
|
|
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
|
|
1382
|
-
import { NodeSelection, Plugin as
|
|
1383
|
-
import { Decoration as
|
|
1384
|
-
import { useEffect as
|
|
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
|
|
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 =
|
|
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) =>
|
|
1822
|
+
const decorate = (doc) => DecorationSet3.create(
|
|
1433
1823
|
doc,
|
|
1434
1824
|
referenceCardPlacements(doc).map(
|
|
1435
|
-
(p) =>
|
|
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
|
|
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] =
|
|
1458
|
-
|
|
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
|
|
1524
|
-
var key3 = new
|
|
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 =
|
|
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
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
1715
|
-
opens && /* @__PURE__ */
|
|
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__ */
|
|
1729
|
-
opens && /* @__PURE__ */
|
|
1730
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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 =
|
|
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
|
|
1925
|
-
key: new
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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 =
|
|
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
|
|
2216
|
-
key: new
|
|
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 =
|
|
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,
|