@threadlabs/looma 0.23.21 → 0.23.22
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/components/shared/overlay.js +1 -1
- package/components/ui-image/ui-image.html +177 -0
- package/components/ui-image/ui-image.js +107 -0
- package/components/ui-menu/ui-menu.js +1 -1
- package/components/ui-popover/ui-popover.js +4 -1
- package/components/ui-separator/ui-separator.html +18 -0
- package/dist/index.js +24 -23
- package/editor/chunks/extensions.js +633 -20
- package/editor/extensions/block-selection.d.ts +6 -0
- package/editor/extensions/expand.d.ts +31 -0
- package/editor/extensions/image.d.ts +12 -0
- package/editor/extensions/index.d.ts +4 -1
- package/editor/extensions/index.js +2 -2
- package/editor/extensions/preset.d.ts +8 -0
- package/editor/extensions/slash-command.d.ts +31 -3
- package/editor/extensions/table-of-contents.d.ts +58 -0
- package/editor/index.js +2 -2
- package/package.json +1 -1
- package/styles/ui-image.css +153 -0
- package/styles/ui-separator.css +16 -0
- package/vanilla/UiImage.d.ts +21 -0
- package/vanilla/UiImage.js +84 -0
- package/vanilla/UiSeparator.d.ts +2 -0
- package/vanilla/UiSeparator.js +10 -2
- package/vanilla/index.js +1 -0
- package/vue/UiImage.d.ts +100 -0
- package/vue/UiImage.js +2 -0
- package/vue/UiImage.vue +463 -0
- package/vue/UiSeparator.d.ts +18 -0
- package/vue/UiSeparator.vue +66 -1
- package/vue/UiSidebar.d.ts +1 -1
- package/vue/chunks/UiImage.js +313 -0
- package/vue/chunks/UiSeparator.js +79 -22
- package/vue/components.css +169 -9
- package/vue/editor/LoomaEditor.d.ts +19 -2
- package/vue/editor/divider.d.ts +6 -0
- package/vue/editor/expand.d.ts +7 -0
- package/vue/editor/image-controls.d.ts +19 -0
- package/vue/editor/image-delivery.d.ts +2 -2
- package/vue/editor/image.d.ts +7 -0
- package/vue/editor/index.d.ts +1 -1
- package/vue/editor/index.js +1188 -52
- package/vue/editor/table-of-contents.d.ts +7 -0
- package/vue/index.d.ts +1 -0
- package/vue/index.js +2 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { n as TABLE_CELL_BACKGROUND_PRESETS } from "./table-backgrounds.js";
|
|
2
|
-
import { Extension, Mark, Node as Node$1, callOrReturn, canInsertNode, combineTransactionSteps, escapeForRegEx, findChildren, findChildrenInRange, findParentNodeClosestToPos, getAttributes, getChangedRanges, getExtensionField, getMarksBetween, isNodeEmpty, isNodeSelection, markInputRule, markPasteRule, mergeAttributes, nodeInputRule, textInputRule, textblockTypeInputRule, wrappingInputRule } from "@tiptap/core";
|
|
2
|
+
import { Extension, Mark, Node as Node$1, callOrReturn, canInsertNode, combineTransactionSteps, escapeForRegEx, findChildren, findChildrenInRange, findParentNodeClosestToPos, getAttributes, getChangedRanges, getExtensionField, getMarksBetween, getText, getTextSerializersFromSchema, isNodeEmpty, isNodeSelection, markInputRule, markPasteRule, mergeAttributes, nodeInputRule, textInputRule, textblockTypeInputRule, wrappingInputRule } from "@tiptap/core";
|
|
3
3
|
import { NodeSelection, Plugin, PluginKey, Selection, TextSelection } from "@tiptap/pm/state";
|
|
4
4
|
import { Decoration, DecorationSet } from "@tiptap/pm/view";
|
|
5
|
+
import { DOMParser, DOMSerializer, Fragment, Node as Node$2, Slice } from "@tiptap/pm/model";
|
|
5
6
|
import { history, redo, undo } from "@tiptap/pm/history";
|
|
6
7
|
import { dropCursor } from "@tiptap/pm/dropcursor";
|
|
7
8
|
import { gapCursor } from "@tiptap/pm/gapcursor";
|
|
8
9
|
import { createLowlight } from "lowlight";
|
|
9
|
-
import { DOMParser, Node as Node$2, Slice } from "@tiptap/pm/model";
|
|
10
10
|
import { Mapping } from "@tiptap/pm/transform";
|
|
11
11
|
import MarkdownIt from "markdown-it";
|
|
12
12
|
import { CellSelection, TableMap, addColumn, addColumnAfter, addColumnBefore, addRow, addRowAfter, addRowBefore, cellAround, columnResizing, deleteCellSelection, deleteColumn, deleteRow, deleteTable, fixTables, goToNextCell, mergeCells, moveTableColumn, moveTableRow, setCellAttr, splitCell, tableEditing, toggleHeader, toggleHeaderCell } from "@tiptap/pm/tables";
|
|
@@ -277,6 +277,391 @@ var LoomaChip = Node$1.create({
|
|
|
277
277
|
}
|
|
278
278
|
});
|
|
279
279
|
//#endregion
|
|
280
|
+
//#region src/editor/extensions/expand.ts
|
|
281
|
+
/**
|
|
282
|
+
* Reveals collapsed ancestors before a host navigates to a document position.
|
|
283
|
+
* @contract Navigation changes presentation only, including in read-only mode.
|
|
284
|
+
*/
|
|
285
|
+
async function revealLoomaExpandAt(editor, position) {
|
|
286
|
+
const { node } = editor.view.domAtPos(position);
|
|
287
|
+
const target = node instanceof Element ? node : node.parentElement;
|
|
288
|
+
const pending = [];
|
|
289
|
+
target?.dispatchEvent(new CustomEvent("looma-editor-reveal", {
|
|
290
|
+
bubbles: true,
|
|
291
|
+
detail: { pending }
|
|
292
|
+
}));
|
|
293
|
+
await Promise.all(pending);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* A block container whose summary and initial expansion survive serialization.
|
|
297
|
+
* @ownership The document owns attributes/body; node views own reader toggles.
|
|
298
|
+
* @lifecycle Default views unregister their editor subscriptions on destroy.
|
|
299
|
+
*/
|
|
300
|
+
var LoomaExpand = Node$1.create({
|
|
301
|
+
name: "loomaExpand",
|
|
302
|
+
group: "block",
|
|
303
|
+
content: "block+",
|
|
304
|
+
defining: true,
|
|
305
|
+
isolating: true,
|
|
306
|
+
addOptions: () => ({ nodeView: null }),
|
|
307
|
+
addAttributes() {
|
|
308
|
+
return {
|
|
309
|
+
summary: {
|
|
310
|
+
default: "Details",
|
|
311
|
+
parseHTML: (element) => element.querySelector(":scope > summary")?.textContent ?? "Details",
|
|
312
|
+
renderHTML: () => ({})
|
|
313
|
+
},
|
|
314
|
+
open: {
|
|
315
|
+
default: false,
|
|
316
|
+
parseHTML: (element) => element.hasAttribute("open"),
|
|
317
|
+
renderHTML: () => ({})
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
},
|
|
321
|
+
parseHTML() {
|
|
322
|
+
return [{
|
|
323
|
+
tag: "details",
|
|
324
|
+
getContent: (element, schema) => {
|
|
325
|
+
if (!(element instanceof Element)) return Fragment.from(schema.nodes.paragraph.create());
|
|
326
|
+
const body = element.ownerDocument.createElement("div");
|
|
327
|
+
const authoredBody = element.querySelector(":scope > [data-looma-expand-body]");
|
|
328
|
+
for (const child of (authoredBody ?? element).childNodes) {
|
|
329
|
+
if (child instanceof Element && child.localName === "summary") continue;
|
|
330
|
+
body.append(child.cloneNode(true));
|
|
331
|
+
}
|
|
332
|
+
const content = DOMParser.fromSchema(schema).parse(body).content;
|
|
333
|
+
return content.size ? content : Fragment.from(schema.nodes.paragraph.create());
|
|
334
|
+
}
|
|
335
|
+
}];
|
|
336
|
+
},
|
|
337
|
+
renderHTML({ node }) {
|
|
338
|
+
return [
|
|
339
|
+
"details",
|
|
340
|
+
{
|
|
341
|
+
"data-looma-expand": "",
|
|
342
|
+
...node.attrs.open ? { open: "" } : {}
|
|
343
|
+
},
|
|
344
|
+
[
|
|
345
|
+
"summary",
|
|
346
|
+
{},
|
|
347
|
+
String(node.attrs.summary)
|
|
348
|
+
],
|
|
349
|
+
[
|
|
350
|
+
"div",
|
|
351
|
+
{ "data-looma-expand-body": "" },
|
|
352
|
+
0
|
|
353
|
+
]
|
|
354
|
+
];
|
|
355
|
+
},
|
|
356
|
+
renderText({ node }) {
|
|
357
|
+
return `${node.attrs.summary}\n${getText(node, { textSerializers: getTextSerializersFromSchema(node.type.schema) })}`;
|
|
358
|
+
},
|
|
359
|
+
addCommands() {
|
|
360
|
+
return {
|
|
361
|
+
insertLoomaExpand: (attributes = {}) => ({ chain, state, dispatch }) => {
|
|
362
|
+
const from = state.selection.from;
|
|
363
|
+
const content = {
|
|
364
|
+
type: this.name,
|
|
365
|
+
attrs: {
|
|
366
|
+
summary: attributes.summary ?? "Details",
|
|
367
|
+
open: attributes.open === true
|
|
368
|
+
},
|
|
369
|
+
content: [{ type: "paragraph" }]
|
|
370
|
+
};
|
|
371
|
+
if (!dispatch) return chain().insertContent(content).run();
|
|
372
|
+
return chain().insertContent(content).command(({ tr, commands }) => {
|
|
373
|
+
let body = -1;
|
|
374
|
+
tr.doc.descendants((node, position) => {
|
|
375
|
+
if (node.type.name === this.name && position >= from - 1 && body < 0) body = position + 2;
|
|
376
|
+
});
|
|
377
|
+
return body >= 0 && commands.setTextSelection(body);
|
|
378
|
+
}).run();
|
|
379
|
+
},
|
|
380
|
+
exitLoomaExpand: () => ({ state, chain }) => {
|
|
381
|
+
const { $from } = state.selection;
|
|
382
|
+
for (let depth = $from.depth; depth > 0; depth--) {
|
|
383
|
+
if ($from.node(depth).type.name !== this.name) continue;
|
|
384
|
+
const after = $from.after(depth);
|
|
385
|
+
return chain().insertContentAt(after, { type: "paragraph" }).setTextSelection(after + 1).run();
|
|
386
|
+
}
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
},
|
|
391
|
+
addExtensions() {
|
|
392
|
+
return [Extension.create({
|
|
393
|
+
name: "loomaExpandExit",
|
|
394
|
+
priority: 110,
|
|
395
|
+
addKeyboardShortcuts() {
|
|
396
|
+
return { "Mod-Enter": () => this.editor.commands.exitLoomaExpand() };
|
|
397
|
+
}
|
|
398
|
+
})];
|
|
399
|
+
},
|
|
400
|
+
addNodeView() {
|
|
401
|
+
if (this.options.nodeView) return this.options.nodeView;
|
|
402
|
+
return ({ editor, node }) => {
|
|
403
|
+
const dom = document.createElement("details");
|
|
404
|
+
dom.dataset.loomaExpand = "";
|
|
405
|
+
const summary = document.createElement("summary");
|
|
406
|
+
summary.contentEditable = "false";
|
|
407
|
+
const contentDOM = document.createElement("div");
|
|
408
|
+
contentDOM.dataset.loomaExpandBody = "";
|
|
409
|
+
dom.append(summary, contentDOM);
|
|
410
|
+
let current = node;
|
|
411
|
+
let editable = editor.isEditable;
|
|
412
|
+
dom.open = editable || Boolean(node.attrs.open);
|
|
413
|
+
summary.textContent = node.attrs.summary;
|
|
414
|
+
const reveal = () => {
|
|
415
|
+
dom.open = true;
|
|
416
|
+
};
|
|
417
|
+
const refresh = () => {
|
|
418
|
+
if (editable !== editor.isEditable) {
|
|
419
|
+
editable = editor.isEditable;
|
|
420
|
+
dom.open = editable || Boolean(current.attrs.open);
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
dom.addEventListener("looma-editor-reveal", reveal);
|
|
424
|
+
editor.on("update", refresh);
|
|
425
|
+
return {
|
|
426
|
+
dom,
|
|
427
|
+
contentDOM,
|
|
428
|
+
update(next) {
|
|
429
|
+
if (next.type !== current.type) return false;
|
|
430
|
+
if (next.attrs.open !== current.attrs.open) dom.open = editor.isEditable || Boolean(next.attrs.open);
|
|
431
|
+
current = next;
|
|
432
|
+
summary.textContent = next.attrs.summary;
|
|
433
|
+
refresh();
|
|
434
|
+
return true;
|
|
435
|
+
},
|
|
436
|
+
stopEvent: (event) => summary.contains(event.target),
|
|
437
|
+
ignoreMutation: (mutation) => mutation.type !== "selection" && !contentDOM.contains(mutation.target),
|
|
438
|
+
destroy() {
|
|
439
|
+
dom.removeEventListener("looma-editor-reveal", reveal);
|
|
440
|
+
editor.off("update", refresh);
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
//#endregion
|
|
447
|
+
//#region src/editor/extensions/table-of-contents.ts
|
|
448
|
+
/** Normalize loaded configuration without persisting unsupported presentation values. */
|
|
449
|
+
function normalizeTableOfContentsConfig(attributes) {
|
|
450
|
+
return {
|
|
451
|
+
format: attributes.format === "bulleted" || attributes.format === "numbered" ? attributes.format : "plain",
|
|
452
|
+
depth: attributes.depth === 1 || attributes.depth === 2 ? attributes.depth : 3
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Derives nonempty headings throughout the document, independent of TOC placement.
|
|
457
|
+
* @contract Depth is a maximum heading level. Relative nesting follows existing
|
|
458
|
+
* ancestors rather than inserting artificial entries for skipped levels.
|
|
459
|
+
*/
|
|
460
|
+
function getTableOfContentsEntries(doc, depth = 3) {
|
|
461
|
+
const entries = [];
|
|
462
|
+
const ancestors = [];
|
|
463
|
+
doc.descendants((node, position) => {
|
|
464
|
+
if (node.type.name !== "heading" || node.attrs.level > depth || !node.textContent.trim()) return;
|
|
465
|
+
const level = Number(node.attrs.level);
|
|
466
|
+
while (ancestors.length && ancestors[ancestors.length - 1] >= level) ancestors.pop();
|
|
467
|
+
entries.push({
|
|
468
|
+
id: String(node.attrs.id ?? ""),
|
|
469
|
+
text: node.textContent.trim(),
|
|
470
|
+
level,
|
|
471
|
+
depth: ancestors.length,
|
|
472
|
+
position
|
|
473
|
+
});
|
|
474
|
+
ancestors.push(level);
|
|
475
|
+
});
|
|
476
|
+
return entries;
|
|
477
|
+
}
|
|
478
|
+
/** Shared nesting for semantic HTML and the adapter's component composition. */
|
|
479
|
+
function tableOfContentsTree(entries) {
|
|
480
|
+
const roots = [];
|
|
481
|
+
const parents = [];
|
|
482
|
+
for (const entry of entries) {
|
|
483
|
+
const branch = {
|
|
484
|
+
entry,
|
|
485
|
+
children: []
|
|
486
|
+
};
|
|
487
|
+
parents.length = entry.depth;
|
|
488
|
+
(parents[entry.depth - 1]?.children ?? roots).push(branch);
|
|
489
|
+
parents.push(branch);
|
|
490
|
+
}
|
|
491
|
+
return roots;
|
|
492
|
+
}
|
|
493
|
+
function anchorTransaction(state) {
|
|
494
|
+
let hasToc = false;
|
|
495
|
+
const headings = [];
|
|
496
|
+
state.doc.descendants((node, position) => {
|
|
497
|
+
if (node.type.name === "loomaTableOfContents") hasToc = true;
|
|
498
|
+
if (node.type.name === "heading") headings.push({
|
|
499
|
+
node,
|
|
500
|
+
position
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
if (!hasToc) return null;
|
|
504
|
+
const reserved = new Set(headings.map(({ node }) => String(node.attrs.id ?? "")).filter(Boolean));
|
|
505
|
+
const used = /* @__PURE__ */ new Set();
|
|
506
|
+
const transaction = state.tr;
|
|
507
|
+
let sequence = 1;
|
|
508
|
+
for (const { node, position } of headings) {
|
|
509
|
+
let id = typeof node.attrs.id === "string" ? node.attrs.id : "";
|
|
510
|
+
if (!id || /\s/.test(id) || used.has(id)) {
|
|
511
|
+
do
|
|
512
|
+
id = `looma-heading-${sequence++}`;
|
|
513
|
+
while (reserved.has(id) || used.has(id));
|
|
514
|
+
transaction.setNodeMarkup(position, void 0, {
|
|
515
|
+
...node.attrs,
|
|
516
|
+
id
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
used.add(id);
|
|
520
|
+
}
|
|
521
|
+
return transaction.docChanged ? transaction : null;
|
|
522
|
+
}
|
|
523
|
+
var LoomaHeadingAnchors = Extension.create({
|
|
524
|
+
name: "loomaHeadingAnchors",
|
|
525
|
+
addGlobalAttributes() {
|
|
526
|
+
return [{
|
|
527
|
+
types: ["heading"],
|
|
528
|
+
attributes: { id: { default: null } }
|
|
529
|
+
}];
|
|
530
|
+
},
|
|
531
|
+
onCreate() {
|
|
532
|
+
const transaction = anchorTransaction(this.editor.state);
|
|
533
|
+
if (transaction) this.editor.view.dispatch(transaction.setMeta("addToHistory", false));
|
|
534
|
+
},
|
|
535
|
+
addProseMirrorPlugins() {
|
|
536
|
+
return [new Plugin({ appendTransaction: (transactions, _oldState, state) => transactions.some((transaction) => transaction.docChanged) ? anchorTransaction(state) : null })];
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
function contentsHtml(doc, config) {
|
|
540
|
+
const branches = tableOfContentsTree(getTableOfContentsEntries(doc, config.depth));
|
|
541
|
+
const list = (items) => [
|
|
542
|
+
config.format === "plain" ? "div" : config.format === "numbered" ? "ol" : "ul",
|
|
543
|
+
{ role: "list" },
|
|
544
|
+
...items.map(({ entry, children }) => [
|
|
545
|
+
config.format === "plain" ? "div" : "li",
|
|
546
|
+
{ role: "listitem" },
|
|
547
|
+
[
|
|
548
|
+
"a",
|
|
549
|
+
{ href: `#${entry.id}` },
|
|
550
|
+
entry.text
|
|
551
|
+
],
|
|
552
|
+
...children.length ? [list(children)] : []
|
|
553
|
+
])
|
|
554
|
+
];
|
|
555
|
+
return [
|
|
556
|
+
"nav",
|
|
557
|
+
{
|
|
558
|
+
"data-looma-toc": "",
|
|
559
|
+
"data-format": config.format,
|
|
560
|
+
"data-depth": config.depth,
|
|
561
|
+
"aria-label": "Table of contents"
|
|
562
|
+
},
|
|
563
|
+
[
|
|
564
|
+
"strong",
|
|
565
|
+
{},
|
|
566
|
+
"Table of contents"
|
|
567
|
+
],
|
|
568
|
+
branches.length ? list(branches) : [
|
|
569
|
+
"p",
|
|
570
|
+
{},
|
|
571
|
+
"Add headings to build your table of contents."
|
|
572
|
+
]
|
|
573
|
+
];
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Scrolls within this editor so multiple documents cannot cross-navigate by ID.
|
|
577
|
+
* @contract Reader navigation does not edit content or invoke link-editing UI.
|
|
578
|
+
*/
|
|
579
|
+
async function navigateTableOfContents(editor, id) {
|
|
580
|
+
const target = [...editor.view.dom.querySelectorAll("h1[id], h2[id], h3[id]")].find((heading) => heading.id === id);
|
|
581
|
+
if (!target) return;
|
|
582
|
+
const entry = getTableOfContentsEntries(editor.state.doc).find((heading) => heading.id === id);
|
|
583
|
+
if (entry) await revealLoomaExpandAt(editor, entry.position + 1);
|
|
584
|
+
if (!target.isConnected || editor.isDestroyed) return;
|
|
585
|
+
target.scrollIntoView({
|
|
586
|
+
block: "start",
|
|
587
|
+
behavior: "auto"
|
|
588
|
+
});
|
|
589
|
+
target.tabIndex = -1;
|
|
590
|
+
target.focus({ preventScroll: true });
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Automatic whole-document navigation with durable configuration only.
|
|
594
|
+
* @ownership The schema owns configuration/anchors; node views derive entries.
|
|
595
|
+
* @lifecycle Headless views subscribe to transactions and unsubscribe on destroy.
|
|
596
|
+
*/
|
|
597
|
+
var LoomaTableOfContents = Node$1.create({
|
|
598
|
+
name: "loomaTableOfContents",
|
|
599
|
+
group: "block",
|
|
600
|
+
atom: true,
|
|
601
|
+
selectable: true,
|
|
602
|
+
isolating: true,
|
|
603
|
+
addOptions: () => ({ nodeView: null }),
|
|
604
|
+
addExtensions: () => [LoomaHeadingAnchors],
|
|
605
|
+
addAttributes() {
|
|
606
|
+
return {
|
|
607
|
+
format: {
|
|
608
|
+
default: "plain",
|
|
609
|
+
parseHTML: (element) => normalizeTableOfContentsConfig({ format: element.getAttribute("data-format") }).format,
|
|
610
|
+
renderHTML: () => ({})
|
|
611
|
+
},
|
|
612
|
+
depth: {
|
|
613
|
+
default: 3,
|
|
614
|
+
parseHTML: (element) => normalizeTableOfContentsConfig({ depth: Number(element.getAttribute("data-depth")) }).depth,
|
|
615
|
+
renderHTML: () => ({})
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
},
|
|
619
|
+
parseHTML: () => [{ tag: "nav[data-looma-toc]" }],
|
|
620
|
+
renderHTML({ node }) {
|
|
621
|
+
return contentsHtml(this.editor?.view?.state.doc ?? node, normalizeTableOfContentsConfig(node.attrs));
|
|
622
|
+
},
|
|
623
|
+
addCommands() {
|
|
624
|
+
return { insertLoomaTableOfContents: (config = {}) => ({ commands }) => commands.insertContent({
|
|
625
|
+
type: this.name,
|
|
626
|
+
attrs: normalizeTableOfContentsConfig(config)
|
|
627
|
+
}) };
|
|
628
|
+
},
|
|
629
|
+
addNodeView() {
|
|
630
|
+
if (this.options.nodeView) return this.options.nodeView;
|
|
631
|
+
return ({ editor, node }) => {
|
|
632
|
+
const dom = document.createElement("div");
|
|
633
|
+
dom.contentEditable = "false";
|
|
634
|
+
let current = node;
|
|
635
|
+
const render = () => {
|
|
636
|
+
const { dom: content } = DOMSerializer.renderSpec(document, contentsHtml(editor.state.doc, normalizeTableOfContentsConfig(current.attrs)));
|
|
637
|
+
dom.replaceChildren(content);
|
|
638
|
+
};
|
|
639
|
+
dom.addEventListener("click", (event) => {
|
|
640
|
+
const anchor = event.target.closest("a");
|
|
641
|
+
if (!anchor) return;
|
|
642
|
+
event.preventDefault();
|
|
643
|
+
navigateTableOfContents(editor, anchor.getAttribute("href").slice(1));
|
|
644
|
+
});
|
|
645
|
+
editor.on("transaction", render);
|
|
646
|
+
render();
|
|
647
|
+
return {
|
|
648
|
+
dom,
|
|
649
|
+
update(next) {
|
|
650
|
+
if (next.type !== current.type) return false;
|
|
651
|
+
current = next;
|
|
652
|
+
render();
|
|
653
|
+
return true;
|
|
654
|
+
},
|
|
655
|
+
stopEvent: () => true,
|
|
656
|
+
ignoreMutation: () => true,
|
|
657
|
+
destroy: () => {
|
|
658
|
+
editor.off("transaction", render);
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
//#endregion
|
|
280
665
|
//#region ../../node_modules/.pnpm/@tiptap+extension-document@2.27.2_@tiptap+core@2.27.2_@tiptap+pm@2.27.2_/node_modules/@tiptap/extension-document/dist/index.js
|
|
281
666
|
/**
|
|
282
667
|
* The default document node which represents the top level node of the editor.
|
|
@@ -3104,6 +3489,45 @@ var Image = Node$1.create({
|
|
|
3104
3489
|
}
|
|
3105
3490
|
});
|
|
3106
3491
|
//#endregion
|
|
3492
|
+
//#region src/editor/extensions/image.ts
|
|
3493
|
+
/** Accepts only positive, integral CSS-pixel dimensions. */
|
|
3494
|
+
function normalizeImageDimension(value) {
|
|
3495
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : void 0;
|
|
3496
|
+
}
|
|
3497
|
+
/** Unknown legacy values retain ordinary block placement. */
|
|
3498
|
+
function normalizeImagePlacement(value) {
|
|
3499
|
+
return value === "center" || value === "wrap-left" || value === "wrap-right" ? value : "block";
|
|
3500
|
+
}
|
|
3501
|
+
/** Portable image attributes shared by every editor adapter.
|
|
3502
|
+
* @contract Keeps Tiptap's existing `image` name and insertion command. Delivery
|
|
3503
|
+
* attributes stay transient; dimensions and placement survive HTML and JSON.
|
|
3504
|
+
*/
|
|
3505
|
+
var LoomaImage = Image.extend({ addAttributes() {
|
|
3506
|
+
return {
|
|
3507
|
+
...this.parent?.(),
|
|
3508
|
+
width: {
|
|
3509
|
+
default: null,
|
|
3510
|
+
parseHTML: (element) => normalizeImageDimension(Number(element.getAttribute("width"))) ?? null,
|
|
3511
|
+
renderHTML: (attrs) => normalizeImageDimension(attrs.width) ? { width: attrs.width } : {}
|
|
3512
|
+
},
|
|
3513
|
+
height: {
|
|
3514
|
+
default: null,
|
|
3515
|
+
parseHTML: (element) => normalizeImageDimension(Number(element.getAttribute("height"))) ?? null,
|
|
3516
|
+
renderHTML: (attrs) => normalizeImageDimension(attrs.height) ? { height: attrs.height } : {}
|
|
3517
|
+
},
|
|
3518
|
+
responsive: {
|
|
3519
|
+
default: null,
|
|
3520
|
+
parseHTML: (element) => element.hasAttribute("data-looma-responsive") || null,
|
|
3521
|
+
renderHTML: (attrs) => attrs.responsive === true ? { "data-looma-responsive": "" } : {}
|
|
3522
|
+
},
|
|
3523
|
+
placement: {
|
|
3524
|
+
default: "block",
|
|
3525
|
+
parseHTML: (element) => normalizeImagePlacement(element.getAttribute("data-placement")),
|
|
3526
|
+
renderHTML: (attrs) => normalizeImagePlacement(attrs.placement) === "block" ? {} : { "data-placement": normalizeImagePlacement(attrs.placement) }
|
|
3527
|
+
}
|
|
3528
|
+
};
|
|
3529
|
+
} });
|
|
3530
|
+
//#endregion
|
|
3107
3531
|
//#region ../../node_modules/.pnpm/@tiptap+extension-highlight@2.27.2_@tiptap+core@2.27.2_@tiptap+pm@2.27.2_/node_modules/@tiptap/extension-highlight/dist/index.js
|
|
3108
3532
|
/**
|
|
3109
3533
|
* Matches a highlight to a ==highlight== on input.
|
|
@@ -5550,6 +5974,33 @@ var TableRow = Node$1.create({
|
|
|
5550
5974
|
}
|
|
5551
5975
|
});
|
|
5552
5976
|
//#endregion
|
|
5977
|
+
//#region src/editor/extensions/block-selection.ts
|
|
5978
|
+
/** Selects atomic visual blocks by pointer and keeps text Tab input in the document.
|
|
5979
|
+
* @contract List and table keymaps run first; Shift-Tab outside a list remains
|
|
5980
|
+
* browser navigation so keyboard users can leave the editing surface.
|
|
5981
|
+
*/
|
|
5982
|
+
var LoomaBlockSelection = Extension.create({
|
|
5983
|
+
name: "loomaBlockSelection",
|
|
5984
|
+
priority: 50,
|
|
5985
|
+
addKeyboardShortcuts() {
|
|
5986
|
+
return { Tab: () => {
|
|
5987
|
+
const editor = this.editor;
|
|
5988
|
+
if (!editor.isEditable || !(editor.state.selection instanceof TextSelection)) return false;
|
|
5989
|
+
if (editor.isActive("table")) return false;
|
|
5990
|
+
if (editor.isActive("listItem") || editor.isActive("taskItem")) return true;
|
|
5991
|
+
return editor.commands.insertContent(" ");
|
|
5992
|
+
} };
|
|
5993
|
+
},
|
|
5994
|
+
addProseMirrorPlugins() {
|
|
5995
|
+
return [new Plugin({ props: { handleClickOn: (view, _position, node, nodePosition, _event, direct) => {
|
|
5996
|
+
if (!view.editable || !direct || !["image", "horizontalRule"].includes(node.type.name)) return false;
|
|
5997
|
+
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePosition)));
|
|
5998
|
+
view.focus();
|
|
5999
|
+
return true;
|
|
6000
|
+
} } })];
|
|
6001
|
+
}
|
|
6002
|
+
});
|
|
6003
|
+
//#endregion
|
|
5553
6004
|
//#region src/editor/extensions/list-behavior.ts
|
|
5554
6005
|
/**
|
|
5555
6006
|
* Looma list behavior extension:
|
|
@@ -9342,7 +9793,8 @@ function getLoomaTableExtensions() {
|
|
|
9342
9793
|
* the code and explicit language stay in the document schema.
|
|
9343
9794
|
*/
|
|
9344
9795
|
function getDefaultEditorExtensions(options = {}) {
|
|
9345
|
-
const { placeholder = "Type “/” for commands, or start writing…", linkOpenOnClick = false, linkBaseUrl, imageInline = false, mention = createLoomaMentionExtension(), disableHighlight = false, codeLanguages, codeLowlight, codeBlockNodeView } = options;
|
|
9796
|
+
const { placeholder = "Type “/” for commands, or start writing…", linkOpenOnClick = false, linkBaseUrl, imageInline = false, imageNodeView, dividerNodeView, mention = createLoomaMentionExtension(), disableHighlight = false, codeLanguages, codeLowlight, codeBlockNodeView, tableOfContentsNodeView, expandNodeView } = options;
|
|
9797
|
+
const image = LoomaImage.configure({ inline: imageInline });
|
|
9346
9798
|
const codeBlock = LoomaCodeBlock.configure({ lowlight: codeLowlight ?? createLowlight(codeLanguages) });
|
|
9347
9799
|
return [
|
|
9348
9800
|
Document,
|
|
@@ -9365,7 +9817,9 @@ function getDefaultEditorExtensions(options = {}) {
|
|
|
9365
9817
|
Blockquote,
|
|
9366
9818
|
LoomaCallout,
|
|
9367
9819
|
LoomaChip,
|
|
9368
|
-
|
|
9820
|
+
LoomaExpand.configure({ nodeView: expandNodeView ?? null }),
|
|
9821
|
+
LoomaTableOfContents.configure({ nodeView: tableOfContentsNodeView ?? null }),
|
|
9822
|
+
dividerNodeView ? HorizontalRule.extend({ addNodeView: () => dividerNodeView }) : HorizontalRule,
|
|
9369
9823
|
HardBreak,
|
|
9370
9824
|
History,
|
|
9371
9825
|
Dropcursor,
|
|
@@ -9378,7 +9832,7 @@ function getDefaultEditorExtensions(options = {}) {
|
|
|
9378
9832
|
}
|
|
9379
9833
|
}),
|
|
9380
9834
|
...linkBaseUrl ? [createSiteRelativeLinks(linkBaseUrl)] : [],
|
|
9381
|
-
|
|
9835
|
+
imageNodeView ? image.extend({ addNodeView: () => imageNodeView }) : image,
|
|
9382
9836
|
(disableHighlight ? StoredOnlyHighlight : Highlight).configure({ multicolor: false }),
|
|
9383
9837
|
Code,
|
|
9384
9838
|
LoomaSmartPaste,
|
|
@@ -9391,7 +9845,8 @@ function getDefaultEditorExtensions(options = {}) {
|
|
|
9391
9845
|
...mention ? [mention] : [],
|
|
9392
9846
|
LoomaTableKit,
|
|
9393
9847
|
LoomaListBehavior,
|
|
9394
|
-
LoomaActiveBlock
|
|
9848
|
+
LoomaActiveBlock,
|
|
9849
|
+
LoomaBlockSelection
|
|
9395
9850
|
];
|
|
9396
9851
|
}
|
|
9397
9852
|
//#endregion
|
|
@@ -9833,7 +10288,8 @@ var CALLOUT_COMMANDS = [
|
|
|
9833
10288
|
* Builds Looma's default command policy as fresh objects for one editor.
|
|
9834
10289
|
* Image and link commands delegate their picker because Looma does not own
|
|
9835
10290
|
* upload, persistence, or destination search. Link appears only when a picker
|
|
9836
|
-
* callback is supplied, so a headless
|
|
10291
|
+
* callback is supplied. Image follows the same rule, so a headless inventory
|
|
10292
|
+
* has no dead picker actions.
|
|
9837
10293
|
*
|
|
9838
10294
|
* @ownership Returned command objects belong to the caller and are recreated
|
|
9839
10295
|
* per call so one editor cannot mutate another editor's command inventory.
|
|
@@ -9943,7 +10399,8 @@ function getDefaultSlashCommands(onOpenImagePicker, onOpenChipEditor, onOpenLink
|
|
|
9943
10399
|
"chip",
|
|
9944
10400
|
"label",
|
|
9945
10401
|
"badge",
|
|
9946
|
-
"tag"
|
|
10402
|
+
"tag",
|
|
10403
|
+
"status"
|
|
9947
10404
|
],
|
|
9948
10405
|
command: ({ editor, range }) => {
|
|
9949
10406
|
if (editor.chain().focus().deleteRange(range).setTextSelection(range.from).insertLoomaChip({ label: "" }).run()) onOpenChipEditor?.(editor, range.from);
|
|
@@ -9990,6 +10447,34 @@ function getDefaultSlashCommands(onOpenImagePicker, onOpenChipEditor, onOpenLink
|
|
|
9990
10447
|
insertTableAtRange(editor, range);
|
|
9991
10448
|
}
|
|
9992
10449
|
},
|
|
10450
|
+
{
|
|
10451
|
+
title: "Table of contents",
|
|
10452
|
+
description: "Automatic links to document headings",
|
|
10453
|
+
icon: "list",
|
|
10454
|
+
keywords: [
|
|
10455
|
+
"toc",
|
|
10456
|
+
"contents",
|
|
10457
|
+
"tableofcontents",
|
|
10458
|
+
"outline"
|
|
10459
|
+
],
|
|
10460
|
+
command: ({ editor, range }) => {
|
|
10461
|
+
editor.chain().focus().deleteRange(range).insertLoomaTableOfContents().run();
|
|
10462
|
+
}
|
|
10463
|
+
},
|
|
10464
|
+
{
|
|
10465
|
+
title: "Expand",
|
|
10466
|
+
description: "Collapsible section with a summary",
|
|
10467
|
+
icon: "chevron-down",
|
|
10468
|
+
keywords: [
|
|
10469
|
+
"expand",
|
|
10470
|
+
"toggle",
|
|
10471
|
+
"details",
|
|
10472
|
+
"collapse"
|
|
10473
|
+
],
|
|
10474
|
+
command: ({ editor, range }) => {
|
|
10475
|
+
editor.chain().focus().deleteRange(range).insertLoomaExpand().run();
|
|
10476
|
+
}
|
|
10477
|
+
},
|
|
9993
10478
|
{
|
|
9994
10479
|
title: "Divider",
|
|
9995
10480
|
description: "Horizontal rule",
|
|
@@ -10018,7 +10503,7 @@ function getDefaultSlashCommands(onOpenImagePicker, onOpenChipEditor, onOpenLink
|
|
|
10018
10503
|
onOpenLinkEditor();
|
|
10019
10504
|
}
|
|
10020
10505
|
}] : [],
|
|
10021
|
-
{
|
|
10506
|
+
...onOpenImagePicker ? [{
|
|
10022
10507
|
title: "Image",
|
|
10023
10508
|
description: "Upload an image",
|
|
10024
10509
|
icon: "image",
|
|
@@ -10032,8 +10517,87 @@ function getDefaultSlashCommands(onOpenImagePicker, onOpenChipEditor, onOpenLink
|
|
|
10032
10517
|
editor.chain().focus().deleteRange(range).run();
|
|
10033
10518
|
onOpenImagePicker?.();
|
|
10034
10519
|
}
|
|
10520
|
+
}] : []
|
|
10521
|
+
].map((command) => ({
|
|
10522
|
+
...command,
|
|
10523
|
+
id: command.title.toLowerCase().replaceAll(" ", "-"),
|
|
10524
|
+
group: CALLOUT_COMMANDS.some((callout) => callout.title === command.title) ? "Callouts" : [
|
|
10525
|
+
"Chip",
|
|
10526
|
+
"Inline code",
|
|
10527
|
+
"Link",
|
|
10528
|
+
"Image",
|
|
10529
|
+
"Table",
|
|
10530
|
+
"Table of contents",
|
|
10531
|
+
"Expand"
|
|
10532
|
+
].includes(command.title) ? "Insertions" : "Basic blocks",
|
|
10533
|
+
isAvailable: (context) => canRunDefaultCommand(command.title, context)
|
|
10534
|
+
})).sort((a, b) => [
|
|
10535
|
+
"Basic blocks",
|
|
10536
|
+
"Callouts",
|
|
10537
|
+
"Insertions"
|
|
10538
|
+
].indexOf(a.group) - [
|
|
10539
|
+
"Basic blocks",
|
|
10540
|
+
"Callouts",
|
|
10541
|
+
"Insertions"
|
|
10542
|
+
].indexOf(b.group));
|
|
10543
|
+
}
|
|
10544
|
+
function canRunDefaultCommand(title, { editor, range }) {
|
|
10545
|
+
const chain = editor.can().chain().deleteRange(range);
|
|
10546
|
+
switch (title) {
|
|
10547
|
+
case "Text": return editor.isActive("paragraph") || chain.setParagraph().run();
|
|
10548
|
+
case "Heading 1": return editor.isActive("heading", { level: 1 }) || chain.setHeading({ level: 1 }).run();
|
|
10549
|
+
case "Heading 2": return editor.isActive("heading", { level: 2 }) || chain.setHeading({ level: 2 }).run();
|
|
10550
|
+
case "Heading 3": return editor.isActive("heading", { level: 3 }) || chain.setHeading({ level: 3 }).run();
|
|
10551
|
+
case "Bullet list": return chain.toggleBulletList().run();
|
|
10552
|
+
case "Numbered list": return chain.toggleOrderedList().run();
|
|
10553
|
+
case "Checklist": return chain.toggleTaskList().run();
|
|
10554
|
+
case "Blockquote": return chain.toggleBlockquote().run();
|
|
10555
|
+
case "Info": return chain.setLoomaCallout("info").run();
|
|
10556
|
+
case "Note": return chain.setLoomaCallout("note").run();
|
|
10557
|
+
case "Warning": return chain.setLoomaCallout("warning").run();
|
|
10558
|
+
case "Chip": return chain.insertLoomaChip({ label: "" }).run();
|
|
10559
|
+
case "Inline code": return chain.toggleCode().run();
|
|
10560
|
+
case "Code block": return chain.toggleCodeBlock().run();
|
|
10561
|
+
case "Table": return chain.insertTable({
|
|
10562
|
+
rows: 3,
|
|
10563
|
+
cols: 3,
|
|
10564
|
+
withHeaderRow: true
|
|
10565
|
+
}).run();
|
|
10566
|
+
case "Table of contents": return chain.insertLoomaTableOfContents().run();
|
|
10567
|
+
case "Expand": return chain.insertLoomaExpand().run();
|
|
10568
|
+
case "Divider": return chain.setHorizontalRule().run();
|
|
10569
|
+
default: return chain.run();
|
|
10570
|
+
}
|
|
10571
|
+
}
|
|
10572
|
+
/**
|
|
10573
|
+
* Ranks exact names/aliases before partial matches, then matching categories.
|
|
10574
|
+
* Other ties retain inventory order.
|
|
10575
|
+
* @contract Capability checks run against the current range; a failing host
|
|
10576
|
+
* predicate omits that command rather than exposing an action that may destroy text.
|
|
10577
|
+
*/
|
|
10578
|
+
function filterLoomaSlashCommands(commands, query, context) {
|
|
10579
|
+
const term = query.toLowerCase().trim();
|
|
10580
|
+
return commands.map((command, index) => {
|
|
10581
|
+
const names = [
|
|
10582
|
+
command.title,
|
|
10583
|
+
...command.keywords,
|
|
10584
|
+
command.id ?? ""
|
|
10585
|
+
].map((name) => name.toLowerCase());
|
|
10586
|
+
const rank = !term || names.includes(term) ? 0 : names.some((name) => name.startsWith(term)) ? 1 : names.some((name) => name.includes(term)) ? 2 : 3;
|
|
10587
|
+
let available = true;
|
|
10588
|
+
if (context && command.isAvailable) try {
|
|
10589
|
+
available = command.isAvailable(context);
|
|
10590
|
+
} catch {
|
|
10591
|
+
available = false;
|
|
10035
10592
|
}
|
|
10036
|
-
|
|
10593
|
+
return {
|
|
10594
|
+
command,
|
|
10595
|
+
index,
|
|
10596
|
+
rank,
|
|
10597
|
+
groupMatch: Boolean(term && command.group?.toLowerCase().startsWith(term)),
|
|
10598
|
+
available
|
|
10599
|
+
};
|
|
10600
|
+
}).filter((item) => item.rank < 3 && item.available).sort((a, b) => a.rank - b.rank || Number(b.groupMatch) - Number(a.groupMatch) || a.index - b.index).map((item) => item.command);
|
|
10037
10601
|
}
|
|
10038
10602
|
var EMPTY_STATE = {
|
|
10039
10603
|
active: false,
|
|
@@ -10041,7 +10605,8 @@ var EMPTY_STATE = {
|
|
|
10041
10605
|
selectedIndex: 0,
|
|
10042
10606
|
query: "",
|
|
10043
10607
|
rect: null,
|
|
10044
|
-
select: null
|
|
10608
|
+
select: null,
|
|
10609
|
+
highlight: null
|
|
10045
10610
|
};
|
|
10046
10611
|
/**
|
|
10047
10612
|
* Framework-neutral slash-command extension used by the turnkey editor.
|
|
@@ -10058,10 +10623,25 @@ var LoomaSlashCommand = Extension.create({
|
|
|
10058
10623
|
addOptions() {
|
|
10059
10624
|
return { commands: getDefaultSlashCommands() };
|
|
10060
10625
|
},
|
|
10626
|
+
addStorage: () => ({ dismiss: () => {} }),
|
|
10627
|
+
addCommands() {
|
|
10628
|
+
return { dismissLoomaSlashMenu: () => ({ dispatch }) => {
|
|
10629
|
+
if (dispatch) this.storage.dismiss();
|
|
10630
|
+
return true;
|
|
10631
|
+
} };
|
|
10632
|
+
},
|
|
10061
10633
|
addProseMirrorPlugins() {
|
|
10062
10634
|
let selectedIndex = 0;
|
|
10063
10635
|
let currentProps = null;
|
|
10636
|
+
let generation = 0;
|
|
10637
|
+
let dismissed = null;
|
|
10638
|
+
const isCurrent = (props) => {
|
|
10639
|
+
const state = SuggestionPluginKey.getState(this.editor.state);
|
|
10640
|
+
return state?.active && state.query === props.query && state.range.from === props.range.from && state.range.to === props.range.to;
|
|
10641
|
+
};
|
|
10064
10642
|
const publish = (props) => {
|
|
10643
|
+
const revision = ++generation;
|
|
10644
|
+
const document = this.editor.state.doc;
|
|
10065
10645
|
if (!props) {
|
|
10066
10646
|
this.options.onStateChange?.({ ...EMPTY_STATE });
|
|
10067
10647
|
return;
|
|
@@ -10073,23 +10653,55 @@ var LoomaSlashCommand = Extension.create({
|
|
|
10073
10653
|
query: props.query,
|
|
10074
10654
|
rect: props.clientRect?.() ?? null,
|
|
10075
10655
|
select: (index) => {
|
|
10656
|
+
if (revision !== generation || props !== currentProps || document !== this.editor.state.doc || !this.editor.isEditable || !isCurrent(props)) return;
|
|
10076
10657
|
const item = props.items[index];
|
|
10077
|
-
if (item
|
|
10658
|
+
if (item && filterLoomaSlashCommands([item], "", {
|
|
10659
|
+
editor: this.editor,
|
|
10660
|
+
range: props.range
|
|
10661
|
+
}).length) props.command(item);
|
|
10662
|
+
},
|
|
10663
|
+
highlight: (index) => {
|
|
10664
|
+
if (revision !== generation || props !== currentProps || index < 0 || index >= props.items.length) return;
|
|
10665
|
+
selectedIndex = index;
|
|
10666
|
+
publish(props);
|
|
10078
10667
|
}
|
|
10079
10668
|
});
|
|
10080
10669
|
};
|
|
10670
|
+
this.storage.dismiss = () => {
|
|
10671
|
+
const range = SuggestionPluginKey.getState(this.editor.state)?.range;
|
|
10672
|
+
if (range) dismissed = {
|
|
10673
|
+
...range,
|
|
10674
|
+
document: this.editor.state.doc
|
|
10675
|
+
};
|
|
10676
|
+
currentProps = null;
|
|
10677
|
+
publish(null);
|
|
10678
|
+
};
|
|
10081
10679
|
return [Suggestion({
|
|
10082
10680
|
editor: this.editor,
|
|
10083
10681
|
char: "/",
|
|
10084
10682
|
allowSpaces: false,
|
|
10085
10683
|
startOfLine: false,
|
|
10086
|
-
|
|
10087
|
-
|
|
10088
|
-
const
|
|
10089
|
-
if (
|
|
10090
|
-
return
|
|
10684
|
+
allow: ({ state, range }) => {
|
|
10685
|
+
if (dismissed?.document === state.doc && dismissed.from === range.from && dismissed.to === range.to) return false;
|
|
10686
|
+
const { $from } = state.selection;
|
|
10687
|
+
for (let depth = $from.depth; depth >= 0; depth--) if ($from.node(depth).type.spec.code) return false;
|
|
10688
|
+
return !state.schema.marks.code?.isInSet(state.storedMarks ?? $from.marks());
|
|
10689
|
+
},
|
|
10690
|
+
items: ({ query, editor }) => {
|
|
10691
|
+
const range = SuggestionPluginKey.getState(editor.state)?.range ?? {
|
|
10692
|
+
from: editor.state.selection.from,
|
|
10693
|
+
to: editor.state.selection.to
|
|
10694
|
+
};
|
|
10695
|
+
return filterLoomaSlashCommands(this.options.commands, query, {
|
|
10696
|
+
editor,
|
|
10697
|
+
range
|
|
10698
|
+
});
|
|
10091
10699
|
},
|
|
10092
10700
|
command: ({ editor, range, props }) => {
|
|
10701
|
+
if (!editor.isEditable || !currentProps || !isCurrent(currentProps) || !this.options.commands.includes(props) || !filterLoomaSlashCommands([props], "", {
|
|
10702
|
+
editor,
|
|
10703
|
+
range
|
|
10704
|
+
}).length) return;
|
|
10093
10705
|
props.command({
|
|
10094
10706
|
editor,
|
|
10095
10707
|
range
|
|
@@ -10097,11 +10709,13 @@ var LoomaSlashCommand = Extension.create({
|
|
|
10097
10709
|
},
|
|
10098
10710
|
render: () => ({
|
|
10099
10711
|
onStart: (props) => {
|
|
10712
|
+
if (!isCurrent(props)) return;
|
|
10100
10713
|
currentProps = props;
|
|
10101
10714
|
selectedIndex = 0;
|
|
10102
10715
|
publish(props);
|
|
10103
10716
|
},
|
|
10104
10717
|
onUpdate: (props) => {
|
|
10718
|
+
if (!isCurrent(props)) return;
|
|
10105
10719
|
currentProps = props;
|
|
10106
10720
|
if (selectedIndex >= props.items.length) selectedIndex = 0;
|
|
10107
10721
|
publish(props);
|
|
@@ -10124,8 +10738,7 @@ var LoomaSlashCommand = Extension.create({
|
|
|
10124
10738
|
return true;
|
|
10125
10739
|
}
|
|
10126
10740
|
if (event.key === "Escape") {
|
|
10127
|
-
|
|
10128
|
-
publish(null);
|
|
10741
|
+
this.editor.commands.dismissLoomaSlashMenu();
|
|
10129
10742
|
return true;
|
|
10130
10743
|
}
|
|
10131
10744
|
return false;
|
|
@@ -10156,4 +10769,4 @@ function createLoomaSlashCommandExtension(options = {}) {
|
|
|
10156
10769
|
});
|
|
10157
10770
|
}
|
|
10158
10771
|
//#endregion
|
|
10159
|
-
export {
|
|
10772
|
+
export { LoomaImage as A, normalizeLoomaChipColor as B, siteRelativeHref as C, MAX_MENTION_RESULT_LIMIT as D, DEFAULT_MENTION_RESULT_LIMIT as E, normalizeTableOfContentsConfig as F, LOOMA_ACTIVE_BLOCK_TYPING_IDLE_MS as G, LoomaCallout as H, LoomaExpand as I, LoomaActiveBlock as K, revealLoomaExpandAt as L, normalizeImagePlacement as M, LoomaTableOfContents as N, filterLoomaMentionItems as O, getTableOfContentsEntries as P, LOOMA_CHIP_COLORS as R, createSiteRelativeLinks as S, createLoomaMentionExtension as T, LOOMA_ACTIVE_BLOCK_BLUR_GRACE_MS as U, LOOMA_CALLOUT_TONES as V, LOOMA_ACTIVE_BLOCK_CLASS as W, getActiveTableCellAlignment as _, getActiveTableUiState as a, setActiveTableCellBackground as b, insertTableAtRange as c, LoomaTableKit as d, getDefaultEditorExtensions as f, LoomaTableHeader as g, LoomaTableCell as h, getDefaultSlashCommands as i, normalizeImageDimension as j, normalizeMentionResultLimit as k, normalizeActiveTableColumnWidths as l, LoomaTable as m, createLoomaSlashCommandExtension as n, handleTableAction as o, getLoomaTableExtensions as p, LoomaActiveBlockPluginKey as q, filterLoomaSlashCommands as r, handleTableOverlayAction as s, LoomaSlashCommand as t, shouldShowTextFormattingToolbar as u, getActiveTableCellBackground as v, LoomaMentionSuggestionPluginKey as w, LoomaSmartPaste as x, setActiveTableCellAlignment as y, LoomaChip as z };
|