@threadlabs/looma 0.29.1 → 0.29.2
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/chip-editing.d.ts +39 -0
- package/package.json +1 -1
- package/vue/editor/LoomaEditor.d.ts +2 -2
- package/vue/editor/compact/index.d.ts +2 -2
- package/vue/editor/index.js +240 -76
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/core";
|
|
2
|
+
import { type LoomaChipColor } from "./extensions/chip.js";
|
|
3
|
+
/** The chip editor's state: whether it is open, and the label and tone of the chip it edits. */
|
|
4
|
+
export interface LoomaChipEditingState {
|
|
5
|
+
readonly open: boolean;
|
|
6
|
+
readonly label: string;
|
|
7
|
+
readonly color: LoomaChipColor;
|
|
8
|
+
}
|
|
9
|
+
export declare const LOOMA_CHIP_EDITING_IDLE: LoomaChipEditingState;
|
|
10
|
+
/**
|
|
11
|
+
* The chip editor as a state machine: it opens on one chip and writes each label and tone change to
|
|
12
|
+
* that chip as the author makes it.
|
|
13
|
+
*
|
|
14
|
+
* @ownership The host owns presentation: the popover, its anchor, and focus. This owns which chip is
|
|
15
|
+
* edited and the node attributes it writes.
|
|
16
|
+
* @failure A change after the chip was deleted, or moved out of its node, closes the editor and writes
|
|
17
|
+
* nothing.
|
|
18
|
+
*/
|
|
19
|
+
export interface LoomaChipEditing {
|
|
20
|
+
readonly state: LoomaChipEditingState;
|
|
21
|
+
/** The edited chip's element, for anchoring the editor, or null while it is closed. */
|
|
22
|
+
readonly element: HTMLElement | null;
|
|
23
|
+
/** Calls `listener` after every state change; returns the unsubscribe function. */
|
|
24
|
+
subscribe(listener: () => void): () => void;
|
|
25
|
+
/**
|
|
26
|
+
* Opens on the chip at `position`.
|
|
27
|
+
* @failure Returns false, and stays as it was, when the editor is read-only or no chip is there.
|
|
28
|
+
*/
|
|
29
|
+
open(position: number): boolean;
|
|
30
|
+
setLabel(label: string): void;
|
|
31
|
+
setColor(color: LoomaChipColor): void;
|
|
32
|
+
close(): void;
|
|
33
|
+
}
|
|
34
|
+
export interface LoomaChipEditingOptions {
|
|
35
|
+
editor: Editor;
|
|
36
|
+
/** Read on each opening, so a host can change it while the editor runs. */
|
|
37
|
+
isEditable: () => boolean;
|
|
38
|
+
}
|
|
39
|
+
export declare function createChipEditing(options: LoomaChipEditingOptions): LoomaChipEditing;
|
package/package.json
CHANGED
|
@@ -402,10 +402,10 @@ export declare const LoomaEditor: import("vue").DefineComponent<import("vue").Ex
|
|
|
402
402
|
onImageActivate?: ((_detail: LoomaImageActivationDetail) => any) | undefined;
|
|
403
403
|
onImageRenditionError?: ((_detail: LoomaImageRenditionErrorDetail) => any) | undefined;
|
|
404
404
|
}>, {
|
|
405
|
-
extensions: LoomaEditorExtensions | undefined;
|
|
406
|
-
editable: boolean;
|
|
407
405
|
label: string;
|
|
408
406
|
placeholder: string;
|
|
407
|
+
extensions: LoomaEditorExtensions | undefined;
|
|
408
|
+
editable: boolean;
|
|
409
409
|
linkBaseUrl: string;
|
|
410
410
|
disableHighlight: boolean;
|
|
411
411
|
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
|
+
id: string;
|
|
66
|
+
label: string;
|
|
65
67
|
extensions: AnyExtension[];
|
|
66
68
|
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.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { computed, createApp, defineComponent, h, nextTick, onBeforeUnmount, onMounted, onUpdated, reactive, ref, shallowRef, useId, watch } from "vue";
|
|
2
|
-
import { DEFAULT_MENTION_RESULT_LIMIT, LOOMA_ICONS, createLoomaMentionExtension, createLoomaSlashCommandExtension, getActiveTableUiState, getDefaultEditorExtensions, getDefaultSlashCommands, getTableOfContentsEntries, getVisualViewportRect, handleTableAction, handleTableOverlayAction, measureTableOverlayGeometry, normalizeActiveTableColumnWidths,
|
|
2
|
+
import { DEFAULT_MENTION_RESULT_LIMIT, LOOMA_ICONS, createLoomaMentionExtension, createLoomaSlashCommandExtension, getActiveTableUiState, getDefaultEditorExtensions, getDefaultSlashCommands, getTableOfContentsEntries, getVisualViewportRect, handleTableAction, handleTableOverlayAction, measureTableOverlayGeometry, normalizeActiveTableColumnWidths, normalizeTableOfContentsConfig } from "@threadlabs/looma/editor";
|
|
3
3
|
import { Button, Callout, Card, Checkbox, Cluster, Disclosure, EditorBlockActions, EditorChipEditor, EditorCodeLanguage, EditorImageToolbar, EditorInsertTableGrid, EditorLinkCard, EditorLinkForm, EditorMentionMenu, EditorMentionMenuItem, EditorSlashMenu, EditorSlashMenuGroup, EditorSlashMenuItem, EditorSurface, EditorTableContextMenu, EditorTableOverlay, EditorTableToolbar, EditorToolbar, FormField, Icon, IconButton, Image, Input, List, Menu, MenuItem, Popover, Separator, Stack, StatusMessage, Text, Tooltip } from "@threadlabs/looma/vue";
|
|
4
4
|
import { Editor, Extension, Node as Node$1, getText, getTextSerializersFromSchema, isNodeSelection, mergeAttributes, nodeInputRule, posToDOMRect } from "@tiptap/core";
|
|
5
5
|
import { Editor as Editor$1 } from "@tiptap/vue-3";
|
|
@@ -1536,6 +1536,221 @@ function validLinkHref(value) {
|
|
|
1536
1536
|
}
|
|
1537
1537
|
}
|
|
1538
1538
|
//#endregion
|
|
1539
|
+
//#region src/markdown/index.ts
|
|
1540
|
+
/**
|
|
1541
|
+
* Callout tones a document stores, in the order the editor offers them. The Callout component also
|
|
1542
|
+
* takes `neutral` and `success`, which Markdown and the editor store as `note`.
|
|
1543
|
+
*/
|
|
1544
|
+
var LOOMA_CALLOUT_TONES = [
|
|
1545
|
+
"note",
|
|
1546
|
+
"tip",
|
|
1547
|
+
"info",
|
|
1548
|
+
"important",
|
|
1549
|
+
"warning",
|
|
1550
|
+
"danger"
|
|
1551
|
+
];
|
|
1552
|
+
/** The hues chips and swatches take as their tone, written `:chip[Label]{tone=green}`. */
|
|
1553
|
+
var LOOMA_CHIP_TONES = [
|
|
1554
|
+
"neutral",
|
|
1555
|
+
"blue",
|
|
1556
|
+
"green",
|
|
1557
|
+
"yellow",
|
|
1558
|
+
"red",
|
|
1559
|
+
"purple"
|
|
1560
|
+
];
|
|
1561
|
+
/**
|
|
1562
|
+
* Keeps a chip tone within the palette.
|
|
1563
|
+
* @failure Unknown values become `neutral`.
|
|
1564
|
+
*/
|
|
1565
|
+
function normalizeLoomaChipTone(value) {
|
|
1566
|
+
return LOOMA_CHIP_TONES.includes(value) ? value : "neutral";
|
|
1567
|
+
}
|
|
1568
|
+
[...LOOMA_CALLOUT_TONES];
|
|
1569
|
+
/**
|
|
1570
|
+
* The anchor a heading's text derives: NFC, lowercase, keeping letters, numbers and combining
|
|
1571
|
+
* marks, with every other run of characters one hyphen.
|
|
1572
|
+
* @failure Text with no letters or numbers, such as only emoji, derives `heading`.
|
|
1573
|
+
*/
|
|
1574
|
+
function loomaHeadingSlug(text) {
|
|
1575
|
+
return text.normalize("NFC").toLowerCase().replace(/[^\p{L}\p{N}\p{M}]+/gu, "-").replace(/^-+|-+$/g, "") || "heading";
|
|
1576
|
+
}
|
|
1577
|
+
/**
|
|
1578
|
+
* Gives every heading of a document its anchor, in document order.
|
|
1579
|
+
* @contract A custom ID is kept unless an earlier heading already has it. Any other heading takes
|
|
1580
|
+
* its slug, or the slug's first free suffix (`-1`, `-2`…), never one a later custom ID reserves.
|
|
1581
|
+
*/
|
|
1582
|
+
function assignLoomaHeadingIds(headings) {
|
|
1583
|
+
const reserved = new Set(headings.map(({ id }) => id).filter((id) => Boolean(id)));
|
|
1584
|
+
const used = /* @__PURE__ */ new Set();
|
|
1585
|
+
return headings.map(({ text, id: custom }) => {
|
|
1586
|
+
let id = custom || loomaHeadingSlug(text);
|
|
1587
|
+
if (custom ? used.has(id) : used.has(id) || reserved.has(id)) {
|
|
1588
|
+
const stem = id;
|
|
1589
|
+
let suffix = 1;
|
|
1590
|
+
while (used.has(`${stem}-${suffix}`) || reserved.has(`${stem}-${suffix}`)) suffix++;
|
|
1591
|
+
id = `${stem}-${suffix}`;
|
|
1592
|
+
}
|
|
1593
|
+
used.add(id);
|
|
1594
|
+
return id;
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1597
|
+
//#endregion
|
|
1598
|
+
//#region src/editor/extensions/chip.ts
|
|
1599
|
+
var CHIP_PLACEHOLDER = "Set a label";
|
|
1600
|
+
/** Keep imported or programmatic colors within the supported palette. */
|
|
1601
|
+
function normalizeLoomaChipColor(value) {
|
|
1602
|
+
return normalizeLoomaChipTone(value);
|
|
1603
|
+
}
|
|
1604
|
+
Node$1.create({
|
|
1605
|
+
name: "loomaChip",
|
|
1606
|
+
group: "inline",
|
|
1607
|
+
inline: true,
|
|
1608
|
+
atom: true,
|
|
1609
|
+
selectable: true,
|
|
1610
|
+
addAttributes() {
|
|
1611
|
+
return {
|
|
1612
|
+
label: {
|
|
1613
|
+
default: "",
|
|
1614
|
+
parseHTML: (element) => element.getAttribute("data-label") ?? (element.hasAttribute("data-placeholder") ? "" : element.textContent ?? "")
|
|
1615
|
+
},
|
|
1616
|
+
color: {
|
|
1617
|
+
default: "neutral",
|
|
1618
|
+
parseHTML: (element) => normalizeLoomaChipColor(element.getAttribute("data-color"))
|
|
1619
|
+
}
|
|
1620
|
+
};
|
|
1621
|
+
},
|
|
1622
|
+
parseHTML() {
|
|
1623
|
+
return [{ tag: "span[data-looma-chip]" }];
|
|
1624
|
+
},
|
|
1625
|
+
renderHTML({ node }) {
|
|
1626
|
+
const label = String(node.attrs.label ?? "");
|
|
1627
|
+
return [
|
|
1628
|
+
"span",
|
|
1629
|
+
{
|
|
1630
|
+
"data-looma-chip": "",
|
|
1631
|
+
"data-label": label,
|
|
1632
|
+
"data-color": normalizeLoomaChipColor(node.attrs.color),
|
|
1633
|
+
...label ? {} : { "data-placeholder": "" }
|
|
1634
|
+
},
|
|
1635
|
+
label || CHIP_PLACEHOLDER
|
|
1636
|
+
];
|
|
1637
|
+
},
|
|
1638
|
+
renderText({ node }) {
|
|
1639
|
+
return String(node.attrs.label ?? "");
|
|
1640
|
+
},
|
|
1641
|
+
addNodeView() {
|
|
1642
|
+
return ({ node, editor }) => {
|
|
1643
|
+
const dom = document.createElement("span");
|
|
1644
|
+
dom.dataset.loomaChip = "";
|
|
1645
|
+
dom.contentEditable = "false";
|
|
1646
|
+
dom.setAttribute("role", "button");
|
|
1647
|
+
dom.setAttribute("aria-disabled", String(!editor.isEditable));
|
|
1648
|
+
dom.tabIndex = 0;
|
|
1649
|
+
const update = (next) => {
|
|
1650
|
+
if (next.type !== node.type) return false;
|
|
1651
|
+
const label = String(next.attrs.label ?? "");
|
|
1652
|
+
if (dom.dataset.label !== label) {
|
|
1653
|
+
dom.dataset.label = label;
|
|
1654
|
+
dom.textContent = label || CHIP_PLACEHOLDER;
|
|
1655
|
+
dom.setAttribute("aria-label", label ? `Edit chip: ${label}` : "Set chip label");
|
|
1656
|
+
if (label) delete dom.dataset.placeholder;
|
|
1657
|
+
else dom.dataset.placeholder = "";
|
|
1658
|
+
}
|
|
1659
|
+
const color = normalizeLoomaChipColor(next.attrs.color);
|
|
1660
|
+
if (dom.dataset.color !== color) dom.dataset.color = color;
|
|
1661
|
+
return true;
|
|
1662
|
+
};
|
|
1663
|
+
update(node);
|
|
1664
|
+
return {
|
|
1665
|
+
dom,
|
|
1666
|
+
update,
|
|
1667
|
+
stopEvent: (event) => event.type === "click" || event.type === "keydown"
|
|
1668
|
+
};
|
|
1669
|
+
};
|
|
1670
|
+
},
|
|
1671
|
+
addCommands() {
|
|
1672
|
+
return { insertLoomaChip: (attributes = {}) => ({ commands, state }) => {
|
|
1673
|
+
const selection = state.selection;
|
|
1674
|
+
const label = attributes.label ?? state.doc.textBetween(selection.from, selection.to);
|
|
1675
|
+
return commands.insertContent({
|
|
1676
|
+
type: this.name,
|
|
1677
|
+
attrs: {
|
|
1678
|
+
label,
|
|
1679
|
+
color: normalizeLoomaChipColor(attributes.color)
|
|
1680
|
+
}
|
|
1681
|
+
});
|
|
1682
|
+
} };
|
|
1683
|
+
}
|
|
1684
|
+
});
|
|
1685
|
+
//#endregion
|
|
1686
|
+
//#region src/editor/chip-editing.ts
|
|
1687
|
+
var LOOMA_CHIP_EDITING_IDLE = Object.freeze({
|
|
1688
|
+
open: false,
|
|
1689
|
+
label: "",
|
|
1690
|
+
color: "neutral"
|
|
1691
|
+
});
|
|
1692
|
+
function createChipEditing(options) {
|
|
1693
|
+
const { editor } = options;
|
|
1694
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1695
|
+
let state = LOOMA_CHIP_EDITING_IDLE;
|
|
1696
|
+
let element = null;
|
|
1697
|
+
const set = (next) => {
|
|
1698
|
+
state = next;
|
|
1699
|
+
listeners.forEach((listener) => listener());
|
|
1700
|
+
};
|
|
1701
|
+
const close = () => {
|
|
1702
|
+
element = null;
|
|
1703
|
+
if (state.open) set({
|
|
1704
|
+
...state,
|
|
1705
|
+
open: false
|
|
1706
|
+
});
|
|
1707
|
+
};
|
|
1708
|
+
const change = (changes) => {
|
|
1709
|
+
if (!element || editor.isDestroyed || !element.isConnected) return close();
|
|
1710
|
+
const position = editor.view.posAtDOM(element, 0);
|
|
1711
|
+
const node = editor.state.doc.nodeAt(position);
|
|
1712
|
+
if (node?.type.name !== "loomaChip") return close();
|
|
1713
|
+
set({
|
|
1714
|
+
...state,
|
|
1715
|
+
...changes
|
|
1716
|
+
});
|
|
1717
|
+
editor.view.dispatch(editor.state.tr.setNodeMarkup(position, void 0, {
|
|
1718
|
+
...node.attrs,
|
|
1719
|
+
...changes
|
|
1720
|
+
}));
|
|
1721
|
+
};
|
|
1722
|
+
return {
|
|
1723
|
+
get state() {
|
|
1724
|
+
return state;
|
|
1725
|
+
},
|
|
1726
|
+
get element() {
|
|
1727
|
+
return element;
|
|
1728
|
+
},
|
|
1729
|
+
subscribe(listener) {
|
|
1730
|
+
listeners.add(listener);
|
|
1731
|
+
return () => {
|
|
1732
|
+
listeners.delete(listener);
|
|
1733
|
+
};
|
|
1734
|
+
},
|
|
1735
|
+
open(position) {
|
|
1736
|
+
if (!options.isEditable() || editor.isDestroyed) return false;
|
|
1737
|
+
const node = editor.state.doc.nodeAt(position);
|
|
1738
|
+
const dom = editor.view.nodeDOM(position);
|
|
1739
|
+
if (node?.type.name !== "loomaChip" || !(dom instanceof HTMLElement)) return false;
|
|
1740
|
+
element = dom;
|
|
1741
|
+
set({
|
|
1742
|
+
open: true,
|
|
1743
|
+
label: String(node.attrs.label ?? ""),
|
|
1744
|
+
color: normalizeLoomaChipColor(node.attrs.color)
|
|
1745
|
+
});
|
|
1746
|
+
return true;
|
|
1747
|
+
},
|
|
1748
|
+
setLabel: (label) => change({ label }),
|
|
1749
|
+
setColor: (color) => change({ color }),
|
|
1750
|
+
close
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
//#endregion
|
|
1539
1754
|
//#region src/editor/extensions/relative-links.ts
|
|
1540
1755
|
/** Keep other origins and non-web schemes intact; same-origin links retain path, query, and fragment. */
|
|
1541
1756
|
function siteRelativeHref(href, baseUrl) {
|
|
@@ -2056,34 +2271,6 @@ function formatEditorShortcut(keys, apple) {
|
|
|
2056
2271
|
].filter(Boolean).join("+");
|
|
2057
2272
|
}
|
|
2058
2273
|
var isApplePlatform = () => typeof navigator !== "undefined" && /mac|iphone|ipad|ipod/i.test(navigator.userAgentData?.platform || navigator.platform || navigator.userAgent);
|
|
2059
|
-
/**
|
|
2060
|
-
* The anchor a heading's text derives: NFC, lowercase, keeping letters, numbers and combining
|
|
2061
|
-
* marks, with every other run of characters one hyphen.
|
|
2062
|
-
* @failure Text with no letters or numbers, such as only emoji, derives `heading`.
|
|
2063
|
-
*/
|
|
2064
|
-
function loomaHeadingSlug(text) {
|
|
2065
|
-
return text.normalize("NFC").toLowerCase().replace(/[^\p{L}\p{N}\p{M}]+/gu, "-").replace(/^-+|-+$/g, "") || "heading";
|
|
2066
|
-
}
|
|
2067
|
-
/**
|
|
2068
|
-
* Gives every heading of a document its anchor, in document order.
|
|
2069
|
-
* @contract A custom ID is kept unless an earlier heading already has it. Any other heading takes
|
|
2070
|
-
* its slug, or the slug's first free suffix (`-1`, `-2`…), never one a later custom ID reserves.
|
|
2071
|
-
*/
|
|
2072
|
-
function assignLoomaHeadingIds(headings) {
|
|
2073
|
-
const reserved = new Set(headings.map(({ id }) => id).filter((id) => Boolean(id)));
|
|
2074
|
-
const used = /* @__PURE__ */ new Set();
|
|
2075
|
-
return headings.map(({ text, id: custom }) => {
|
|
2076
|
-
let id = custom || loomaHeadingSlug(text);
|
|
2077
|
-
if (custom ? used.has(id) : used.has(id) || reserved.has(id)) {
|
|
2078
|
-
const stem = id;
|
|
2079
|
-
let suffix = 1;
|
|
2080
|
-
while (used.has(`${stem}-${suffix}`) || reserved.has(`${stem}-${suffix}`)) suffix++;
|
|
2081
|
-
id = `${stem}-${suffix}`;
|
|
2082
|
-
}
|
|
2083
|
-
used.add(id);
|
|
2084
|
-
return id;
|
|
2085
|
-
});
|
|
2086
|
-
}
|
|
2087
2274
|
//#endregion
|
|
2088
2275
|
//#region src/editor/extensions/expand.ts
|
|
2089
2276
|
/**
|
|
@@ -3215,9 +3402,8 @@ var LoomaEditor = defineComponent({
|
|
|
3215
3402
|
chipEditorRoot.value = element instanceof HTMLElement ? element : null;
|
|
3216
3403
|
};
|
|
3217
3404
|
const chipInput = () => chipEditorRoot.value?.querySelector("[data-chip-label]");
|
|
3218
|
-
|
|
3219
|
-
const
|
|
3220
|
-
const chipColor = ref("neutral");
|
|
3405
|
+
let chipEditing;
|
|
3406
|
+
const chipState = shallowRef(LOOMA_CHIP_EDITING_IDLE);
|
|
3221
3407
|
const toolbarScope = `looma-editor-tool-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
3222
3408
|
const tooltipFor = ref("");
|
|
3223
3409
|
const tooltipLabel = ref("");
|
|
@@ -3320,39 +3506,16 @@ var LoomaEditor = defineComponent({
|
|
|
3320
3506
|
menuStyle: {},
|
|
3321
3507
|
capabilities: { ...EMPTY_CAPABILITIES }
|
|
3322
3508
|
});
|
|
3323
|
-
const openChipEditor = (
|
|
3324
|
-
if (!
|
|
3325
|
-
const node = instance.state.doc.nodeAt(position);
|
|
3326
|
-
const element = instance.view.nodeDOM(position);
|
|
3327
|
-
if (node?.type.name !== "loomaChip" || !(element instanceof HTMLElement)) return;
|
|
3509
|
+
const openChipEditor = (_instance, position) => {
|
|
3510
|
+
if (!chipEditing?.open(position)) return;
|
|
3328
3511
|
root.value?.querySelector(`#${chipAnchorId}`)?.removeAttribute("id");
|
|
3329
|
-
element.id = chipAnchorId;
|
|
3330
|
-
chipLabel.value = String(node.attrs.label ?? "");
|
|
3331
|
-
chipColor.value = normalizeLoomaChipColor(node.attrs.color);
|
|
3332
|
-
chipOpen.value = true;
|
|
3512
|
+
chipEditing.element.id = chipAnchorId;
|
|
3333
3513
|
nextTick(() => chipInput()?.focus());
|
|
3334
3514
|
};
|
|
3335
|
-
const changeChip = (changes) => {
|
|
3336
|
-
const instance = editor.value;
|
|
3337
|
-
const element = root.value?.querySelector(`#${chipAnchorId}`);
|
|
3338
|
-
if (!instance || !element) {
|
|
3339
|
-
chipOpen.value = false;
|
|
3340
|
-
return;
|
|
3341
|
-
}
|
|
3342
|
-
const position = instance.view.posAtDOM(element, 0);
|
|
3343
|
-
const node = instance.state.doc.nodeAt(position);
|
|
3344
|
-
if (node?.type.name !== "loomaChip") {
|
|
3345
|
-
chipOpen.value = false;
|
|
3346
|
-
return;
|
|
3347
|
-
}
|
|
3348
|
-
instance.view.dispatch(instance.state.tr.setNodeMarkup(position, void 0, {
|
|
3349
|
-
...node.attrs,
|
|
3350
|
-
...changes
|
|
3351
|
-
}));
|
|
3352
|
-
};
|
|
3353
3515
|
const closeChip = (focusChip = false) => {
|
|
3354
|
-
|
|
3355
|
-
|
|
3516
|
+
const element = chipEditing?.element;
|
|
3517
|
+
chipEditing?.close();
|
|
3518
|
+
if (focusChip) element?.focus();
|
|
3356
3519
|
};
|
|
3357
3520
|
const found = reactive(/* @__PURE__ */ new Set());
|
|
3358
3521
|
const answers = (name) => {
|
|
@@ -3565,6 +3728,14 @@ var LoomaEditor = defineComponent({
|
|
|
3565
3728
|
linkState.value = engine.state;
|
|
3566
3729
|
});
|
|
3567
3730
|
linkEditing = engine;
|
|
3731
|
+
const chips = createChipEditing({
|
|
3732
|
+
editor: session.editor,
|
|
3733
|
+
isEditable: () => props.editable
|
|
3734
|
+
});
|
|
3735
|
+
chips.subscribe(() => {
|
|
3736
|
+
chipState.value = chips.state;
|
|
3737
|
+
});
|
|
3738
|
+
chipEditing = chips;
|
|
3568
3739
|
const imageUploads = createImageUploads({
|
|
3569
3740
|
editor: session.editor,
|
|
3570
3741
|
upload: () => async (file, init) => {
|
|
@@ -3597,6 +3768,7 @@ var LoomaEditor = defineComponent({
|
|
|
3597
3768
|
const previous = session;
|
|
3598
3769
|
const content = edited ? previous.editor.getJSON() : props.modelValue;
|
|
3599
3770
|
linkEditing?.destroy();
|
|
3771
|
+
chipEditing?.close();
|
|
3600
3772
|
formatting?.destroy();
|
|
3601
3773
|
uploads?.cancel();
|
|
3602
3774
|
previous.destroy();
|
|
@@ -3721,7 +3893,7 @@ var LoomaEditor = defineComponent({
|
|
|
3721
3893
|
root.value?.querySelectorAll("[data-looma-chip]").forEach((chip) => {
|
|
3722
3894
|
chip.setAttribute("aria-disabled", String(!editable));
|
|
3723
3895
|
});
|
|
3724
|
-
if (!editable)
|
|
3896
|
+
if (!editable) chipEditing?.close();
|
|
3725
3897
|
});
|
|
3726
3898
|
watch([
|
|
3727
3899
|
() => linkState.value.surface === "popover",
|
|
@@ -4691,24 +4863,16 @@ var LoomaEditor = defineComponent({
|
|
|
4691
4863
|
}, [loomaIcon("image"), h("span", "Drop image to upload")]) : null,
|
|
4692
4864
|
h(Popover, {
|
|
4693
4865
|
class: "looma-editor__chip-popover",
|
|
4694
|
-
open:
|
|
4866
|
+
open: chipState.value.open,
|
|
4695
4867
|
for: chipAnchorId,
|
|
4696
4868
|
placement: "bottom-start",
|
|
4697
|
-
onClose: () =>
|
|
4698
|
-
chipOpen.value = false;
|
|
4699
|
-
}
|
|
4869
|
+
onClose: () => chipEditing?.close()
|
|
4700
4870
|
}, () => h(EditorChipEditor, {
|
|
4701
4871
|
ref: setChipEditorRoot,
|
|
4702
|
-
label:
|
|
4703
|
-
color:
|
|
4704
|
-
onLabel: (event) =>
|
|
4705
|
-
|
|
4706
|
-
changeChip({ label: chipLabel.value });
|
|
4707
|
-
},
|
|
4708
|
-
onColor: (event) => {
|
|
4709
|
-
chipColor.value = event.detail.color;
|
|
4710
|
-
changeChip({ color: event.detail.color });
|
|
4711
|
-
},
|
|
4872
|
+
label: chipState.value.label,
|
|
4873
|
+
color: chipState.value.color,
|
|
4874
|
+
onLabel: (event) => chipEditing?.setLabel(event.detail.label),
|
|
4875
|
+
onColor: (event) => chipEditing?.setColor(event.detail.color),
|
|
4712
4876
|
onDone: () => closeChip(true)
|
|
4713
4877
|
})),
|
|
4714
4878
|
h(Popover, {
|