@threadlabs/looma 0.28.0 → 0.28.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/editor/code-highlighting.d.ts +25 -0
- package/editor/content.d.ts +10 -0
- package/{vue/editor → editor}/image-delivery.d.ts +1 -1
- package/editor/selection-geometry.d.ts +8 -0
- package/editor/shortcuts.d.ts +6 -0
- package/package.json +1 -1
- package/vue/editor/LoomaEditor.d.ts +3 -3
- package/vue/editor/compact/index.d.ts +2 -2
- package/vue/editor/index.d.ts +1 -1
- package/vue/editor/index.js +140 -102
- /package/{vue/editor → editor}/code-language-catalog.d.ts +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/core";
|
|
2
|
+
import { createLowlight } from "lowlight";
|
|
3
|
+
import type { LoomaCodeLanguages } from "./extensions/preset.js";
|
|
4
|
+
/** Code-block highlighting for one editor: its lowlight registry, picker languages, and grammar loading. */
|
|
5
|
+
export interface LoomaCodeHighlighting {
|
|
6
|
+
/** The registry the code-block extension highlights with. */
|
|
7
|
+
readonly lowlight: ReturnType<typeof createLowlight>;
|
|
8
|
+
/** Languages the picker offers, in display order. */
|
|
9
|
+
readonly languageNames: readonly string[];
|
|
10
|
+
/**
|
|
11
|
+
* Loads the grammar a code block needs, then re-highlights the document.
|
|
12
|
+
*
|
|
13
|
+
* @contract Does nothing when the host supplied its own languages; each grammar loads once.
|
|
14
|
+
* @failure A failed import is forgotten so a later call retries it.
|
|
15
|
+
*/
|
|
16
|
+
loadForCodeBlock(editor: Editor, language: unknown, value: string): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Highlighting from the host's `codeLanguages`, or, when that is null, from the built-in catalog,
|
|
20
|
+
* whose grammars load on demand and whose automatic detection uses a common subset.
|
|
21
|
+
*
|
|
22
|
+
* @lifecycle `onGrammarsLoaded` runs after each lazy load, before the document is re-highlighted,
|
|
23
|
+
* because the lowlight registry is mutable rather than reactive.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createCodeHighlighting(codeLanguages: LoomaCodeLanguages | null, onGrammarsLoaded: () => void): LoomaCodeHighlighting;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { JSONContent } from "@tiptap/core";
|
|
2
|
+
/** Whether a controlled document already matches the editor, so applying it would only reset the selection. */
|
|
3
|
+
export declare function sameDocument(left: JSONContent, right: JSONContent): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* A link destination the editor may store: a site-relative path, fragment, or query, or an
|
|
6
|
+
* absolute http, https, mailto, or tel URL.
|
|
7
|
+
*
|
|
8
|
+
* @failure Returns null for empty input, control characters, other schemes, and unparseable URLs.
|
|
9
|
+
*/
|
|
10
|
+
export declare function validLinkHref(value: string): string | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Extension, type Editor, type JSONContent } from "@tiptap/core";
|
|
2
|
-
export { normalizeImageDimension } from "
|
|
2
|
+
export { normalizeImageDimension } from "./extensions/image.js";
|
|
3
3
|
/** What caused an overlay to open or close. */
|
|
4
4
|
type OverlayTrigger = "keyboard" | "pointer" | "programmatic";
|
|
5
5
|
/**
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/core";
|
|
2
|
+
import type { SlashMenuAnchorRect } from "./slash-menu.js";
|
|
3
|
+
/** A plain copy of a client rectangle, the anchor shape the slash and mention menus accept as a prop. */
|
|
4
|
+
export declare function menuAnchorRect(rect: DOMRect | null): SlashMenuAnchorRect | null;
|
|
5
|
+
/** The rendered table that holds the selection's start. */
|
|
6
|
+
export declare function selectedTableElement(editor: Editor): HTMLTableElement | null;
|
|
7
|
+
/** The rendered cell that holds the selection's start. */
|
|
8
|
+
export declare function selectedTableCellElement(editor: Editor): HTMLTableCellElement | null;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shows a key binding in ProseMirror notation ("Mod-Shift-8") the way the reader's platform writes
|
|
3
|
+
* it: modifier symbols in Apple's order on Apple devices (⇧⌘8), and Ctrl+Shift+8 elsewhere.
|
|
4
|
+
*/
|
|
5
|
+
export declare function formatEditorShortcut(keys: string, apple: boolean): string;
|
|
6
|
+
export declare const isApplePlatform: () => boolean;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ import "./looma-editor.css";
|
|
|
3
3
|
import { type AnyExtension, type Editor, type JSONContent } from "@tiptap/core";
|
|
4
4
|
import { type PropType, type VNode } from "vue";
|
|
5
5
|
import { type LoomaSlashCommand, type LoomaMentionItem, type LoomaMentionProvider, type LoomaCodeLanguages } from "@threadlabs/looma/editor";
|
|
6
|
-
import { type LoomaImageActivationDetail, type LoomaImageAttributeResolver, type LoomaImageDescriptor, type LoomaImageRenditionErrorDetail } from "
|
|
6
|
+
import { type LoomaImageActivationDetail, type LoomaImageAttributeResolver, type LoomaImageDescriptor, type LoomaImageRenditionErrorDetail } from "../../editor/image-delivery.js";
|
|
7
7
|
/**
|
|
8
8
|
* Host upload result normalized into the editor's durable image descriptor.
|
|
9
9
|
* `url` becomes the stored `src`; optional dimensions preserve layout before
|
|
@@ -368,10 +368,10 @@ export declare const LoomaEditor: import("vue").DefineComponent<import("vue").Ex
|
|
|
368
368
|
onImageActivate?: ((_detail: LoomaImageActivationDetail) => any) | undefined;
|
|
369
369
|
onImageRenditionError?: ((_detail: LoomaImageRenditionErrorDetail) => any) | undefined;
|
|
370
370
|
}>, {
|
|
371
|
-
label: string;
|
|
372
|
-
placeholder: string;
|
|
373
371
|
extensions: AnyExtension[];
|
|
374
372
|
editable: boolean;
|
|
373
|
+
label: string;
|
|
374
|
+
placeholder: string;
|
|
375
375
|
linkBaseUrl: string;
|
|
376
376
|
disableHighlight: boolean;
|
|
377
377
|
codeLanguages: Readonly<Record<string, import("highlight.js").LanguageFn>> | null;
|
|
@@ -62,10 +62,10 @@ export declare const LoomaCompactEditor: import("vue").DefineComponent<import("v
|
|
|
62
62
|
"onUpdate:modelValue"?: ((_value: JSONContent) => any) | undefined;
|
|
63
63
|
onReady?: ((_editor: Editor) => any) | undefined;
|
|
64
64
|
}>, {
|
|
65
|
-
label: string;
|
|
66
|
-
id: string;
|
|
67
65
|
extensions: AnyExtension[];
|
|
68
66
|
editable: boolean;
|
|
67
|
+
label: string;
|
|
68
|
+
id: string;
|
|
69
69
|
modelValue: JSONContent;
|
|
70
70
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
71
71
|
/** Renders basic compact JSON as escaped Vue nodes, including during SSR. */
|
package/vue/editor/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export * from "@threadlabs/looma/editor";
|
|
2
2
|
export * from "./primitives.js";
|
|
3
3
|
export { LoomaEditor, type LoomaEditorToolbarMode, type LoomaEditorSelectionAction, type LoomaEditorSelectionActionDetail, type LoomaEditorRangeAction, type LoomaEditorRangeActionDetail, type LoomaEditorSlashCommands, type LoomaLinkTarget, type LoomaLinkSearch, type LoomaLinkResolve, type LoomaImageUploader, type LoomaImageUploadResult, } from "./LoomaEditor.js";
|
|
4
|
-
export type { LoomaImageActivationDetail, LoomaImageActivationTrigger, LoomaImageAttributeResolver, LoomaImageDescriptor, LoomaImageRenditionErrorDetail, LoomaImageRenditionAttributes, } from "
|
|
4
|
+
export type { LoomaImageActivationDetail, LoomaImageActivationTrigger, LoomaImageAttributeResolver, LoomaImageDescriptor, LoomaImageRenditionErrorDetail, LoomaImageRenditionAttributes, } from "../../editor/image-delivery.js";
|
package/vue/editor/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import { Button, Callout, Card, Checkbox, Cluster, Combobox, Disclosure, EditorI
|
|
|
4
4
|
import { Extension, Node as Node$1, getText, getTextSerializersFromSchema, mergeAttributes, nodeInputRule, posToDOMRect } from "@tiptap/core";
|
|
5
5
|
import { BubbleMenu, EditorContent, useEditor } from "@tiptap/vue-3";
|
|
6
6
|
import { closeHistory } from "@tiptap/pm/history";
|
|
7
|
-
import { createLowlight } from "lowlight";
|
|
8
7
|
import { AllSelection, NodeSelection, Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
|
|
9
8
|
import { Decoration, DecorationSet } from "@tiptap/pm/view";
|
|
9
|
+
import { createLowlight } from "lowlight";
|
|
10
10
|
import { DOMParser, DOMSerializer, Fragment as Fragment$1 } from "@tiptap/pm/model";
|
|
11
11
|
export * from "@threadlabs/looma/editor";
|
|
12
12
|
//#region src/vue/editor/primitives.ts
|
|
@@ -272,7 +272,7 @@ Image$1.extend({ addAttributes() {
|
|
|
272
272
|
};
|
|
273
273
|
} });
|
|
274
274
|
//#endregion
|
|
275
|
-
//#region src/
|
|
275
|
+
//#region src/editor/image-delivery.ts
|
|
276
276
|
function optionalString(value) {
|
|
277
277
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
278
278
|
}
|
|
@@ -409,7 +409,7 @@ function imageUploadContent(image) {
|
|
|
409
409
|
};
|
|
410
410
|
}
|
|
411
411
|
//#endregion
|
|
412
|
-
//#region src/
|
|
412
|
+
//#region src/editor/code-language-catalog.ts
|
|
413
413
|
var codeLanguageCatalog = {
|
|
414
414
|
"1c": () => import("../chunks/1c.js").then((module) => module.default),
|
|
415
415
|
"abnf": () => import("../chunks/abnf.js").then((module) => module.default),
|
|
@@ -628,6 +628,134 @@ var autoCodeLanguageNames = [
|
|
|
628
628
|
"yaml"
|
|
629
629
|
];
|
|
630
630
|
//#endregion
|
|
631
|
+
//#region src/editor/code-highlighting.ts
|
|
632
|
+
/**
|
|
633
|
+
* Highlighting from the host's `codeLanguages`, or, when that is null, from the built-in catalog,
|
|
634
|
+
* whose grammars load on demand and whose automatic detection uses a common subset.
|
|
635
|
+
*
|
|
636
|
+
* @lifecycle `onGrammarsLoaded` runs after each lazy load, before the document is re-highlighted,
|
|
637
|
+
* because the lowlight registry is mutable rather than reactive.
|
|
638
|
+
*/
|
|
639
|
+
function createCodeHighlighting(codeLanguages, onGrammarsLoaded) {
|
|
640
|
+
const registry = createLowlight(codeLanguages ?? void 0);
|
|
641
|
+
const lowlight = codeLanguages === null ? {
|
|
642
|
+
...registry,
|
|
643
|
+
highlightAuto: (value) => registry.highlightAuto(value, { subset: [...autoCodeLanguageNames] })
|
|
644
|
+
} : registry;
|
|
645
|
+
const languageNames = codeLanguages === null ? [...autoCodeLanguageNames, ...Object.keys(codeLanguageCatalog).filter((name) => !autoCodeLanguageNames.includes(name)).sort()] : Object.keys(codeLanguages).sort();
|
|
646
|
+
const grammarLoads = /* @__PURE__ */ new Map();
|
|
647
|
+
let catalogLoad;
|
|
648
|
+
const refresh = (editor) => {
|
|
649
|
+
if (editor.isDestroyed) return;
|
|
650
|
+
onGrammarsLoaded();
|
|
651
|
+
const tr = editor.state.tr;
|
|
652
|
+
editor.state.doc.descendants((node, pos) => {
|
|
653
|
+
if (node.type.name === "codeBlock") tr.setNodeMarkup(pos, void 0, node.attrs);
|
|
654
|
+
});
|
|
655
|
+
if (tr.docChanged) editor.view.dispatch(tr.setMeta("addToHistory", false));
|
|
656
|
+
};
|
|
657
|
+
const loadGrammar = (name) => {
|
|
658
|
+
const existing = grammarLoads.get(name);
|
|
659
|
+
if (existing) return existing;
|
|
660
|
+
const pending = codeLanguageCatalog[name]().then((grammar) => {
|
|
661
|
+
registry.register({ [name]: grammar });
|
|
662
|
+
}).catch((error) => {
|
|
663
|
+
grammarLoads.delete(name);
|
|
664
|
+
throw error;
|
|
665
|
+
});
|
|
666
|
+
grammarLoads.set(name, pending);
|
|
667
|
+
return pending;
|
|
668
|
+
};
|
|
669
|
+
return {
|
|
670
|
+
lowlight,
|
|
671
|
+
languageNames,
|
|
672
|
+
loadForCodeBlock(editor, language, value) {
|
|
673
|
+
if (codeLanguages !== null || editor.isDestroyed) return;
|
|
674
|
+
if (typeof language === "string" && Object.hasOwn(codeLanguageCatalog, language)) {
|
|
675
|
+
if (registry.registered(language) || grammarLoads.has(language)) return;
|
|
676
|
+
loadGrammar(language).then(() => refresh(editor)).catch(() => {});
|
|
677
|
+
} else if (!language && value.trim()) catalogLoad ??= Promise.all(autoCodeLanguageNames.map((name) => loadGrammar(name))).then(() => refresh(editor)).catch(() => {
|
|
678
|
+
catalogLoad = void 0;
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
//#endregion
|
|
684
|
+
//#region src/editor/content.ts
|
|
685
|
+
/** Whether a controlled document already matches the editor, so applying it would only reset the selection. */
|
|
686
|
+
function sameDocument(left, right) {
|
|
687
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* A link destination the editor may store: a site-relative path, fragment, or query, or an
|
|
691
|
+
* absolute http, https, mailto, or tel URL.
|
|
692
|
+
*
|
|
693
|
+
* @failure Returns null for empty input, control characters, other schemes, and unparseable URLs.
|
|
694
|
+
*/
|
|
695
|
+
function validLinkHref(value) {
|
|
696
|
+
const href = value.trim();
|
|
697
|
+
if (!href || /[\u0000-\u001f\u007f]/.test(href)) return null;
|
|
698
|
+
if (/^(\/|#|\?)/.test(href)) return href;
|
|
699
|
+
try {
|
|
700
|
+
const url = new URL(href);
|
|
701
|
+
return [
|
|
702
|
+
"http:",
|
|
703
|
+
"https:",
|
|
704
|
+
"mailto:",
|
|
705
|
+
"tel:"
|
|
706
|
+
].includes(url.protocol) ? href : null;
|
|
707
|
+
} catch {
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
//#endregion
|
|
712
|
+
//#region src/editor/selection-geometry.ts
|
|
713
|
+
/** A plain copy of a client rectangle, the anchor shape the slash and mention menus accept as a prop. */
|
|
714
|
+
function menuAnchorRect(rect) {
|
|
715
|
+
if (!rect) return null;
|
|
716
|
+
return {
|
|
717
|
+
left: rect.left,
|
|
718
|
+
top: rect.top,
|
|
719
|
+
right: rect.right,
|
|
720
|
+
bottom: rect.bottom,
|
|
721
|
+
x: rect.x,
|
|
722
|
+
y: rect.y,
|
|
723
|
+
width: rect.width,
|
|
724
|
+
height: rect.height
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
function selectionElement(editor) {
|
|
728
|
+
const { node } = editor.view.domAtPos(editor.state.selection.from);
|
|
729
|
+
return node instanceof HTMLElement ? node : node.parentElement;
|
|
730
|
+
}
|
|
731
|
+
/** The rendered table that holds the selection's start. */
|
|
732
|
+
function selectedTableElement(editor) {
|
|
733
|
+
return selectionElement(editor)?.closest("table");
|
|
734
|
+
}
|
|
735
|
+
/** The rendered cell that holds the selection's start. */
|
|
736
|
+
function selectedTableCellElement(editor) {
|
|
737
|
+
return selectionElement(editor)?.closest("td, th");
|
|
738
|
+
}
|
|
739
|
+
//#endregion
|
|
740
|
+
//#region src/editor/shortcuts.ts
|
|
741
|
+
/**
|
|
742
|
+
* Shows a key binding in ProseMirror notation ("Mod-Shift-8") the way the reader's platform writes
|
|
743
|
+
* it: modifier symbols in Apple's order on Apple devices (⇧⌘8), and Ctrl+Shift+8 elsewhere.
|
|
744
|
+
*/
|
|
745
|
+
function formatEditorShortcut(keys, apple) {
|
|
746
|
+
const parts = keys.split("-");
|
|
747
|
+
const key = (parts.pop() ?? "").toUpperCase();
|
|
748
|
+
const has = (name) => parts.includes(name);
|
|
749
|
+
if (apple) return `${has("Ctrl") ? "⌃" : ""}${has("Alt") ? "⌥" : ""}${has("Shift") ? "⇧" : ""}${has("Mod") ? "⌘" : ""}${key}`;
|
|
750
|
+
return [
|
|
751
|
+
has("Mod") || has("Ctrl") ? "Ctrl" : "",
|
|
752
|
+
has("Alt") ? "Alt" : "",
|
|
753
|
+
has("Shift") ? "Shift" : "",
|
|
754
|
+
key
|
|
755
|
+
].filter(Boolean).join("+");
|
|
756
|
+
}
|
|
757
|
+
var isApplePlatform = () => typeof navigator !== "undefined" && /mac|iphone|ipad|ipod/i.test(navigator.userAgentData?.platform || navigator.platform || navigator.userAgent);
|
|
758
|
+
//#endregion
|
|
631
759
|
//#region src/editor/extensions/expand.ts
|
|
632
760
|
/**
|
|
633
761
|
* Reveals collapsed ancestors before a host navigates to a document position.
|
|
@@ -1669,23 +1797,6 @@ var imageNodeView = ({ editor, node, getPos, decorations }) => {
|
|
|
1669
1797
|
};
|
|
1670
1798
|
//#endregion
|
|
1671
1799
|
//#region src/vue/editor/LoomaEditor.ts
|
|
1672
|
-
/**
|
|
1673
|
-
* Shows a key binding in ProseMirror notation ("Mod-Shift-8") the way the reader's platform writes
|
|
1674
|
-
* it: modifier symbols in Apple's order on Apple devices (⇧⌘8), and Ctrl+Shift+8 elsewhere.
|
|
1675
|
-
*/
|
|
1676
|
-
function formatEditorShortcut(keys, apple) {
|
|
1677
|
-
const parts = keys.split("-");
|
|
1678
|
-
const key = (parts.pop() ?? "").toUpperCase();
|
|
1679
|
-
const has = (name) => parts.includes(name);
|
|
1680
|
-
if (apple) return `${has("Ctrl") ? "⌃" : ""}${has("Alt") ? "⌥" : ""}${has("Shift") ? "⇧" : ""}${has("Mod") ? "⌘" : ""}${key}`;
|
|
1681
|
-
return [
|
|
1682
|
-
has("Mod") || has("Ctrl") ? "Ctrl" : "",
|
|
1683
|
-
has("Alt") ? "Alt" : "",
|
|
1684
|
-
has("Shift") ? "Shift" : "",
|
|
1685
|
-
key
|
|
1686
|
-
].filter(Boolean).join("+");
|
|
1687
|
-
}
|
|
1688
|
-
var isApplePlatform = () => typeof navigator !== "undefined" && /mac|iphone|ipad|ipod/i.test(navigator.userAgentData?.platform || navigator.platform || navigator.userAgent);
|
|
1689
1800
|
var EMPTY_DOCUMENT = {
|
|
1690
1801
|
type: "doc",
|
|
1691
1802
|
content: []
|
|
@@ -1708,38 +1819,6 @@ var EMPTY_CAPABILITIES = {
|
|
|
1708
1819
|
canMergeCells: false,
|
|
1709
1820
|
canSplitCell: false
|
|
1710
1821
|
};
|
|
1711
|
-
function sameDocument(left, right) {
|
|
1712
|
-
return JSON.stringify(left) === JSON.stringify(right);
|
|
1713
|
-
}
|
|
1714
|
-
function validLinkHref(value) {
|
|
1715
|
-
const href = value.trim();
|
|
1716
|
-
if (!href || /[\u0000-\u001f\u007f]/.test(href)) return null;
|
|
1717
|
-
if (/^(\/|#|\?)/.test(href)) return href;
|
|
1718
|
-
try {
|
|
1719
|
-
const url = new URL(href);
|
|
1720
|
-
return [
|
|
1721
|
-
"http:",
|
|
1722
|
-
"https:",
|
|
1723
|
-
"mailto:",
|
|
1724
|
-
"tel:"
|
|
1725
|
-
].includes(url.protocol) ? href : null;
|
|
1726
|
-
} catch {
|
|
1727
|
-
return null;
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
function managedMenuAnchorRect(rect) {
|
|
1731
|
-
if (!rect) return null;
|
|
1732
|
-
return {
|
|
1733
|
-
left: rect.left,
|
|
1734
|
-
top: rect.top,
|
|
1735
|
-
right: rect.right,
|
|
1736
|
-
bottom: rect.bottom,
|
|
1737
|
-
x: rect.x,
|
|
1738
|
-
y: rect.y,
|
|
1739
|
-
width: rect.width,
|
|
1740
|
-
height: rect.height
|
|
1741
|
-
};
|
|
1742
|
-
}
|
|
1743
1822
|
function slashMenuRows(items) {
|
|
1744
1823
|
const groups = [];
|
|
1745
1824
|
for (const [index, item] of items.entries()) {
|
|
@@ -1760,14 +1839,6 @@ function slashMenuRows(items) {
|
|
|
1760
1839
|
label
|
|
1761
1840
|
}, () => rows)] : rows);
|
|
1762
1841
|
}
|
|
1763
|
-
function selectedTableElement(editor) {
|
|
1764
|
-
const { node } = editor.view.domAtPos(editor.state.selection.from);
|
|
1765
|
-
return (node instanceof HTMLElement ? node : node.parentElement)?.closest("table");
|
|
1766
|
-
}
|
|
1767
|
-
function selectedTableCellElement(editor) {
|
|
1768
|
-
const { node } = editor.view.domAtPos(editor.state.selection.from);
|
|
1769
|
-
return (node instanceof HTMLElement ? node : node.parentElement)?.closest("td, th");
|
|
1770
|
-
}
|
|
1771
1842
|
function loomaIcon(name) {
|
|
1772
1843
|
return h("svg", {
|
|
1773
1844
|
class: "looma-icon",
|
|
@@ -2144,12 +2215,10 @@ var LoomaEditor = defineComponent({
|
|
|
2144
2215
|
};
|
|
2145
2216
|
};
|
|
2146
2217
|
const authorHighlight = !props.disableHighlight;
|
|
2147
|
-
const
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
} : codeLowlight;
|
|
2152
|
-
const codeLanguageNames = props.codeLanguages === null ? [...autoCodeLanguageNames, ...Object.keys(codeLanguageCatalog).filter((name) => !autoCodeLanguageNames.includes(name)).sort()] : Object.keys(props.codeLanguages).sort();
|
|
2218
|
+
const codeHighlighting = createCodeHighlighting(props.codeLanguages, () => {
|
|
2219
|
+
codeUi.grammarVersion += 1;
|
|
2220
|
+
});
|
|
2221
|
+
const codeLanguageNames = codeHighlighting.languageNames;
|
|
2153
2222
|
const codeUi = reactive({
|
|
2154
2223
|
open: false,
|
|
2155
2224
|
pos: 0,
|
|
@@ -2158,38 +2227,7 @@ var LoomaEditor = defineComponent({
|
|
|
2158
2227
|
grammarVersion: 0,
|
|
2159
2228
|
style: {}
|
|
2160
2229
|
});
|
|
2161
|
-
const
|
|
2162
|
-
let catalogLoad;
|
|
2163
|
-
const refreshCodeHighlights = (instance) => {
|
|
2164
|
-
if (instance.isDestroyed) return;
|
|
2165
|
-
codeUi.grammarVersion += 1;
|
|
2166
|
-
const tr = instance.state.tr;
|
|
2167
|
-
instance.state.doc.descendants((node, pos) => {
|
|
2168
|
-
if (node.type.name === "codeBlock") tr.setNodeMarkup(pos, void 0, node.attrs);
|
|
2169
|
-
});
|
|
2170
|
-
if (tr.docChanged) instance.view.dispatch(tr.setMeta("addToHistory", false));
|
|
2171
|
-
};
|
|
2172
|
-
const loadGrammar = (name) => {
|
|
2173
|
-
const existing = grammarLoads.get(name);
|
|
2174
|
-
if (existing) return existing;
|
|
2175
|
-
const pending = codeLanguageCatalog[name]().then((grammar) => {
|
|
2176
|
-
codeLowlight.register({ [name]: grammar });
|
|
2177
|
-
}).catch((error) => {
|
|
2178
|
-
grammarLoads.delete(name);
|
|
2179
|
-
throw error;
|
|
2180
|
-
});
|
|
2181
|
-
grammarLoads.set(name, pending);
|
|
2182
|
-
return pending;
|
|
2183
|
-
};
|
|
2184
|
-
const loadForCodeBlock = (instance, language, value) => {
|
|
2185
|
-
if (props.codeLanguages !== null || instance.isDestroyed) return;
|
|
2186
|
-
if (typeof language === "string" && Object.hasOwn(codeLanguageCatalog, language)) {
|
|
2187
|
-
if (codeLowlight.registered(language) || grammarLoads.has(language)) return;
|
|
2188
|
-
loadGrammar(language).then(() => refreshCodeHighlights(instance)).catch(() => {});
|
|
2189
|
-
} else if (!language && value.trim()) catalogLoad ??= Promise.all(autoCodeLanguageNames.map((name) => loadGrammar(name))).then(() => refreshCodeHighlights(instance)).catch(() => {
|
|
2190
|
-
catalogLoad = void 0;
|
|
2191
|
-
});
|
|
2192
|
-
};
|
|
2230
|
+
const loadForCodeBlock = codeHighlighting.loadForCodeBlock;
|
|
2193
2231
|
const editor = useEditor({
|
|
2194
2232
|
extensions: [
|
|
2195
2233
|
...getDefaultEditorExtensions({
|
|
@@ -2198,7 +2236,7 @@ var LoomaEditor = defineComponent({
|
|
|
2198
2236
|
mention: mentionExtension ?? false,
|
|
2199
2237
|
disableHighlight: props.disableHighlight,
|
|
2200
2238
|
codeLanguages: props.codeLanguages ?? void 0,
|
|
2201
|
-
codeLowlight:
|
|
2239
|
+
codeLowlight: codeHighlighting.lowlight,
|
|
2202
2240
|
tableOfContentsNodeView,
|
|
2203
2241
|
expandNodeView,
|
|
2204
2242
|
dividerNodeView,
|
|
@@ -2823,7 +2861,7 @@ var LoomaEditor = defineComponent({
|
|
|
2823
2861
|
};
|
|
2824
2862
|
const codeLanguageOptions = computed(() => {
|
|
2825
2863
|
codeUi.grammarVersion;
|
|
2826
|
-
const detected = codeUi.open && codeUi.text.trim() ?
|
|
2864
|
+
const detected = codeUi.open && codeUi.text.trim() ? codeHighlighting.lowlight.highlightAuto(codeUi.text).data?.language : null;
|
|
2827
2865
|
return [
|
|
2828
2866
|
{
|
|
2829
2867
|
value: "auto",
|
|
@@ -3836,7 +3874,7 @@ var LoomaEditor = defineComponent({
|
|
|
3836
3874
|
open: true,
|
|
3837
3875
|
query: slash.query,
|
|
3838
3876
|
selectedIndex: slash.selectedIndex,
|
|
3839
|
-
anchorRect:
|
|
3877
|
+
anchorRect: menuAnchorRect(slash.rect),
|
|
3840
3878
|
onHighlight: (event) => {
|
|
3841
3879
|
slash.highlight?.(event.detail.index);
|
|
3842
3880
|
},
|
|
@@ -3857,7 +3895,7 @@ var LoomaEditor = defineComponent({
|
|
|
3857
3895
|
query: mention.query,
|
|
3858
3896
|
items: mention.items,
|
|
3859
3897
|
selectedIndex: mention.selectedIndex,
|
|
3860
|
-
anchorRect:
|
|
3898
|
+
anchorRect: menuAnchorRect(mention.rect),
|
|
3861
3899
|
loading: mention.loading,
|
|
3862
3900
|
onHighlight: (event) => {
|
|
3863
3901
|
mention.selectedIndex = event.detail.index;
|
|
File without changes
|