@threadlabs/looma 0.32.0 → 0.32.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/chunks/extensions.js +17 -1
- package/editor/extensions/slash-command.d.ts +1 -1
- package/editor/file-uploads.d.ts +31 -0
- package/editor/icons.d.ts +1 -0
- package/editor/index.js +2 -1
- package/package.json +1 -1
- package/vue/editor/LoomaEditor.d.ts +18 -2
- package/vue/editor/index.d.ts +2 -1
- package/vue/editor/index.js +119 -5
|
@@ -11986,7 +11986,7 @@ var CALLOUT_COMMANDS = [
|
|
|
11986
11986
|
* @ownership Returned command objects belong to the caller and are recreated
|
|
11987
11987
|
* per call so one editor cannot mutate another editor's command inventory.
|
|
11988
11988
|
*/
|
|
11989
|
-
function getDefaultSlashCommands(onOpenImagePicker, onOpenChipEditor, onOpenLinkEditor) {
|
|
11989
|
+
function getDefaultSlashCommands(onOpenImagePicker, onOpenChipEditor, onOpenLinkEditor, onOpenFilePicker) {
|
|
11990
11990
|
return [
|
|
11991
11991
|
{
|
|
11992
11992
|
title: "Text",
|
|
@@ -12209,6 +12209,21 @@ function getDefaultSlashCommands(onOpenImagePicker, onOpenChipEditor, onOpenLink
|
|
|
12209
12209
|
onOpenLinkEditor();
|
|
12210
12210
|
}
|
|
12211
12211
|
}] : [],
|
|
12212
|
+
...onOpenFilePicker ? [{
|
|
12213
|
+
title: "File attachment",
|
|
12214
|
+
description: "Attach a file",
|
|
12215
|
+
icon: "paperclip",
|
|
12216
|
+
keywords: [
|
|
12217
|
+
"file",
|
|
12218
|
+
"attachment",
|
|
12219
|
+
"upload",
|
|
12220
|
+
"pdf"
|
|
12221
|
+
],
|
|
12222
|
+
command: ({ editor, range }) => {
|
|
12223
|
+
editor.chain().focus().deleteRange(range).run();
|
|
12224
|
+
onOpenFilePicker();
|
|
12225
|
+
}
|
|
12226
|
+
}] : [],
|
|
12212
12227
|
...onOpenImagePicker ? [{
|
|
12213
12228
|
title: "Image",
|
|
12214
12229
|
description: "Upload an image",
|
|
@@ -12228,6 +12243,7 @@ function getDefaultSlashCommands(onOpenImagePicker, onOpenChipEditor, onOpenLink
|
|
|
12228
12243
|
...command,
|
|
12229
12244
|
id: command.title.toLowerCase().replaceAll(" ", "-"),
|
|
12230
12245
|
group: CALLOUT_COMMANDS.some((callout) => callout.title === command.title) ? "Callouts" : [
|
|
12246
|
+
"File attachment",
|
|
12231
12247
|
"Chip",
|
|
12232
12248
|
"Inline code",
|
|
12233
12249
|
"Link",
|
|
@@ -79,7 +79,7 @@ declare module "@tiptap/core" {
|
|
|
79
79
|
* @ownership Returned command objects belong to the caller and are recreated
|
|
80
80
|
* per call so one editor cannot mutate another editor's command inventory.
|
|
81
81
|
*/
|
|
82
|
-
export declare function getDefaultSlashCommands(onOpenImagePicker?: () => void, onOpenChipEditor?: (editor: Editor, position: number) => void, onOpenLinkEditor?: () => void): LoomaSlashCommand[];
|
|
82
|
+
export declare function getDefaultSlashCommands(onOpenImagePicker?: () => void, onOpenChipEditor?: (editor: Editor, position: number) => void, onOpenLinkEditor?: () => void, onOpenFilePicker?: () => void): LoomaSlashCommand[];
|
|
83
83
|
/**
|
|
84
84
|
* Ranks exact names/aliases before partial matches, then matching categories.
|
|
85
85
|
* Other ties retain inventory order.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Editor } from '@tiptap/core';
|
|
2
|
+
/** A retained file, represented as a readable ordinary link in the document. */
|
|
3
|
+
export interface LoomaFileDescriptor {
|
|
4
|
+
href: string;
|
|
5
|
+
name: string;
|
|
6
|
+
size: number;
|
|
7
|
+
contentType: string;
|
|
8
|
+
}
|
|
9
|
+
/** The application retains the bytes and returns their authorized download URL. */
|
|
10
|
+
export type LoomaFileUpload = (file: File, init: {
|
|
11
|
+
signal: AbortSignal;
|
|
12
|
+
progress: (loaded: number, total: number) => void;
|
|
13
|
+
}) => PromiseLike<LoomaFileDescriptor | null> | LoomaFileDescriptor | null;
|
|
14
|
+
/** File insertion status, independent of the document and its undo history. */
|
|
15
|
+
export interface LoomaFileUploadsState {
|
|
16
|
+
uploading: boolean;
|
|
17
|
+
progress: {
|
|
18
|
+
loaded: number;
|
|
19
|
+
total: number;
|
|
20
|
+
} | null;
|
|
21
|
+
}
|
|
22
|
+
/** Captures the caret before asynchronous transport; later transactions map that caret. */
|
|
23
|
+
export declare function createFileUploads(options: {
|
|
24
|
+
editor: Editor;
|
|
25
|
+
upload: () => LoomaFileUpload | undefined;
|
|
26
|
+
onError: (error: unknown, file: File) => void;
|
|
27
|
+
onState?: (state: LoomaFileUploadsState) => void;
|
|
28
|
+
}): {
|
|
29
|
+
cancel(): void;
|
|
30
|
+
insert(file: File): Promise<void>;
|
|
31
|
+
};
|
package/editor/icons.d.ts
CHANGED
package/editor/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { n as TABLE_CELL_BACKGROUND_PRESETS, t as TABLE_CELL_BACKGROUND_OPTIONS
|
|
|
2
2
|
import { n as resolveTableCellAt, t as measureTableOverlayGeometry } from "./chunks/ui.js";
|
|
3
3
|
import { $ as LOOMA_ACTIVE_BLOCK_BLUR_GRACE_MS, A as filterLoomaMentionItems, B as LOOMA_FOOTNOTE_LABEL, C as loomaMarkdownToHtml, D as createLoomaMentionExtension, E as LoomaMentionSuggestionPluginKey, F as LoomaTableOfContents, G as LoomaFigcaption, H as LoomaFootnoteReference, I as getTableOfContentsEntries, J as revealLoomaExpandAt, K as LoomaFigure, L as normalizeTableOfContentsConfig, M as LoomaImage, N as normalizeImageDimension, O as DEFAULT_MENTION_RESULT_LIMIT, P as normalizeImagePlacement, Q as LoomaCallout, R as LoomaTab, S as loomaMarkdownFromDoc, T as siteRelativeHref, U as LoomaFootnotes, V as LoomaFootnote, W as findLoomaFootnote, X as LoomaChip, Y as LOOMA_CHIP_COLORS, Z as normalizeLoomaChipColor, _ as getActiveTableCellAlignment, a as getActiveTableUiState, b as setActiveTableCellBackground, c as insertTableAtRange, d as LoomaTableKit, et as LOOMA_ACTIVE_BLOCK_CLASS, f as getDefaultEditorExtensions, g as LoomaTableHeader, h as LoomaTableCell, i as getDefaultSlashCommands, j as normalizeMentionResultLimit, k as MAX_MENTION_RESULT_LIMIT, l as normalizeActiveTableColumnWidths, m as LoomaTable, n as createLoomaSlashCommandExtension, nt as LoomaActiveBlock, o as handleTableAction, p as getLoomaTableExtensions, q as LoomaExpand, r as filterLoomaSlashCommands, rt as LoomaActiveBlockPluginKey, s as handleTableOverlayAction, t as LoomaSlashCommand, tt as LOOMA_ACTIVE_BLOCK_TYPING_IDLE_MS, u as shouldShowTextFormattingToolbar, v as getActiveTableCellBackground, w as createSiteRelativeLinks, x as LoomaSmartPaste, y as setActiveTableCellAlignment, z as LoomaTabs } from "./chunks/extensions.js";
|
|
4
4
|
import { a as setReferenceDisplay, i as referenceDisplay, n as LoomaReferencePresentation, o as LOOMA_CALLOUT_TONES, r as getReferenceDisplay, t as LoomaReference } from "./chunks/reference-display.js";
|
|
5
|
-
import { AlignCenter, AlignLeft, AlignRight, ArrowLeft, Bell, Bold, BookUser, Braces, Calculator, Check, ChevronDown, ChevronLeft, ChevronRight, CircleCheck, CircleDot, CircleQuestionMark, CircleX, CodeXml, Columns3, Compass, CreditCard, Ellipsis, Eraser, ExternalLink, FileText, Folder, GripHorizontal, GripVertical, Heading1, Heading2, Heading3, Highlighter, History, Image, Info, Italic, LayoutDashboard, Lightbulb, Link, List, ListOrdered, ListTodo, LoaderCircle, Merge, MessageSquareWarning, Minus, NotebookPen, PaintBucket, PanelBottom, PanelLeft, PanelRight, PanelTop, Pencil, Pilcrow, Plus, Quote, Receipt, Redo2, Rows3, Search, Settings, Split, Strikethrough, Superscript, Table2, Tag, Trash2, TriangleAlert, Truck, Underline, Undo2, Unlink, UserRound, Users, X } from "lucide";
|
|
5
|
+
import { AlignCenter, AlignLeft, AlignRight, ArrowLeft, Bell, Bold, BookUser, Braces, Calculator, Check, ChevronDown, ChevronLeft, ChevronRight, CircleCheck, CircleDot, CircleQuestionMark, CircleX, CodeXml, Columns3, Compass, CreditCard, Ellipsis, Eraser, ExternalLink, FileText, Folder, GripHorizontal, GripVertical, Heading1, Heading2, Heading3, Highlighter, History, Image, Info, Italic, LayoutDashboard, Lightbulb, Link, List, ListOrdered, ListTodo, LoaderCircle, Merge, MessageSquareWarning, Minus, NotebookPen, PaintBucket, PanelBottom, PanelLeft, PanelRight, PanelTop, Paperclip, Pencil, Pilcrow, Plus, Quote, Receipt, Redo2, Rows3, Search, Settings, Split, Strikethrough, Superscript, Table2, Tag, Trash2, TriangleAlert, Truck, Underline, Undo2, Unlink, UserRound, Users, X } from "lucide";
|
|
6
6
|
//#region src/editor/icons.ts
|
|
7
7
|
/** The opinionated Lucide set used by Looma's shipped interaction surfaces. */
|
|
8
8
|
var LOOMA_ICONS = {
|
|
@@ -43,6 +43,7 @@ var LOOMA_ICONS = {
|
|
|
43
43
|
highlighter: Highlighter,
|
|
44
44
|
history: History,
|
|
45
45
|
image: Image,
|
|
46
|
+
paperclip: Paperclip,
|
|
46
47
|
info: Info,
|
|
47
48
|
italic: Italic,
|
|
48
49
|
"layout-dashboard": LayoutDashboard,
|
package/package.json
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type LoomaFileDescriptor } from "../../editor/file-uploads.js";
|
|
1
2
|
import "../../components/ui-editor-surface/ui-editor-surface.css";
|
|
2
3
|
import "./looma-editor.css";
|
|
3
4
|
import { type AnyExtension, type Editor, type JSONContent } from "@tiptap/core";
|
|
@@ -77,6 +78,10 @@ export type LoomaMentionQuery = LoomaResponder<LoomaMentionQueryDetail, LoomaMen
|
|
|
77
78
|
* @failure A rejection leaves the document unchanged and emits `uploadError`.
|
|
78
79
|
*/
|
|
79
80
|
export type LoomaImageUploader = LoomaResponder<LoomaImageUploadDetail, LoomaImageDescriptor>;
|
|
81
|
+
/** Uploads a file and returns its retained link; rejection leaves authored content unchanged. */
|
|
82
|
+
export type LoomaFileUploader = LoomaResponder<{
|
|
83
|
+
file: File;
|
|
84
|
+
}, LoomaFileDescriptor>;
|
|
80
85
|
/**
|
|
81
86
|
* Turnkey Vue editor that composes Looma's framework-neutral Tiptap extensions
|
|
82
87
|
* with declarative menus, image delivery, and table interaction chrome.
|
|
@@ -174,7 +179,12 @@ export declare const LoomaEditor: import("vue").DefineComponent<import("vue").Ex
|
|
|
174
179
|
type: StringConstructor;
|
|
175
180
|
default: string;
|
|
176
181
|
};
|
|
177
|
-
/** Answers `
|
|
182
|
+
/** Answers `file-upload` with a retained ordinary file link. */
|
|
183
|
+
fileUpload: {
|
|
184
|
+
type: PropType<LoomaFileUploader | undefined>;
|
|
185
|
+
default: undefined;
|
|
186
|
+
};
|
|
187
|
+
/** Answers `image-upload` with the image to insert. */
|
|
178
188
|
imageUpload: {
|
|
179
189
|
type: PropType<LoomaImageUploader | undefined>;
|
|
180
190
|
default: undefined;
|
|
@@ -324,7 +334,12 @@ export declare const LoomaEditor: import("vue").DefineComponent<import("vue").Ex
|
|
|
324
334
|
type: StringConstructor;
|
|
325
335
|
default: string;
|
|
326
336
|
};
|
|
327
|
-
/** Answers `
|
|
337
|
+
/** Answers `file-upload` with a retained ordinary file link. */
|
|
338
|
+
fileUpload: {
|
|
339
|
+
type: PropType<LoomaFileUploader | undefined>;
|
|
340
|
+
default: undefined;
|
|
341
|
+
};
|
|
342
|
+
/** Answers `image-upload` with the image to insert. */
|
|
328
343
|
imageUpload: {
|
|
329
344
|
type: PropType<LoomaImageUploader | undefined>;
|
|
330
345
|
default: undefined;
|
|
@@ -402,6 +417,7 @@ export declare const LoomaEditor: import("vue").DefineComponent<import("vue").Ex
|
|
|
402
417
|
linkSearch: LoomaLinkSearch | undefined;
|
|
403
418
|
linkResolve: LoomaLinkResolve | undefined;
|
|
404
419
|
imageUpload: LoomaImageUploader | undefined;
|
|
420
|
+
fileUpload: LoomaFileUploader | undefined;
|
|
405
421
|
modelValue: JSONContent;
|
|
406
422
|
contentDensity: "comfortable" | "compact";
|
|
407
423
|
mentionItems: LoomaMentionItem[];
|
package/vue/editor/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from "@threadlabs/looma/editor";
|
|
2
2
|
export * from "./primitives.js";
|
|
3
|
-
export { LoomaEditor, type LoomaEditorToolbarMode, type LoomaEditorSelectionAction, type LoomaEditorSelectionActionDetail, type LoomaEditorRangeAction, type LoomaEditorRangeActionDetail, type LoomaEditorExtensions, type LoomaEditorSlashCommands, type LoomaSlashCommandsDetail, type LoomaLinkTarget, type LoomaLinkSearch, type LoomaLinkSearchDetail, type LoomaLinkResolve, type LoomaLinkResolveDetail, type LoomaMentionQuery, type LoomaMentionQueryDetail, type LoomaImageUploader, type LoomaImageUploadDetail, type LoomaRequestInit, type LoomaResponder, } from "./LoomaEditor.js";
|
|
3
|
+
export { LoomaEditor, type LoomaEditorToolbarMode, type LoomaEditorSelectionAction, type LoomaEditorSelectionActionDetail, type LoomaEditorRangeAction, type LoomaEditorRangeActionDetail, type LoomaEditorExtensions, type LoomaEditorSlashCommands, type LoomaSlashCommandsDetail, type LoomaLinkTarget, type LoomaLinkSearch, type LoomaLinkSearchDetail, type LoomaLinkResolve, type LoomaLinkResolveDetail, type LoomaMentionQuery, type LoomaMentionQueryDetail, type LoomaFileUploader, type LoomaImageUploader, type LoomaImageUploadDetail, type LoomaRequestInit, type LoomaResponder, } from "./LoomaEditor.js";
|
|
4
4
|
export type { LoomaImageActivationDetail, LoomaImageActivationTrigger, LoomaImageAttributeResolver, LoomaImageSourceResolver, LoomaImageDescriptor, LoomaImageRenditionErrorDetail, LoomaImageRenditionAttributes, } from "../../editor/image-delivery.js";
|
|
5
|
+
export type { LoomaFileDescriptor } from "../../editor/file-uploads.js";
|
package/vue/editor/index.js
CHANGED
|
@@ -47,6 +47,73 @@ var EDITOR_ADAPTER_COMPONENT_TAG_MAP = {
|
|
|
47
47
|
EditorFootnoteEditor: "ui-editor-footnote-editor"
|
|
48
48
|
};
|
|
49
49
|
//#endregion
|
|
50
|
+
//#region src/editor/file-uploads.ts
|
|
51
|
+
/** Captures the caret before asynchronous transport; later transactions map that caret. */
|
|
52
|
+
function createFileUploads(options) {
|
|
53
|
+
let active;
|
|
54
|
+
const state = (uploading, progress = null) => options.onState?.({
|
|
55
|
+
uploading,
|
|
56
|
+
progress
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
cancel() {
|
|
60
|
+
active?.abort();
|
|
61
|
+
state(false);
|
|
62
|
+
},
|
|
63
|
+
async insert(file) {
|
|
64
|
+
const upload = options.upload();
|
|
65
|
+
if (!upload || options.editor.isDestroyed) return;
|
|
66
|
+
active?.abort();
|
|
67
|
+
const controller = new AbortController();
|
|
68
|
+
active = controller;
|
|
69
|
+
const { editor } = options;
|
|
70
|
+
let position = editor.state.selection.from;
|
|
71
|
+
const map = ({ transaction }) => {
|
|
72
|
+
position = transaction.mapping.map(position);
|
|
73
|
+
};
|
|
74
|
+
editor.on("transaction", map);
|
|
75
|
+
state(true);
|
|
76
|
+
try {
|
|
77
|
+
const answer = await upload(file, {
|
|
78
|
+
signal: controller.signal,
|
|
79
|
+
progress: (loaded, total) => {
|
|
80
|
+
if (!controller.signal.aborted) state(true, {
|
|
81
|
+
loaded,
|
|
82
|
+
total
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
if (!answer || controller.signal.aborted || editor.isDestroyed || !editor.isEditable) return;
|
|
87
|
+
if (!/^(?:https?:\/\/|\/(?!\/))/.test(answer.href) || !Number.isSafeInteger(answer.size) || answer.size < 0) throw new Error("Invalid file descriptor");
|
|
88
|
+
const size = answer.size < 1e3 ? `${answer.size} B` : answer.size < 1e6 ? `${Math.ceil(answer.size / 1e3)} KB` : `${Number((answer.size / 1e6).toFixed(1))} MB`;
|
|
89
|
+
editor.chain().focus().insertContentAt(position, [{
|
|
90
|
+
type: "text",
|
|
91
|
+
text: answer.name || file.name,
|
|
92
|
+
marks: [{
|
|
93
|
+
type: "link",
|
|
94
|
+
attrs: {
|
|
95
|
+
href: answer.href,
|
|
96
|
+
target: "_blank",
|
|
97
|
+
rel: "noopener noreferrer"
|
|
98
|
+
}
|
|
99
|
+
}]
|
|
100
|
+
}, {
|
|
101
|
+
type: "text",
|
|
102
|
+
text: ` (${answer.contentType || "application/octet-stream"}, ${size}) `
|
|
103
|
+
}]).run();
|
|
104
|
+
} catch (error) {
|
|
105
|
+
if (!controller.signal.aborted) options.onError(error, file);
|
|
106
|
+
} finally {
|
|
107
|
+
editor.off("transaction", map);
|
|
108
|
+
if (active === controller) {
|
|
109
|
+
active = void 0;
|
|
110
|
+
state(false);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
50
117
|
//#region src/components/shared/overlay.js
|
|
51
118
|
function stateFor$1(document) {
|
|
52
119
|
const key = Symbol.for("@threadlabs/looma/overlay-stack/v1");
|
|
@@ -14546,7 +14613,8 @@ var EDITOR_REQUESTS = {
|
|
|
14546
14613
|
"mention-query": "mentionQuery",
|
|
14547
14614
|
"link-search": "linkSearch",
|
|
14548
14615
|
"link-resolve": "linkResolve",
|
|
14549
|
-
"image-upload": "imageUpload"
|
|
14616
|
+
"image-upload": "imageUpload",
|
|
14617
|
+
"file-upload": "fileUpload"
|
|
14550
14618
|
};
|
|
14551
14619
|
var EDITOR_REQUEST_NAMES = Object.keys(EDITOR_REQUESTS);
|
|
14552
14620
|
var EMPTY_DOCUMENT = {
|
|
@@ -14680,7 +14748,12 @@ var LoomaEditor = defineComponent({
|
|
|
14680
14748
|
type: String,
|
|
14681
14749
|
default: "Item"
|
|
14682
14750
|
},
|
|
14683
|
-
/** Answers `
|
|
14751
|
+
/** Answers `file-upload` with a retained ordinary file link. */
|
|
14752
|
+
fileUpload: {
|
|
14753
|
+
type: Function,
|
|
14754
|
+
default: void 0
|
|
14755
|
+
},
|
|
14756
|
+
/** Answers `image-upload` with the image to insert. */
|
|
14684
14757
|
imageUpload: {
|
|
14685
14758
|
type: Function,
|
|
14686
14759
|
default: void 0
|
|
@@ -14750,6 +14823,12 @@ var LoomaEditor = defineComponent({
|
|
|
14750
14823
|
const formatAnchorId = `looma-editor-format-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
14751
14824
|
const formatOpen = ref(false);
|
|
14752
14825
|
const fileInput = ref(null);
|
|
14826
|
+
const attachmentInput = ref(null);
|
|
14827
|
+
const fileUploadState = shallowRef({
|
|
14828
|
+
uploading: false,
|
|
14829
|
+
progress: null
|
|
14830
|
+
});
|
|
14831
|
+
let attachmentUploads;
|
|
14753
14832
|
const tablePickerAnchorId = `looma-editor-table-picker-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
14754
14833
|
const blockActionAnchorId = `ui-block-tools-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
14755
14834
|
const linkAnchorId = `looma-editor-link-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
@@ -14918,9 +14997,11 @@ var LoomaEditor = defineComponent({
|
|
|
14918
14997
|
let slashDefaults;
|
|
14919
14998
|
const defaultSlashCommands = () => {
|
|
14920
14999
|
const uploads = answers("image-upload");
|
|
14921
|
-
|
|
15000
|
+
const files = answers("file-upload");
|
|
15001
|
+
if (slashDefaults?.uploads !== uploads || slashDefaults?.files !== files) slashDefaults = {
|
|
14922
15002
|
uploads,
|
|
14923
|
-
|
|
15003
|
+
files,
|
|
15004
|
+
commands: getDefaultSlashCommands(uploads ? () => fileInput.value?.click() : void 0, openChipEditor, () => openLinkEditor(), files ? () => attachmentInput.value?.click() : void 0)
|
|
14924
15005
|
};
|
|
14925
15006
|
return slashDefaults.commands;
|
|
14926
15007
|
};
|
|
@@ -14946,7 +15027,7 @@ var LoomaEditor = defineComponent({
|
|
|
14946
15027
|
const current = new Set(EDITOR_REQUEST_NAMES.filter(answers));
|
|
14947
15028
|
const arrived = (name) => current.has(name) && !responders.has(name);
|
|
14948
15029
|
const extensionsArrived = arrived("extensions");
|
|
14949
|
-
const slashChanged = arrived("slash-commands") || current.has("image-upload") !== responders.has("image-upload");
|
|
15030
|
+
const slashChanged = arrived("slash-commands") || current.has("image-upload") !== responders.has("image-upload") || current.has("file-upload") !== responders.has("file-upload");
|
|
14950
15031
|
responders = current;
|
|
14951
15032
|
if (extensionsArrived) askExtensions();
|
|
14952
15033
|
if (slashChanged) askSlashCommands();
|
|
@@ -15122,6 +15203,14 @@ var LoomaEditor = defineComponent({
|
|
|
15122
15203
|
uploadState.value = imageUploads.state;
|
|
15123
15204
|
});
|
|
15124
15205
|
uploads = imageUploads;
|
|
15206
|
+
attachmentUploads = createFileUploads({
|
|
15207
|
+
editor: session.editor,
|
|
15208
|
+
upload: () => (file, init) => ask("file-upload", { file }, init),
|
|
15209
|
+
onError: (error, file) => emit("uploadError", error, file),
|
|
15210
|
+
onState: (value) => {
|
|
15211
|
+
fileUploadState.value = value;
|
|
15212
|
+
}
|
|
15213
|
+
});
|
|
15125
15214
|
const instance = session.editor;
|
|
15126
15215
|
formatting = createFormattingSelection({
|
|
15127
15216
|
editor: instance,
|
|
@@ -15142,6 +15231,7 @@ var LoomaEditor = defineComponent({
|
|
|
15142
15231
|
footnoteEditing?.close();
|
|
15143
15232
|
formatting?.destroy();
|
|
15144
15233
|
uploads?.cancel();
|
|
15234
|
+
attachmentUploads?.cancel();
|
|
15145
15235
|
previous.destroy();
|
|
15146
15236
|
build(content);
|
|
15147
15237
|
};
|
|
@@ -15167,6 +15257,7 @@ var LoomaEditor = defineComponent({
|
|
|
15167
15257
|
onBeforeUnmount(() => {
|
|
15168
15258
|
const element = session?.editor.options.element;
|
|
15169
15259
|
element?.parentNode?.replaceChild(element.cloneNode(true), element);
|
|
15260
|
+
attachmentUploads?.cancel();
|
|
15170
15261
|
connection.abort();
|
|
15171
15262
|
stopAnnouncements?.();
|
|
15172
15263
|
linkEditing?.destroy();
|
|
@@ -15712,6 +15803,12 @@ var LoomaEditor = defineComponent({
|
|
|
15712
15803
|
if (dragLeaveTimer) clearTimeout(dragLeaveTimer);
|
|
15713
15804
|
if (tablePointerFrame !== null) cancelAnimationFrame(tablePointerFrame);
|
|
15714
15805
|
});
|
|
15806
|
+
const onAttachmentChange = async (event) => {
|
|
15807
|
+
const input = event.target;
|
|
15808
|
+
const file = input.files?.[0];
|
|
15809
|
+
input.value = "";
|
|
15810
|
+
if (file) await attachmentUploads?.insert(file);
|
|
15811
|
+
};
|
|
15715
15812
|
const onFileChange = async (event) => {
|
|
15716
15813
|
const input = event.target;
|
|
15717
15814
|
const files = Array.from(input.files ?? []);
|
|
@@ -15954,6 +16051,7 @@ var LoomaEditor = defineComponent({
|
|
|
15954
16051
|
variant: tablePickerOpen.value ? "solid" : "ghost",
|
|
15955
16052
|
"aria-expanded": tablePickerOpen.value ? "true" : "false"
|
|
15956
16053
|
}, () => loomaIcon("table")),
|
|
16054
|
+
commandButton("Attach file", "paperclip", false, fileUploadState.value.uploading || !answers("file-upload"), () => attachmentInput.value?.click()),
|
|
15957
16055
|
commandButton(uploadState.value.uploading ? "Uploading image" : "Insert image", "image", false, uploadState.value.uploading || !answers("image-upload"), () => fileInput.value?.click()),
|
|
15958
16056
|
h("span", {
|
|
15959
16057
|
class: "divider",
|
|
@@ -16143,6 +16241,22 @@ var LoomaEditor = defineComponent({
|
|
|
16143
16241
|
"aria-hidden": "true",
|
|
16144
16242
|
onChange: onFileChange
|
|
16145
16243
|
}),
|
|
16244
|
+
h("input", {
|
|
16245
|
+
ref: attachmentInput,
|
|
16246
|
+
class: "looma-editor__file-input",
|
|
16247
|
+
type: "file",
|
|
16248
|
+
tabindex: -1,
|
|
16249
|
+
"aria-hidden": "true",
|
|
16250
|
+
onChange: onAttachmentChange
|
|
16251
|
+
}),
|
|
16252
|
+
fileUploadState.value.uploading ? h(StatusMessage, { kind: "loading" }, {
|
|
16253
|
+
default: () => "Attaching file…",
|
|
16254
|
+
action: () => h(Button, {
|
|
16255
|
+
size: "sm",
|
|
16256
|
+
variant: "ghost",
|
|
16257
|
+
onClick: () => attachmentUploads?.cancel()
|
|
16258
|
+
}, () => "Cancel")
|
|
16259
|
+
}) : null,
|
|
16146
16260
|
uploadState.value.uploading ? h(StatusMessage, { kind: "loading" }, {
|
|
16147
16261
|
default: () => uploadProgressText(uploadState.value.progress),
|
|
16148
16262
|
action: () => h(Button, {
|