@estiva-app/ui 0.72.0-widgets2.2 → 0.73.0-inline-text.1
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/InlineText.d.ts +56 -0
- package/dist/InlineText.d.ts.map +1 -0
- package/dist/SelectionToolbar.d.ts +17 -1
- package/dist/SelectionToolbar.d.ts.map +1 -1
- package/dist/editor.d.ts +4 -1
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +748 -240
- 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 +403 -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/InlineText.mdx +64 -0
- package/src/InlineText.stories.tsx +86 -0
- package/src/InlineText.test.tsx +187 -0
- package/src/InlineText.tsx +187 -0
- package/src/SelectionToolbar.actions.test.tsx +44 -0
- package/src/SelectionToolbar.mdx +1 -0
- package/src/SelectionToolbar.tsx +36 -2
- package/src/editor.ts +16 -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 +3 -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 -105
- 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 -585
- package/dist/widgets-2.js.map +0 -7
- package/src/widgets-2/fixtures.ts +0 -161
- package/src/widgets-2/places.tsx +0 -316
- 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,592 @@ 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 doc2 = editor.state.doc;
|
|
460
|
+
if (doc2.textContent.length > 0) return false;
|
|
461
|
+
let empty = true;
|
|
462
|
+
doc2.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/InlineText.tsx
|
|
531
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useImperativeHandle as useImperativeHandle2, useRef as useRef3, useState as useState3 } from "react";
|
|
532
|
+
import { Extension as Extension3, Node as Node2 } from "@tiptap/core";
|
|
533
|
+
import { history, redo, undo } from "@tiptap/pm/history";
|
|
534
|
+
import { EditorContent as EditorContent2, useEditor } from "@tiptap/react";
|
|
535
|
+
import { cn as cn2 } from "@estiva-app/ui";
|
|
536
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
537
|
+
var VARIANT = {
|
|
538
|
+
title: "text-h2 text-text-primary",
|
|
539
|
+
summary: "text-body-1 text-text-secondary"
|
|
540
|
+
};
|
|
541
|
+
var ROOM = "-mx-2 px-2 py-1";
|
|
542
|
+
var OneLine = Node2.create({ name: "doc", topNode: true, content: "paragraph" });
|
|
543
|
+
var Paragraph = Node2.create({
|
|
544
|
+
name: "paragraph",
|
|
545
|
+
content: "text*",
|
|
546
|
+
parseHTML: () => [{ tag: "p" }],
|
|
547
|
+
renderHTML: () => ["p", 0]
|
|
548
|
+
});
|
|
549
|
+
var Text = Node2.create({ name: "text" });
|
|
550
|
+
var Undo = Extension3.create({
|
|
551
|
+
name: "inlineTextUndo",
|
|
552
|
+
addProseMirrorPlugins: () => [history()],
|
|
553
|
+
addKeyboardShortcuts() {
|
|
554
|
+
const run = (command) => () => command(this.editor.state, this.editor.view.dispatch);
|
|
555
|
+
return { "Mod-z": run(undo), "Shift-Mod-z": run(redo), "Mod-y": run(redo) };
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
var doc = (text) => ({ type: "doc", content: [{ type: "paragraph", content: text ? [{ type: "text", text }] : [] }] });
|
|
559
|
+
var oneLine = (text) => text.replace(/\s+/g, " ").trim();
|
|
560
|
+
function InlineText({ value, placeholder, label, onCommit, onText, onEnter, variant = "title", clearable = false, readOnly = false, className, ref }) {
|
|
561
|
+
const saved = useRef3(value);
|
|
562
|
+
const [empty, setEmpty] = useState3(!value);
|
|
563
|
+
const latest = useRef3({ onEnter, onText, onCommit, clearable });
|
|
564
|
+
latest.current = { onEnter, onText, onCommit, clearable };
|
|
565
|
+
const save = useCallback3(async (text) => {
|
|
566
|
+
const next = oneLine(text);
|
|
567
|
+
if (next === saved.current) return;
|
|
568
|
+
if (!next && !latest.current.clearable) return;
|
|
569
|
+
if (await latest.current.onCommit(next)) saved.current = next;
|
|
570
|
+
}, []);
|
|
571
|
+
const editor = useEditor({
|
|
572
|
+
extensions: [OneLine, Paragraph, Text, Undo],
|
|
573
|
+
content: doc(value),
|
|
574
|
+
editable: !readOnly,
|
|
575
|
+
editorProps: {
|
|
576
|
+
attributes: {
|
|
577
|
+
"aria-label": label,
|
|
578
|
+
role: "textbox",
|
|
579
|
+
"aria-multiline": "false",
|
|
580
|
+
"aria-placeholder": placeholder,
|
|
581
|
+
...readOnly ? { "aria-readonly": "true" } : {},
|
|
582
|
+
class: "outline-none"
|
|
583
|
+
},
|
|
584
|
+
handleKeyDown: (view, event) => {
|
|
585
|
+
if (event.key === "Enter") {
|
|
586
|
+
event.preventDefault();
|
|
587
|
+
void save(view.state.doc.textContent);
|
|
588
|
+
latest.current.onEnter?.();
|
|
589
|
+
return true;
|
|
590
|
+
}
|
|
591
|
+
if (event.key === "Escape") {
|
|
592
|
+
view.dom.blur();
|
|
593
|
+
return true;
|
|
594
|
+
}
|
|
595
|
+
return false;
|
|
596
|
+
},
|
|
597
|
+
// A paste is its plain text on this one line, whatever it was copied from.
|
|
598
|
+
handlePaste: (view, event) => {
|
|
599
|
+
const text = event.clipboardData?.getData("text/plain");
|
|
600
|
+
if (text == null) return false;
|
|
601
|
+
view.dispatch(view.state.tr.insertText(text.replace(/\s+/g, " ")));
|
|
602
|
+
return true;
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
onFocus: ({ editor: e }) => latest.current.onText?.(e.getText()),
|
|
606
|
+
onUpdate: ({ editor: e }) => {
|
|
607
|
+
setEmpty(e.isEmpty);
|
|
608
|
+
latest.current.onText?.(e.getText());
|
|
609
|
+
},
|
|
610
|
+
onBlur: ({ editor: e }) => {
|
|
611
|
+
latest.current.onText?.(null);
|
|
612
|
+
if (e.isEmpty && saved.current && !latest.current.clearable) {
|
|
613
|
+
e.commands.setContent(doc(saved.current), { emitUpdate: false });
|
|
614
|
+
setEmpty(false);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
void save(e.getText());
|
|
618
|
+
}
|
|
619
|
+
}, [readOnly]);
|
|
620
|
+
useEffect3(() => {
|
|
621
|
+
if (!editor || editor.isDestroyed || value === saved.current || editor.isFocused) return;
|
|
622
|
+
if (oneLine(editor.getText()) !== saved.current) return;
|
|
623
|
+
editor.commands.setContent(doc(value), { emitUpdate: false });
|
|
624
|
+
saved.current = value;
|
|
625
|
+
setEmpty(!value);
|
|
626
|
+
}, [editor, value]);
|
|
627
|
+
useImperativeHandle2(ref, () => ({
|
|
628
|
+
focus: (at = "start") => editor?.commands.focus(at)
|
|
629
|
+
}), [editor]);
|
|
630
|
+
return /* @__PURE__ */ jsxs3("div", { className: cn2("relative", VARIANT[variant], className), children: [
|
|
631
|
+
/* @__PURE__ */ jsx4(EditorContent2, { editor, className: cn2(ROOM, !readOnly && "cursor-text") }),
|
|
632
|
+
empty && !readOnly && /* @__PURE__ */ jsx4("span", { "aria-hidden": true, className: "pointer-events-none absolute left-0 top-1 text-text-muted", children: placeholder })
|
|
633
|
+
] });
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// src/CommentHighlights.ts
|
|
637
|
+
import { Extension as Extension4 } from "@tiptap/core";
|
|
638
|
+
import { Plugin as Plugin2, PluginKey as PluginKey2 } from "@tiptap/pm/state";
|
|
639
|
+
import { Decoration as Decoration2, DecorationSet as DecorationSet2 } from "@tiptap/pm/view";
|
|
640
|
+
var commentHighlightsKey = new PluginKey2("commentHighlights");
|
|
641
|
+
var COMMENT_HIGHLIGHT_CLASSES = {
|
|
642
|
+
rest: "cursor-pointer rounded-sm bg-warning-muted",
|
|
643
|
+
active: "cursor-pointer rounded-sm bg-warning-muted underline decoration-warning-default decoration-2 underline-offset-4"
|
|
644
|
+
};
|
|
645
|
+
var QUOTE_WHOLE_MAX = 1e3;
|
|
646
|
+
var QUOTE_END_LENGTH = 150;
|
|
647
|
+
var QUOTE_CONTEXT_LENGTH = 32;
|
|
648
|
+
function placesIn(doc2) {
|
|
649
|
+
const places = /* @__PURE__ */ new Map();
|
|
650
|
+
const walk = (parent, parentPos) => {
|
|
651
|
+
parent.forEach((node, offset, index) => {
|
|
652
|
+
const pos = parentPos + offset;
|
|
653
|
+
const id = node.attrs.blockId;
|
|
654
|
+
if (typeof id === "string" && id && !places.has(id)) places.set(id, { node, pos, parent: parentPos, index });
|
|
655
|
+
if (!node.isTextblock && !node.isLeaf) walk(node, pos + 1);
|
|
656
|
+
});
|
|
657
|
+
};
|
|
658
|
+
walk(doc2, 0);
|
|
659
|
+
return places;
|
|
660
|
+
}
|
|
661
|
+
function textOf(block) {
|
|
662
|
+
let text = "";
|
|
663
|
+
const starts = [];
|
|
664
|
+
const ends = [];
|
|
665
|
+
block.node.descendants((node, offset) => {
|
|
666
|
+
const at = block.pos + 1 + offset;
|
|
667
|
+
if (node.isText && node.text) {
|
|
668
|
+
for (let i = 0; i < node.text.length; i++) starts.push(at + i), ends.push(at + i + 1);
|
|
669
|
+
text += node.text;
|
|
670
|
+
} else if (node.isInline && node.isLeaf) {
|
|
671
|
+
const wire = typeof node.attrs.uri === "string" ? node.attrs.uri : "";
|
|
672
|
+
for (let i = 0; i < wire.length; i++) starts.push(at), ends.push(at + node.nodeSize);
|
|
673
|
+
text += wire;
|
|
674
|
+
}
|
|
675
|
+
return true;
|
|
676
|
+
});
|
|
677
|
+
return { text, starts, ends };
|
|
678
|
+
}
|
|
679
|
+
function find(text, words, from, context) {
|
|
680
|
+
let first = -1;
|
|
681
|
+
for (let at = text.indexOf(words, from); at !== -1; at = text.indexOf(words, at + 1)) {
|
|
682
|
+
if (first === -1) first = at;
|
|
683
|
+
if (context(at)) return at;
|
|
684
|
+
}
|
|
685
|
+
return first;
|
|
686
|
+
}
|
|
687
|
+
function runIn(doc2, places, ids) {
|
|
688
|
+
const present = ids.map((id) => places.get(id)).filter((p) => !!p);
|
|
689
|
+
if (present.length === 0) return null;
|
|
690
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
691
|
+
for (const p of present) byParent.set(p.parent, [...byParent.get(p.parent) ?? [], p]);
|
|
692
|
+
const group = [...byParent.values()].reduce((best, one) => one.length > best.length ? one : best);
|
|
693
|
+
const low = Math.min(...group.map((p) => p.index));
|
|
694
|
+
const high = Math.max(...group.map((p) => p.index));
|
|
695
|
+
const contentStart = group[0].parent;
|
|
696
|
+
const parent = contentStart === 0 ? doc2 : doc2.nodeAt(contentStart - 1);
|
|
697
|
+
if (!parent) return group;
|
|
698
|
+
const run = [];
|
|
699
|
+
parent.forEach((node, offset, index) => {
|
|
700
|
+
if (index >= low && index <= high) run.push({ node, pos: contentStart + offset, parent: contentStart, index });
|
|
701
|
+
});
|
|
702
|
+
return run;
|
|
703
|
+
}
|
|
704
|
+
function placeOf(doc2, anchor, places = placesIn(doc2)) {
|
|
705
|
+
const run = runIn(doc2, places, anchor.blocks);
|
|
706
|
+
if (!run) return { state: "detached" };
|
|
707
|
+
const from = run[0].pos;
|
|
708
|
+
const to = run[run.length - 1].pos + run[run.length - 1].node.nodeSize;
|
|
709
|
+
const { quote } = anchor;
|
|
710
|
+
if (!quote) return { state: "resolved", from, to, words: false };
|
|
711
|
+
const reworded = { state: "reworded", from, to };
|
|
712
|
+
const firstId = anchor.blocks[0];
|
|
713
|
+
const lastId = anchor.blocks[anchor.blocks.length - 1];
|
|
714
|
+
const first = run.findIndex((p) => p.node.attrs.blockId === firstId);
|
|
715
|
+
const last = run.findIndex((p) => p.node.attrs.blockId === lastId);
|
|
716
|
+
if (first === -1 || last === -1 || last < first) return reworded;
|
|
717
|
+
const a = textOf(run[first]);
|
|
718
|
+
const b = first === last ? a : textOf(run[last]);
|
|
719
|
+
const prefix = quote.prefix && quote.prefix.length <= QUOTE_CONTEXT_LENGTH ? quote.prefix : void 0;
|
|
720
|
+
const suffix = quote.suffix && quote.suffix.length <= QUOTE_CONTEXT_LENGTH ? quote.suffix : void 0;
|
|
721
|
+
const before = (text, i) => !prefix || text.slice(Math.max(0, i - prefix.length), i) === prefix;
|
|
722
|
+
const after = (text, i) => !suffix || text.slice(i, i + suffix.length) === suffix;
|
|
723
|
+
if (quote.end === void 0) {
|
|
724
|
+
const at = find(a.text, quote.start, 0, (i) => before(a.text, i) && after(a.text, i + quote.start.length));
|
|
725
|
+
if (at === -1 || quote.start === "") return reworded;
|
|
726
|
+
return { state: "resolved", from: a.starts[at], to: a.ends[at + quote.start.length - 1], words: true };
|
|
727
|
+
}
|
|
728
|
+
const startAt = find(a.text, quote.start, 0, (i) => before(a.text, i));
|
|
729
|
+
if (startAt === -1 || quote.start === "") return reworded;
|
|
730
|
+
const endFrom = first === last ? startAt + quote.start.length : 0;
|
|
731
|
+
const endAt = find(b.text, quote.end, endFrom, (i) => after(b.text, i + quote.end.length));
|
|
732
|
+
if (endAt === -1 || quote.end === "") return reworded;
|
|
733
|
+
return { state: "resolved", from: a.starts[startAt], to: b.ends[endAt + quote.end.length - 1], words: true };
|
|
734
|
+
}
|
|
735
|
+
var CommentHighlights = Extension4.create({
|
|
736
|
+
name: "commentHighlights",
|
|
737
|
+
addOptions() {
|
|
738
|
+
return { onSelect: null };
|
|
739
|
+
},
|
|
740
|
+
addProseMirrorPlugins() {
|
|
741
|
+
const options = this.options;
|
|
742
|
+
const editor = this.editor;
|
|
743
|
+
return [
|
|
744
|
+
new Plugin2({
|
|
745
|
+
key: commentHighlightsKey,
|
|
746
|
+
state: {
|
|
747
|
+
init: () => ({ anchors: [], active: null }),
|
|
748
|
+
apply(tr, previous) {
|
|
749
|
+
const meta = tr.getMeta(commentHighlightsKey);
|
|
750
|
+
return meta ?? previous;
|
|
751
|
+
}
|
|
752
|
+
},
|
|
753
|
+
props: {
|
|
754
|
+
decorations(state) {
|
|
755
|
+
const { anchors, active } = commentHighlightsKey.getState(state) ?? { anchors: [], active: null };
|
|
756
|
+
const places = placesIn(state.doc);
|
|
757
|
+
const drawn = anchors.flatMap((anchor) => {
|
|
758
|
+
const place2 = placeOf(state.doc, anchor, places);
|
|
759
|
+
if (place2.state !== "resolved") return [];
|
|
760
|
+
const attrs = { class: anchor.id === active ? COMMENT_HIGHLIGHT_CLASSES.active : COMMENT_HIGHLIGHT_CLASSES.rest, "data-comment-id": anchor.id };
|
|
761
|
+
if (place2.words) return [Decoration2.inline(place2.from, place2.to, attrs)];
|
|
762
|
+
const blocks = [];
|
|
763
|
+
state.doc.nodesBetween(place2.from, place2.to, (node, pos) => {
|
|
764
|
+
if (pos < place2.from || pos + node.nodeSize > place2.to) return true;
|
|
765
|
+
blocks.push(Decoration2.node(pos, pos + node.nodeSize, attrs));
|
|
766
|
+
return false;
|
|
767
|
+
});
|
|
768
|
+
return blocks;
|
|
769
|
+
});
|
|
770
|
+
return drawn.length ? DecorationSet2.create(state.doc, drawn) : null;
|
|
771
|
+
},
|
|
772
|
+
handleClick(view, pos) {
|
|
773
|
+
const { anchors } = commentHighlightsKey.getState(view.state) ?? { anchors: [] };
|
|
774
|
+
const places = placesIn(view.state.doc);
|
|
775
|
+
let hit = null;
|
|
776
|
+
for (const anchor of anchors) {
|
|
777
|
+
const place2 = placeOf(view.state.doc, anchor, places);
|
|
778
|
+
if (place2.state !== "resolved" || pos < place2.from || pos >= place2.to) continue;
|
|
779
|
+
const size = place2.to - place2.from;
|
|
780
|
+
if (!hit || size < hit.size) hit = { id: anchor.id, size };
|
|
781
|
+
}
|
|
782
|
+
if (hit) {
|
|
783
|
+
options.onSelect?.(hit.id);
|
|
784
|
+
editor.emit("commentSelect", { id: hit.id });
|
|
785
|
+
}
|
|
786
|
+
return false;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
})
|
|
790
|
+
];
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
function setCommentAnchors(editor, anchors, active = null) {
|
|
794
|
+
if (editor.isDestroyed) return;
|
|
795
|
+
editor.view.dispatch(editor.state.tr.setMeta(commentHighlightsKey, { anchors, active }));
|
|
796
|
+
}
|
|
797
|
+
function commentPlace(editor, anchor) {
|
|
798
|
+
return placeOf(editor.state.doc, anchor);
|
|
799
|
+
}
|
|
800
|
+
function commentElement(editor, anchor) {
|
|
801
|
+
const drawn = editor.view.dom.querySelector(`[data-comment-id="${CSS.escape(anchor.id)}"]`);
|
|
802
|
+
if (drawn) return drawn;
|
|
803
|
+
const place2 = placeOf(editor.state.doc, anchor);
|
|
804
|
+
if (place2.state === "detached") return null;
|
|
805
|
+
const dom = editor.view.nodeDOM(place2.from);
|
|
806
|
+
return dom instanceof HTMLElement ? dom : null;
|
|
807
|
+
}
|
|
808
|
+
function quoteText(quote) {
|
|
809
|
+
return quote.end ? `${quote.start} \u2026 ${quote.end}` : quote.start;
|
|
810
|
+
}
|
|
811
|
+
function headOf(text, length) {
|
|
812
|
+
if (text.length <= length) return text;
|
|
813
|
+
const cut = text.lastIndexOf(" ", length);
|
|
814
|
+
return text.slice(0, cut > length / 2 ? cut : length);
|
|
815
|
+
}
|
|
816
|
+
function tailOf(text, length) {
|
|
817
|
+
if (text.length <= length) return text;
|
|
818
|
+
const from = text.length - length;
|
|
819
|
+
const cut = text.indexOf(" ", from);
|
|
820
|
+
return text.slice(cut !== -1 && cut < from + length / 2 ? cut + 1 : from);
|
|
821
|
+
}
|
|
822
|
+
function occurrences(text, words) {
|
|
823
|
+
let count = 0;
|
|
824
|
+
for (let at = text.indexOf(words); words && at !== -1; at = text.indexOf(words, at + 1)) count++;
|
|
825
|
+
return count;
|
|
826
|
+
}
|
|
827
|
+
function offsetIn(block, pos) {
|
|
828
|
+
const at = block.starts.findIndex((start) => start >= pos);
|
|
829
|
+
return at === -1 ? block.starts.length : at;
|
|
830
|
+
}
|
|
831
|
+
function anchorOfSelection(editor) {
|
|
832
|
+
const { doc: doc2, selection } = editor.state;
|
|
833
|
+
if (selection.empty) return null;
|
|
834
|
+
const { $from, $to } = selection;
|
|
835
|
+
const places = placesIn(doc2);
|
|
836
|
+
const around = (depth) => {
|
|
837
|
+
for (let d = depth; d > 0; d--) {
|
|
838
|
+
const id = $from.node(d).attrs.blockId;
|
|
839
|
+
if (typeof id === "string" && id && places.has(id)) return places.get(id);
|
|
840
|
+
}
|
|
841
|
+
return void 0;
|
|
842
|
+
};
|
|
843
|
+
let run;
|
|
844
|
+
if ($from.parent === $to.parent && $from.parent.isTextblock) {
|
|
845
|
+
const found = around($from.depth);
|
|
846
|
+
if (!found) return null;
|
|
847
|
+
run = [found];
|
|
848
|
+
} else {
|
|
849
|
+
const depth = $from.sharedDepth($to.pos);
|
|
850
|
+
const low = $from.index(depth);
|
|
851
|
+
const high = $to.pos >= $to.end(depth) ? $from.node(depth).childCount - 1 : $to.index(depth);
|
|
852
|
+
run = [];
|
|
853
|
+
for (let i = low; i <= high; i++) {
|
|
854
|
+
const id = $from.node(depth).child(i).attrs.blockId;
|
|
855
|
+
const place2 = typeof id === "string" ? places.get(id) : void 0;
|
|
856
|
+
if (!place2) {
|
|
857
|
+
const found = around(depth);
|
|
858
|
+
if (!found) return null;
|
|
859
|
+
run = [found];
|
|
860
|
+
break;
|
|
861
|
+
}
|
|
862
|
+
run.push(place2);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
let firstText = textOf(run[0]);
|
|
866
|
+
let lastText = run.length === 1 ? firstText : textOf(run[run.length - 1]);
|
|
867
|
+
let start = offsetIn(firstText, selection.from);
|
|
868
|
+
let end = offsetIn(lastText, selection.to);
|
|
869
|
+
if (run.length > 1 && start >= firstText.text.length) run = run.slice(1), firstText = textOf(run[0]), start = 0;
|
|
870
|
+
if (run.length > 1 && end <= 0) run = run.slice(0, -1), lastText = textOf(run[run.length - 1]), end = lastText.text.length;
|
|
871
|
+
if (run.length === 1) lastText = firstText;
|
|
872
|
+
if (run.length === 1 && firstText.text && start >= end) return null;
|
|
873
|
+
const blocks = run.map((p) => p.node.attrs.blockId);
|
|
874
|
+
if (start === 0 && end >= lastText.text.length) return { blocks };
|
|
875
|
+
const single = run.length === 1;
|
|
876
|
+
const quote = { start: "" };
|
|
877
|
+
if (single && end - start <= QUOTE_WHOLE_MAX) {
|
|
878
|
+
quote.start = firstText.text.slice(start, end);
|
|
879
|
+
} else {
|
|
880
|
+
const startWords = single ? firstText.text.slice(start, end) : firstText.text.slice(start);
|
|
881
|
+
const endWords = single ? startWords : lastText.text.slice(0, end);
|
|
882
|
+
quote.start = headOf(startWords, QUOTE_END_LENGTH);
|
|
883
|
+
quote.end = tailOf(endWords, QUOTE_END_LENGTH);
|
|
884
|
+
}
|
|
885
|
+
if (!quote.start || quote.end === "") return { blocks };
|
|
886
|
+
const prefix = firstText.text.slice(Math.max(0, start - QUOTE_CONTEXT_LENGTH), start);
|
|
887
|
+
const suffix = lastText.text.slice(end, end + QUOTE_CONTEXT_LENGTH);
|
|
888
|
+
if (prefix && occurrences(firstText.text, quote.start) > 1) quote.prefix = prefix;
|
|
889
|
+
if (suffix && occurrences(lastText.text, quote.end ?? quote.start) > 1) quote.suffix = suffix;
|
|
890
|
+
return { blocks, quote };
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// src/PastedImages.ts
|
|
894
|
+
import { Extension as Extension5 } from "@tiptap/core";
|
|
895
|
+
import { Plugin as Plugin3, PluginKey as PluginKey3 } from "@tiptap/pm/state";
|
|
896
|
+
var IMAGE_EXTENSIONS = {
|
|
897
|
+
"image/png": "png",
|
|
898
|
+
"image/jpeg": "jpg",
|
|
899
|
+
"image/gif": "gif",
|
|
900
|
+
"image/webp": "webp",
|
|
901
|
+
"image/heic": "heic",
|
|
902
|
+
"image/heif": "heif",
|
|
903
|
+
"image/svg+xml": "svg"
|
|
904
|
+
};
|
|
905
|
+
var GENERIC_STEMS = /* @__PURE__ */ new Set(["image", "blob", "unknown", "untitled", "screenshot"]);
|
|
906
|
+
function extensionFor(contentType) {
|
|
907
|
+
const type = contentType.toLowerCase();
|
|
908
|
+
return IMAGE_EXTENSIONS[type] ?? type.split("/")[1]?.split("+")[0] ?? "png";
|
|
909
|
+
}
|
|
910
|
+
function pastedImageName(contentType, at = /* @__PURE__ */ new Date(), index = 0) {
|
|
911
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
912
|
+
const stamp = `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())} ${pad(at.getHours())}-${pad(at.getMinutes())}-${pad(at.getSeconds())}`;
|
|
913
|
+
const nth = index > 0 ? ` (${index + 1})` : "";
|
|
914
|
+
return `Screenshot ${stamp}${nth}.${extensionFor(contentType)}`;
|
|
915
|
+
}
|
|
916
|
+
function hasUsableName(name) {
|
|
917
|
+
const dot = name.lastIndexOf(".");
|
|
918
|
+
if (dot <= 0 || dot === name.length - 1) return false;
|
|
919
|
+
return !GENERIC_STEMS.has(name.slice(0, dot).toLowerCase());
|
|
920
|
+
}
|
|
921
|
+
function pastedImages(source, at = /* @__PURE__ */ new Date()) {
|
|
922
|
+
if (!source) return [];
|
|
923
|
+
if (source.getData("text/plain").trim() !== "") return [];
|
|
924
|
+
const images = Array.from(source.files ?? []).filter((f) => f.type.toLowerCase().startsWith("image/"));
|
|
925
|
+
let generated = 0;
|
|
926
|
+
return images.map(
|
|
927
|
+
(file) => hasUsableName(file.name) ? file : new File([file], pastedImageName(file.type, at, generated++), { type: file.type, lastModified: file.lastModified })
|
|
928
|
+
);
|
|
929
|
+
}
|
|
930
|
+
var PastedImages = Extension5.create({
|
|
931
|
+
name: "pastedImages",
|
|
932
|
+
addOptions() {
|
|
933
|
+
return { onImages: () => false };
|
|
934
|
+
},
|
|
935
|
+
addProseMirrorPlugins() {
|
|
936
|
+
const options = this.options;
|
|
937
|
+
return [
|
|
938
|
+
new Plugin3({
|
|
939
|
+
key: new PluginKey3("pastedImages"),
|
|
940
|
+
props: {
|
|
941
|
+
handlePaste: (_view, event) => {
|
|
942
|
+
const files = pastedImages(event.clipboardData);
|
|
943
|
+
return files.length > 0 && options.onImages(files);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
})
|
|
947
|
+
];
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
// src/PastedMarkdown.ts
|
|
952
|
+
import { Extension as Extension6 } from "@tiptap/core";
|
|
953
|
+
import { Slice } from "@tiptap/pm/model";
|
|
954
|
+
import { Plugin as Plugin4, PluginKey as PluginKey4 } from "@tiptap/pm/state";
|
|
955
|
+
function inTableCell($context) {
|
|
956
|
+
for (let depth = $context.depth; depth > 0; depth--) {
|
|
957
|
+
const role = $context.node(depth).type.spec.tableRole;
|
|
958
|
+
if (role === "cell" || role === "header_cell") return true;
|
|
959
|
+
}
|
|
960
|
+
return false;
|
|
961
|
+
}
|
|
962
|
+
var hasTable = (blocks) => blocks.some((block) => block.type === "table" || hasTable(block.content ?? []));
|
|
963
|
+
var PastedMarkdown = Extension6.create({
|
|
964
|
+
name: "pastedMarkdown",
|
|
965
|
+
addOptions() {
|
|
966
|
+
return { read: () => void 0 };
|
|
967
|
+
},
|
|
968
|
+
addProseMirrorPlugins() {
|
|
969
|
+
const options = this.options;
|
|
970
|
+
return [
|
|
971
|
+
new Plugin4({
|
|
972
|
+
key: new PluginKey4("pastedMarkdown"),
|
|
973
|
+
props: {
|
|
974
|
+
// Reached only for a text paste outside code; `plain` is the Shift paste.
|
|
975
|
+
clipboardTextParser: (text, $context, plain, view) => {
|
|
976
|
+
if (plain) return void 0;
|
|
977
|
+
try {
|
|
978
|
+
const blocks = options.read(text.replace(/\r\n?/g, "\n"))?.content ?? [];
|
|
979
|
+
if (blocks.every((block) => block.type === "paragraph")) return void 0;
|
|
980
|
+
if (inTableCell($context) && hasTable(blocks)) return void 0;
|
|
981
|
+
return Slice.maxOpen(view.state.schema.nodeFromJSON({ type: "doc", content: blocks }).content);
|
|
982
|
+
} catch {
|
|
983
|
+
return void 0;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
})
|
|
988
|
+
];
|
|
989
|
+
}
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
// src/CodeBlockColours.ts
|
|
993
|
+
import { CodeBlockLowlight } from "@tiptap/extension-code-block-lowlight";
|
|
994
|
+
|
|
995
|
+
// src/codeColours.ts
|
|
996
|
+
import { createElement } from "react";
|
|
997
|
+
import { common, createLowlight } from "lowlight";
|
|
998
|
+
var instance;
|
|
999
|
+
function lowlight() {
|
|
1000
|
+
return instance ??= createLowlight(common);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
// src/CodeBlockColours.ts
|
|
1004
|
+
var namedOnly = {
|
|
1005
|
+
highlight: (language, value) => lowlight().highlight(language, value),
|
|
1006
|
+
highlightAuto: (value) => ({ type: "root", children: [{ type: "text", value }], data: { language: void 0, relevance: 0 } }),
|
|
1007
|
+
listLanguages: () => lowlight().listLanguages(),
|
|
1008
|
+
registered: (language) => lowlight().registered(language)
|
|
1009
|
+
};
|
|
1010
|
+
var CodeBlockColours = CodeBlockLowlight.configure({ lowlight: namedOnly });
|
|
1011
|
+
|
|
515
1012
|
// src/EditorBlockHandle.tsx
|
|
516
1013
|
import { useMemo } from "react";
|
|
517
1014
|
import { IconCopy, IconTrash } from "@tabler/icons-react";
|
|
@@ -520,15 +1017,16 @@ import { Selection } from "@tiptap/pm/state";
|
|
|
520
1017
|
import { MenuItem, MenuSub } from "@estiva-app/ui";
|
|
521
1018
|
|
|
522
1019
|
// src/ComposerTriggers.tsx
|
|
523
|
-
import { Extension as
|
|
524
|
-
import { PluginKey as
|
|
1020
|
+
import { Extension as Extension7 } from "@tiptap/core";
|
|
1021
|
+
import { PluginKey as PluginKey5 } from "@tiptap/pm/state";
|
|
525
1022
|
import Mention from "@tiptap/extension-mention";
|
|
526
1023
|
import Suggestion from "@tiptap/suggestion";
|
|
527
1024
|
import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
|
|
528
1025
|
import { Avatar } from "@estiva-app/ui";
|
|
529
1026
|
import { EnterHint } from "@estiva-app/ui";
|
|
530
1027
|
import { inlineChipClassName } from "@estiva-app/ui";
|
|
531
|
-
import {
|
|
1028
|
+
import { WithTooltip } from "@estiva-app/ui";
|
|
1029
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
532
1030
|
var PEOPLE_LIMIT = 6;
|
|
533
1031
|
function filterPeople(people, query) {
|
|
534
1032
|
const q = query.toLowerCase();
|
|
@@ -546,8 +1044,8 @@ function peopleMenu(urgent) {
|
|
|
546
1044
|
row: (person) => ({
|
|
547
1045
|
label: person.name,
|
|
548
1046
|
description: person.description,
|
|
549
|
-
leading: person.avatar ?? /* @__PURE__ */
|
|
550
|
-
hint: /* @__PURE__ */
|
|
1047
|
+
leading: person.avatar ?? /* @__PURE__ */ jsx5(Avatar, { size: 32, alt: person.name }),
|
|
1048
|
+
hint: /* @__PURE__ */ jsx5(EnterHint, {}),
|
|
551
1049
|
size: "tall"
|
|
552
1050
|
})
|
|
553
1051
|
};
|
|
@@ -674,10 +1172,13 @@ var CaptionedReference = Mention.extend({
|
|
|
674
1172
|
addNodeView() {
|
|
675
1173
|
const { icon, iconFor } = this.options;
|
|
676
1174
|
return ReactNodeViewRenderer(
|
|
677
|
-
({ node }) =>
|
|
678
|
-
|
|
679
|
-
/* @__PURE__ */
|
|
680
|
-
|
|
1175
|
+
({ node }) => (
|
|
1176
|
+
// 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.
|
|
1177
|
+
/* @__PURE__ */ jsx5(NodeViewWrapper, { as: "span", children: /* @__PURE__ */ jsx5(WithTooltip, { inline: true, label: captionOf(node.attrs.label, node.attrs.snippet), children: /* @__PURE__ */ jsxs4("span", { className: inlineChipClassName("neutral", "max-w-[24ch] cursor-default"), children: [
|
|
1178
|
+
/* @__PURE__ */ jsx5("span", { className: "flex items-center justify-center w-4 h-4 shrink-0 text-text-secondary", children: iconFor?.(node.attrs.uri ?? null) ?? icon }),
|
|
1179
|
+
/* @__PURE__ */ jsx5("span", { className: "truncate", children: captionOf(node.attrs.label, node.attrs.snippet) })
|
|
1180
|
+
] }) }) })
|
|
1181
|
+
),
|
|
681
1182
|
{ as: "span" }
|
|
682
1183
|
);
|
|
683
1184
|
}
|
|
@@ -698,11 +1199,11 @@ function referenceMenu({ ariaLabel, sectionLabel, icon, iconFor }) {
|
|
|
698
1199
|
return groups;
|
|
699
1200
|
},
|
|
700
1201
|
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__ */
|
|
1202
|
+
row: (item) => ({ leading: item.icon ?? iconFor?.(item.uri) ?? icon, label: captionOf(item.label, item.snippet), description: item.description, hint: /* @__PURE__ */ jsx5(EnterHint, {}) })
|
|
702
1203
|
};
|
|
703
1204
|
}
|
|
704
1205
|
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 =
|
|
1206
|
+
var ReferenceTrigger = Extension7.create({
|
|
706
1207
|
name: "referenceTrigger",
|
|
707
1208
|
addOptions() {
|
|
708
1209
|
return { items: () => [], nodeName: "captionedReference", ariaLabel: "References", sectionLabel: "References", icon: null };
|
|
@@ -713,7 +1214,7 @@ var ReferenceTrigger = Extension4.create({
|
|
|
713
1214
|
Suggestion({
|
|
714
1215
|
editor: this.editor,
|
|
715
1216
|
char: "[",
|
|
716
|
-
pluginKey: new
|
|
1217
|
+
pluginKey: new PluginKey5("referenceTrigger"),
|
|
717
1218
|
...listening("]"),
|
|
718
1219
|
// As a mention's: only where the chip may go.
|
|
719
1220
|
allow: ({ state, range }) => {
|
|
@@ -818,7 +1319,7 @@ function filterSlashSections(sections, query) {
|
|
|
818
1319
|
const q = query.toLowerCase();
|
|
819
1320
|
return sections.map((section) => ({ ...section, commands: q ? section.commands.filter((command) => matches(command, q)) : section.commands }));
|
|
820
1321
|
}
|
|
821
|
-
var SlashCommands =
|
|
1322
|
+
var SlashCommands = Extension7.create({
|
|
822
1323
|
name: "slashCommands",
|
|
823
1324
|
addOptions() {
|
|
824
1325
|
return { sections: [formatSection()] };
|
|
@@ -830,7 +1331,7 @@ var SlashCommands = Extension4.create({
|
|
|
830
1331
|
editor: this.editor,
|
|
831
1332
|
char: "/",
|
|
832
1333
|
startOfLine: false,
|
|
833
|
-
pluginKey: new
|
|
1334
|
+
pluginKey: new PluginKey5("slashCommands"),
|
|
834
1335
|
items: ({ query, editor }) => filterSlashSections(sections, query).flatMap(
|
|
835
1336
|
(section, at) => section.commands.filter((command) => offers(editor, command)).map((command) => ({ ...command, section: at }))
|
|
836
1337
|
),
|
|
@@ -852,7 +1353,7 @@ var SlashCommands = Extension4.create({
|
|
|
852
1353
|
});
|
|
853
1354
|
|
|
854
1355
|
// src/EditorBlockHandle.tsx
|
|
855
|
-
import { Fragment, jsx as
|
|
1356
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
856
1357
|
function editorBlocks(view) {
|
|
857
1358
|
const out = [];
|
|
858
1359
|
view.state.doc.forEach((node, pos) => {
|
|
@@ -919,8 +1420,8 @@ function EditorBlockHandle({ editor, turnInto = turnIntoRows, actions, children,
|
|
|
919
1420
|
const node = pos === void 0 ? null : editor.state.doc.nodeAt(pos);
|
|
920
1421
|
if (pos === void 0 || !node) return null;
|
|
921
1422
|
const turnRows = typeof turnInto === "function" ? turnInto(node, editor) : node.isTextblock ? turnInto : [];
|
|
922
|
-
return /* @__PURE__ */
|
|
923
|
-
turnRows.length > 0 && /* @__PURE__ */
|
|
1423
|
+
return /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1424
|
+
turnRows.length > 0 && /* @__PURE__ */ jsx6(MenuSub, { label: "Turn into", children: turnRows.map((row) => /* @__PURE__ */ jsx6(
|
|
924
1425
|
MenuItem,
|
|
925
1426
|
{
|
|
926
1427
|
label: row.label,
|
|
@@ -932,8 +1433,8 @@ function EditorBlockHandle({ editor, turnInto = turnIntoRows, actions, children,
|
|
|
932
1433
|
},
|
|
933
1434
|
row.label
|
|
934
1435
|
)) }),
|
|
935
|
-
/* @__PURE__ */
|
|
936
|
-
/* @__PURE__ */
|
|
1436
|
+
/* @__PURE__ */ jsx6(MenuItem, { label: "Duplicate", leading: /* @__PURE__ */ jsx6(IconCopy, { size: 16, stroke: 1.5, className: "text-text-secondary" }), onClick: () => duplicateBlock(editor, pos) }),
|
|
1437
|
+
/* @__PURE__ */ jsx6(MenuItem, { label: "Delete", destructive: true, leading: /* @__PURE__ */ jsx6(IconTrash, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: () => deleteBlock(editor, pos) })
|
|
937
1438
|
] });
|
|
938
1439
|
},
|
|
939
1440
|
startDrag: (block, event) => {
|
|
@@ -955,7 +1456,7 @@ function EditorBlockHandle({ editor, turnInto = turnIntoRows, actions, children,
|
|
|
955
1456
|
}
|
|
956
1457
|
};
|
|
957
1458
|
}, [editor, turnInto]);
|
|
958
|
-
return /* @__PURE__ */
|
|
1459
|
+
return /* @__PURE__ */ jsx6(BlockHandle, { editing, actions, className, children });
|
|
959
1460
|
}
|
|
960
1461
|
var LISTS = ["bulletList", "orderedList"];
|
|
961
1462
|
var isList = (node) => LISTS.includes(node.type.name);
|
|
@@ -1061,19 +1562,14 @@ function turnIntoRows(node, editor) {
|
|
|
1061
1562
|
}
|
|
1062
1563
|
|
|
1063
1564
|
// src/EditorTableControls.tsx
|
|
1064
|
-
import { useCallback as
|
|
1565
|
+
import { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
|
|
1065
1566
|
import { TextSelection } from "@tiptap/pm/state";
|
|
1066
1567
|
import { addColumnAfter, addColumnBefore, addRowAfter, addRowBefore, deleteColumn, deleteRow, deleteTable, toggleHeader } from "@tiptap/pm/tables";
|
|
1067
1568
|
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
|
|
1569
|
+
import { cn as cn3 } from "@estiva-app/ui";
|
|
1570
|
+
import { IconButton as IconButton2 } from "@estiva-app/ui";
|
|
1075
1571
|
import { Menu, MenuItem as MenuItem2, MenuSeparator } from "@estiva-app/ui";
|
|
1076
|
-
import { Fragment as Fragment2, jsx as
|
|
1572
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1077
1573
|
function inCell(editor, cell, command) {
|
|
1078
1574
|
const { view } = editor;
|
|
1079
1575
|
if (!view.dom.contains(cell)) return false;
|
|
@@ -1119,13 +1615,13 @@ function place(frame, { table, row, cell }) {
|
|
|
1119
1615
|
}
|
|
1120
1616
|
var ICON = { size: 16, stroke: 1.5, className: "text-text-secondary" };
|
|
1121
1617
|
var keepFocus = (e) => e.preventDefault();
|
|
1122
|
-
var HANDLE_BOX =
|
|
1618
|
+
var HANDLE_BOX = cn3(FLOATING_SURFACE_CLASSES, "shadow-none");
|
|
1123
1619
|
function EditorTableControls({ editor, children, className }) {
|
|
1124
|
-
const frame =
|
|
1125
|
-
const [hovered, setHovered] =
|
|
1126
|
-
const [menu, setMenu] =
|
|
1620
|
+
const frame = useRef4(null);
|
|
1621
|
+
const [hovered, setHovered] = useState4(null);
|
|
1622
|
+
const [menu, setMenu] = useState4(null);
|
|
1127
1623
|
const editable = !!editor && editor.isEditable;
|
|
1128
|
-
const follow =
|
|
1624
|
+
const follow = useCallback4(
|
|
1129
1625
|
(target) => {
|
|
1130
1626
|
if (!editor || !frame.current || !(target instanceof Element)) return;
|
|
1131
1627
|
if (target.closest("[data-table-control]")) return;
|
|
@@ -1141,7 +1637,7 @@ function EditorTableControls({ editor, children, className }) {
|
|
|
1141
1637
|
},
|
|
1142
1638
|
[editor]
|
|
1143
1639
|
);
|
|
1144
|
-
|
|
1640
|
+
useEffect4(() => {
|
|
1145
1641
|
if (!editor) return;
|
|
1146
1642
|
const changed = ({ transaction }) => {
|
|
1147
1643
|
if (transaction.docChanged && !menu) setHovered(null);
|
|
@@ -1157,11 +1653,11 @@ function EditorTableControls({ editor, children, className }) {
|
|
|
1157
1653
|
setMenu(null);
|
|
1158
1654
|
setHovered(null);
|
|
1159
1655
|
};
|
|
1160
|
-
return /* @__PURE__ */
|
|
1656
|
+
return /* @__PURE__ */ jsxs6(
|
|
1161
1657
|
"div",
|
|
1162
1658
|
{
|
|
1163
1659
|
ref: frame,
|
|
1164
|
-
className:
|
|
1660
|
+
className: cn3("relative", className),
|
|
1165
1661
|
onMouseMove: (e) => {
|
|
1166
1662
|
if (!menu) follow(e.target);
|
|
1167
1663
|
},
|
|
@@ -1170,39 +1666,39 @@ function EditorTableControls({ editor, children, className }) {
|
|
|
1170
1666
|
},
|
|
1171
1667
|
children: [
|
|
1172
1668
|
children,
|
|
1173
|
-
shown && editor && /* @__PURE__ */
|
|
1174
|
-
/* @__PURE__ */
|
|
1669
|
+
shown && editor && /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1670
|
+
/* @__PURE__ */ jsx7("div", { "data-table-control": true, className: cn3(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__ */ jsxs6(
|
|
1175
1671
|
Menu,
|
|
1176
1672
|
{
|
|
1177
1673
|
open: menu === "row",
|
|
1178
1674
|
onOpenChange: (open) => setMenu(open ? "row" : null),
|
|
1179
|
-
trigger: /* @__PURE__ */
|
|
1675
|
+
trigger: /* @__PURE__ */ jsx7(IconButton2, { "aria-label": "Row menu", tooltip: "Row", className: "h-6 w-4 p-0", children: /* @__PURE__ */ jsx7(IconGripVertical, { size: 16, stroke: 1.5 }) }),
|
|
1180
1676
|
children: [
|
|
1181
|
-
!isHeaderRow(shown.row) && /* @__PURE__ */
|
|
1182
|
-
/* @__PURE__ */
|
|
1183
|
-
/* @__PURE__ */
|
|
1184
|
-
/* @__PURE__ */
|
|
1185
|
-
/* @__PURE__ */
|
|
1677
|
+
!isHeaderRow(shown.row) && /* @__PURE__ */ jsx7(MenuItem2, { label: "Insert above", leading: /* @__PURE__ */ jsx7(IconRowInsertTop, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addRowBefore)) }),
|
|
1678
|
+
/* @__PURE__ */ jsx7(MenuItem2, { label: "Insert below", leading: /* @__PURE__ */ jsx7(IconRowInsertBottom, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addRowAfter)) }),
|
|
1679
|
+
/* @__PURE__ */ jsx7(MenuSeparator, {}),
|
|
1680
|
+
/* @__PURE__ */ jsx7(MenuItem2, { label: "Delete", destructive: true, leading: /* @__PURE__ */ jsx7(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => deleteTableRow(editor, shown.cell)) }),
|
|
1681
|
+
/* @__PURE__ */ jsx7(MenuItem2, { label: "Delete table", destructive: true, leading: /* @__PURE__ */ jsx7(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => inCell(editor, shown.cell, deleteTable)) })
|
|
1186
1682
|
]
|
|
1187
1683
|
}
|
|
1188
1684
|
) }),
|
|
1189
|
-
/* @__PURE__ */
|
|
1685
|
+
/* @__PURE__ */ jsx7("div", { "data-table-control": true, className: cn3(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__ */ jsxs6(
|
|
1190
1686
|
Menu,
|
|
1191
1687
|
{
|
|
1192
1688
|
open: menu === "column",
|
|
1193
1689
|
onOpenChange: (open) => setMenu(open ? "column" : null),
|
|
1194
|
-
trigger: /* @__PURE__ */
|
|
1690
|
+
trigger: /* @__PURE__ */ jsx7(IconButton2, { "aria-label": "Column menu", tooltip: "Column", className: "h-4 w-6 p-0", children: /* @__PURE__ */ jsx7(IconGripHorizontal, { size: 16, stroke: 1.5 }) }),
|
|
1195
1691
|
children: [
|
|
1196
|
-
/* @__PURE__ */
|
|
1197
|
-
/* @__PURE__ */
|
|
1198
|
-
/* @__PURE__ */
|
|
1199
|
-
/* @__PURE__ */
|
|
1200
|
-
/* @__PURE__ */
|
|
1692
|
+
/* @__PURE__ */ jsx7(MenuItem2, { label: "Insert left", leading: /* @__PURE__ */ jsx7(IconColumnInsertLeft, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addColumnBefore)) }),
|
|
1693
|
+
/* @__PURE__ */ jsx7(MenuItem2, { label: "Insert right", leading: /* @__PURE__ */ jsx7(IconColumnInsertRight, { ...ICON }), onClick: run(() => inCell(editor, shown.cell, addColumnAfter)) }),
|
|
1694
|
+
/* @__PURE__ */ jsx7(MenuSeparator, {}),
|
|
1695
|
+
/* @__PURE__ */ jsx7(MenuItem2, { label: "Delete", destructive: true, leading: /* @__PURE__ */ jsx7(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => deleteTableColumn(editor, shown.cell)) }),
|
|
1696
|
+
/* @__PURE__ */ jsx7(MenuItem2, { label: "Delete table", destructive: true, leading: /* @__PURE__ */ jsx7(IconTrash2, { size: 16, stroke: 1.5, className: "text-error-default" }), onClick: run(() => inCell(editor, shown.cell, deleteTable)) })
|
|
1201
1697
|
]
|
|
1202
1698
|
}
|
|
1203
1699
|
) }),
|
|
1204
|
-
shown.row === shown.table.rows[shown.table.rows.length - 1] && /* @__PURE__ */
|
|
1205
|
-
shown.cell === shown.row.cells[shown.row.cells.length - 1] && /* @__PURE__ */
|
|
1700
|
+
shown.row === shown.table.rows[shown.table.rows.length - 1] && /* @__PURE__ */ jsx7("div", { "data-table-control": true, className: cn3(HANDLE_BOX, "absolute flex h-4"), style: { left: shown.tableBox.left, top: shown.tableBox.top + shown.tableBox.height, width: shown.tableBox.width }, children: /* @__PURE__ */ jsx7(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__ */ jsx7(IconPlus, { size: 12, stroke: 1.5 }) }) }),
|
|
1701
|
+
shown.cell === shown.row.cells[shown.row.cells.length - 1] && /* @__PURE__ */ jsx7("div", { "data-table-control": true, className: cn3(HANDLE_BOX, "absolute flex w-4"), style: { left: shown.tableBox.left + shown.tableBox.width, top: shown.tableBox.top, height: shown.tableBox.height }, children: /* @__PURE__ */ jsx7(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__ */ jsx7(IconPlus, { size: 12, stroke: 1.5 }) }) })
|
|
1206
1702
|
] })
|
|
1207
1703
|
]
|
|
1208
1704
|
}
|
|
@@ -1210,27 +1706,27 @@ function EditorTableControls({ editor, children, className }) {
|
|
|
1210
1706
|
}
|
|
1211
1707
|
|
|
1212
1708
|
// src/BlockNodes.tsx
|
|
1213
|
-
import { Extension as
|
|
1709
|
+
import { Extension as Extension11, InputRule, Node as Node3 } from "@tiptap/core";
|
|
1214
1710
|
import { DOMSerializer } from "@tiptap/pm/model";
|
|
1215
|
-
import { Plugin as
|
|
1711
|
+
import { Plugin as Plugin8, PluginKey as PluginKey9 } from "@tiptap/pm/state";
|
|
1216
1712
|
import { Mapping, ReplaceAroundStep } from "@tiptap/pm/transform";
|
|
1217
1713
|
import { NodeViewWrapper as NodeViewWrapper2, ReactNodeViewRenderer as ReactNodeViewRenderer2, ReactRenderer as ReactRenderer2 } from "@tiptap/react";
|
|
1218
1714
|
import { Checkbox } from "@estiva-app/ui";
|
|
1219
1715
|
import { calloutLook } from "@estiva-app/ui";
|
|
1220
1716
|
|
|
1221
1717
|
// src/ReferenceMenu.tsx
|
|
1222
|
-
import { useCallback as
|
|
1223
|
-
import { Extension as
|
|
1718
|
+
import { useCallback as useCallback5 } from "react";
|
|
1719
|
+
import { Extension as Extension10 } from "@tiptap/core";
|
|
1224
1720
|
import { useEditorState } from "@tiptap/react";
|
|
1225
|
-
import { NodeSelection as NodeSelection2, Plugin as
|
|
1721
|
+
import { NodeSelection as NodeSelection2, Plugin as Plugin7, PluginKey as PluginKey8, TextSelection as TextSelection2 } from "@tiptap/pm/state";
|
|
1226
1722
|
import { ReplaceStep } from "@tiptap/pm/transform";
|
|
1227
1723
|
import { IconCheck } from "@tabler/icons-react";
|
|
1228
1724
|
|
|
1229
1725
|
// src/LinkChips.ts
|
|
1230
|
-
import { Extension as
|
|
1726
|
+
import { Extension as Extension8 } from "@tiptap/core";
|
|
1231
1727
|
import { closeHistory } from "@tiptap/pm/history";
|
|
1232
|
-
import { Plugin as
|
|
1233
|
-
var key = new
|
|
1728
|
+
import { Plugin as Plugin5, PluginKey as PluginKey6 } from "@tiptap/pm/state";
|
|
1729
|
+
var key = new PluginKey6("linkChips");
|
|
1234
1730
|
var CHIPS_MADE = "linkChipsMade";
|
|
1235
1731
|
var PASTES_KEPT = 8;
|
|
1236
1732
|
var LINK_OR_URL = /(\[[^[\]\n]+\]\((?:https?:\/\/|mailto:)[^\s)]+\))|(https?:\/\/[^\s<>"'`]+)/g;
|
|
@@ -1248,10 +1744,10 @@ function urlRuns(text) {
|
|
|
1248
1744
|
}
|
|
1249
1745
|
return out;
|
|
1250
1746
|
}
|
|
1251
|
-
function findLinkChips(
|
|
1747
|
+
function findLinkChips(doc2, selection, referenceOf, pasted = []) {
|
|
1252
1748
|
const found = { chips: [], fills: [], open: [] };
|
|
1253
1749
|
const open = /* @__PURE__ */ new Set();
|
|
1254
|
-
|
|
1750
|
+
doc2.descendants((node, pos) => {
|
|
1255
1751
|
if (node.type.spec.code) return false;
|
|
1256
1752
|
if (node.type.name === "reference") {
|
|
1257
1753
|
const href = typeof node.attrs.href === "string" ? node.attrs.href : "";
|
|
@@ -1305,7 +1801,7 @@ function refreshLinkChips(editor) {
|
|
|
1305
1801
|
const tr = apply(editor.state, findLinkChips(editor.state.doc, editor.state.selection, chips.options.referenceOf, chips.pasted));
|
|
1306
1802
|
if (tr) editor.view.dispatch(tr);
|
|
1307
1803
|
}
|
|
1308
|
-
var LinkChips =
|
|
1804
|
+
var LinkChips = Extension8.create({
|
|
1309
1805
|
name: "linkChips",
|
|
1310
1806
|
addOptions() {
|
|
1311
1807
|
return { referenceOf: null, ask: null, limit: 24 };
|
|
@@ -1314,7 +1810,7 @@ var LinkChips = Extension5.create({
|
|
|
1314
1810
|
const options = this.options;
|
|
1315
1811
|
const editor = this.editor;
|
|
1316
1812
|
return [
|
|
1317
|
-
new
|
|
1813
|
+
new Plugin5({
|
|
1318
1814
|
key,
|
|
1319
1815
|
// The options, where `refreshLinkChips` can read them from the state alone, and where the last pastes landed.
|
|
1320
1816
|
state: {
|
|
@@ -1378,18 +1874,18 @@ import { MenuItem as MenuItem3, MenuSection, MenuSeparator as MenuSeparator2 } f
|
|
|
1378
1874
|
import { Popover as Popover2 } from "@estiva-app/ui";
|
|
1379
1875
|
|
|
1380
1876
|
// src/ReferenceCards.ts
|
|
1381
|
-
import { Extension as
|
|
1382
|
-
import { NodeSelection, Plugin as
|
|
1383
|
-
import { Decoration as
|
|
1384
|
-
import { useEffect as
|
|
1877
|
+
import { Extension as Extension9 } from "@tiptap/core";
|
|
1878
|
+
import { NodeSelection, Plugin as Plugin6, PluginKey as PluginKey7 } from "@tiptap/pm/state";
|
|
1879
|
+
import { Decoration as Decoration3, DecorationSet as DecorationSet3 } from "@tiptap/pm/view";
|
|
1880
|
+
import { useEffect as useEffect5, useState as useState5 } from "react";
|
|
1385
1881
|
function layoutOf(raw) {
|
|
1386
1882
|
if (typeof raw !== "string" || raw === "" || raw === "none") return void 0;
|
|
1387
1883
|
return raw === "detailed" ? "detailed" : "compact";
|
|
1388
1884
|
}
|
|
1389
|
-
function referenceCardPlacements(
|
|
1885
|
+
function referenceCardPlacements(doc2) {
|
|
1390
1886
|
const out = [];
|
|
1391
1887
|
const seen = /* @__PURE__ */ new Map();
|
|
1392
|
-
|
|
1888
|
+
doc2.descendants((node, pos, parent) => {
|
|
1393
1889
|
if (!node.isTextblock) return true;
|
|
1394
1890
|
const cards = [];
|
|
1395
1891
|
node.forEach((child) => {
|
|
@@ -1408,7 +1904,7 @@ function referenceCardPlacements(doc) {
|
|
|
1408
1904
|
});
|
|
1409
1905
|
return out;
|
|
1410
1906
|
}
|
|
1411
|
-
var key2 = new
|
|
1907
|
+
var key2 = new PluginKey7("referenceCards");
|
|
1412
1908
|
function elementFor(storage, slotKey) {
|
|
1413
1909
|
let element = storage.elements.get(slotKey);
|
|
1414
1910
|
if (!element) {
|
|
@@ -1422,17 +1918,17 @@ function elementFor(storage, slotKey) {
|
|
|
1422
1918
|
function storageOf(editor) {
|
|
1423
1919
|
return editor.storage.referenceCards;
|
|
1424
1920
|
}
|
|
1425
|
-
var ReferenceCards =
|
|
1921
|
+
var ReferenceCards = Extension9.create({
|
|
1426
1922
|
name: "referenceCards",
|
|
1427
1923
|
addStorage() {
|
|
1428
1924
|
return { elements: /* @__PURE__ */ new Map() };
|
|
1429
1925
|
},
|
|
1430
1926
|
addProseMirrorPlugins() {
|
|
1431
1927
|
const storage = this.storage;
|
|
1432
|
-
const decorate = (
|
|
1433
|
-
|
|
1434
|
-
referenceCardPlacements(
|
|
1435
|
-
(p) =>
|
|
1928
|
+
const decorate = (doc2) => DecorationSet3.create(
|
|
1929
|
+
doc2,
|
|
1930
|
+
referenceCardPlacements(doc2).map(
|
|
1931
|
+
(p) => Decoration3.widget(p.pos, () => elementFor(storage, p.key), {
|
|
1436
1932
|
key: p.key,
|
|
1437
1933
|
side: 1,
|
|
1438
1934
|
ignoreSelection: true,
|
|
@@ -1442,7 +1938,7 @@ var ReferenceCards = Extension6.create({
|
|
|
1442
1938
|
)
|
|
1443
1939
|
);
|
|
1444
1940
|
return [
|
|
1445
|
-
new
|
|
1941
|
+
new Plugin6({
|
|
1446
1942
|
key: key2,
|
|
1447
1943
|
state: {
|
|
1448
1944
|
init: (_, state) => decorate(state.doc),
|
|
@@ -1454,8 +1950,8 @@ var ReferenceCards = Extension6.create({
|
|
|
1454
1950
|
}
|
|
1455
1951
|
});
|
|
1456
1952
|
function useReferenceCards(editor) {
|
|
1457
|
-
const [slots, setSlots] =
|
|
1458
|
-
|
|
1953
|
+
const [slots, setSlots] = useState5([]);
|
|
1954
|
+
useEffect5(() => {
|
|
1459
1955
|
if (!editor) return;
|
|
1460
1956
|
const storage = storageOf(editor);
|
|
1461
1957
|
if (!storage) return;
|
|
@@ -1520,8 +2016,8 @@ function setReferenceCardAt(editor, pos, layout) {
|
|
|
1520
2016
|
}
|
|
1521
2017
|
|
|
1522
2018
|
// src/ReferenceMenu.tsx
|
|
1523
|
-
import { Fragment as Fragment3, jsx as
|
|
1524
|
-
var key3 = new
|
|
2019
|
+
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2020
|
+
var key3 = new PluginKey8("referenceMenu");
|
|
1525
2021
|
var LAYOUTS = [
|
|
1526
2022
|
{ layout: "none", label: "None" },
|
|
1527
2023
|
{ layout: "compact", label: "Compact" },
|
|
@@ -1600,14 +2096,14 @@ function caretAfter(state, pos) {
|
|
|
1600
2096
|
const node = state.doc.nodeAt(pos);
|
|
1601
2097
|
return state.tr.setSelection(TextSelection2.create(state.doc, pos + (node?.nodeSize ?? 1)));
|
|
1602
2098
|
}
|
|
1603
|
-
var ReferenceMenu =
|
|
2099
|
+
var ReferenceMenu = Extension10.create({
|
|
1604
2100
|
name: "referenceMenu",
|
|
1605
2101
|
// Before the editor's own keys, so Enter on a highlighted row is the row's, not a new line.
|
|
1606
2102
|
priority: 1e3,
|
|
1607
2103
|
addProseMirrorPlugins() {
|
|
1608
2104
|
const editor = this.editor;
|
|
1609
2105
|
return [
|
|
1610
|
-
new
|
|
2106
|
+
new Plugin7({
|
|
1611
2107
|
key: key3,
|
|
1612
2108
|
state: {
|
|
1613
2109
|
init: () => null,
|
|
@@ -1682,7 +2178,7 @@ function ReferenceMenuView({ editor }) {
|
|
|
1682
2178
|
return { pos: open.pos, active: open.active, named: !!node.attrs.uri, layout };
|
|
1683
2179
|
}
|
|
1684
2180
|
});
|
|
1685
|
-
const keepFocus2 =
|
|
2181
|
+
const keepFocus2 = useCallback5((list) => {
|
|
1686
2182
|
const panel = list?.closest('[role="dialog"]');
|
|
1687
2183
|
if (!panel) return;
|
|
1688
2184
|
const keep = (event) => event.preventDefault();
|
|
@@ -1699,7 +2195,7 @@ function ReferenceMenuView({ editor }) {
|
|
|
1699
2195
|
};
|
|
1700
2196
|
return (
|
|
1701
2197
|
// finalFocus={false}: focus never left the text.
|
|
1702
|
-
/* @__PURE__ */
|
|
2198
|
+
/* @__PURE__ */ jsx8(
|
|
1703
2199
|
Popover2,
|
|
1704
2200
|
{
|
|
1705
2201
|
anchor,
|
|
@@ -1711,8 +2207,8 @@ function ReferenceMenuView({ editor }) {
|
|
|
1711
2207
|
align: "left",
|
|
1712
2208
|
ariaLabel: "Link",
|
|
1713
2209
|
finalFocus: false,
|
|
1714
|
-
children: shown && /* @__PURE__ */
|
|
1715
|
-
opens && /* @__PURE__ */
|
|
2210
|
+
children: shown && /* @__PURE__ */ jsxs7("div", { ref: keepFocus2, role: "menu", "aria-label": "Link", className: "flex flex-col gap-0.5", children: [
|
|
2211
|
+
opens && /* @__PURE__ */ jsx8(
|
|
1716
2212
|
MenuItem3,
|
|
1717
2213
|
{
|
|
1718
2214
|
role: "menuitem",
|
|
@@ -1725,9 +2221,9 @@ function ReferenceMenuView({ editor }) {
|
|
|
1725
2221
|
}
|
|
1726
2222
|
}
|
|
1727
2223
|
),
|
|
1728
|
-
shown.named && /* @__PURE__ */
|
|
1729
|
-
opens && /* @__PURE__ */
|
|
1730
|
-
/* @__PURE__ */
|
|
2224
|
+
shown.named && /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
2225
|
+
opens && /* @__PURE__ */ jsx8(MenuSeparator2, {}),
|
|
2226
|
+
/* @__PURE__ */ jsx8("div", { role: "group", "aria-label": "Card", children: /* @__PURE__ */ jsx8(MenuSection, { label: "Card", children: LAYOUTS.map(({ layout, label }, i) => /* @__PURE__ */ jsx8(
|
|
1731
2227
|
MenuItem3,
|
|
1732
2228
|
{
|
|
1733
2229
|
role: "menuitemradio",
|
|
@@ -1735,7 +2231,7 @@ function ReferenceMenuView({ editor }) {
|
|
|
1735
2231
|
tabIndex: -1,
|
|
1736
2232
|
label,
|
|
1737
2233
|
selected: shown.active === i + (opens ? 1 : 0),
|
|
1738
|
-
trailing: shown.layout === layout ? /* @__PURE__ */
|
|
2234
|
+
trailing: shown.layout === layout ? /* @__PURE__ */ jsx8(IconCheck, { size: 16, "aria-hidden": true }) : void 0,
|
|
1739
2235
|
onMouseDown: (event) => {
|
|
1740
2236
|
event.preventDefault();
|
|
1741
2237
|
run(layout);
|
|
@@ -1751,7 +2247,7 @@ function ReferenceMenuView({ editor }) {
|
|
|
1751
2247
|
}
|
|
1752
2248
|
|
|
1753
2249
|
// src/BlockNodes.tsx
|
|
1754
|
-
import { jsx as
|
|
2250
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1755
2251
|
var BLOCK_TYPES = [
|
|
1756
2252
|
"paragraph",
|
|
1757
2253
|
"heading",
|
|
@@ -1784,9 +2280,9 @@ function holdsText(node) {
|
|
|
1784
2280
|
});
|
|
1785
2281
|
return found;
|
|
1786
2282
|
}
|
|
1787
|
-
function claimsIn(
|
|
2283
|
+
function claimsIn(doc2) {
|
|
1788
2284
|
const claims = /* @__PURE__ */ new Map();
|
|
1789
|
-
|
|
2285
|
+
doc2.descendants((node, pos, parent) => {
|
|
1790
2286
|
const fixed = node.type.name === "unknownBlock";
|
|
1791
2287
|
if (!fixed && !BLOCK_TYPE_SET.has(node.type.name)) return;
|
|
1792
2288
|
if (parent?.type.name === "listItem" && LISTS2.has(node.type.name)) return;
|
|
@@ -1821,8 +2317,8 @@ function textStart({ pos, node }) {
|
|
|
1821
2317
|
}
|
|
1822
2318
|
return start;
|
|
1823
2319
|
}
|
|
1824
|
-
function repeatedBlockIds(
|
|
1825
|
-
const claims = claimsIn(
|
|
2320
|
+
function repeatedBlockIds(doc2, before, mapping) {
|
|
2321
|
+
const claims = claimsIn(doc2);
|
|
1826
2322
|
let previous;
|
|
1827
2323
|
const losers = [];
|
|
1828
2324
|
for (const [id, copies] of claims) {
|
|
@@ -1848,7 +2344,7 @@ var idOf = (node) => {
|
|
|
1848
2344
|
const id = node.attrs.blockId;
|
|
1849
2345
|
return typeof id === "string" && id !== "" ? id : void 0;
|
|
1850
2346
|
};
|
|
1851
|
-
function addressedBlocks(
|
|
2347
|
+
function addressedBlocks(doc2) {
|
|
1852
2348
|
const out = [];
|
|
1853
2349
|
const visit = (node, pos) => {
|
|
1854
2350
|
if (!BLOCK_TYPE_SET.has(node.type.name)) return;
|
|
@@ -1858,15 +2354,15 @@ function addressedBlocks(doc) {
|
|
|
1858
2354
|
for (const list of innerLists(node, pos)) list.node.forEach((child, offset) => visit(child, list.pos + 1 + offset));
|
|
1859
2355
|
}
|
|
1860
2356
|
};
|
|
1861
|
-
|
|
2357
|
+
doc2.forEach((node, offset) => visit(node, offset));
|
|
1862
2358
|
return out;
|
|
1863
2359
|
}
|
|
1864
|
-
function unnamedBlocks(
|
|
1865
|
-
return addressedBlocks(
|
|
2360
|
+
function unnamedBlocks(doc2) {
|
|
2361
|
+
return addressedBlocks(doc2).filter((b) => idOf(b.node) === void 0).map((b) => b.pos);
|
|
1866
2362
|
}
|
|
1867
|
-
function hiddenIds(
|
|
2363
|
+
function hiddenIds(doc2) {
|
|
1868
2364
|
const out = [];
|
|
1869
|
-
|
|
2365
|
+
doc2.descendants((node, pos) => {
|
|
1870
2366
|
if (!FLATTENED.has(node.type.name)) return;
|
|
1871
2367
|
node.forEach((child, offset) => {
|
|
1872
2368
|
const inner = child.isTextblock || node.type.name === "listItem" && LISTS2.has(child.type.name);
|
|
@@ -1875,10 +2371,10 @@ function hiddenIds(doc) {
|
|
|
1875
2371
|
});
|
|
1876
2372
|
return out;
|
|
1877
2373
|
}
|
|
1878
|
-
function handedOver(
|
|
2374
|
+
function handedOver(doc2, before, mapping, unnamed) {
|
|
1879
2375
|
const out = /* @__PURE__ */ new Map();
|
|
1880
2376
|
if (unnamed.length === 0) return out;
|
|
1881
|
-
const now = new Set(addressedBlocks(
|
|
2377
|
+
const now = new Set(addressedBlocks(doc2).map((b) => idOf(b.node)));
|
|
1882
2378
|
const gone = addressedBlocks(before).filter((b) => !b.node.isLeaf && idOf(b.node) !== void 0 && !now.has(idOf(b.node))).map((b) => ({ ...b, start: textStart(b) })).sort((a, b) => a.start - b.start || b.pos - a.pos);
|
|
1883
2379
|
for (const old of gone) {
|
|
1884
2380
|
const id = idOf(old.node);
|
|
@@ -1887,7 +2383,7 @@ function handedOver(doc, before, mapping, unnamed) {
|
|
|
1887
2383
|
let inner;
|
|
1888
2384
|
for (const pos of unnamed) {
|
|
1889
2385
|
if (out.has(pos)) continue;
|
|
1890
|
-
if (pos < at && at < pos +
|
|
2386
|
+
if (pos < at && at < pos + doc2.nodeAt(pos).nodeSize && (inner === void 0 || pos > inner)) inner = pos;
|
|
1891
2387
|
}
|
|
1892
2388
|
if (inner !== void 0) {
|
|
1893
2389
|
out.set(inner, id);
|
|
@@ -1909,7 +2405,7 @@ function bringsInBlocks(transactions) {
|
|
|
1909
2405
|
})
|
|
1910
2406
|
);
|
|
1911
2407
|
}
|
|
1912
|
-
var BlockId =
|
|
2408
|
+
var BlockId = Extension11.create({
|
|
1913
2409
|
name: "blockId",
|
|
1914
2410
|
onCreate() {
|
|
1915
2411
|
const { state, view } = this.editor;
|
|
@@ -1921,8 +2417,8 @@ var BlockId = Extension8.create({
|
|
|
1921
2417
|
},
|
|
1922
2418
|
addProseMirrorPlugins() {
|
|
1923
2419
|
return [
|
|
1924
|
-
new
|
|
1925
|
-
key: new
|
|
2420
|
+
new Plugin8({
|
|
2421
|
+
key: new PluginKey9("blockIdSplit"),
|
|
1926
2422
|
appendTransaction: (transactions, old, state) => {
|
|
1927
2423
|
if (!bringsInBlocks(transactions)) return null;
|
|
1928
2424
|
const mapping = new Mapping();
|
|
@@ -1957,7 +2453,7 @@ var BlockId = Extension8.create({
|
|
|
1957
2453
|
}
|
|
1958
2454
|
});
|
|
1959
2455
|
var webUrl = (raw) => raw && /^https?:\/\/\S+$/i.test(raw) ? raw : null;
|
|
1960
|
-
var ReferenceNode =
|
|
2456
|
+
var ReferenceNode = Node3.create({
|
|
1961
2457
|
name: "reference",
|
|
1962
2458
|
group: "inline",
|
|
1963
2459
|
inline: true,
|
|
@@ -1996,7 +2492,7 @@ var ReferenceNode = Node2.create({
|
|
|
1996
2492
|
return ReactNodeViewRenderer2(({ node, editor, getPos }) => {
|
|
1997
2493
|
const uri = String(node.attrs.uri ?? "");
|
|
1998
2494
|
const href = typeof node.attrs.href === "string" && node.attrs.href ? node.attrs.href : void 0;
|
|
1999
|
-
return /* @__PURE__ */
|
|
2495
|
+
return /* @__PURE__ */ jsx9(
|
|
2000
2496
|
NodeViewWrapper2,
|
|
2001
2497
|
{
|
|
2002
2498
|
as: "span",
|
|
@@ -2007,13 +2503,13 @@ var ReferenceNode = Node2.create({
|
|
|
2007
2503
|
event.preventDefault();
|
|
2008
2504
|
event.stopPropagation();
|
|
2009
2505
|
},
|
|
2010
|
-
children: uri ? /* @__PURE__ */
|
|
2506
|
+
children: uri ? /* @__PURE__ */ jsx9(View, { uri, ...href ? { href } : {} }) : /* @__PURE__ */ jsx9("span", { children: href })
|
|
2011
2507
|
}
|
|
2012
2508
|
);
|
|
2013
2509
|
});
|
|
2014
2510
|
}
|
|
2015
2511
|
});
|
|
2016
|
-
var UnknownBlock =
|
|
2512
|
+
var UnknownBlock = Node3.create({
|
|
2017
2513
|
name: "unknownBlock",
|
|
2018
2514
|
group: "block",
|
|
2019
2515
|
atom: true,
|
|
@@ -2038,7 +2534,7 @@ var UnknownBlock = Node2.create({
|
|
|
2038
2534
|
function UnknownBlockView({ node }) {
|
|
2039
2535
|
const source = node.attrs.source;
|
|
2040
2536
|
const text = String(node.attrs.text ?? "");
|
|
2041
|
-
return /* @__PURE__ */
|
|
2537
|
+
return /* @__PURE__ */ jsx9(
|
|
2042
2538
|
NodeViewWrapper2,
|
|
2043
2539
|
{
|
|
2044
2540
|
"data-block-id": source?.id,
|
|
@@ -2048,7 +2544,7 @@ function UnknownBlockView({ node }) {
|
|
|
2048
2544
|
}
|
|
2049
2545
|
);
|
|
2050
2546
|
}
|
|
2051
|
-
var AttachmentNode =
|
|
2547
|
+
var AttachmentNode = Node3.create({
|
|
2052
2548
|
name: "attachment",
|
|
2053
2549
|
group: "block",
|
|
2054
2550
|
atom: true,
|
|
@@ -2078,7 +2574,7 @@ var AttachmentNode = Node2.create({
|
|
|
2078
2574
|
addNodeView() {
|
|
2079
2575
|
const View = this.options.view;
|
|
2080
2576
|
if (!View) return null;
|
|
2081
|
-
return ReactNodeViewRenderer2(({ node }) => /* @__PURE__ */
|
|
2577
|
+
return ReactNodeViewRenderer2(({ node }) => /* @__PURE__ */ jsx9(NodeViewWrapper2, { className: "my-2", children: /* @__PURE__ */ jsx9(View, { attrs: node.attrs }) }));
|
|
2082
2578
|
}
|
|
2083
2579
|
});
|
|
2084
2580
|
var TICK = "checklistTick";
|
|
@@ -2147,7 +2643,7 @@ function listItemView(editor, node, view, getPos) {
|
|
|
2147
2643
|
}
|
|
2148
2644
|
};
|
|
2149
2645
|
}
|
|
2150
|
-
var Checklist =
|
|
2646
|
+
var Checklist = Extension11.create({
|
|
2151
2647
|
name: "checklist",
|
|
2152
2648
|
// Before the list item's own Enter and Backspace.
|
|
2153
2649
|
priority: 101,
|
|
@@ -2212,14 +2708,14 @@ var Checklist = Extension8.create({
|
|
|
2212
2708
|
addProseMirrorPlugins() {
|
|
2213
2709
|
const editor = this.editor;
|
|
2214
2710
|
return [
|
|
2215
|
-
new
|
|
2216
|
-
key: new
|
|
2711
|
+
new Plugin8({
|
|
2712
|
+
key: new PluginKey9("checklist"),
|
|
2217
2713
|
props: { nodeViews: { listItem: (node, view, getPos) => listItemView(editor, node, view, getPos) } }
|
|
2218
2714
|
})
|
|
2219
2715
|
];
|
|
2220
2716
|
}
|
|
2221
2717
|
});
|
|
2222
|
-
var Callout =
|
|
2718
|
+
var Callout = Extension11.create({
|
|
2223
2719
|
name: "callout",
|
|
2224
2720
|
addGlobalAttributes() {
|
|
2225
2721
|
return [
|
|
@@ -2240,13 +2736,18 @@ var Callout = Extension8.create({
|
|
|
2240
2736
|
export {
|
|
2241
2737
|
AttachmentNode,
|
|
2242
2738
|
BlockId,
|
|
2739
|
+
COMPOSE_EDITOR_CLASSES,
|
|
2243
2740
|
Callout,
|
|
2244
2741
|
CaptionedReference,
|
|
2245
2742
|
Checklist,
|
|
2246
2743
|
CodeBlockColours,
|
|
2744
|
+
CommentHighlights,
|
|
2745
|
+
ComposeBox,
|
|
2746
|
+
ComposeKeys,
|
|
2247
2747
|
EditorBlockHandle,
|
|
2248
2748
|
EditorTableControls,
|
|
2249
2749
|
FORMATS,
|
|
2750
|
+
InlineText,
|
|
2250
2751
|
KeptSelection,
|
|
2251
2752
|
LinkChips,
|
|
2252
2753
|
PastedImages,
|
|
@@ -2261,10 +2762,13 @@ export {
|
|
|
2261
2762
|
SlashCommands,
|
|
2262
2763
|
UnknownBlock,
|
|
2263
2764
|
UrgentPersonMention,
|
|
2765
|
+
anchorOfSelection,
|
|
2264
2766
|
appendTableColumn,
|
|
2265
2767
|
appendTableRow,
|
|
2266
2768
|
applyFormat,
|
|
2267
2769
|
blockDropCursor,
|
|
2770
|
+
commentElement,
|
|
2771
|
+
commentPlace,
|
|
2268
2772
|
deleteBlock,
|
|
2269
2773
|
deleteTableColumn,
|
|
2270
2774
|
deleteTableRow,
|
|
@@ -2278,16 +2782,20 @@ export {
|
|
|
2278
2782
|
isReferenceMenuOpen,
|
|
2279
2783
|
isSuggestionActive,
|
|
2280
2784
|
isSuggestionOpen,
|
|
2785
|
+
keepSelection,
|
|
2281
2786
|
moveBlock,
|
|
2282
2787
|
normalizeHref,
|
|
2283
2788
|
pastedImageName,
|
|
2284
2789
|
pastedImages,
|
|
2285
2790
|
peopleMenu,
|
|
2791
|
+
quoteText,
|
|
2286
2792
|
referenceAtSelection,
|
|
2287
2793
|
referenceCardPlacements,
|
|
2288
2794
|
referenceMenu,
|
|
2289
2795
|
referenceMenuClick,
|
|
2290
2796
|
refreshLinkChips,
|
|
2797
|
+
releaseSelection,
|
|
2798
|
+
setCommentAnchors,
|
|
2291
2799
|
setReferenceCard,
|
|
2292
2800
|
setReferenceCardAt,
|
|
2293
2801
|
startBlockDrag,
|