@threadlabs/looma 0.28.11 → 0.28.13
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/ui-editor-chip-editor/ui-editor-chip-editor.html +32 -0
- package/components/ui-editor-chip-editor/ui-editor-chip-editor.js +33 -0
- package/components/ui-radio-group/ui-radio-group.html +13 -1
- package/components/ui-swatch/ui-swatch.html +69 -0
- package/dist/index.js +38 -37
- package/editor/formatting-selection.d.ts +49 -0
- package/package.json +1 -1
- package/styles/ui-editor-chip-editor.css +1 -0
- package/styles/ui-radio-group.css +9 -0
- package/styles/ui-swatch.css +76 -0
- package/vanilla/UiEditorChipEditor.d.ts +18 -0
- package/vanilla/UiEditorChipEditor.js +45 -0
- package/vanilla/UiRadioGroup.d.ts +1 -0
- package/vanilla/UiRadioGroup.js +18 -13
- package/vanilla/UiSwatch.d.ts +14 -0
- package/vanilla/UiSwatch.js +54 -0
- package/vanilla/index.js +2 -0
- package/vue/UiEditorChipEditor.d.ts +45 -0
- package/vue/UiEditorChipEditor.js +2 -0
- package/vue/UiEditorChipEditor.vue +163 -0
- package/vue/UiRadioGroup.d.ts +9 -0
- package/vue/UiRadioGroup.vue +44 -2
- package/vue/UiSwatch.d.ts +16 -0
- package/vue/UiSwatch.js +2 -0
- package/vue/UiSwatch.vue +150 -0
- package/vue/chunks/UiEditorChipEditor.js +157 -0
- package/vue/chunks/UiEditorImageToolbar.js +2 -2
- package/vue/chunks/UiEditorLinkCard.js +1 -1
- package/vue/chunks/UiEditorLinkForm.js +2 -2
- package/vue/chunks/UiRadioGroup.js +26 -3
- package/vue/chunks/UiSwatch.js +78 -0
- package/vue/components.css +461 -443
- package/vue/editor/index.js +132 -109
- package/vue/editor/primitives.d.ts +9 -1
- package/vue/index.d.ts +2 -0
- package/vue/index.js +6 -4
package/vue/editor/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { computed, createApp, defineComponent, h, nextTick, onBeforeUnmount, onMounted, reactive, ref, shallowRef, useId, watch } from "vue";
|
|
2
|
-
import { DEFAULT_MENTION_RESULT_LIMIT,
|
|
3
|
-
import { Button, Callout, Card, Checkbox, Cluster, Disclosure, EditorBlockActions, 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, Text, Tooltip } from "@threadlabs/looma/vue";
|
|
2
|
+
import { DEFAULT_MENTION_RESULT_LIMIT, LOOMA_ICONS, createLoomaMentionExtension, createLoomaSlashCommandExtension, getActiveTableUiState, getDefaultEditorExtensions, getDefaultSlashCommands, getTableOfContentsEntries, getVisualViewportRect, handleTableAction, handleTableOverlayAction, measureTableOverlayGeometry, normalizeActiveTableColumnWidths, normalizeLoomaChipColor, normalizeTableOfContentsConfig } from "@threadlabs/looma/editor";
|
|
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, 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";
|
|
6
6
|
import { closeHistory } from "@tiptap/pm/history";
|
|
@@ -28,7 +28,8 @@ var EDITOR_ADAPTER_COMPONENT_TAG_MAP = {
|
|
|
28
28
|
EditorLinkCard: "ui-editor-link-card",
|
|
29
29
|
EditorLinkForm: "ui-editor-link-form",
|
|
30
30
|
EditorBlockActions: "ui-editor-block-actions",
|
|
31
|
-
EditorCodeLanguage: "ui-editor-code-language"
|
|
31
|
+
EditorCodeLanguage: "ui-editor-code-language",
|
|
32
|
+
EditorChipEditor: "ui-editor-chip-editor"
|
|
32
33
|
};
|
|
33
34
|
//#endregion
|
|
34
35
|
//#region src/components/shared/overlay.js
|
|
@@ -1130,6 +1131,76 @@ function runBlockAction(editor, action) {
|
|
|
1130
1131
|
return true;
|
|
1131
1132
|
}
|
|
1132
1133
|
//#endregion
|
|
1134
|
+
//#region src/editor/formatting-selection.ts
|
|
1135
|
+
var HOLD_MS = 500;
|
|
1136
|
+
var HOLD_SLOP_PX = 8;
|
|
1137
|
+
function createFormattingSelection(options) {
|
|
1138
|
+
const { editor } = options;
|
|
1139
|
+
let dismissedSelection = null;
|
|
1140
|
+
let heldSelection = null;
|
|
1141
|
+
let held = null;
|
|
1142
|
+
let timer;
|
|
1143
|
+
const cancel = () => {
|
|
1144
|
+
clearTimeout(timer);
|
|
1145
|
+
timer = void 0;
|
|
1146
|
+
held = null;
|
|
1147
|
+
};
|
|
1148
|
+
return {
|
|
1149
|
+
active() {
|
|
1150
|
+
const selection = editor.state.selection;
|
|
1151
|
+
return (selection instanceof TextSelection || selection instanceof AllSelection && Boolean(editor.state.doc.textContent)) && !dismissedSelection?.eq(selection) && (!selection.empty || Boolean(heldSelection?.eq(selection)) || options.shownAtCaret());
|
|
1152
|
+
},
|
|
1153
|
+
dismissed: (selection) => Boolean(dismissedSelection?.eq(selection)),
|
|
1154
|
+
dismiss(selection) {
|
|
1155
|
+
const current = editor.state.selection;
|
|
1156
|
+
dismissedSelection = selection !== void 0 ? selection : current instanceof TextSelection || current instanceof AllSelection ? current : null;
|
|
1157
|
+
heldSelection = null;
|
|
1158
|
+
},
|
|
1159
|
+
undismiss() {
|
|
1160
|
+
dismissedSelection = null;
|
|
1161
|
+
},
|
|
1162
|
+
release() {
|
|
1163
|
+
heldSelection = null;
|
|
1164
|
+
},
|
|
1165
|
+
selectionChanged() {
|
|
1166
|
+
const selection = editor.state.selection;
|
|
1167
|
+
if (!dismissedSelection?.eq(selection)) dismissedSelection = null;
|
|
1168
|
+
if (!heldSelection?.eq(selection)) heldSelection = null;
|
|
1169
|
+
},
|
|
1170
|
+
press: {
|
|
1171
|
+
down(event) {
|
|
1172
|
+
cancel();
|
|
1173
|
+
if (!options.canHold() || editor.isDestroyed || event.button !== 0 || !event.isPrimary || !(event.target instanceof Element) || !editor.view.dom.contains(event.target) || event.target.closest("button, input, select, textarea, [data-looma-image-node]")) return;
|
|
1174
|
+
held = {
|
|
1175
|
+
id: event.pointerId,
|
|
1176
|
+
x: event.clientX,
|
|
1177
|
+
y: event.clientY,
|
|
1178
|
+
time: event.timeStamp
|
|
1179
|
+
};
|
|
1180
|
+
timer = setTimeout(() => {
|
|
1181
|
+
timer = void 0;
|
|
1182
|
+
const selection = editor.state.selection;
|
|
1183
|
+
if (!held || !options.canHold() || !editor.isFocused || options.menuOpen() || !(selection instanceof TextSelection)) return;
|
|
1184
|
+
dismissedSelection = null;
|
|
1185
|
+
heldSelection = selection;
|
|
1186
|
+
options.onHold(selection);
|
|
1187
|
+
}, HOLD_MS);
|
|
1188
|
+
},
|
|
1189
|
+
move(event) {
|
|
1190
|
+
if (held?.id === event.pointerId && Math.hypot(event.clientX - held.x, event.clientY - held.y) > HOLD_SLOP_PX) cancel();
|
|
1191
|
+
},
|
|
1192
|
+
end(event) {
|
|
1193
|
+
if (held?.id === event.pointerId) cancel();
|
|
1194
|
+
},
|
|
1195
|
+
cancel,
|
|
1196
|
+
viewportChanged(event) {
|
|
1197
|
+
if (!event || !held || event.timeStamp >= held.time) cancel();
|
|
1198
|
+
}
|
|
1199
|
+
},
|
|
1200
|
+
destroy: cancel
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
//#endregion
|
|
1133
1204
|
//#region src/editor/table-overlay.ts
|
|
1134
1205
|
function mapTableCells(table) {
|
|
1135
1206
|
const rows = Array.from(table.rows);
|
|
@@ -2856,7 +2927,12 @@ var LoomaEditor = defineComponent({
|
|
|
2856
2927
|
let linkEditing;
|
|
2857
2928
|
const linkState = shallowRef(LOOMA_LINK_EDITING_IDLE);
|
|
2858
2929
|
const chipAnchorId = `looma-editor-chip-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
2859
|
-
const
|
|
2930
|
+
const chipEditorRoot = ref(null);
|
|
2931
|
+
const setChipEditorRoot = (instance) => {
|
|
2932
|
+
const element = instance?.$el;
|
|
2933
|
+
chipEditorRoot.value = element instanceof HTMLElement ? element : null;
|
|
2934
|
+
};
|
|
2935
|
+
const chipInput = () => chipEditorRoot.value?.querySelector("[data-chip-label]");
|
|
2860
2936
|
const chipOpen = ref(false);
|
|
2861
2937
|
const chipLabel = ref("");
|
|
2862
2938
|
const chipColor = ref("neutral");
|
|
@@ -2902,29 +2978,18 @@ var LoomaEditor = defineComponent({
|
|
|
2902
2978
|
const mobileToolbarStyle = ref({});
|
|
2903
2979
|
const mobile = ref(typeof window !== "undefined" && window.innerWidth <= 767);
|
|
2904
2980
|
const editorFocused = ref(false);
|
|
2905
|
-
let
|
|
2906
|
-
let heldFormattingSelection = null;
|
|
2981
|
+
let formatting;
|
|
2907
2982
|
let formattingPopup = null;
|
|
2908
2983
|
let linkPopup = null;
|
|
2909
2984
|
let imagePopup = null;
|
|
2910
|
-
let heldPressTimer;
|
|
2911
|
-
let heldPress = null;
|
|
2912
2985
|
const floatingFormattingMode = () => props.toolbarMode !== "sticky" && !(props.toolbarMode === "popover" && props.toolbarOpen) && !mobile.value;
|
|
2913
2986
|
const formattingPickerOpen = () => linkState.value.surface === "popover" || tablePickerOpen.value || formatOpen.value;
|
|
2914
|
-
const cancelHeldPress = () => {
|
|
2915
|
-
clearTimeout(heldPressTimer);
|
|
2916
|
-
heldPressTimer = void 0;
|
|
2917
|
-
heldPress = null;
|
|
2918
|
-
};
|
|
2919
2987
|
const activeRangeActions = (instance) => {
|
|
2920
2988
|
const selection = instance.state.selection;
|
|
2921
2989
|
if (!(selection instanceof TextSelection) || !selection.empty) return [];
|
|
2922
2990
|
return props.rangeActions.filter((action) => Number.isSafeInteger(action.from) && Number.isSafeInteger(action.to) && action.from >= 0 && action.to > action.from && action.to <= instance.state.doc.content.size && action.from <= selection.from && selection.from <= action.to);
|
|
2923
2991
|
};
|
|
2924
|
-
const
|
|
2925
|
-
const selection = instance.state.selection;
|
|
2926
|
-
return (selection instanceof TextSelection || selection instanceof AllSelection && Boolean(instance.state.doc.textContent)) && !dismissedFormattingSelection?.eq(selection) && (!selection.empty || Boolean(heldFormattingSelection?.eq(selection)) || activeRangeActions(instance).length > 0);
|
|
2927
|
-
};
|
|
2992
|
+
const formattingActive = () => formatting?.active() ?? false;
|
|
2928
2993
|
const editorStateVersion = ref(0);
|
|
2929
2994
|
const mobileToolbarMode = ref("formatting");
|
|
2930
2995
|
let dragLeaveTimer = null;
|
|
@@ -2979,7 +3044,7 @@ var LoomaEditor = defineComponent({
|
|
|
2979
3044
|
chipLabel.value = String(node.attrs.label ?? "");
|
|
2980
3045
|
chipColor.value = normalizeLoomaChipColor(node.attrs.color);
|
|
2981
3046
|
chipOpen.value = true;
|
|
2982
|
-
nextTick(() => chipInput
|
|
3047
|
+
nextTick(() => chipInput()?.focus());
|
|
2983
3048
|
};
|
|
2984
3049
|
const changeChip = (changes) => {
|
|
2985
3050
|
const instance = editor.value;
|
|
@@ -3094,7 +3159,7 @@ var LoomaEditor = defineComponent({
|
|
|
3094
3159
|
window.open(href, "_blank", "noopener,noreferrer");
|
|
3095
3160
|
return true;
|
|
3096
3161
|
}
|
|
3097
|
-
|
|
3162
|
+
formatting?.undismiss();
|
|
3098
3163
|
requestAnimationFrame(() => {
|
|
3099
3164
|
if (view.isDestroyed) return;
|
|
3100
3165
|
editorStateVersion.value += 1;
|
|
@@ -3117,10 +3182,9 @@ var LoomaEditor = defineComponent({
|
|
|
3117
3182
|
onSelectionUpdate: ({ editor: instance }) => {
|
|
3118
3183
|
rememberSelection(instance);
|
|
3119
3184
|
if (floatingFormattingMode()) {
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
if (!
|
|
3123
|
-
if (!formattingSelectionActive(instance)) formattingPopup?.hide();
|
|
3185
|
+
instance.state.selection;
|
|
3186
|
+
formatting?.selectionChanged();
|
|
3187
|
+
if (!formattingActive()) formattingPopup?.hide();
|
|
3124
3188
|
}
|
|
3125
3189
|
},
|
|
3126
3190
|
onUpdate: ({ editor: instance }) => {
|
|
@@ -3143,6 +3207,17 @@ var LoomaEditor = defineComponent({
|
|
|
3143
3207
|
linkState.value = engine.state;
|
|
3144
3208
|
});
|
|
3145
3209
|
linkEditing = engine;
|
|
3210
|
+
const instance = session.editor;
|
|
3211
|
+
formatting = createFormattingSelection({
|
|
3212
|
+
editor: instance,
|
|
3213
|
+
canHold: () => floatingFormattingMode() && !tableResizeActive && props.editable,
|
|
3214
|
+
menuOpen: () => slash.active || mention.active,
|
|
3215
|
+
shownAtCaret: () => activeRangeActions(instance).length > 0,
|
|
3216
|
+
onHold: (selection) => {
|
|
3217
|
+
formattingPopup?.setAnchor(() => posToDOMRect(instance.view, selection.from, selection.to));
|
|
3218
|
+
formattingPopup?.show();
|
|
3219
|
+
}
|
|
3220
|
+
});
|
|
3146
3221
|
});
|
|
3147
3222
|
const attachDocument = (element) => {
|
|
3148
3223
|
if (element instanceof HTMLElement) session?.attach(element);
|
|
@@ -3164,7 +3239,7 @@ var LoomaEditor = defineComponent({
|
|
|
3164
3239
|
const to = selection?.to ?? current.to;
|
|
3165
3240
|
linkEditing?.open(from, to, context ? "context" : "popover");
|
|
3166
3241
|
nextTick(() => {
|
|
3167
|
-
if (context) (props.toolbarMode === "contextual" && floatingFormattingMode() &&
|
|
3242
|
+
if (context) (props.toolbarMode === "contextual" && floatingFormattingMode() && formattingActive() ? formattingPopup : linkPopup)?.setAnchor(() => posToDOMRect(instance.view, instance.state.selection.from, instance.state.selection.to));
|
|
3168
3243
|
(linkState.value.mode === "url" ? linkDestinationInput() : linkFormRoot.value?.querySelector("[data-link-search]"))?.focus();
|
|
3169
3244
|
});
|
|
3170
3245
|
};
|
|
@@ -3172,8 +3247,7 @@ var LoomaEditor = defineComponent({
|
|
|
3172
3247
|
linkEditing?.close();
|
|
3173
3248
|
const range = linkState.value.range;
|
|
3174
3249
|
if (restoreFocus && range) editor.value?.chain().focus().setTextSelection(range.to).run();
|
|
3175
|
-
|
|
3176
|
-
heldFormattingSelection = null;
|
|
3250
|
+
formatting?.dismiss(editor.value?.state.selection ?? null);
|
|
3177
3251
|
linkPopup?.hide();
|
|
3178
3252
|
formattingPopup?.hide();
|
|
3179
3253
|
};
|
|
@@ -3242,8 +3316,8 @@ var LoomaEditor = defineComponent({
|
|
|
3242
3316
|
editor.value?.commands.dismissLoomaSlashMenu();
|
|
3243
3317
|
});
|
|
3244
3318
|
watch(() => props.editable, (editable) => {
|
|
3245
|
-
|
|
3246
|
-
|
|
3319
|
+
formatting?.press.cancel();
|
|
3320
|
+
formatting?.release();
|
|
3247
3321
|
editor.value?.setEditable(editable);
|
|
3248
3322
|
if (!editable) formattingPopup?.hide();
|
|
3249
3323
|
if (editor.value) imageDelivery.reset(editor.value);
|
|
@@ -3258,7 +3332,7 @@ var LoomaEditor = defineComponent({
|
|
|
3258
3332
|
formatOpen
|
|
3259
3333
|
], ([linking, table, format]) => {
|
|
3260
3334
|
if (linking || table || format || !floatingFormattingMode() || editor.value?.isFocused || formattingPopup?.element.contains(document.activeElement)) return;
|
|
3261
|
-
|
|
3335
|
+
formatting?.release();
|
|
3262
3336
|
formattingPopup?.hide();
|
|
3263
3337
|
});
|
|
3264
3338
|
watch(() => props.rangeActions, () => {
|
|
@@ -3434,12 +3508,12 @@ var LoomaEditor = defineComponent({
|
|
|
3434
3508
|
updateMobileViewport();
|
|
3435
3509
|
};
|
|
3436
3510
|
const onEditorBlur = () => {
|
|
3437
|
-
|
|
3511
|
+
formatting?.press.cancel();
|
|
3438
3512
|
queueMicrotask(updateTableUi);
|
|
3439
3513
|
updateCodeUi();
|
|
3440
3514
|
setTimeout(() => {
|
|
3441
3515
|
if (!tableInteractionActive && !editor.value?.isFocused && !mobileToolbarShell.value?.contains(document.activeElement)) editorFocused.value = false;
|
|
3442
|
-
if (!editor.value?.isFocused && !formattingPickerOpen() && !formattingPopup?.element.contains(document.activeElement))
|
|
3516
|
+
if (!editor.value?.isFocused && !formattingPickerOpen() && !formattingPopup?.element.contains(document.activeElement)) formatting?.release();
|
|
3443
3517
|
}, 0);
|
|
3444
3518
|
};
|
|
3445
3519
|
const bindEditorUi = (instance) => {
|
|
@@ -3465,15 +3539,15 @@ var LoomaEditor = defineComponent({
|
|
|
3465
3539
|
}, { immediate: true });
|
|
3466
3540
|
const onViewportChange = (event) => {
|
|
3467
3541
|
if (event?.type === "scroll" && event.target instanceof Node && (tableToolbarShell.value?.contains(event.target) || tableMenuShell.value?.contains(event.target))) return;
|
|
3468
|
-
|
|
3542
|
+
formatting?.press.viewportChanged(event);
|
|
3469
3543
|
const wasMobile = mobile.value;
|
|
3470
3544
|
if (slash.active && slash.getRect) slash.rect = slash.getRect();
|
|
3471
3545
|
if (mention.active && mention.getRect) mention.rect = mention.getRect();
|
|
3472
3546
|
updateMobileViewport();
|
|
3473
|
-
if (wasMobile !== mobile.value)
|
|
3547
|
+
if (wasMobile !== mobile.value) formatting?.release();
|
|
3474
3548
|
updateTableUi();
|
|
3475
3549
|
updateCodeUi();
|
|
3476
|
-
if (floatingFormattingMode() && editor.value && !
|
|
3550
|
+
if (floatingFormattingMode() && editor.value && !formattingActive()) formattingPopup?.hide();
|
|
3477
3551
|
tableUi.menuOpen = false;
|
|
3478
3552
|
};
|
|
3479
3553
|
let stopViewport;
|
|
@@ -3510,42 +3584,17 @@ var LoomaEditor = defineComponent({
|
|
|
3510
3584
|
}, 0);
|
|
3511
3585
|
if ((tableUi.toolbarOpen || tableUi.overlayOpen || tableUi.menuOpen) && !inElement(root.value) && !inTableUi) closeTableUi();
|
|
3512
3586
|
};
|
|
3513
|
-
const onFormattingPointerDown = (event) =>
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
if (!floatingFormattingMode() || tableResizeActive || !props.editable || !instance || event.button !== 0 || !event.isPrimary || !(event.target instanceof Element) || !instance.view.dom.contains(event.target) || event.target.closest("button, input, select, textarea, [data-looma-image-node]")) return;
|
|
3517
|
-
heldPress = {
|
|
3518
|
-
id: event.pointerId,
|
|
3519
|
-
x: event.clientX,
|
|
3520
|
-
y: event.clientY,
|
|
3521
|
-
time: event.timeStamp
|
|
3522
|
-
};
|
|
3523
|
-
heldPressTimer = setTimeout(() => {
|
|
3524
|
-
heldPressTimer = void 0;
|
|
3525
|
-
const selection = instance.state.selection;
|
|
3526
|
-
if (!heldPress || !floatingFormattingMode() || tableResizeActive || !props.editable || !instance.isFocused || slash.active || mention.active || !(selection instanceof TextSelection)) return;
|
|
3527
|
-
dismissedFormattingSelection = null;
|
|
3528
|
-
heldFormattingSelection = selection;
|
|
3529
|
-
formattingPopup?.setAnchor(() => posToDOMRect(instance.view, selection.from, selection.to));
|
|
3530
|
-
formattingPopup?.show();
|
|
3531
|
-
}, 500);
|
|
3532
|
-
};
|
|
3533
|
-
const onFormattingPointerMove = (event) => {
|
|
3534
|
-
if (heldPress?.id === event.pointerId && Math.hypot(event.clientX - heldPress.x, event.clientY - heldPress.y) > 8) cancelHeldPress();
|
|
3535
|
-
};
|
|
3536
|
-
const onFormattingPointerEnd = (event) => {
|
|
3537
|
-
if (heldPress?.id === event.pointerId) cancelHeldPress();
|
|
3538
|
-
};
|
|
3587
|
+
const onFormattingPointerDown = (event) => formatting?.press.down(event);
|
|
3588
|
+
const onFormattingPointerMove = (event) => formatting?.press.move(event);
|
|
3589
|
+
const onFormattingPointerEnd = (event) => formatting?.press.end(event);
|
|
3539
3590
|
const onFormattingKeyDown = (event) => {
|
|
3540
|
-
|
|
3591
|
+
formatting?.press.cancel();
|
|
3541
3592
|
if (event.key !== "Escape" || !(event.target instanceof Node) || !(root.value?.contains(event.target) || formattingPopup?.element.contains(event.target) || linkPopup?.element.contains(event.target)) || !(formatOpen.value || formattingPopup?.isOpen() || linkPopup?.isOpen())) return false;
|
|
3542
3593
|
dismissFormatting();
|
|
3543
3594
|
return true;
|
|
3544
3595
|
};
|
|
3545
3596
|
const dismissFormatting = () => {
|
|
3546
|
-
|
|
3547
|
-
dismissedFormattingSelection = selection instanceof TextSelection || selection instanceof AllSelection ? selection : null;
|
|
3548
|
-
heldFormattingSelection = null;
|
|
3597
|
+
formatting?.dismiss();
|
|
3549
3598
|
formatOpen.value = false;
|
|
3550
3599
|
formattingPopup?.hide();
|
|
3551
3600
|
linkPopup?.hide();
|
|
@@ -3568,10 +3617,10 @@ var LoomaEditor = defineComponent({
|
|
|
3568
3617
|
editor: instance,
|
|
3569
3618
|
element,
|
|
3570
3619
|
pluginKey: "looma-text-formatting-menu",
|
|
3571
|
-
shouldShow: ({ editor: menuEditor }) => (props.toolbarMode !== "popover" || !props.toolbarOpen) && !slash.active && !mention.active && (!props.editable && (props.selectionActions.length > 0 || props.rangeActions.length > 0) || menuEditor.isFocused || formattingPopup?.element.contains(document.activeElement) || linkState.value.surface === "context" || formattingPickerOpen()) &&
|
|
3620
|
+
shouldShow: ({ editor: menuEditor }) => (props.toolbarMode !== "popover" || !props.toolbarOpen) && !slash.active && !mention.active && (!props.editable && (props.selectionActions.length > 0 || props.rangeActions.length > 0) || menuEditor.isFocused || formattingPopup?.element.contains(document.activeElement) || linkState.value.surface === "context" || formattingPickerOpen()) && formattingActive(),
|
|
3572
3621
|
boundary: () => props.toolbarMode === "contextual" ? root.value : null,
|
|
3573
3622
|
related: editorRoot,
|
|
3574
|
-
onHide: () => instance.isEditable && floatingFormattingMode() && formattingPickerOpen() &&
|
|
3623
|
+
onHide: () => instance.isEditable && floatingFormattingMode() && formattingPickerOpen() && formattingActive() ? false : void 0,
|
|
3575
3624
|
onDismiss: (reason) => reason === "escape" ? dismissFormatting() : formattingPopup?.hide()
|
|
3576
3625
|
}));
|
|
3577
3626
|
const linkSurfaceRef = surfaceRef((surface) => {
|
|
@@ -3580,7 +3629,7 @@ var LoomaEditor = defineComponent({
|
|
|
3580
3629
|
editor: instance,
|
|
3581
3630
|
element,
|
|
3582
3631
|
pluginKey: "looma-link-context-menu",
|
|
3583
|
-
shouldShow: ({ editor: menuEditor, from, to }) => from === to && menuEditor.isActive("link") && linkState.value.surface !== "popover" && !
|
|
3632
|
+
shouldShow: ({ editor: menuEditor, from, to }) => from === to && menuEditor.isActive("link") && linkState.value.surface !== "popover" && !formatting?.dismissed(menuEditor.state.selection) && Boolean(menuEditor.isFocused || linkState.value.surface === "context" || linkPopup?.element.contains(document.activeElement)) && !(props.toolbarMode === "contextual" && floatingFormattingMode() && formattingActive()),
|
|
3584
3633
|
maxWidth: () => Math.min(480, window.innerWidth - 24),
|
|
3585
3634
|
related: editorRoot,
|
|
3586
3635
|
onDismiss: (reason) => reason === "escape" ? dismissFormatting() : linkPopup?.hide()
|
|
@@ -3747,7 +3796,7 @@ var LoomaEditor = defineComponent({
|
|
|
3747
3796
|
window.removeEventListener("keyup", onLinkNavigationModifier);
|
|
3748
3797
|
window.removeEventListener("pointermove", onLinkNavigationModifier);
|
|
3749
3798
|
window.removeEventListener("blur", clearLinkNavigationModifier);
|
|
3750
|
-
|
|
3799
|
+
formatting?.destroy();
|
|
3751
3800
|
formattingPopup = null;
|
|
3752
3801
|
document.removeEventListener("pointerdown", onDocumentPointerDown, true);
|
|
3753
3802
|
document.removeEventListener("pointerdown", onFormattingPointerDown);
|
|
@@ -4177,12 +4226,12 @@ var LoomaEditor = defineComponent({
|
|
|
4177
4226
|
ref: formattingSurfaceRef,
|
|
4178
4227
|
class: "looma-editor__floating-shell looma-editor__formatting-shell",
|
|
4179
4228
|
hidden: true
|
|
4180
|
-
}, [props.toolbarMode === "contextual" ? h(Stack, { gap: "xs" }, () => [renderToolbar(instance, true), (linkState.value.surface === "context" || instance.state.selection.empty && instance.isActive("link")) && linkState.value.surface !== "popover" &&
|
|
4229
|
+
}, [props.toolbarMode === "contextual" ? h(Stack, { gap: "xs" }, () => [renderToolbar(instance, true), (linkState.value.surface === "context" || instance.state.selection.empty && instance.isActive("link")) && linkState.value.surface !== "popover" && formattingActive() ? renderLinkContextCard(instance) : null]) : renderToolbar(instance, true, props.toolbarMode === "popover")])]) : null,
|
|
4181
4230
|
instance && props.editable ? h("div", { key: "looma-link-host" }, [h("div", {
|
|
4182
4231
|
ref: linkSurfaceRef,
|
|
4183
4232
|
class: "looma-editor__floating-shell looma-editor__link-shell",
|
|
4184
4233
|
hidden: true
|
|
4185
|
-
}, [props.toolbarMode === "contextual" && floatingFormattingMode() &&
|
|
4234
|
+
}, [props.toolbarMode === "contextual" && floatingFormattingMode() && formattingActive() ? null : renderLinkContextCard(instance)])]) : null,
|
|
4186
4235
|
instance && props.editable && !mobile.value && props.toolbarMode === "popover" && props.toolbarTriggerId ? h(Popover, {
|
|
4187
4236
|
class: "looma-editor__formatting-popover",
|
|
4188
4237
|
role: "region",
|
|
@@ -4267,46 +4316,20 @@ var LoomaEditor = defineComponent({
|
|
|
4267
4316
|
onClose: () => {
|
|
4268
4317
|
chipOpen.value = false;
|
|
4269
4318
|
}
|
|
4270
|
-
}, () => h(
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
type: "text",
|
|
4277
|
-
value: chipLabel.value,
|
|
4278
|
-
placeholder: "Set a label",
|
|
4279
|
-
"aria-label": "Chip text",
|
|
4280
|
-
onInput: (event) => {
|
|
4281
|
-
chipLabel.value = event.target.value;
|
|
4319
|
+
}, () => h(EditorChipEditor, {
|
|
4320
|
+
ref: setChipEditorRoot,
|
|
4321
|
+
label: chipLabel.value,
|
|
4322
|
+
color: chipColor.value,
|
|
4323
|
+
onLabel: (event) => {
|
|
4324
|
+
chipLabel.value = event.detail.label;
|
|
4282
4325
|
changeChip({ label: chipLabel.value });
|
|
4283
4326
|
},
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
}), h("div", {
|
|
4291
|
-
class: "looma-editor__chip-colors",
|
|
4292
|
-
role: "group",
|
|
4293
|
-
"aria-label": "Chip color"
|
|
4294
|
-
}, LOOMA_CHIP_COLORS.map((color) => h("button", {
|
|
4295
|
-
type: "button",
|
|
4296
|
-
class: "looma-editor__chip-color",
|
|
4297
|
-
"data-color": color,
|
|
4298
|
-
"aria-label": `${color[0].toUpperCase()}${color.slice(1)} chip`,
|
|
4299
|
-
"aria-pressed": chipColor.value === color,
|
|
4300
|
-
onClick: () => {
|
|
4301
|
-
if (chipColor.value === color) {
|
|
4302
|
-
chipInput.value?.focus();
|
|
4303
|
-
return;
|
|
4304
|
-
}
|
|
4305
|
-
chipColor.value = color;
|
|
4306
|
-
changeChip({ color });
|
|
4307
|
-
chipInput.value?.focus();
|
|
4308
|
-
}
|
|
4309
|
-
}, chipColor.value === color ? "✓" : "")))])),
|
|
4327
|
+
onColor: (event) => {
|
|
4328
|
+
chipColor.value = event.detail.color;
|
|
4329
|
+
changeChip({ color: event.detail.color });
|
|
4330
|
+
},
|
|
4331
|
+
onDone: () => closeChip(true)
|
|
4332
|
+
})),
|
|
4310
4333
|
h(Popover, {
|
|
4311
4334
|
class: "looma-editor__link-popover",
|
|
4312
4335
|
size: "sm",
|
|
@@ -4470,4 +4493,4 @@ var LoomaEditor = defineComponent({
|
|
|
4470
4493
|
}
|
|
4471
4494
|
});
|
|
4472
4495
|
//#endregion
|
|
4473
|
-
export { EDITOR_ADAPTER_COMPONENT_TAG_MAP, EditorBlockActions, EditorCodeLanguage, EditorImageToolbar, EditorInsertTableGrid, EditorLinkCard, EditorLinkForm, EditorMentionMenu, EditorMentionMenuItem, EditorSlashMenu, EditorSlashMenuGroup, EditorSlashMenuItem, EditorTableContextMenu, EditorTableOverlay, EditorTableToolbar, EditorToolbar, LoomaEditor };
|
|
4496
|
+
export { EDITOR_ADAPTER_COMPONENT_TAG_MAP, EditorBlockActions, EditorChipEditor, EditorCodeLanguage, EditorImageToolbar, EditorInsertTableGrid, EditorLinkCard, EditorLinkForm, EditorMentionMenu, EditorMentionMenuItem, EditorSlashMenu, EditorSlashMenuGroup, EditorSlashMenuItem, EditorTableContextMenu, EditorTableOverlay, EditorTableToolbar, EditorToolbar, LoomaEditor };
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* `@threadlabs/looma/vue`, re-exported beside the editor that composes them.
|
|
4
4
|
*/
|
|
5
5
|
import type { InsertTableEventDetail, MentionMenuHighlightEventDetail, MentionMenuSelectEventDetail, SlashMenuHighlightEventDetail, SlashMenuSelectEventDetail, TableContextMenuActionEventDetail } from "@threadlabs/looma/editor";
|
|
6
|
-
export { EditorBlockActions, EditorCodeLanguage, EditorImageToolbar, EditorInsertTableGrid, EditorLinkCard, EditorLinkForm, EditorMentionMenu, EditorMentionMenuItem, EditorSlashMenu, EditorSlashMenuGroup, EditorSlashMenuItem, EditorTableContextMenu, EditorTableOverlay, EditorTableToolbar, EditorToolbar, } from "@threadlabs/looma/vue";
|
|
6
|
+
export { EditorBlockActions, EditorChipEditor, EditorCodeLanguage, EditorImageToolbar, EditorInsertTableGrid, EditorLinkCard, EditorLinkForm, EditorMentionMenu, EditorMentionMenuItem, EditorSlashMenu, EditorSlashMenuGroup, EditorSlashMenuItem, EditorTableContextMenu, EditorTableOverlay, EditorTableToolbar, EditorToolbar, } from "@threadlabs/looma/vue";
|
|
7
7
|
/** The editor components' event details, by event name. */
|
|
8
8
|
export interface VueEditorAdapterEventMap {
|
|
9
9
|
highlight: MentionMenuHighlightEventDetail | SlashMenuHighlightEventDetail;
|
|
@@ -39,6 +39,13 @@ export interface VueEditorAdapterEventMap {
|
|
|
39
39
|
language: {
|
|
40
40
|
value: string;
|
|
41
41
|
};
|
|
42
|
+
label: {
|
|
43
|
+
label: string;
|
|
44
|
+
};
|
|
45
|
+
color: {
|
|
46
|
+
color: "neutral" | "blue" | "green" | "yellow" | "red" | "purple";
|
|
47
|
+
};
|
|
48
|
+
done: Record<string, never>;
|
|
42
49
|
"add-row-before": {
|
|
43
50
|
boundaryIndex: number;
|
|
44
51
|
};
|
|
@@ -107,4 +114,5 @@ export declare const EDITOR_ADAPTER_COMPONENT_TAG_MAP: {
|
|
|
107
114
|
readonly EditorLinkForm: "ui-editor-link-form";
|
|
108
115
|
readonly EditorBlockActions: "ui-editor-block-actions";
|
|
109
116
|
readonly EditorCodeLanguage: "ui-editor-code-language";
|
|
117
|
+
readonly EditorChipEditor: "ui-editor-chip-editor";
|
|
110
118
|
};
|
package/vue/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export { default as Dialog } from "./UiDialog.js";
|
|
|
20
20
|
export { default as Disclosure } from "./UiDisclosure.js";
|
|
21
21
|
export { default as Editable } from "./UiEditable.js";
|
|
22
22
|
export { default as EditorBlockActions } from "./UiEditorBlockActions.js";
|
|
23
|
+
export { default as EditorChipEditor } from "./UiEditorChipEditor.js";
|
|
23
24
|
export { default as EditorCodeLanguage } from "./UiEditorCodeLanguage.js";
|
|
24
25
|
export { default as EditorImageToolbar } from "./UiEditorImageToolbar.js";
|
|
25
26
|
export { default as EditorInsertTableGrid } from "./UiEditorInsertTableGrid.js";
|
|
@@ -66,6 +67,7 @@ export { default as Sidebar } from "./UiSidebar.js";
|
|
|
66
67
|
export { default as Spinner } from "./UiSpinner.js";
|
|
67
68
|
export { default as Stack } from "./UiStack.js";
|
|
68
69
|
export { default as StatusMessage } from "./UiStatusMessage.js";
|
|
70
|
+
export { default as Swatch } from "./UiSwatch.js";
|
|
69
71
|
export { default as Switch } from "./UiSwitch.js";
|
|
70
72
|
export { default as Switcher } from "./UiSwitcher.js";
|
|
71
73
|
export { default as Table } from "./UiTable.js";
|
package/vue/index.js
CHANGED
|
@@ -26,13 +26,16 @@ import { t as UiEditable_default } from "./chunks/UiEditable.js";
|
|
|
26
26
|
import { t as UiMenu_default } from "./chunks/UiMenu.js";
|
|
27
27
|
import { t as UiMenuItem_default } from "./chunks/UiMenuItem.js";
|
|
28
28
|
import { t as UiEditorBlockActions_default } from "./chunks/UiEditorBlockActions.js";
|
|
29
|
+
import { t as UiInput_default } from "./chunks/UiInput.js";
|
|
30
|
+
import { t as UiRadioGroup_default } from "./chunks/UiRadioGroup.js";
|
|
31
|
+
import { t as UiStack_default } from "./chunks/UiStack.js";
|
|
32
|
+
import { t as UiSwatch_default } from "./chunks/UiSwatch.js";
|
|
33
|
+
import { t as UiEditorChipEditor_default } from "./chunks/UiEditorChipEditor.js";
|
|
29
34
|
import { t as UiEditorCodeLanguage_default } from "./chunks/UiEditorCodeLanguage.js";
|
|
30
35
|
import { t as UiEditorToolbar_default } from "./chunks/UiEditorToolbar.js";
|
|
31
36
|
import { t as UiFormField_default } from "./chunks/UiFormField.js";
|
|
32
37
|
import { t as UiIconButton_default } from "./chunks/UiIconButton.js";
|
|
33
|
-
import { t as UiInput_default } from "./chunks/UiInput.js";
|
|
34
38
|
import { t as UiPopover_default } from "./chunks/UiPopover.js";
|
|
35
|
-
import { t as UiStack_default } from "./chunks/UiStack.js";
|
|
36
39
|
import { t as UiText_default } from "./chunks/UiText.js";
|
|
37
40
|
import { t as UiEditorImageToolbar_default } from "./chunks/UiEditorImageToolbar.js";
|
|
38
41
|
import { t as UiEditorInsertTableGrid_default } from "./chunks/UiEditorInsertTableGrid.js";
|
|
@@ -60,7 +63,6 @@ import { t as UiMeter_default } from "./chunks/UiMeter.js";
|
|
|
60
63
|
import { t as UiNavItem_default } from "./chunks/UiNavItem.js";
|
|
61
64
|
import { t as UiPageHeader_default } from "./chunks/UiPageHeader.js";
|
|
62
65
|
import { t as UiRadio_default } from "./chunks/UiRadio.js";
|
|
63
|
-
import { t as UiRadioGroup_default } from "./chunks/UiRadioGroup.js";
|
|
64
66
|
import { t as UiReel_default } from "./chunks/UiReel.js";
|
|
65
67
|
import { t as UiSearchShell_default } from "./chunks/UiSearchShell.js";
|
|
66
68
|
import { t as UiSection_default } from "./chunks/UiSection.js";
|
|
@@ -79,4 +81,4 @@ import { t as UiTopBar_default } from "./chunks/UiTopBar.js";
|
|
|
79
81
|
import { t as UiTree_default } from "./chunks/UiTree.js";
|
|
80
82
|
import { t as UiTreeItem_default } from "./chunks/UiTreeItem.js";
|
|
81
83
|
import { trackInputModality } from "@threadlabs/looma/components/shared/input-modality.js";
|
|
82
|
-
export { UiActionBar_default as ActionBar, UiAffordanceScope_default as AffordanceScope, UiAvatar_default as Avatar, UiAvatarGroup_default as AvatarGroup, UiBadge_default as Badge, UiBreadcrumbItem_default as BreadcrumbItem, UiBreadcrumbs_default as Breadcrumbs, UiButton_default as Button, UiCallout_default as Callout, UiCard_default as Card, UiCheckbox_default as Checkbox, UiCluster_default as Cluster, UiCombobox_default as Combobox, UiContainer_default as Container, UiContextMenu_default as ContextMenu, UiCover_default as Cover, UiDescriptionItem_default as DescriptionItem, UiDescriptionList_default as DescriptionList, UiDialog_default as Dialog, UiDisclosure_default as Disclosure, UiEditable_default as Editable, UiEditorBlockActions_default as EditorBlockActions, UiEditorCodeLanguage_default as EditorCodeLanguage, UiEditorImageToolbar_default as EditorImageToolbar, UiEditorInsertTableGrid_default as EditorInsertTableGrid, UiEditorLinkCard_default as EditorLinkCard, UiEditorLinkForm_default as EditorLinkForm, UiEditorMentionMenu_default as EditorMentionMenu, UiEditorMentionMenuItem_default as EditorMentionMenuItem, UiEditorSlashMenu_default as EditorSlashMenu, UiEditorSlashMenuGroup_default as EditorSlashMenuGroup, UiEditorSlashMenuItem_default as EditorSlashMenuItem, UiEditorSurface_default as EditorSurface, UiEditorTableContextMenu_default as EditorTableContextMenu, UiEditorTableOverlay_default as EditorTableOverlay, UiEditorTableToolbar_default as EditorTableToolbar, UiEditorToolbar_default as EditorToolbar, UiFloatingActionButton_default as FloatingActionButton, UiFormField_default as FormField, UiGrid_default as Grid, UiIcon_default as Icon, UiIconButton_default as IconButton, UiImage_default as Image, UiInput_default as Input, UiInputGroup_default as InputGroup, UiList_default as List, UiListItem_default as ListItem, UiListbox_default as Listbox, UiMenu_default as Menu, UiMenuGroup_default as MenuGroup, UiMenuItem_default as MenuItem, UiMeter_default as Meter, UiNavItem_default as NavItem, UiPageHeader_default as PageHeader, UiPopover_default as Popover, UiRadio_default as Radio, UiRadioGroup_default as RadioGroup, UiReel_default as Reel, UiScrollArea_default as ScrollArea, UiSearchResultRow_default as SearchResultRow, UiSearchShell_default as SearchShell, UiSection_default as Section, UiSelect_default as Select, UiSeparator_default as Separator, UiSidebar_default as Sidebar, UiSpinner_default as Spinner, UiStack_default as Stack, UiStatusMessage_default as StatusMessage, UiSwitch_default as Switch, UiSwitcher_default as Switcher, UiTable_default as Table, UiTabs_default as Tabs, UiText_default as Text, UiTextarea_default as Textarea, UiToast_default as Toast, UiToastRegion_default as ToastRegion, UiTooltip_default as Tooltip, UiTopBar_default as TopBar, UiTree_default as Tree, UiTreeItem_default as TreeItem, trackInputModality };
|
|
84
|
+
export { UiActionBar_default as ActionBar, UiAffordanceScope_default as AffordanceScope, UiAvatar_default as Avatar, UiAvatarGroup_default as AvatarGroup, UiBadge_default as Badge, UiBreadcrumbItem_default as BreadcrumbItem, UiBreadcrumbs_default as Breadcrumbs, UiButton_default as Button, UiCallout_default as Callout, UiCard_default as Card, UiCheckbox_default as Checkbox, UiCluster_default as Cluster, UiCombobox_default as Combobox, UiContainer_default as Container, UiContextMenu_default as ContextMenu, UiCover_default as Cover, UiDescriptionItem_default as DescriptionItem, UiDescriptionList_default as DescriptionList, UiDialog_default as Dialog, UiDisclosure_default as Disclosure, UiEditable_default as Editable, UiEditorBlockActions_default as EditorBlockActions, UiEditorChipEditor_default as EditorChipEditor, UiEditorCodeLanguage_default as EditorCodeLanguage, UiEditorImageToolbar_default as EditorImageToolbar, UiEditorInsertTableGrid_default as EditorInsertTableGrid, UiEditorLinkCard_default as EditorLinkCard, UiEditorLinkForm_default as EditorLinkForm, UiEditorMentionMenu_default as EditorMentionMenu, UiEditorMentionMenuItem_default as EditorMentionMenuItem, UiEditorSlashMenu_default as EditorSlashMenu, UiEditorSlashMenuGroup_default as EditorSlashMenuGroup, UiEditorSlashMenuItem_default as EditorSlashMenuItem, UiEditorSurface_default as EditorSurface, UiEditorTableContextMenu_default as EditorTableContextMenu, UiEditorTableOverlay_default as EditorTableOverlay, UiEditorTableToolbar_default as EditorTableToolbar, UiEditorToolbar_default as EditorToolbar, UiFloatingActionButton_default as FloatingActionButton, UiFormField_default as FormField, UiGrid_default as Grid, UiIcon_default as Icon, UiIconButton_default as IconButton, UiImage_default as Image, UiInput_default as Input, UiInputGroup_default as InputGroup, UiList_default as List, UiListItem_default as ListItem, UiListbox_default as Listbox, UiMenu_default as Menu, UiMenuGroup_default as MenuGroup, UiMenuItem_default as MenuItem, UiMeter_default as Meter, UiNavItem_default as NavItem, UiPageHeader_default as PageHeader, UiPopover_default as Popover, UiRadio_default as Radio, UiRadioGroup_default as RadioGroup, UiReel_default as Reel, UiScrollArea_default as ScrollArea, UiSearchResultRow_default as SearchResultRow, UiSearchShell_default as SearchShell, UiSection_default as Section, UiSelect_default as Select, UiSeparator_default as Separator, UiSidebar_default as Sidebar, UiSpinner_default as Spinner, UiStack_default as Stack, UiStatusMessage_default as StatusMessage, UiSwatch_default as Swatch, UiSwitch_default as Switch, UiSwitcher_default as Switcher, UiTable_default as Table, UiTabs_default as Tabs, UiText_default as Text, UiTextarea_default as Textarea, UiToast_default as Toast, UiToastRegion_default as ToastRegion, UiTooltip_default as Tooltip, UiTopBar_default as TopBar, UiTree_default as Tree, UiTreeItem_default as TreeItem, trackInputModality };
|