@threadlabs/looma 0.15.7 → 0.16.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/components/shared/icons.js +1 -0
- package/components/ui-badge/ui-badge.html +3 -8
- package/components/ui-dialog/ui-dialog.html +11 -4
- package/components/ui-dialog/ui-dialog.js +4 -2
- package/components/ui-icon/ui-icon.html +1 -0
- package/dist/index.js +1 -1
- package/editor/chunks/extensions.js +124 -4
- package/editor/extensions/chip.d.ts +26 -0
- package/editor/extensions/index.d.ts +1 -0
- package/editor/extensions/index.js +2 -2
- package/editor/extensions/slash-command.d.ts +2 -1
- package/editor/icons.d.ts +1 -0
- package/editor/index.js +4 -3
- package/package.json +1 -1
- package/styles/ui-badge.css +3 -8
- package/vanilla/UiDialog.d.ts +1 -0
- package/vanilla/UiDialog.js +1 -1
- package/vanilla/UiIcon.js +1 -1
- package/vue/UiBadge.vue +7 -8
- package/vue/UiDialog.d.ts +2 -1
- package/vue/UiDialog.vue +2 -1
- package/vue/UiIcon.vue +4 -0
- package/vue/UiSearchShell.d.ts +1 -1
- package/vue/chunks/UiBadge.js +1 -1
- package/vue/chunks/UiDialog.js +6 -2
- package/vue/chunks/UiIcon.js +11 -1
- package/vue/components.css +165 -63
- package/vue/editor/index.js +115 -2
package/vue/editor/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineComponent, h, nextTick, onBeforeUnmount, onMounted, reactive, ref, useId, watch } from "vue";
|
|
2
|
-
import { DEFAULT_MENTION_RESULT_LIMIT, LOOMA_ICONS, createLoomaMentionExtension, createLoomaSlashCommandExtension, getActiveTableUiState, getDefaultEditorExtensions, getVisualViewportRect, handleTableAction, handleTableOverlayAction, measureTableOverlayGeometry, normalizeActiveTableColumnWidths, resolveTableCellAt, shouldShowTextFormattingToolbar } from "@threadlabs/looma/editor";
|
|
2
|
+
import { DEFAULT_MENTION_RESULT_LIMIT, LOOMA_CHIP_COLORS, LOOMA_ICONS, createLoomaMentionExtension, createLoomaSlashCommandExtension, getActiveTableUiState, getDefaultEditorExtensions, getVisualViewportRect, handleTableAction, handleTableOverlayAction, measureTableOverlayGeometry, normalizeActiveTableColumnWidths, normalizeLoomaChipColor, resolveTableCellAt, shouldShowTextFormattingToolbar } from "@threadlabs/looma/editor";
|
|
3
3
|
import { EditorInsertTableGrid, EditorMentionMenu, EditorSlashMenu, EditorTableContextMenu, EditorTableOverlay, EditorTableToolbar, EditorToolbar, IconButton, Menu, MenuItem, Popover, Tooltip } from "@threadlabs/looma/vue";
|
|
4
4
|
import { BubbleMenu, EditorContent, useEditor } from "@tiptap/vue-3";
|
|
5
5
|
import { Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
|
|
@@ -353,6 +353,11 @@ var LoomaEditor = defineComponent({
|
|
|
353
353
|
const linkText = ref("");
|
|
354
354
|
const linkNewTab = ref(true);
|
|
355
355
|
const linkError = ref("");
|
|
356
|
+
const chipAnchorId = `looma-editor-chip-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
357
|
+
const chipInput = ref(null);
|
|
358
|
+
const chipOpen = ref(false);
|
|
359
|
+
const chipLabel = ref("");
|
|
360
|
+
const chipColor = ref("neutral");
|
|
356
361
|
let linkSelection = null;
|
|
357
362
|
const toolbarScope = `looma-editor-tool-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
358
363
|
const tooltipFor = ref("");
|
|
@@ -435,8 +440,43 @@ var LoomaEditor = defineComponent({
|
|
|
435
440
|
menuStyle: {},
|
|
436
441
|
capabilities: { ...EMPTY_CAPABILITIES }
|
|
437
442
|
});
|
|
443
|
+
const openChipEditor = (instance, position) => {
|
|
444
|
+
if (!props.editable) return;
|
|
445
|
+
const node = instance.state.doc.nodeAt(position);
|
|
446
|
+
const element = instance.view.nodeDOM(position);
|
|
447
|
+
if (node?.type.name !== "loomaChip" || !(element instanceof HTMLElement)) return;
|
|
448
|
+
root.value?.querySelector(`#${chipAnchorId}`)?.removeAttribute("id");
|
|
449
|
+
element.id = chipAnchorId;
|
|
450
|
+
chipLabel.value = String(node.attrs.label ?? "");
|
|
451
|
+
chipColor.value = normalizeLoomaChipColor(node.attrs.color);
|
|
452
|
+
chipOpen.value = true;
|
|
453
|
+
nextTick(() => chipInput.value?.focus());
|
|
454
|
+
};
|
|
455
|
+
const changeChip = (changes) => {
|
|
456
|
+
const instance = editor.value;
|
|
457
|
+
const element = root.value?.querySelector(`#${chipAnchorId}`);
|
|
458
|
+
if (!instance || !element) {
|
|
459
|
+
chipOpen.value = false;
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const position = instance.view.posAtDOM(element, 0);
|
|
463
|
+
const node = instance.state.doc.nodeAt(position);
|
|
464
|
+
if (node?.type.name !== "loomaChip") {
|
|
465
|
+
chipOpen.value = false;
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
instance.view.dispatch(instance.state.tr.setNodeMarkup(position, void 0, {
|
|
469
|
+
...node.attrs,
|
|
470
|
+
...changes
|
|
471
|
+
}));
|
|
472
|
+
};
|
|
473
|
+
const closeChip = (focusChip = false) => {
|
|
474
|
+
chipOpen.value = false;
|
|
475
|
+
if (focusChip) root.value?.querySelector(`#${chipAnchorId}`)?.focus();
|
|
476
|
+
};
|
|
438
477
|
const slashExtension = createLoomaSlashCommandExtension({
|
|
439
478
|
onOpenImagePicker: () => fileInput.value?.click(),
|
|
479
|
+
onOpenChipEditor: openChipEditor,
|
|
440
480
|
onStateChange: (state) => {
|
|
441
481
|
Object.assign(slash, state);
|
|
442
482
|
}
|
|
@@ -602,7 +642,13 @@ var LoomaEditor = defineComponent({
|
|
|
602
642
|
instance.view.dispatch(transaction);
|
|
603
643
|
instance.commands.focus();
|
|
604
644
|
};
|
|
605
|
-
watch(() => props.editable, (editable) =>
|
|
645
|
+
watch(() => props.editable, (editable) => {
|
|
646
|
+
editor.value?.setEditable(editable);
|
|
647
|
+
root.value?.querySelectorAll("[data-looma-chip]").forEach((chip) => {
|
|
648
|
+
chip.setAttribute("aria-disabled", String(!editable));
|
|
649
|
+
});
|
|
650
|
+
if (!editable) chipOpen.value = false;
|
|
651
|
+
});
|
|
606
652
|
watch(() => props.label, (label) => {
|
|
607
653
|
editor.value?.setOptions({ editorProps: { attributes: {
|
|
608
654
|
role: "textbox",
|
|
@@ -796,6 +842,18 @@ var LoomaEditor = defineComponent({
|
|
|
796
842
|
trigger
|
|
797
843
|
});
|
|
798
844
|
};
|
|
845
|
+
const chipElementForEvent = (event) => {
|
|
846
|
+
const element = event.target instanceof Element ? event.target.closest("[data-looma-chip]") : null;
|
|
847
|
+
return element && root.value?.contains(element) ? element : null;
|
|
848
|
+
};
|
|
849
|
+
const onChipClickCapture = (event) => {
|
|
850
|
+
const chip = chipElementForEvent(event);
|
|
851
|
+
if (chip && editor.value && props.editable) {
|
|
852
|
+
event.preventDefault();
|
|
853
|
+
event.stopPropagation();
|
|
854
|
+
openChipEditor(editor.value, editor.value.view.posAtDOM(chip, 0));
|
|
855
|
+
}
|
|
856
|
+
};
|
|
799
857
|
const onImageClick = (event) => {
|
|
800
858
|
const element = imageElementForEvent(event);
|
|
801
859
|
if (element && !props.editable) activateImage(element, "pointer");
|
|
@@ -806,6 +864,12 @@ var LoomaEditor = defineComponent({
|
|
|
806
864
|
};
|
|
807
865
|
const onImageKeyDown = (event) => {
|
|
808
866
|
if (event.key !== "Enter" && event.key !== " ") return;
|
|
867
|
+
const chip = chipElementForEvent(event);
|
|
868
|
+
if (chip && editor.value && props.editable) {
|
|
869
|
+
event.preventDefault();
|
|
870
|
+
openChipEditor(editor.value, editor.value.view.posAtDOM(chip, 0));
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
809
873
|
const element = imageElementForEvent(event);
|
|
810
874
|
if (!element) return;
|
|
811
875
|
event.preventDefault();
|
|
@@ -1149,6 +1213,7 @@ var LoomaEditor = defineComponent({
|
|
|
1149
1213
|
}, 100);
|
|
1150
1214
|
},
|
|
1151
1215
|
onDrop,
|
|
1216
|
+
onClickCapture: onChipClickCapture,
|
|
1152
1217
|
onClick: onImageClick,
|
|
1153
1218
|
onDblclick: onImageDoubleClick,
|
|
1154
1219
|
onKeydown: onImageKeyDown
|
|
@@ -1213,6 +1278,54 @@ var LoomaEditor = defineComponent({
|
|
|
1213
1278
|
class: "looma-editor__drop-overlay",
|
|
1214
1279
|
"aria-hidden": "true"
|
|
1215
1280
|
}, [loomaIcon("image"), h("span", "Drop image to upload")]) : null,
|
|
1281
|
+
h(Popover, {
|
|
1282
|
+
class: "looma-editor__chip-popover",
|
|
1283
|
+
open: chipOpen.value,
|
|
1284
|
+
for: chipAnchorId,
|
|
1285
|
+
placement: mobile.value ? "top-start" : "bottom-start",
|
|
1286
|
+
onClose: () => {
|
|
1287
|
+
chipOpen.value = false;
|
|
1288
|
+
}
|
|
1289
|
+
}, () => h("div", {
|
|
1290
|
+
class: "looma-editor__chip-form",
|
|
1291
|
+
role: "dialog",
|
|
1292
|
+
"aria-label": "Edit chip"
|
|
1293
|
+
}, [h("input", {
|
|
1294
|
+
ref: chipInput,
|
|
1295
|
+
type: "text",
|
|
1296
|
+
value: chipLabel.value,
|
|
1297
|
+
placeholder: "Set a label",
|
|
1298
|
+
"aria-label": "Chip text",
|
|
1299
|
+
onInput: (event) => {
|
|
1300
|
+
chipLabel.value = event.target.value;
|
|
1301
|
+
changeChip({ label: chipLabel.value });
|
|
1302
|
+
},
|
|
1303
|
+
onKeydown: (event) => {
|
|
1304
|
+
if (event.key === "Enter" || event.key === "Escape") {
|
|
1305
|
+
event.preventDefault();
|
|
1306
|
+
closeChip(true);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
}), h("div", {
|
|
1310
|
+
class: "looma-editor__chip-colors",
|
|
1311
|
+
role: "group",
|
|
1312
|
+
"aria-label": "Chip color"
|
|
1313
|
+
}, LOOMA_CHIP_COLORS.map((color) => h("button", {
|
|
1314
|
+
type: "button",
|
|
1315
|
+
class: "looma-editor__chip-color",
|
|
1316
|
+
"data-color": color,
|
|
1317
|
+
"aria-label": `${color[0].toUpperCase()}${color.slice(1)} chip`,
|
|
1318
|
+
"aria-pressed": chipColor.value === color,
|
|
1319
|
+
onClick: () => {
|
|
1320
|
+
if (chipColor.value === color) {
|
|
1321
|
+
chipInput.value?.focus();
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
chipColor.value = color;
|
|
1325
|
+
changeChip({ color });
|
|
1326
|
+
chipInput.value?.focus();
|
|
1327
|
+
}
|
|
1328
|
+
}, chipColor.value === color ? "✓" : "")))])),
|
|
1216
1329
|
h(Popover, {
|
|
1217
1330
|
class: "looma-editor__link-popover",
|
|
1218
1331
|
open: linkOpen.value,
|