feat: [cont.] support inserting multiple images (#9875)

* feat: support inserting multiple images

* Initial

* handleAppOnDrop, onImageToolbarButtonClick, pasteFromClipboard

* Initial get history working

* insertMultipleImages -> insertImages

* Bug fixes, improvements

* Remove redundant branch

* Refactor addElementsFromMixedContentPaste

* History, drag & drop bug fixes

* Update snapshots

* Remove redundant try-catch

* Refactor pasteFromClipboard

* Plain paste check in mermaid paste

* Move comment

* processClipboardData -> insertClipboardContent

* Redundant variable

* Redundant variable

* Refactor insertImages

* createImagePlaceholder -> newImagePlaceholder

* Get rid of unneeded NEVER schedule, filter out failed images

* Trigger CI

* Position placeholders before initializing

* Don't mutate scene with positionElementsOnGrid, captureUpdate: CaptureUpdateAction.IMMEDIATELY

* Comment

* Move positionOnGrid out of file

* Rename file

* Get rid of generic

* Initial tests

* More asserts, test paste

* Test image tool

* De-duplicate

* Stricter assert, move rest of logic outside of waitFor

* Modify history tests

* De-duplicate update snapshots

* Trigger CI

* Fix package build

* Make setupImageTest more explicit

* Re-introduce generic to use latest placeholder versions

* newElementWith instead of mutateElement to delete failed placeholder

* Insert failed images separately with CaptureUpdateAction.NEVER

* Refactor

* Don't re-order elements

* WIP

* Get rid of 'never' for failed

* refactor type check

* align max file size constant

* make grid padding scale to zoom

---------

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
Omar Brikaa
2025-09-01 18:31:24 +03:00
committed by GitHub
parent ae89608985
commit 3bdaafe4b5
15 changed files with 895 additions and 502 deletions
+27 -17
View File
@@ -478,33 +478,43 @@ export class API {
});
};
static drop = async (blob: Blob) => {
static drop = async (_blobs: Blob[] | Blob) => {
const blobs = Array.isArray(_blobs) ? _blobs : [_blobs];
const fileDropEvent = createEvent.drop(GlobalTestState.interactiveCanvas);
const text = await new Promise<string>((resolve, reject) => {
try {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result as string);
};
reader.readAsText(blob);
} catch (error: any) {
reject(error);
}
});
const texts = await Promise.all(
blobs.map(
(blob) =>
new Promise<string>((resolve, reject) => {
try {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result as string);
};
reader.readAsText(blob);
} catch (error: any) {
reject(error);
}
}),
),
);
const files = [blob] as File[] & { item: (index: number) => File };
const files = blobs as File[] & { item: (index: number) => File };
files.item = (index: number) => files[index];
Object.defineProperty(fileDropEvent, "dataTransfer", {
value: {
files,
getData: (type: string) => {
if (type === blob.type || type === "text") {
return text;
const idx = blobs.findIndex((b) => b.type === type);
if (idx >= 0) {
return texts[idx];
}
if (type === "text") {
return texts.join("\n");
}
return "";
},
types: [blob.type],
types: Array.from(new Set(blobs.map((b) => b.type))),
},
});
Object.defineProperty(fileDropEvent, "clientX", {
@@ -513,7 +523,7 @@ export class API {
Object.defineProperty(fileDropEvent, "clientY", {
value: 0,
});
await fireEvent(GlobalTestState.interactiveCanvas, fileDropEvent);
};