@myoc/excalidraw 0.19.543 → 0.19.545

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/dist/dev/index.js CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  canvasToBlob,
15
15
  constrainScrollState,
16
16
  createFile,
17
+ dataURLToFile,
17
18
  dataURLToString,
18
19
  encodePngMetadata,
19
20
  exportToCanvas,
@@ -64,10 +65,10 @@ import {
64
65
  serializeAsJSON,
65
66
  strokeRectWithRotation_simple,
66
67
  zoomToFitBounds
67
- } from "./chunk-6OYO4QVO.js";
68
+ } from "./chunk-GWV63UBO.js";
68
69
  import {
69
70
  define_import_meta_env_default
70
- } from "./chunk-VQRWPJBP.js";
71
+ } from "./chunk-CK7JCUHP.js";
71
72
  import {
72
73
  en_default
73
74
  } from "./chunk-35XUJXYN.js";
@@ -10337,9 +10338,11 @@ import {
10337
10338
  isInitializedImageElement
10338
10339
  } from "@excalidraw/element";
10339
10340
  import { getContainingFrame } from "@excalidraw/element";
10341
+ var WEB_EXCALIDRAW_CLIPBOARD_MIME_TYPE = `web ${MIME_TYPES2.excalidrawClipboard}`;
10340
10342
  var probablySupportsClipboardReadText = "clipboard" in navigator && "readText" in navigator.clipboard;
10341
10343
  var probablySupportsClipboardWriteText = "clipboard" in navigator && "writeText" in navigator.clipboard;
10342
10344
  var probablySupportsClipboardBlob = "clipboard" in navigator && "write" in navigator.clipboard && "ClipboardItem" in window && "toBlob" in HTMLCanvasElement.prototype;
10345
+ var supportsClipboardBlob = () => "clipboard" in navigator && "write" in navigator.clipboard && "ClipboardItem" in window && "toBlob" in HTMLCanvasElement.prototype;
10343
10346
  var clipboardContainsElements = (contents) => {
10344
10347
  if ([
10345
10348
  EXPORT_DATA_TYPES.excalidraw,
@@ -10434,8 +10437,69 @@ var serializeAsClipboardJSON = ({
10434
10437
  };
10435
10438
  return JSON.stringify(contents);
10436
10439
  };
10440
+ var convertImageFileToPNG = async (file2) => {
10441
+ const bitmap = await createImageBitmap(file2);
10442
+ try {
10443
+ const canvas = document.createElement("canvas");
10444
+ canvas.width = bitmap.width;
10445
+ canvas.height = bitmap.height;
10446
+ const context = canvas.getContext("2d");
10447
+ if (!context) {
10448
+ throw new Error("Could not create a canvas context for clipboard image");
10449
+ }
10450
+ context.drawImage(bitmap, 0, 0);
10451
+ return await new Promise((resolve, reject) => {
10452
+ canvas.toBlob((blob) => {
10453
+ if (blob) {
10454
+ resolve(blob);
10455
+ } else {
10456
+ reject(new Error("Could not encode clipboard image as PNG"));
10457
+ }
10458
+ }, MIME_TYPES2.png);
10459
+ });
10460
+ } finally {
10461
+ bitmap.close();
10462
+ }
10463
+ };
10437
10464
  var copyToClipboard = async (elements, files, clipboardEvent) => {
10438
10465
  const json = serializeAsClipboardJSON({ elements, files });
10466
+ const imageFile = elements.length === 1 && isInitializedImageElement(elements[0]) ? files?.[elements[0].fileId] : null;
10467
+ const clipboardFile = imageFile && isSupportedImageFileType(imageFile.mimeType) && imageFile.dataURL ? dataURLToFile(imageFile.dataURL, imageFile.fileName) : null;
10468
+ if (clipboardFile) {
10469
+ const clipboardImagePNG = clipboardFile.type === MIME_TYPES2.png ? clipboardFile : convertImageFileToPNG(clipboardFile);
10470
+ if (supportsClipboardBlob()) {
10471
+ try {
10472
+ await navigator.clipboard.write([
10473
+ new ClipboardItem({
10474
+ [WEB_EXCALIDRAW_CLIPBOARD_MIME_TYPE]: new Blob([json], {
10475
+ type: MIME_TYPES2.excalidrawClipboard
10476
+ }),
10477
+ [MIME_TYPES2.png]: clipboardImagePNG
10478
+ })
10479
+ ]);
10480
+ return;
10481
+ } catch (error) {
10482
+ console.error("Error copying image with ClipboardItem", error);
10483
+ }
10484
+ }
10485
+ if (clipboardEvent?.clipboardData?.items) {
10486
+ try {
10487
+ const clipboardImageFile = clipboardFile.type === MIME_TYPES2.png ? clipboardFile : new File(
10488
+ [await clipboardImagePNG],
10489
+ `${clipboardFile.name.replace(/\.[^/.]+$/, "") || "image"}.png`,
10490
+ { type: MIME_TYPES2.png }
10491
+ );
10492
+ clipboardEvent.clipboardData.items.add(clipboardImageFile);
10493
+ await copyTextToSystemClipboard(
10494
+ { [MIME_TYPES2.excalidrawClipboard]: json },
10495
+ clipboardEvent
10496
+ );
10497
+ return;
10498
+ } catch (error) {
10499
+ console.error("Error copying image to clipboard event", error);
10500
+ }
10501
+ }
10502
+ }
10439
10503
  await copyTextToSystemClipboard(
10440
10504
  {
10441
10505
  [MIME_TYPES2.excalidrawClipboard]: json,
@@ -10511,11 +10575,21 @@ var readSystemClipboard = async () => {
10511
10575
  }
10512
10576
  for (const item of clipboardItems) {
10513
10577
  for (const type of item.types) {
10578
+ if (type === WEB_EXCALIDRAW_CLIPBOARD_MIME_TYPE) {
10579
+ try {
10580
+ types[MIME_TYPES2.excalidrawClipboard] = await (await item.getType(type)).text();
10581
+ } catch (error) {
10582
+ console.warn(
10583
+ `Cannot retrieve ${type} from clipboardItem: ${error.message}`
10584
+ );
10585
+ }
10586
+ continue;
10587
+ }
10514
10588
  if (!isMemberOf(ALLOWED_PASTE_MIME_TYPES, type)) {
10515
10589
  continue;
10516
10590
  }
10517
10591
  try {
10518
- if (type === MIME_TYPES2.text || type === MIME_TYPES2.html) {
10592
+ if (type === MIME_TYPES2.text || type === MIME_TYPES2.html || type === MIME_TYPES2.excalidrawClipboard) {
10519
10593
  types[type] = await (await item.getType(type)).text();
10520
10594
  } else if (isSupportedImageFileType(type)) {
10521
10595
  const imageBlob = await item.getType(type);
@@ -10764,10 +10838,10 @@ var parseDataTransferEvent = async (event) => {
10764
10838
  });
10765
10839
  };
10766
10840
  var parseClipboard = async (dataList, isPlainPaste = false) => {
10767
- const parsedEventData = await parseClipboardEventTextData(
10768
- dataList,
10769
- isPlainPaste
10841
+ const excalidrawClipboardData = dataList.getData(
10842
+ MIME_TYPES2.excalidrawClipboard
10770
10843
  );
10844
+ const parsedEventData = excalidrawClipboardData ? { type: "text", value: excalidrawClipboardData } : await parseClipboardEventTextData(dataList, isPlainPaste);
10771
10845
  if (parsedEventData.type === "mixedContent") {
10772
10846
  return {
10773
10847
  mixedContent: parsedEventData.value
@@ -10970,7 +11044,7 @@ var exportCanvas = async (type, elements, appState, files, {
10970
11044
  let blob = canvasToBlob(tempCanvas);
10971
11045
  if (appState.exportEmbedScene) {
10972
11046
  blob = blob.then(
10973
- (blob2) => import("./data/image-MKDSIQJM.js").then(
11047
+ (blob2) => import("./data/image-LHD6YZAK.js").then(
10974
11048
  ({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
10975
11049
  blob: blob2,
10976
11050
  metadata: serializeAsJSON(elements, appState, files, "local")
@@ -15206,7 +15280,12 @@ import { arrayToMap as arrayToMap23, findIndex, findLastIndex as findLastIndex2
15206
15280
  import { isFiniteNumber } from "@excalidraw/math";
15207
15281
 
15208
15282
  // ../element/src/gif.ts
15209
- import { decode, decodeFrames } from "modern-gif";
15283
+ import { decodeAnimated } from "@discourse/gif";
15284
+ var GIF_WORKER_FILENAME = "gif.worker.js";
15285
+ var gifWorkerUrl = new URL(
15286
+ GIF_WORKER_FILENAME,
15287
+ import.meta.url
15288
+ ).toString();
15210
15289
 
15211
15290
  // ../element/src/image.ts
15212
15291
  import {
@@ -31724,21 +31803,34 @@ var GifPlaybackControls = ({
31724
31803
  app.ensureGifPlaybackLoop();
31725
31804
  }
31726
31805
  };
31727
- const deferredGifBadges = app.scene.getNonDeletedElements().filter(
31728
- (element) => isInitializedImageElement4(element) && !liveAppState.selectedElementIds[element.id] && files[element.fileId]?.mimeType === MIME_TYPES10.gif && app.imageCache.get(element.fileId)?.gifDecodeStatus === "deferred"
31729
- ).map((element) => {
31806
+ const deferredGifControls = app.scene.getNonDeletedElements().flatMap((element) => {
31807
+ if (!isInitializedImageElement4(element) || files[element.fileId]?.mimeType !== MIME_TYPES10.gif || app.imageCache.get(element.fileId)?.gifDecodeStatus !== "deferred") {
31808
+ return [];
31809
+ }
31730
31810
  const position = getGifControlPosition(element, liveAppState);
31731
- return /* @__PURE__ */ jsx113(
31732
- "span",
31733
- {
31734
- className: "gif-playback-controls gif-playback-controls__deferred-badge",
31735
- role: "img",
31736
- "aria-label": "GIF paused",
31737
- style: position,
31738
- children: CirclePauseIcon
31739
- },
31740
- element.id
31741
- );
31811
+ return [
31812
+ /* @__PURE__ */ jsx113(
31813
+ "div",
31814
+ {
31815
+ className: "gif-playback-controls gif-playback-controls--deferred",
31816
+ style: position,
31817
+ onPointerDown: (event) => event.stopPropagation(),
31818
+ children: /* @__PURE__ */ jsx113(
31819
+ "button",
31820
+ {
31821
+ type: "button",
31822
+ className: "gif-playback-controls__load-large",
31823
+ title: "Load Large GIF",
31824
+ onClick: () => {
31825
+ app.loadDeferredGif(element.fileId);
31826
+ },
31827
+ children: "Load Large GIF"
31828
+ }
31829
+ )
31830
+ },
31831
+ element.id
31832
+ )
31833
+ ];
31742
31834
  });
31743
31835
  const selectedElements = app.scene.getSelectedElements(liveAppState);
31744
31836
  const selectedElementControls = () => {
@@ -31769,29 +31861,6 @@ var GifPlaybackControls = ({
31769
31861
  leftTop.y - liveAppState.offsetTop + 16
31770
31862
  )
31771
31863
  );
31772
- if (cacheEntry?.gifDecodeStatus === "deferred") {
31773
- const position = getGifControlPosition(selectedElement, liveAppState);
31774
- return /* @__PURE__ */ jsx113(
31775
- "div",
31776
- {
31777
- className: "gif-playback-controls gif-playback-controls--deferred",
31778
- style: position,
31779
- onPointerDown: (event) => event.stopPropagation(),
31780
- children: /* @__PURE__ */ jsx113(
31781
- "button",
31782
- {
31783
- type: "button",
31784
- className: "gif-playback-controls__load-large",
31785
- title: "Load Large GIF",
31786
- onClick: () => {
31787
- app.loadDeferredGif(selectedElement.fileId);
31788
- },
31789
- children: "Load Large GIF"
31790
- }
31791
- )
31792
- }
31793
- );
31794
- }
31795
31864
  if (cacheEntry?.gifDecodeStatus === "pending") {
31796
31865
  return null;
31797
31866
  }
@@ -32138,7 +32207,7 @@ var GifPlaybackControls = ({
32138
32207
  );
32139
32208
  };
32140
32209
  return /* @__PURE__ */ jsxs59(Fragment18, { children: [
32141
- deferredGifBadges,
32210
+ deferredGifControls,
32142
32211
  selectedElementControls()
32143
32212
  ] });
32144
32213
  };
@@ -37559,9 +37628,30 @@ var App = class _App extends React41.Component {
37559
37628
  if (event && (!(elementUnderCursor instanceof HTMLCanvasElement) || isWritableElement4(target))) {
37560
37629
  return;
37561
37630
  }
37562
- const dataTransferList = await parseDataTransferEvent(event);
37563
- const filesList = dataTransferList.getFiles();
37564
- const data = await parseClipboard(dataTransferList, isPlainPaste);
37631
+ let dataTransferList = await parseDataTransferEvent(event);
37632
+ let filesList = dataTransferList.getFiles();
37633
+ let data = await parseClipboard(dataTransferList, isPlainPaste);
37634
+ if (!data.elements && filesList.length > 0 && !isPlainPaste) {
37635
+ try {
37636
+ const systemClipboard = await readSystemClipboard();
37637
+ const excalidrawJSON = systemClipboard[MIME_TYPES11.excalidrawClipboard];
37638
+ if (typeof excalidrawJSON === "string") {
37639
+ dataTransferList = await parseDataTransferEvent(
37640
+ createPasteEvent({
37641
+ types: {
37642
+ [MIME_TYPES11.excalidrawClipboard]: excalidrawJSON
37643
+ }
37644
+ })
37645
+ );
37646
+ filesList = dataTransferList.getFiles();
37647
+ data = await parseClipboard(dataTransferList, isPlainPaste);
37648
+ }
37649
+ } catch (error) {
37650
+ console.warn(
37651
+ `Could not read editable image clipboard data: ${error.message}`
37652
+ );
37653
+ }
37654
+ }
37565
37655
  if (this.state.viewModeEnabled) {
37566
37656
  if (!this.containsImagePaste(data, filesList, isPlainPaste)) {
37567
37657
  return;
@@ -44062,6 +44152,19 @@ var App = class _App extends React41.Component {
44062
44152
  return;
44063
44153
  }
44064
44154
  }
44155
+ if (data.elements) {
44156
+ const elements = data.programmaticAPI ? convertToExcalidrawElements(
44157
+ data.elements
44158
+ ) : data.elements;
44159
+ this.addElementsFromPasteOrLibrary({
44160
+ elements,
44161
+ files: data.files || null,
44162
+ position: this.editorInterface.formFactor === "desktop" ? "cursor" : "center",
44163
+ retainSeed: isPlainPaste,
44164
+ preserveFrameChildrenOrder: true
44165
+ });
44166
+ return;
44167
+ }
44065
44168
  const imageFiles = dataTransferFiles.map((data2) => data2.file);
44066
44169
  if (imageFiles.length === 0 && data.text && !isPlainPaste) {
44067
44170
  const trimmedText = data.text.trim();
@@ -44077,19 +44180,6 @@ var App = class _App extends React41.Component {
44077
44180
  }
44078
44181
  return;
44079
44182
  }
44080
- if (data.elements) {
44081
- const elements = data.programmaticAPI ? convertToExcalidrawElements(
44082
- data.elements
44083
- ) : data.elements;
44084
- this.addElementsFromPasteOrLibrary({
44085
- elements,
44086
- files: data.files || null,
44087
- position: this.editorInterface.formFactor === "desktop" ? "cursor" : "center",
44088
- retainSeed: isPlainPaste,
44089
- preserveFrameChildrenOrder: true
44090
- });
44091
- return;
44092
- }
44093
44183
  if (!data.text) {
44094
44184
  return;
44095
44185
  }