@myoc/element 0.19.532 → 0.19.534

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.
Files changed (44) hide show
  1. package/dist/dev/index.js +816 -16
  2. package/dist/dev/index.js.map +4 -4
  3. package/dist/prod/index.js +15 -15
  4. package/dist/types/common/src/constants.d.ts +1 -0
  5. package/dist/types/element/src/gif.d.ts +29 -0
  6. package/dist/types/element/src/image.d.ts +6 -1
  7. package/dist/types/element/src/index.d.ts +2 -0
  8. package/dist/types/element/src/newElement.d.ts +1 -0
  9. package/dist/types/element/src/renderGif.d.ts +5 -0
  10. package/dist/types/element/src/types.d.ts +12 -0
  11. package/dist/types/excalidraw/actions/actionBoundText.d.ts +2 -2
  12. package/dist/types/excalidraw/actions/actionCanvas.d.ts +6 -6
  13. package/dist/types/excalidraw/actions/actionClipboard.d.ts +2 -2
  14. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +1 -1
  15. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +3 -3
  16. package/dist/types/excalidraw/actions/actionDeselect.d.ts +1 -1
  17. package/dist/types/excalidraw/actions/actionElementLock.d.ts +2 -2
  18. package/dist/types/excalidraw/actions/actionExport.d.ts +2 -2
  19. package/dist/types/excalidraw/actions/actionFrame.d.ts +4 -3
  20. package/dist/types/excalidraw/actions/actionGroup.d.ts +2 -2
  21. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +2 -1
  22. package/dist/types/excalidraw/actions/actionLink.d.ts +1 -1
  23. package/dist/types/excalidraw/actions/actionProperties.d.ts +2 -2
  24. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +1 -1
  25. package/dist/types/excalidraw/actions/actionStyles.d.ts +1 -1
  26. package/dist/types/excalidraw/actions/actionToggleArrowBinding.d.ts +1 -1
  27. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +1 -1
  28. package/dist/types/excalidraw/actions/actionToggleMidpointSnapping.d.ts +1 -1
  29. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +1 -1
  30. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +1 -1
  31. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +1 -1
  32. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +1 -1
  33. package/dist/types/excalidraw/components/App.d.ts +8 -1
  34. package/dist/types/excalidraw/components/App.gif.d.ts +18 -0
  35. package/dist/types/excalidraw/components/GifPlaybackControls.d.ts +10 -0
  36. package/dist/types/excalidraw/components/icons.d.ts +4 -0
  37. package/dist/types/excalidraw/data/blob.d.ts +2 -2
  38. package/dist/types/excalidraw/data/json.d.ts +1 -1
  39. package/dist/types/excalidraw/data/restoreGif.d.ts +4 -0
  40. package/dist/types/excalidraw/scene/Renderer.d.ts +1 -0
  41. package/dist/types/excalidraw/scene/types.d.ts +2 -1
  42. package/dist/types/excalidraw/types.d.ts +12 -2
  43. package/dist/types/excalidraw/viewport.d.ts +1 -1
  44. package/package.json +5 -4
package/dist/dev/index.js CHANGED
@@ -14535,7 +14535,11 @@ var determineCustomLinearAngle = (pivotPoint, draggedPoint) => Math.atan2(dragge
14535
14535
 
14536
14536
  // src/image.ts
14537
14537
  init_define_import_meta_env();
14538
- import { MIME_TYPES, SVG_NS } from "@excalidraw/common";
14538
+ import {
14539
+ DEFAULT_GIF_AUTO_DECODE_MAX_FILE_SIZE_BYTES,
14540
+ MIME_TYPES,
14541
+ SVG_NS
14542
+ } from "@excalidraw/common";
14539
14543
 
14540
14544
  // ../../node_modules/thumbhash/thumbhash.js
14541
14545
  init_define_import_meta_env();
@@ -14689,6 +14693,647 @@ function thumbHashToApproximateAspectRatio(hash) {
14689
14693
  return lx / ly;
14690
14694
  }
14691
14695
 
14696
+ // src/gif.ts
14697
+ init_define_import_meta_env();
14698
+
14699
+ // ../../node_modules/modern-gif/dist/index.mjs
14700
+ init_define_import_meta_env();
14701
+ var SIGNATURE = "GIF";
14702
+ var VERSIONS = ["87a", "89a"];
14703
+ var IMAGE_DESCRIPTOR = 44;
14704
+ var EXTENSION = 33;
14705
+ var EXTENSION_APPLICATION = 255;
14706
+ var EXTENSION_APPLICATION_BLOCK_SIZE = 11;
14707
+ var EXTENSION_COMMENT = 254;
14708
+ var EXTENSION_GRAPHIC_CONTROL = 249;
14709
+ var EXTENSION_GRAPHIC_CONTROL_BLOCK_SIZE = 4;
14710
+ var EXTENSION_PLAIN_TEXT = 1;
14711
+ var EXTENSION_PLAIN_TEXT_BLOCK_SIZE = 1;
14712
+ var TRAILER = 59;
14713
+ function mergeBuffers(buffers) {
14714
+ const container = new Uint8Array(
14715
+ buffers.reduce((total, array) => total + array.byteLength, 0)
14716
+ );
14717
+ buffers.reduce((offset, array) => {
14718
+ container.set(array, offset);
14719
+ return offset + array.byteLength;
14720
+ }, 0);
14721
+ return container;
14722
+ }
14723
+ function resovleSource(source, output, options) {
14724
+ let buffer;
14725
+ if (ArrayBuffer.isView(source)) {
14726
+ buffer = source.buffer;
14727
+ } else if (source instanceof ArrayBuffer) {
14728
+ buffer = source;
14729
+ } else {
14730
+ const canvas = document.createElement("canvas");
14731
+ const { width, height } = options || {};
14732
+ const context2d = canvas.getContext("2d");
14733
+ if (!context2d) {
14734
+ throw new Error("Failed to create canvas context2d");
14735
+ }
14736
+ canvas.width = width ?? ("width" in source ? typeof source.width === "number" ? source.width : source.width.baseVal.value : 0);
14737
+ canvas.height = height ?? ("height" in source ? typeof source.height === "number" ? source.height : source.height.baseVal.value : 0);
14738
+ context2d.drawImage(source, 0, 0, canvas.width, canvas.height);
14739
+ buffer = context2d.getImageData(0, 0, canvas.width, canvas.height).data.buffer;
14740
+ }
14741
+ switch (output) {
14742
+ case "uint8Array":
14743
+ return new Uint8Array(buffer);
14744
+ case "uint8ClampedArray":
14745
+ return new Uint8ClampedArray(buffer);
14746
+ case "dataView":
14747
+ return new DataView(buffer);
14748
+ default:
14749
+ throw new Error("Unsupported output format");
14750
+ }
14751
+ }
14752
+ var Reader = class {
14753
+ _view;
14754
+ offset = 0;
14755
+ constructor(source) {
14756
+ this._view = resovleSource(source, "dataView");
14757
+ }
14758
+ readByte() {
14759
+ return this._view.getUint8(this.offset++);
14760
+ }
14761
+ readBytes(length) {
14762
+ return Array.from({ length }).map(() => this.readByte());
14763
+ }
14764
+ readString(length) {
14765
+ return String.fromCharCode(...this.readBytes(length));
14766
+ }
14767
+ readUnsigned() {
14768
+ return [this._view.getUint16(this.offset, true), this.offset += 2][0];
14769
+ }
14770
+ readBits() {
14771
+ return this._view.getUint8(this.offset++).toString(2).padStart(8, "0").split("").map(Number);
14772
+ }
14773
+ readColorTable(length) {
14774
+ return Array.from({ length }, () => Array.from(this.readBytes(3)));
14775
+ }
14776
+ readSubBlock() {
14777
+ const block = [];
14778
+ while (true) {
14779
+ const val = this.readByte();
14780
+ if (val === 0 && this._view.getUint8(this.offset) !== 0)
14781
+ break;
14782
+ block.push(val);
14783
+ }
14784
+ return block;
14785
+ }
14786
+ };
14787
+ function decode(source) {
14788
+ const gif = {};
14789
+ const reader = new Reader(source);
14790
+ const createFrame = () => ({ index: 0, delay: 100, disposal: 0 });
14791
+ const signature = reader.readString(3);
14792
+ const version = reader.readString(3);
14793
+ if (signature !== SIGNATURE || !VERSIONS.includes(version)) {
14794
+ throw new Error("This is not a 87a/89a GIF data.");
14795
+ }
14796
+ gif.version = version;
14797
+ gif.width = reader.readUnsigned();
14798
+ gif.height = reader.readUnsigned();
14799
+ const bits = reader.readBits();
14800
+ gif.globalColorTable = Boolean(bits[0]);
14801
+ gif.colorResoluTion = Number.parseInt(bits.slice(1, 4).join(""), 2) + 1;
14802
+ gif.colorTableSorted = Boolean(bits[4]);
14803
+ const colorTableSize = Number.parseInt(bits.slice(5, 8).join(""), 2);
14804
+ gif.colorTableSize = 2 ** (colorTableSize + 1);
14805
+ gif.backgroundColorIndex = reader.readByte();
14806
+ gif.pixelAspectRatio = reader.readByte();
14807
+ if (gif.globalColorTable) {
14808
+ if (gif.colorTableSize) {
14809
+ gif.colorTable = reader.readColorTable(gif.colorTableSize);
14810
+ } else {
14811
+ reader.readSubBlock();
14812
+ }
14813
+ }
14814
+ gif.frames = [];
14815
+ let frame = createFrame();
14816
+ const flags = [];
14817
+ const extensionFlags = [];
14818
+ while (true) {
14819
+ const flag = reader.readByte();
14820
+ flags.push(flag);
14821
+ if (flag === IMAGE_DESCRIPTOR) {
14822
+ frame.left = reader.readUnsigned();
14823
+ frame.top = reader.readUnsigned();
14824
+ frame.width = reader.readUnsigned();
14825
+ frame.height = reader.readUnsigned();
14826
+ const bits2 = reader.readBits();
14827
+ frame.localColorTable = Boolean(bits2[0]);
14828
+ frame.interlaced = Boolean(bits2[1]);
14829
+ frame.colorTableSorted = Boolean(bits2[2]);
14830
+ frame.reserved = Number.parseInt(bits2.slice(3, 5).join(""), 2);
14831
+ const colorTableSize2 = Number.parseInt(bits2.slice(5, 8).join(""), 2);
14832
+ frame.colorTableSize = 2 ** (colorTableSize2 + 1);
14833
+ if (frame.localColorTable) {
14834
+ frame.colorTable = reader.readColorTable(frame.colorTableSize);
14835
+ }
14836
+ frame.lzwMinCodeSize = reader.readByte();
14837
+ frame.dataPositions = [];
14838
+ while (true) {
14839
+ const length = reader.readByte();
14840
+ if (length === 0)
14841
+ break;
14842
+ const offset = reader.offset;
14843
+ frame.dataPositions.push([offset, length]);
14844
+ reader.offset = offset + length;
14845
+ }
14846
+ gif.frames.push(frame);
14847
+ frame = createFrame();
14848
+ frame.index = gif.frames.length;
14849
+ continue;
14850
+ }
14851
+ if (flag === EXTENSION) {
14852
+ const extensionFlag = reader.readByte();
14853
+ extensionFlags.push(extensionFlag);
14854
+ if (extensionFlag === EXTENSION_APPLICATION) {
14855
+ if (reader.readByte() !== EXTENSION_APPLICATION_BLOCK_SIZE)
14856
+ continue;
14857
+ const application = {
14858
+ identifier: reader.readString(8),
14859
+ code: reader.readString(3),
14860
+ data: []
14861
+ };
14862
+ if (`${application.identifier}${application.code}` === "NETSCAPE2.0") {
14863
+ if (reader.readByte() === 3) {
14864
+ gif.looped = Boolean(reader.readByte());
14865
+ gif.loopCount = reader.readUnsigned();
14866
+ }
14867
+ }
14868
+ application.data = reader.readSubBlock();
14869
+ frame.application = application;
14870
+ continue;
14871
+ }
14872
+ if (extensionFlag === EXTENSION_COMMENT) {
14873
+ frame.comment = reader.readSubBlock().map((val) => String.fromCharCode(val)).join("");
14874
+ continue;
14875
+ }
14876
+ if (extensionFlag === EXTENSION_GRAPHIC_CONTROL) {
14877
+ if (reader.readByte() !== EXTENSION_GRAPHIC_CONTROL_BLOCK_SIZE)
14878
+ continue;
14879
+ const bits2 = reader.readBits();
14880
+ const graphicControl = {
14881
+ // ↓ <Packed Fields>
14882
+ reserved: Number.parseInt(bits2.slice(0, 3).join(""), 2),
14883
+ disposal: Number.parseInt(bits2.slice(3, 6).join(""), 2),
14884
+ userInput: Boolean(bits2[6]),
14885
+ transparent: Boolean(bits2[7]),
14886
+ // ↑ <Packed Fields>
14887
+ delayTime: reader.readUnsigned(),
14888
+ transparentIndex: reader.readByte()
14889
+ };
14890
+ reader.readSubBlock();
14891
+ frame.graphicControl = graphicControl;
14892
+ frame.disposal = graphicControl.disposal;
14893
+ frame.delay = (graphicControl.delayTime || 10) * 10;
14894
+ continue;
14895
+ }
14896
+ if (extensionFlag === EXTENSION_PLAIN_TEXT) {
14897
+ if (reader.readByte() !== EXTENSION_PLAIN_TEXT_BLOCK_SIZE)
14898
+ continue;
14899
+ frame.plainText = {
14900
+ left: reader.readUnsigned(),
14901
+ top: reader.readUnsigned(),
14902
+ width: reader.readUnsigned(),
14903
+ height: reader.readUnsigned(),
14904
+ cellWidth: reader.readByte(),
14905
+ cellHeight: reader.readByte(),
14906
+ colorIndex: reader.readByte(),
14907
+ backgroundColorIndex: reader.readByte(),
14908
+ data: reader.readSubBlock()
14909
+ };
14910
+ continue;
14911
+ }
14912
+ console.warn(
14913
+ `Unknown extension block: 0x${extensionFlag.toString(16)}`,
14914
+ flags.slice(0, flags.length - 1).map((val) => `0x${val.toString(16)}`),
14915
+ extensionFlags.slice(0, extensionFlags.length - 1).map((val) => `0x${val.toString(16)}`)
14916
+ );
14917
+ continue;
14918
+ }
14919
+ if (flag === TRAILER)
14920
+ break;
14921
+ console.warn(
14922
+ `Unknown block: 0x${flag.toString(16)}`,
14923
+ flags.slice(0, flags.length - 1).map((val) => `0x${val.toString(16)}`),
14924
+ extensionFlags.slice(0, extensionFlags.length - 1).map((val) => `0x${val.toString(16)}`)
14925
+ );
14926
+ }
14927
+ return gif;
14928
+ }
14929
+ function createWorker(options) {
14930
+ const callbacks = /* @__PURE__ */ new Map();
14931
+ const { workerUrl } = options;
14932
+ let { workerNumber = 1 } = options;
14933
+ const workers = [...Array.from({ length: workerUrl ? workerNumber : 0 })].map(() => {
14934
+ try {
14935
+ const worker = new Worker(workerUrl);
14936
+ worker.onmessage = onMessage;
14937
+ return worker;
14938
+ } catch (err) {
14939
+ console.warn(err);
14940
+ return null;
14941
+ }
14942
+ }).filter(Boolean);
14943
+ workerNumber = workers.length;
14944
+ function onMessage(event) {
14945
+ const { id, data } = event.data;
14946
+ callbacks.get(id)?.(data);
14947
+ callbacks.delete(id);
14948
+ }
14949
+ const getWorker = /* @__PURE__ */ function() {
14950
+ let id = 0;
14951
+ return (index) => workers[(index ?? id++) % workerNumber];
14952
+ }();
14953
+ const call = /* @__PURE__ */ function() {
14954
+ let id = 0;
14955
+ return (type, data, transfer, index) => {
14956
+ return new Promise((resolve) => {
14957
+ const worker = getWorker(index);
14958
+ if (!worker)
14959
+ return resolve(void 0);
14960
+ callbacks.set(id, resolve);
14961
+ worker.postMessage({ id: id++, type, data }, { transfer });
14962
+ });
14963
+ };
14964
+ }();
14965
+ return {
14966
+ call
14967
+ };
14968
+ }
14969
+ function deinterlace(pixels, width) {
14970
+ const newPixels = Array.from({ length: pixels.length });
14971
+ const rows = pixels.length / width;
14972
+ const offsets = [0, 4, 2, 1];
14973
+ const steps = [8, 8, 4, 2];
14974
+ let fromRow = 0;
14975
+ for (let pass = 0; pass < 4; pass++) {
14976
+ for (let toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) {
14977
+ newPixels.splice.apply(
14978
+ newPixels,
14979
+ [toRow * width, width].concat(
14980
+ pixels.slice(fromRow * width, (fromRow + 1) * width)
14981
+ )
14982
+ );
14983
+ fromRow++;
14984
+ }
14985
+ }
14986
+ return newPixels;
14987
+ }
14988
+ function lzwDecode(minCodeSize, data, pixelCount) {
14989
+ const MAX_STACK_SIZE = 4096;
14990
+ const nullCode = -1;
14991
+ const npix = pixelCount;
14992
+ let available, codeMask, codeSize, inCode, oldCode, code, i;
14993
+ const dstPixels = Array.from({ length: pixelCount });
14994
+ const prefix = Array.from({ length: MAX_STACK_SIZE });
14995
+ const suffix = Array.from({ length: MAX_STACK_SIZE });
14996
+ const pixelStack = Array.from({ length: MAX_STACK_SIZE + 1 });
14997
+ const dataSize = minCodeSize;
14998
+ const clear = 1 << dataSize;
14999
+ const endOfInformation = clear + 1;
15000
+ available = clear + 2;
15001
+ oldCode = nullCode;
15002
+ codeSize = dataSize + 1;
15003
+ codeMask = (1 << codeSize) - 1;
15004
+ for (code = 0; code < clear; code++) {
15005
+ prefix[code] = 0;
15006
+ suffix[code] = code;
15007
+ }
15008
+ let datum, bits, first, top, pi, bi;
15009
+ datum = bits = first = top = pi = bi = 0;
15010
+ for (i = 0; i < npix; ) {
15011
+ if (top === 0) {
15012
+ if (bits < codeSize) {
15013
+ datum += data[bi] << bits;
15014
+ bits += 8;
15015
+ bi++;
15016
+ continue;
15017
+ }
15018
+ code = datum & codeMask;
15019
+ datum >>= codeSize;
15020
+ bits -= codeSize;
15021
+ if (code > available || code === endOfInformation) {
15022
+ break;
15023
+ }
15024
+ if (code === clear) {
15025
+ codeSize = dataSize + 1;
15026
+ codeMask = (1 << codeSize) - 1;
15027
+ available = clear + 2;
15028
+ oldCode = nullCode;
15029
+ continue;
15030
+ }
15031
+ if (oldCode === nullCode) {
15032
+ pixelStack[top++] = suffix[code];
15033
+ oldCode = code;
15034
+ first = code;
15035
+ continue;
15036
+ }
15037
+ inCode = code;
15038
+ if (code === available) {
15039
+ pixelStack[top++] = first;
15040
+ code = oldCode;
15041
+ }
15042
+ while (code > clear) {
15043
+ pixelStack[top++] = suffix[code];
15044
+ code = prefix[code];
15045
+ }
15046
+ first = suffix[code] & 255;
15047
+ pixelStack[top++] = first;
15048
+ if (available < MAX_STACK_SIZE) {
15049
+ prefix[available] = oldCode;
15050
+ suffix[available] = first;
15051
+ available++;
15052
+ if ((available & codeMask) === 0 && available < MAX_STACK_SIZE) {
15053
+ codeSize++;
15054
+ codeMask += available;
15055
+ }
15056
+ }
15057
+ oldCode = inCode;
15058
+ }
15059
+ top--;
15060
+ dstPixels[pi++] = pixelStack[top];
15061
+ i++;
15062
+ }
15063
+ for (i = pi; i < npix; i++) {
15064
+ dstPixels[i] = 0;
15065
+ }
15066
+ return dstPixels;
15067
+ }
15068
+ function decodeFrames(source, options) {
15069
+ const array = resovleSource(source, "uint8Array");
15070
+ if (options?.workerUrl) {
15071
+ return createWorker({ workerUrl: options.workerUrl }).call(
15072
+ "frames:decode",
15073
+ array,
15074
+ [array.buffer]
15075
+ );
15076
+ }
15077
+ const {
15078
+ gif = decode(source),
15079
+ range
15080
+ } = options ?? {};
15081
+ const {
15082
+ width: globalWidth,
15083
+ height: globalHeight,
15084
+ colorTable: globalColorTable,
15085
+ frames: globalFrames
15086
+ } = gif;
15087
+ const frames2 = range ? globalFrames.slice(range[0], range[1] + 1) : globalFrames;
15088
+ const hasDisposal3 = frames2.some((frame) => frame.disposal === 3);
15089
+ let pixels = new Uint8ClampedArray(globalWidth * globalHeight * 4);
15090
+ let previousFrame;
15091
+ let previousPixels = pixels.slice();
15092
+ return frames2.map((frame) => {
15093
+ const {
15094
+ left,
15095
+ top,
15096
+ width,
15097
+ height,
15098
+ interlaced,
15099
+ localColorTable,
15100
+ colorTable,
15101
+ lzwMinCodeSize,
15102
+ dataPositions,
15103
+ graphicControl,
15104
+ delay,
15105
+ disposal
15106
+ } = frame;
15107
+ const previousDisposal = previousFrame?.disposal;
15108
+ const bottom = top + height;
15109
+ const {
15110
+ transparent,
15111
+ transparentIndex: localTransparentIndex
15112
+ } = graphicControl ?? {};
15113
+ const palette2 = localColorTable ? colorTable : globalColorTable;
15114
+ const transparentIndex = transparent ? localTransparentIndex : -1;
15115
+ const compressedData = mergeBuffers(
15116
+ dataPositions.map(
15117
+ ([begin, length]) => array.subarray(begin, begin + length)
15118
+ )
15119
+ );
15120
+ let colorIndexes = lzwDecode(lzwMinCodeSize, compressedData, width * height);
15121
+ if (interlaced) {
15122
+ colorIndexes = deinterlace(colorIndexes, width);
15123
+ }
15124
+ if (previousDisposal === 3) {
15125
+ pixels = previousPixels.slice();
15126
+ } else if (previousDisposal === 2) {
15127
+ const { left: left2, top: top2, width: width2, height: height2 } = previousFrame;
15128
+ const bottom2 = top2 + height2;
15129
+ for (let y = top2; y < bottom2; y++) {
15130
+ const globalOffset = y * globalWidth + left2;
15131
+ for (let x = 0; x < width2; x++) {
15132
+ const index = (globalOffset + x) * 4;
15133
+ pixels[index] = pixels[index + 1] = pixels[index + 2] = pixels[index + 3] = 0;
15134
+ }
15135
+ }
15136
+ }
15137
+ for (let y = top; y < bottom; y++) {
15138
+ const globalOffset = y * globalWidth + left;
15139
+ const localOffset = (y - top) * width;
15140
+ for (let x = 0; x < width; x++) {
15141
+ const colorIndex = colorIndexes[localOffset + x];
15142
+ const index = (globalOffset + x) * 4;
15143
+ if (colorIndex !== transparentIndex) {
15144
+ const [r, g, b2] = palette2?.[colorIndex] ?? [0, 0, 0];
15145
+ pixels[index] = r;
15146
+ pixels[index + 1] = g;
15147
+ pixels[index + 2] = b2;
15148
+ pixels[index + 3] = 255;
15149
+ }
15150
+ }
15151
+ }
15152
+ if (hasDisposal3 && disposal !== 1 && disposal !== 3) {
15153
+ previousPixels = pixels.slice();
15154
+ }
15155
+ previousFrame = frame;
15156
+ return {
15157
+ width: globalWidth,
15158
+ height: globalHeight,
15159
+ delay,
15160
+ data: pixels.slice()
15161
+ };
15162
+ });
15163
+ }
15164
+ var ditherKernels = {
15165
+ "floyd-steinberg": [
15166
+ [7 / 16, 1, 0],
15167
+ [3 / 16, -1, 1],
15168
+ [5 / 16, 0, 1],
15169
+ [1 / 16, 1, 1]
15170
+ ],
15171
+ "atkinson": [
15172
+ [1 / 8, 1, 0],
15173
+ [1 / 8, 2, 0],
15174
+ [1 / 8, -1, 1],
15175
+ [1 / 8, 0, 1],
15176
+ [1 / 8, 1, 1],
15177
+ [1 / 8, 0, 2]
15178
+ ],
15179
+ "stucki": [
15180
+ [8 / 42, 1, 0],
15181
+ [4 / 42, 2, 0],
15182
+ [2 / 42, -2, 1],
15183
+ [4 / 42, -1, 1],
15184
+ [8 / 42, 0, 1],
15185
+ [4 / 42, 1, 1],
15186
+ [2 / 42, 2, 1],
15187
+ [1 / 42, -2, 2],
15188
+ [2 / 42, -1, 2],
15189
+ [4 / 42, 0, 2],
15190
+ [2 / 42, 1, 2],
15191
+ [1 / 42, 2, 2]
15192
+ ]
15193
+ };
15194
+
15195
+ // src/gif.ts
15196
+ var MAX_CONCURRENT_GIF_DECODES = 5;
15197
+ var logGifDecodeMode = (mode, context) => {
15198
+ console.debug("[excalidraw][gif-decode]", {
15199
+ mode,
15200
+ ...context
15201
+ });
15202
+ };
15203
+ var gifWorkerUrl;
15204
+ var configureGifWorkerUrl = (workerUrl) => {
15205
+ gifWorkerUrl = workerUrl;
15206
+ };
15207
+ var dataURLToArrayBuffer = (dataURL) => {
15208
+ const dataIndexStart = dataURL.indexOf(",");
15209
+ const byteString = atob(dataURL.slice(dataIndexStart + 1));
15210
+ const buffer = new ArrayBuffer(byteString.length);
15211
+ const bytes = new Uint8Array(buffer);
15212
+ for (let index = 0; index < byteString.length; index++) {
15213
+ bytes[index] = byteString.charCodeAt(index);
15214
+ }
15215
+ return buffer;
15216
+ };
15217
+ var isKnownModernGifWarning = (message) => typeof message === "string" && message.startsWith("Unknown block: 0x");
15218
+ var suppressKnownModernGifWarnings = async (task) => {
15219
+ const originalWarn = console.warn;
15220
+ console.warn = (...args) => {
15221
+ if (isKnownModernGifWarning(args[0])) {
15222
+ return;
15223
+ }
15224
+ originalWarn(...args);
15225
+ };
15226
+ try {
15227
+ return await task();
15228
+ } finally {
15229
+ console.warn = originalWarn;
15230
+ }
15231
+ };
15232
+ var decodeGifFrames = async (dataURL) => {
15233
+ const buffer = dataURLToArrayBuffer(dataURL);
15234
+ const decodeMode = gifWorkerUrl ? "worker" : "main-thread";
15235
+ logGifDecodeMode(decodeMode, {
15236
+ byteLength: buffer.byteLength,
15237
+ workerUrl: gifWorkerUrl
15238
+ });
15239
+ const { gif, decodedFrames } = await suppressKnownModernGifWarnings(
15240
+ async () => {
15241
+ const gif2 = decode(buffer);
15242
+ return {
15243
+ gif: gif2,
15244
+ decodedFrames: gifWorkerUrl ? await decodeFrames(buffer, { gif: gif2, workerUrl: gifWorkerUrl }) : await decodeFrames(buffer, { gif: gif2 })
15245
+ };
15246
+ }
15247
+ );
15248
+ const frames2 = decodedFrames.map((frame) => {
15249
+ const canvas = document.createElement("canvas");
15250
+ canvas.width = frame.width;
15251
+ canvas.height = frame.height;
15252
+ const context = canvas.getContext("2d");
15253
+ if (context) {
15254
+ const imageData = context.createImageData(frame.width, frame.height);
15255
+ imageData.data.set(frame.data);
15256
+ context.putImageData(imageData, 0, 0);
15257
+ }
15258
+ return canvas;
15259
+ });
15260
+ return {
15261
+ frames: frames2,
15262
+ delays: decodedFrames.map((frame) => Math.max(frame.delay, 16)),
15263
+ width: gif.width,
15264
+ height: gif.height
15265
+ };
15266
+ };
15267
+ var activeGifDecodeCount = 0;
15268
+ var gifDecodeSequence = 0;
15269
+ var gifDecodeSchedulePending = false;
15270
+ var gifDecodeQueue = [];
15271
+ var getDataURLByteLength = (dataURL) => {
15272
+ const dataIndexStart = dataURL.indexOf(",");
15273
+ const encoded = dataURL.slice(dataIndexStart + 1);
15274
+ const padding = encoded.endsWith("==") && 2 || encoded.endsWith("=") && 1 || 0;
15275
+ return Math.floor(encoded.length * 3 / 4) - padding;
15276
+ };
15277
+ var runGifDecodeTask = (task) => {
15278
+ activeGifDecodeCount++;
15279
+ decodeGifFrames(task.dataURL).then(task.resolve, task.reject).finally(() => {
15280
+ activeGifDecodeCount--;
15281
+ queueGifDecodeScheduler();
15282
+ });
15283
+ };
15284
+ var scheduleNextGifDecode = () => {
15285
+ gifDecodeSchedulePending = false;
15286
+ while (activeGifDecodeCount < MAX_CONCURRENT_GIF_DECODES && gifDecodeQueue.length) {
15287
+ runGifDecodeTask(gifDecodeQueue.shift());
15288
+ }
15289
+ };
15290
+ var queueGifDecodeScheduler = () => {
15291
+ if (gifDecodeSchedulePending) {
15292
+ return;
15293
+ }
15294
+ gifDecodeSchedulePending = true;
15295
+ queueMicrotask(scheduleNextGifDecode);
15296
+ };
15297
+ var decodeGifFramesQueued = (dataURL) => {
15298
+ return new Promise((resolve, reject) => {
15299
+ const task = {
15300
+ dataURL,
15301
+ priority: getDataURLByteLength(dataURL),
15302
+ sequence: gifDecodeSequence++,
15303
+ resolve,
15304
+ reject
15305
+ };
15306
+ const insertionIndex = gifDecodeQueue.findIndex(
15307
+ (queuedTask) => queuedTask.priority > task.priority || queuedTask.priority === task.priority && queuedTask.sequence > task.sequence
15308
+ );
15309
+ if (insertionIndex === -1) {
15310
+ gifDecodeQueue.push(task);
15311
+ } else {
15312
+ gifDecodeQueue.splice(insertionIndex, 0, task);
15313
+ }
15314
+ queueGifDecodeScheduler();
15315
+ });
15316
+ };
15317
+ var createGifPlaybackMetadata = (opts = {}) => ({
15318
+ frameIndex: 0,
15319
+ speed: 1,
15320
+ playing: opts.playing ?? false
15321
+ });
15322
+ var getGifRenderFrame = (element, cacheEntry, runtimeFrameIndex) => {
15323
+ const gifFrameIndex = element.gifPlayback?.playing ? runtimeFrameIndex ?? element.gifPlayback.frameIndex : element.gifPlayback?.frameIndex ?? 0;
15324
+ return cacheEntry?.gif?.frames[gifFrameIndex];
15325
+ };
15326
+ var hasActiveGifDecode = (visibleElements, imageCache) => visibleElements.some((element) => {
15327
+ if (!isInitializedImageElement(element)) {
15328
+ return false;
15329
+ }
15330
+ const cacheEntry = imageCache.get(element.fileId);
15331
+ return cacheEntry?.gifDecodeStatus === "pending" && !cacheEntry.gif?.frames.length;
15332
+ });
15333
+ var hasPlayableGif = (visibleElements, imageCache) => visibleElements.some(
15334
+ (element) => isInitializedImageElement(element) && element.gifPlayback?.playing && imageCache.get(element.fileId)?.gif?.frames.length
15335
+ );
15336
+
14692
15337
  // src/image.ts
14693
15338
  var THUMB_HASH_MAX_DIMENSION = 100;
14694
15339
  var thumbHashCanvasCache = /* @__PURE__ */ new Map();
@@ -14774,7 +15419,10 @@ var loadHTMLImageElement = (dataURL) => {
14774
15419
  var updateImageCache = async ({
14775
15420
  fileIds,
14776
15421
  files,
14777
- imageCache
15422
+ imageCache,
15423
+ onImageCacheUpdate,
15424
+ gifAutoDecodeMaxFileSizeBytes = DEFAULT_GIF_AUTO_DECODE_MAX_FILE_SIZE_BYTES,
15425
+ forceGifDecode = false
14778
15426
  }) => {
14779
15427
  const updatedFiles = /* @__PURE__ */ new Map();
14780
15428
  const erroredFiles = /* @__PURE__ */ new Map();
@@ -14793,20 +15441,72 @@ var updateImageCache = async ({
14793
15441
  const imagePromise = loadHTMLImageElement(fileData.dataURL);
14794
15442
  const data = {
14795
15443
  image: imagePromise,
14796
- mimeType: fileData.mimeType
15444
+ mimeType: fileData.mimeType,
15445
+ gifDecodeStatus: fileData.mimeType === MIME_TYPES.gif ? "pending" : void 0
14797
15446
  };
14798
15447
  imageCache.set(fileId, data);
14799
- const image = await imagePromise;
15448
+ if (data.gifDecodeStatus === "pending") {
15449
+ onImageCacheUpdate?.(fileId);
15450
+ }
15451
+ let image = imagePromise;
15452
+ let gif;
15453
+ let gifDecodeStatus;
15454
+ try {
15455
+ image = await imagePromise;
15456
+ if (fileData.mimeType === MIME_TYPES.gif) {
15457
+ const decodingData = {
15458
+ ...data,
15459
+ image,
15460
+ gifDecodeStatus: "pending"
15461
+ };
15462
+ imageCache.set(fileId, decodingData);
15463
+ onImageCacheUpdate?.(fileId);
15464
+ }
15465
+ if (fileData.mimeType === MIME_TYPES.gif && !forceGifDecode && getDataURLByteLength(fileData.dataURL) > gifAutoDecodeMaxFileSizeBytes) {
15466
+ gifDecodeStatus = "deferred";
15467
+ } else {
15468
+ gif = fileData.mimeType === MIME_TYPES.gif ? await decodeGifFramesQueued(fileData.dataURL) : void 0;
15469
+ if (fileData.mimeType === MIME_TYPES.gif) {
15470
+ gifDecodeStatus = "success";
15471
+ }
15472
+ }
15473
+ } catch (error) {
15474
+ erroredFiles.set(fileId, true);
15475
+ if (fileData.mimeType === MIME_TYPES.gif) {
15476
+ gifDecodeStatus = "error";
15477
+ }
15478
+ } finally {
15479
+ if (fileData.mimeType === MIME_TYPES.gif) {
15480
+ imageCache.set(fileId, {
15481
+ ...data,
15482
+ image,
15483
+ gif,
15484
+ gifDecodeStatus: gifDecodeStatus ?? "error"
15485
+ });
15486
+ onImageCacheUpdate?.(fileId);
15487
+ }
15488
+ }
15489
+ if (erroredFiles.has(fileId)) {
15490
+ return;
15491
+ }
14800
15492
  if (previousCacheEntry?.isPlaceholder) {
14801
15493
  imageCache.set(fileId, {
14802
15494
  ...data,
14803
15495
  image,
15496
+ gif,
15497
+ gifDecodeStatus: fileData.mimeType === MIME_TYPES.gif ? gifDecodeStatus : void 0,
14804
15498
  placeholderImage: await previousCacheEntry.image,
14805
15499
  transitionStart: performance.now()
14806
15500
  });
14807
15501
  } else {
14808
- imageCache.set(fileId, { ...data, image });
15502
+ imageCache.set(fileId, {
15503
+ ...data,
15504
+ image,
15505
+ gif,
15506
+ gifDecodeStatus: fileData.mimeType === MIME_TYPES.gif ? gifDecodeStatus : void 0
15507
+ });
14809
15508
  }
15509
+ onImageCacheUpdate?.(fileId);
14810
15510
  } catch (error) {
14811
15511
  erroredFiles.set(fileId, true);
14812
15512
  }
@@ -14870,6 +15570,52 @@ var normalizeSVG = (SVGString) => {
14870
15570
  }
14871
15571
  };
14872
15572
 
15573
+ // src/renderGif.ts
15574
+ init_define_import_meta_env();
15575
+ var drawGifDecodePlaceholder = (element, context, theme, drawImagePlaceholder2) => {
15576
+ drawImagePlaceholder2(element, context, theme);
15577
+ const pulse = 0.55 + Math.sin(performance.now() / 350) * 0.25;
15578
+ const text = "GIF Decoding";
15579
+ const fontFamily = "Assistant, system-ui, BlinkMacSystemFont, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif";
15580
+ const textX = element.width / 2;
15581
+ const textY = element.height / 2;
15582
+ context.save();
15583
+ context.globalAlpha *= pulse;
15584
+ context.textAlign = "center";
15585
+ context.textBaseline = "middle";
15586
+ context.font = `600 100px ${fontFamily}`;
15587
+ const targetTextWidth = element.width * 0.6;
15588
+ const measuredWidth = context.measureText(text).width;
15589
+ const widthFitFontSize = measuredWidth ? 100 * targetTextWidth / measuredWidth : 24;
15590
+ const fontSize = Math.max(
15591
+ 12,
15592
+ Math.min(widthFitFontSize, element.height * 0.35)
15593
+ );
15594
+ context.font = `600 ${fontSize}px ${fontFamily}`;
15595
+ const finalFontSize = Number.parseFloat(
15596
+ context.font.match(/\d+(\.\d+)?px/)?.[0] ?? `${fontSize}`
15597
+ );
15598
+ const finalMeasuredWidth = context.measureText(text).width;
15599
+ const paddingX = Math.max(12, finalFontSize * 0.55);
15600
+ const paddingY = Math.max(8, finalFontSize * 0.35);
15601
+ const pillWidth = finalMeasuredWidth + paddingX * 2;
15602
+ const pillHeight = finalFontSize + paddingY * 2;
15603
+ const pillX = textX - pillWidth / 2;
15604
+ const pillY = textY - pillHeight / 2;
15605
+ const radius = Math.min(pillHeight / 2, finalFontSize * 0.25);
15606
+ context.fillStyle = "rgba(0, 0, 0, 0.62)";
15607
+ context.beginPath();
15608
+ if (context.roundRect) {
15609
+ context.roundRect(pillX, pillY, pillWidth, pillHeight, radius);
15610
+ } else {
15611
+ context.rect(pillX, pillY, pillWidth, pillHeight);
15612
+ }
15613
+ context.fill();
15614
+ context.fillStyle = "#fff";
15615
+ context.fillText(text, textX, textY);
15616
+ context.restore();
15617
+ };
15618
+
14873
15619
  // src/renderElement.ts
14874
15620
  var isPendingImageElement = (element, renderConfig) => isInitializedImageElement(element) && !renderConfig.imageCache.has(element.fileId);
14875
15621
  var getCanvasPadding = (element) => {
@@ -15039,7 +15785,14 @@ var drawElementOnCanvas = (element, rc, context, renderConfig) => {
15039
15785
  context.save();
15040
15786
  const cacheEntry = element.fileId !== null ? renderConfig.imageCache.get(element.fileId) : null;
15041
15787
  const img = isInitializedImageElement(element) ? cacheEntry?.image : void 0;
15042
- if (img != null && !(img instanceof Promise)) {
15788
+ if (cacheEntry?.gifDecodeStatus === "pending" && !cacheEntry.gif?.frames.length) {
15789
+ drawGifDecodePlaceholder(
15790
+ element,
15791
+ context,
15792
+ renderConfig.theme,
15793
+ drawImagePlaceholder
15794
+ );
15795
+ } else if (img != null && !(img instanceof Promise)) {
15043
15796
  if (element.roundness && context.roundRect) {
15044
15797
  context.beginPath();
15045
15798
  context.roundRect(
@@ -15080,11 +15833,17 @@ var drawElementOnCanvas = (element, rc, context, renderConfig) => {
15080
15833
  delete cacheEntry.transitionStart;
15081
15834
  }
15082
15835
  }
15836
+ const gifFrame = getGifRenderFrame(
15837
+ element,
15838
+ cacheEntry,
15839
+ renderConfig.getGifFrameIndex?.(element)
15840
+ );
15841
+ const imageForRender = gifFrame ?? img;
15083
15842
  const { x, y, width, height } = element.crop ? element.crop : {
15084
15843
  x: 0,
15085
15844
  y: 0,
15086
- width: img.naturalWidth,
15087
- height: img.naturalHeight
15845
+ width: imageForRender instanceof HTMLCanvasElement ? imageForRender.width : imageForRender.naturalWidth,
15846
+ height: imageForRender instanceof HTMLCanvasElement ? imageForRender.height : imageForRender.naturalHeight
15088
15847
  };
15089
15848
  const shouldInvertImage = renderConfig.theme === THEME.DARK && cacheEntry?.mimeType === MIME_TYPES2.svg;
15090
15849
  if (shouldInvertImage && isSafari) {
@@ -15096,7 +15855,7 @@ var drawElementOnCanvas = (element, rc, context, renderConfig) => {
15096
15855
  if (tempContext) {
15097
15856
  tempContext.scale(devicePixelRatio, devicePixelRatio);
15098
15857
  tempContext.drawImage(
15099
- img,
15858
+ imageForRender,
15100
15859
  x,
15101
15860
  y,
15102
15861
  width,
@@ -15136,7 +15895,7 @@ var drawElementOnCanvas = (element, rc, context, renderConfig) => {
15136
15895
  context.filter = DARK_THEME_FILTER;
15137
15896
  }
15138
15897
  context.drawImage(
15139
- img,
15898
+ imageForRender,
15140
15899
  x,
15141
15900
  y,
15142
15901
  width,
@@ -18496,7 +19255,8 @@ var newImageElement = (opts) => {
18496
19255
  fileName: opts.fileName ?? null,
18497
19256
  thumbHash: opts.thumbHash ?? null,
18498
19257
  scale: opts.scale ?? [1, 1],
18499
- crop: opts.crop ?? null
19258
+ crop: opts.crop ?? null,
19259
+ gifPlayback: opts.gifPlayback ?? null
18500
19260
  };
18501
19261
  };
18502
19262
 
@@ -22336,10 +23096,10 @@ var dragSelectedElements = (pointerDownState, _selectedElements, offset, scene,
22336
23096
  const elementsToUpdate = new Set(
22337
23097
  selectedElements
22338
23098
  );
22339
- const frames = selectedElements.filter((e) => isFrameLikeElement(e)).map((f) => f.id);
22340
- if (frames.length > 0) {
23099
+ const frames2 = selectedElements.filter((e) => isFrameLikeElement(e)).map((f) => f.id);
23100
+ if (frames2.length > 0) {
22341
23101
  for (const element of scene.getNonDeletedElements()) {
22342
- if (element.frameId !== null && frames.includes(element.frameId)) {
23102
+ if (element.frameId !== null && frames2.includes(element.frameId)) {
22343
23103
  elementsToUpdate.add(element);
22344
23104
  }
22345
23105
  }
@@ -25521,6 +26281,10 @@ var PlusIcon = createIcon(
25521
26281
  ] }),
25522
26282
  tablerIconProps
25523
26283
  );
26284
+ var CirclePauseIcon = createIcon(
26285
+ "M320 112C434.9 112 528 205.1 528 320C528 434.9 434.9 528 320 528C205.1 528 112 434.9 112 320C112 205.1 205.1 112 320 112zM320 576C461.4 576 576 461.4 576 320C576 178.6 461.4 64 320 64C178.6 64 64 178.6 64 320C64 461.4 178.6 576 320 576zM288 248C288 234.7 277.3 224 264 224C250.7 224 240 234.7 240 248L240 392C240 405.3 250.7 416 264 416C277.3 416 288 405.3 288 392L288 248zM400 248C400 234.7 389.3 224 376 224C362.7 224 352 234.7 352 248L352 392C352 405.3 362.7 416 376 416C389.3 416 400 405.3 400 392L400 248z",
26286
+ 640
26287
+ );
25524
26288
  var DotsIcon = createIcon(
25525
26289
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { strokeWidth: "1.5", children: [
25526
26290
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }),
@@ -27364,6 +28128,33 @@ var playerStopFilledIcon = createIcon(
27364
28128
  ] }),
27365
28129
  tablerIconProps
27366
28130
  );
28131
+ var prevFrame = createIcon(
28132
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
28133
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7 5v14" }),
28134
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 6l-9 6l9 6z" })
28135
+ ] }),
28136
+ tablerIconProps
28137
+ );
28138
+ var nextFrame = createIcon(
28139
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
28140
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 5v14" }),
28141
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 6l9 6l-9 6z" })
28142
+ ] }),
28143
+ tablerIconProps
28144
+ );
28145
+ var frames = createIcon(
28146
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { strokeWidth: 1.25, children: [
28147
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }),
28148
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 6h16a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1v-10a1 1 0 0 1 1 -1z" }),
28149
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7 6v12" }),
28150
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 6v12" }),
28151
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 10h4" }),
28152
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 14h4" }),
28153
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 10h4" }),
28154
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 14h4" })
28155
+ ] }),
28156
+ tablerIconProps
28157
+ );
27367
28158
  var tablerCheckIcon = createIcon(
27368
28159
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
27369
28160
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }),
@@ -28947,7 +29738,7 @@ var recognizeShape = (points, previousElement, zoom = 1) => {
28947
29738
  const type = previousElement?.type === "arrow" && recognized !== "arrow" ? "freedraw" : recognized;
28948
29739
  return { type, points, boundingBox };
28949
29740
  };
28950
- var convertToShape = (points, appState, elementsMap, previousElement, frames) => {
29741
+ var convertToShape = (points, appState, elementsMap, previousElement, frames2) => {
28951
29742
  const recognizedShape = recognizeShape(
28952
29743
  points,
28953
29744
  previousElement,
@@ -28955,7 +29746,7 @@ var convertToShape = (points, appState, elementsMap, previousElement, frames) =>
28955
29746
  );
28956
29747
  const boundingBox = recognizedShape.boundingBox;
28957
29748
  const [minX, minY, maxX, maxY] = boundingBox;
28958
- const frameLikeElements = frames ?? getFrameLikeElements([...elementsMap.values()]);
29749
+ const frameLikeElements = frames2 ?? getFrameLikeElements([...elementsMap.values()]);
28959
29750
  const frameId = frameLikeElements.find((frame) => {
28960
29751
  const [fx1, fy1, fx2, fy2] = getElementAbsoluteCoords3(frame, elementsMap);
28961
29752
  return fx1 <= minX && fy1 <= minY && fx2 >= maxX && fy2 >= maxY;
@@ -29252,13 +30043,17 @@ export {
29252
30043
  computeBoundTextPosition,
29253
30044
  computeBucketFillPolygon,
29254
30045
  computeContainerDimensionForBoundText,
30046
+ configureGifWorkerUrl,
29255
30047
  containsCJK,
29256
30048
  convertToExcalidrawElements,
29257
30049
  convertToShape,
29258
30050
  convertToShapeHandlePointerMoveFromPointerDown,
30051
+ createGifPlaybackMetadata,
29259
30052
  createPlaceholderEmbeddableLabel,
29260
30053
  createSrcDoc,
29261
30054
  cropElement,
30055
+ decodeGifFrames,
30056
+ decodeGifFramesQueued,
29262
30057
  deconstructDiamondElement,
29263
30058
  deconstructLinearOrFreeDrawElement,
29264
30059
  deconstructRectanguloidElement,
@@ -29271,6 +30066,7 @@ export {
29271
30066
  dragNewElement,
29272
30067
  dragNewTextElement,
29273
30068
  dragSelectedElements,
30069
+ drawGifDecodePlaceholder,
29274
30070
  duplicateElement,
29275
30071
  duplicateElements,
29276
30072
  editGroupForSelectedElement,
@@ -29321,6 +30117,7 @@ export {
29321
30117
  getCornerRadius,
29322
30118
  getCubicBezierCurveBound,
29323
30119
  getCursorForResizingElement,
30120
+ getDataURLByteLength,
29324
30121
  getDefaultFrameName,
29325
30122
  getDefaultRoundnessTypeForElement,
29326
30123
  getDiamondBaseCorners,
@@ -29350,6 +30147,7 @@ export {
29350
30147
  getFreedrawOutlineAsSegments,
29351
30148
  getFreedrawOutlinePoints,
29352
30149
  getFreedrawStrokeCenterPoints,
30150
+ getGifRenderFrame,
29353
30151
  getGlobalFixedPointForBindableElement,
29354
30152
  getGlobalFixedPoints,
29355
30153
  getHeadingForElbowArrowSnap,
@@ -29416,10 +30214,12 @@ export {
29416
30214
  handleFocusPointHover,
29417
30215
  handleFocusPointPointerDown,
29418
30216
  handleFocusPointPointerUp,
30217
+ hasActiveGifDecode,
29419
30218
  hasBackground,
29420
30219
  hasBoundTextElement,
29421
30220
  hasBoundingBox,
29422
30221
  hasFreedrawMode,
30222
+ hasPlayableGif,
29423
30223
  hasStrokeColor,
29424
30224
  hasStrokeStyle,
29425
30225
  hasStrokeWidth,