microboard-temp 0.2.4 → 0.3.0

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/esm/index.js CHANGED
@@ -33395,6 +33395,7 @@ class BaseItem extends Mbr {
33395
33395
  transformationRenderBlock = undefined;
33396
33396
  board;
33397
33397
  id;
33398
+ onRemoveCallbacks = [];
33398
33399
  shouldUseCustomRender = false;
33399
33400
  shouldRenderOutsideViewRect = true;
33400
33401
  itemType = "";
@@ -33472,6 +33473,12 @@ class BaseItem extends Mbr {
33472
33473
  break;
33473
33474
  }
33474
33475
  }
33476
+ addOnRemoveCallback(cb) {
33477
+ this.onRemoveCallbacks.push(cb);
33478
+ }
33479
+ onRemove() {
33480
+ this.onRemoveCallbacks.forEach((cb) => cb());
33481
+ }
33475
33482
  render(context) {}
33476
33483
  renderHTML(documentFactory) {
33477
33484
  return documentFactory.createElement("div");
@@ -38728,6 +38735,9 @@ class VideoItem extends BaseItem {
38728
38735
  this.loadCallbacks.push(callback);
38729
38736
  };
38730
38737
  getStorageId() {
38738
+ if (!this.isStorageUrl) {
38739
+ return;
38740
+ }
38731
38741
  return this.url.split("/").pop();
38732
38742
  }
38733
38743
  getIsStorageUrl() {
@@ -39000,6 +39010,13 @@ class VideoItem extends BaseItem {
39000
39010
  linkElem.click();
39001
39011
  }
39002
39012
  }
39013
+ onRemove() {
39014
+ const storageId = this.getStorageId();
39015
+ if (storageId) {
39016
+ deleteMedia([storageId], this.board.getBoardId());
39017
+ }
39018
+ super.onRemove();
39019
+ }
39003
39020
  }
39004
39021
  // src/Items/Image/calculatePosition.ts
39005
39022
  function calculatePosition(boardImage, board) {
@@ -39430,432 +39447,122 @@ var captureFrame = (frameTime, video) => {
39430
39447
  return null;
39431
39448
  }
39432
39449
  };
39433
- // src/Items/Audio/Audio.ts
39434
- class AudioItem extends BaseItem {
39450
+ // src/Items/Placeholder/Placeholder.ts
39451
+ var PlaceholderImg = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
39452
+ <path d="M5 11.1L7 9.1L12.5 14.6L16 11.1L19 14.1V5H5V11.1ZM4 3H20C20.2652 3 20.5196 3.10536 20.7071 3.29289C20.8946 3.48043 21 3.73478 21 4V20C21 20.2652 20.8946 20.5196 20.7071 20.7071C20.5196 20.8946 20.2652 21 20 21H4C3.73478 21 3.48043 20.8946 3.29289 20.7071C3.10536 20.5196 3 20.2652 3 20V4C3 3.73478 3.10536 3.48043 3.29289 3.29289C3.48043 3.10536 3.73478 3 4 3ZM15.5 10C15.1022 10 14.7206 9.84196 14.4393 9.56066C14.158 9.27936 14 8.89782 14 8.5C14 8.10218 14.158 7.72064 14.4393 7.43934C14.7206 7.15804 15.1022 7 15.5 7C15.8978 7 16.2794 7.15804 16.5607 7.43934C16.842 7.72064 17 8.10218 17 8.5C17 8.89782 16.842 9.27936 16.5607 9.56066C16.2794 9.84196 15.8978 10 15.5 10Z" fill="white" fill-opacity="0.6"/>
39453
+ </svg>`;
39454
+
39455
+ class Placeholder extends BaseItem {
39435
39456
  events;
39436
- extension;
39437
- itemType = "Audio";
39457
+ miroData;
39458
+ backgroundColor;
39459
+ icon;
39460
+ itemType = "Placeholder";
39461
+ shapeType = "Rectangle";
39438
39462
  parent = "Board";
39439
39463
  transformation;
39440
- linkTo;
39464
+ path = Shapes[this.shapeType].path.copy();
39465
+ mbr = Shapes[this.shapeType].path.getMbr().copy();
39441
39466
  subject = new Subject;
39442
- loadCallbacks = [];
39443
- beforeLoadCallbacks = [];
39444
39467
  transformationRenderBlock = undefined;
39445
- url = "";
39446
- isPlaying = false;
39447
- currentTime = 0;
39448
- isStorageUrl = true;
39449
- constructor(board, isStorageUrl, url, events, id = "", extension2) {
39468
+ iconImage;
39469
+ constructor(board, events, miroData, id = "", backgroundColor = "#E5E5EA", icon = PlaceholderImg?.toString() || "") {
39450
39470
  super(board, id);
39451
39471
  this.events = events;
39452
- this.extension = extension2;
39453
- this.linkTo = new LinkTo(this.id, events);
39454
- this.board = board;
39455
- this.isStorageUrl = isStorageUrl;
39456
- if (url) {
39457
- this.applyUrl(url);
39458
- }
39459
- this.transformation = new Transformation(id, events);
39460
- this.linkTo.subject.subscribe(() => {
39472
+ this.miroData = miroData;
39473
+ this.backgroundColor = backgroundColor;
39474
+ this.icon = icon;
39475
+ this.transformation = new Transformation(this.id, this.events);
39476
+ this.transformation.subject.subscribe((_subject) => {
39477
+ this.transformPath();
39461
39478
  this.updateMbr();
39462
39479
  this.subject.publish(this);
39463
39480
  });
39464
- this.transformation.subject.subscribe(this.onTransform);
39465
- this.right = this.left + conf.AUDIO_DIMENSIONS.width;
39466
- this.bottom = this.top + conf.AUDIO_DIMENSIONS.height;
39467
- this.shouldUseCustomRender = true;
39468
- }
39469
- setCurrentTime(time) {
39470
- this.currentTime = time;
39471
- }
39472
- getCurrentTime() {
39473
- return this.currentTime;
39474
- }
39475
- getIsStorageUrl() {
39476
- return this.isStorageUrl;
39477
- }
39478
- onTransform = () => {
39479
39481
  this.updateMbr();
39480
- this.subject.publish(this);
39481
- };
39482
- doOnceBeforeOnLoad = (callback) => {
39483
- this.loadCallbacks.push(callback);
39484
- };
39485
- doOnceOnLoad = (callback) => {
39486
- this.loadCallbacks.push(callback);
39487
- };
39488
- setIsPlaying(isPlaying) {
39489
- this.isPlaying = isPlaying;
39490
- this.shouldRenderOutsideViewRect = isPlaying;
39491
- this.subject.publish(this);
39492
- }
39493
- getIsPlaying() {
39494
- return this.isPlaying;
39482
+ this.loadIconImage();
39495
39483
  }
39496
- applyUrl(url) {
39497
- if (this.isStorageUrl) {
39498
- try {
39499
- const newUrl = new URL(url);
39500
- this.url = `${window.location.origin}${newUrl.pathname}`;
39501
- } catch (_) {}
39484
+ emit(operation) {
39485
+ if (this.events) {
39486
+ const command = new PlaceholderCommand([this], operation);
39487
+ command.apply();
39488
+ this.events.emit(operation, command);
39502
39489
  } else {
39503
- this.url = url;
39504
- }
39505
- }
39506
- setUrl(url) {
39507
- this.emit({
39508
- class: "Audio",
39509
- method: "setUrl",
39510
- item: [this.getId()],
39511
- url
39512
- });
39513
- }
39514
- getStorageId() {
39515
- return this.url.split("/").pop();
39516
- }
39517
- getUrl() {
39518
- return this.url;
39519
- }
39520
- onLoad = async () => {
39521
- this.shootBeforeLoadCallbacks();
39522
- this.updateMbr();
39523
- this.subject.publish(this);
39524
- this.shootLoadCallbacks();
39525
- };
39526
- onError = (_error) => {
39527
- this.updateMbr();
39528
- this.subject.publish(this);
39529
- this.shootLoadCallbacks();
39530
- };
39531
- updateMbr() {
39532
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
39533
- this.left = translateX;
39534
- this.top = translateY;
39535
- this.right = this.left + conf.AUDIO_DIMENSIONS.width * scaleX;
39536
- this.bottom = this.top + conf.AUDIO_DIMENSIONS.height * scaleY;
39537
- }
39538
- render(context) {
39539
- if (this.transformationRenderBlock) {
39540
- return;
39541
- }
39542
- const ctx = context.ctx;
39543
- const radius = 12 * this.transformation.getScale().x;
39544
- ctx.save();
39545
- ctx.globalCompositeOperation = "destination-out";
39546
- ctx.beginPath();
39547
- ctx.moveTo(this.left + radius, this.top);
39548
- ctx.lineTo(this.left + this.getWidth() - radius, this.top);
39549
- ctx.quadraticCurveTo(this.left + this.getWidth(), this.top, this.left + this.getWidth(), this.top + radius);
39550
- ctx.lineTo(this.left + this.getWidth(), this.top + this.getHeight() - radius);
39551
- ctx.quadraticCurveTo(this.left + this.getWidth(), this.top + this.getHeight(), this.left + this.getWidth() - radius, this.top + this.getHeight());
39552
- ctx.lineTo(this.left + radius, this.top + this.getHeight());
39553
- ctx.quadraticCurveTo(this.left, this.top + this.getHeight(), this.left, this.top + this.getHeight() - radius);
39554
- ctx.lineTo(this.left, this.top + radius);
39555
- ctx.quadraticCurveTo(this.left, this.top, this.left + radius, this.top);
39556
- ctx.closePath();
39557
- ctx.fill();
39558
- ctx.restore();
39559
- }
39560
- renderHTML(documentFactory) {
39561
- const div = documentFactory.createElement("audio-item");
39562
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
39563
- const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
39564
- div.id = this.getId();
39565
- div.style.width = `${conf.AUDIO_DIMENSIONS.width}px`;
39566
- div.style.height = `${conf.AUDIO_DIMENSIONS.height}px`;
39567
- div.style.transformOrigin = "top left";
39568
- div.style.transform = transform;
39569
- div.style.position = "absolute";
39570
- div.setAttribute("audio-url", this.getUrl());
39571
- if (this.extension) {
39572
- div.setAttribute("extension", this.extension);
39573
- }
39574
- if (this.isStorageUrl) {
39575
- div.setAttribute("is-storage-url", "true");
39490
+ this.apply(operation);
39576
39491
  }
39577
- div.setAttribute("data-link-to", "");
39578
- return div;
39579
39492
  }
39580
39493
  serialize() {
39581
39494
  return {
39582
- itemType: "Audio",
39583
- url: this.url,
39495
+ itemType: "Placeholder",
39496
+ backgroundColor: this.backgroundColor,
39497
+ icon: this.icon,
39584
39498
  transformation: this.transformation.serialize(),
39585
- isStorageUrl: this.isStorageUrl,
39586
- extension: this.extension
39499
+ miroData: this.miroData
39587
39500
  };
39588
39501
  }
39589
39502
  deserialize(data) {
39590
- if (data.isStorageUrl) {
39591
- this.isStorageUrl = data.isStorageUrl;
39592
- }
39503
+ this.initPath();
39504
+ this.backgroundColor = data.backgroundColor ?? this.backgroundColor;
39505
+ this.icon = data.icon ?? this.icon;
39506
+ this.miroData = data.miroData;
39593
39507
  if (data.transformation) {
39594
39508
  this.transformation.deserialize(data.transformation);
39509
+ this.transformPath();
39595
39510
  }
39596
- if (data.url) {
39597
- this.setUrl(data.url);
39598
- }
39599
- if (data.extension) {
39600
- this.extension = data.extension;
39601
- }
39511
+ this.subject.publish(this);
39512
+ return this;
39513
+ }
39514
+ setId(id) {
39515
+ this.id = id;
39516
+ this.transformation.setId(id);
39602
39517
  return this;
39603
39518
  }
39519
+ getId() {
39520
+ return this.id;
39521
+ }
39604
39522
  apply(op) {
39605
39523
  switch (op.class) {
39524
+ case "Placeholder":
39525
+ this.applyPlaceholder(op);
39526
+ this.updateMbr();
39527
+ break;
39606
39528
  case "Transformation":
39607
39529
  this.transformation.apply(op);
39608
39530
  break;
39609
- case "LinkTo":
39610
- this.linkTo.apply(op);
39531
+ default:
39532
+ return;
39533
+ }
39534
+ this.subject.publish(this);
39535
+ }
39536
+ applyPlaceholder(op) {
39537
+ switch (op.method) {
39538
+ case "setBackgroundColor":
39539
+ this.applyBackgroundColor(op.backgroundColor);
39611
39540
  break;
39612
- case "Audio":
39613
- if (op.method === "setUrl") {
39614
- this.applyUrl(op.url);
39615
- }
39616
- this.subject.publish(this);
39541
+ case "setIcon":
39542
+ this.applyIcon(op.icon);
39543
+ break;
39544
+ case "setMiroData":
39545
+ this.applyMiroData(op.miroData);
39617
39546
  break;
39618
39547
  }
39619
39548
  }
39620
- emit(operation) {
39621
- if (this.events) {
39622
- const command = new AudioCommand([this], operation);
39623
- command.apply();
39624
- this.events.emit(operation, command);
39625
- } else {
39626
- this.apply(operation);
39627
- }
39549
+ getBackgroundColor() {
39550
+ return this.backgroundColor;
39628
39551
  }
39629
- setId(id) {
39630
- this.id = id;
39631
- this.transformation.setId(id);
39632
- return this;
39552
+ applyBackgroundColor(backgroundColor) {
39553
+ this.backgroundColor = backgroundColor;
39554
+ this.path.setBackgroundColor(backgroundColor);
39633
39555
  }
39634
- getId() {
39635
- return this.id;
39556
+ setBackgroundColor(backgroundColor) {
39557
+ this.emit({
39558
+ class: "Placeholder",
39559
+ method: "setBackgroundColor",
39560
+ item: [this.getId()],
39561
+ backgroundColor
39562
+ });
39636
39563
  }
39637
- shootLoadCallbacks() {
39638
- while (this.loadCallbacks.length > 0) {
39639
- this.loadCallbacks.shift()(this);
39640
- }
39641
- }
39642
- shootBeforeLoadCallbacks() {
39643
- while (this.beforeLoadCallbacks.length > 0) {
39644
- this.beforeLoadCallbacks.shift()(this);
39645
- }
39646
- }
39647
- getPath() {
39648
- const { left, top, right, bottom } = this.getMbr();
39649
- const leftTop = new Point(left, top);
39650
- const rightTop = new Point(right, top);
39651
- const rightBottom = new Point(right, bottom);
39652
- const leftBottom = new Point(left, bottom);
39653
- return new Path([
39654
- new Line(leftTop, rightTop),
39655
- new Line(rightTop, rightBottom),
39656
- new Line(rightBottom, leftBottom),
39657
- new Line(leftBottom, leftTop)
39658
- ], true);
39659
- }
39660
- getSnapAnchorPoints() {
39661
- const mbr = this.getMbr();
39662
- const width2 = mbr.getWidth();
39663
- const height2 = mbr.getHeight();
39664
- return [
39665
- new Point(mbr.left + width2 / 2, mbr.top),
39666
- new Point(mbr.left + width2 / 2, mbr.bottom),
39667
- new Point(mbr.left, mbr.top + height2 / 2),
39668
- new Point(mbr.right, mbr.top + height2 / 2)
39669
- ];
39670
- }
39671
- isClosed() {
39672
- return true;
39673
- }
39674
- getRichText() {
39675
- return null;
39676
- }
39677
- getLinkTo() {
39678
- return;
39679
- }
39680
- getExtension() {
39681
- return this.extension;
39682
- }
39683
- download() {
39684
- if (this.extension) {
39685
- const linkElem = conf.documentFactory.createElement("a");
39686
- linkElem.href = this.url;
39687
- linkElem.setAttribute("download", `${this.board.getBoardId()}.${this.extension}`);
39688
- linkElem.click();
39689
- }
39690
- }
39691
- }
39692
- // src/Items/Audio/AudioHelpers.ts
39693
- var uploadAudioToStorage = async (hash, audioBlob, accessToken, boardId) => {
39694
- return new Promise((resolve2, reject) => {
39695
- fetch(`${window.location.origin}/api/v1/media/audio/${boardId}`, {
39696
- method: "POST",
39697
- headers: {
39698
- "Content-Type": audioBlob.type,
39699
- "x-audio-id": hash,
39700
- Authorization: `Bearer ${accessToken}`
39701
- },
39702
- body: audioBlob
39703
- }).then(async (response) => {
39704
- if (response.status !== 200) {
39705
- return catchErrorResponse(response, "audio");
39706
- }
39707
- return response.json();
39708
- }).then((data) => {
39709
- console.log(data);
39710
- resolve2(data.src);
39711
- }).catch((error) => {
39712
- console.error("Media storage error:", error);
39713
- reject(error);
39714
- });
39715
- });
39716
- };
39717
- var prepareAudio = (file, accessToken, boardId) => {
39718
- return new Promise((resolve2, reject) => {
39719
- const audio = document.createElement("audio");
39720
- audio.src = URL.createObjectURL(file);
39721
- audio.onloadedmetadata = () => {
39722
- fileTosha256(file).then((hash) => {
39723
- uploadAudioToStorage(hash, file, accessToken, boardId).then((url) => {
39724
- resolve2(url);
39725
- }).catch(reject);
39726
- }).catch(() => {
39727
- reject(new Error("Failed to generate hash"));
39728
- });
39729
- };
39730
- audio.onerror = () => {
39731
- reject(new Error("Failed to load audio"));
39732
- };
39733
- });
39734
- };
39735
- var calculateAudioPosition = (board, audioItem) => {
39736
- const cameraMbr = board.camera.getMbr();
39737
- const cameraWidth = cameraMbr.getWidth();
39738
- const translateX = cameraMbr.left + cameraWidth * 0.34;
39739
- const translateY = cameraMbr.getCenter().y - audioItem.getHeight() / 2;
39740
- const scale = cameraWidth * 0.32 / audioItem.getWidth();
39741
- return new Matrix2(translateX, translateY, scale, scale);
39742
- };
39743
- // src/Items/Placeholder/Placeholder.ts
39744
- var PlaceholderImg = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
39745
- <path d="M5 11.1L7 9.1L12.5 14.6L16 11.1L19 14.1V5H5V11.1ZM4 3H20C20.2652 3 20.5196 3.10536 20.7071 3.29289C20.8946 3.48043 21 3.73478 21 4V20C21 20.2652 20.8946 20.5196 20.7071 20.7071C20.5196 20.8946 20.2652 21 20 21H4C3.73478 21 3.48043 20.8946 3.29289 20.7071C3.10536 20.5196 3 20.2652 3 20V4C3 3.73478 3.10536 3.48043 3.29289 3.29289C3.48043 3.10536 3.73478 3 4 3ZM15.5 10C15.1022 10 14.7206 9.84196 14.4393 9.56066C14.158 9.27936 14 8.89782 14 8.5C14 8.10218 14.158 7.72064 14.4393 7.43934C14.7206 7.15804 15.1022 7 15.5 7C15.8978 7 16.2794 7.15804 16.5607 7.43934C16.842 7.72064 17 8.10218 17 8.5C17 8.89782 16.842 9.27936 16.5607 9.56066C16.2794 9.84196 15.8978 10 15.5 10Z" fill="white" fill-opacity="0.6"/>
39746
- </svg>`;
39747
-
39748
- class Placeholder extends BaseItem {
39749
- events;
39750
- miroData;
39751
- backgroundColor;
39752
- icon;
39753
- itemType = "Placeholder";
39754
- shapeType = "Rectangle";
39755
- parent = "Board";
39756
- transformation;
39757
- path = Shapes[this.shapeType].path.copy();
39758
- mbr = Shapes[this.shapeType].path.getMbr().copy();
39759
- subject = new Subject;
39760
- transformationRenderBlock = undefined;
39761
- iconImage;
39762
- constructor(board, events, miroData, id = "", backgroundColor = "#E5E5EA", icon = PlaceholderImg?.toString() || "") {
39763
- super(board, id);
39764
- this.events = events;
39765
- this.miroData = miroData;
39766
- this.backgroundColor = backgroundColor;
39767
- this.icon = icon;
39768
- this.transformation = new Transformation(this.id, this.events);
39769
- this.transformation.subject.subscribe((_subject) => {
39770
- this.transformPath();
39771
- this.updateMbr();
39772
- this.subject.publish(this);
39773
- });
39774
- this.updateMbr();
39775
- this.loadIconImage();
39776
- }
39777
- emit(operation) {
39778
- if (this.events) {
39779
- const command = new PlaceholderCommand([this], operation);
39780
- command.apply();
39781
- this.events.emit(operation, command);
39782
- } else {
39783
- this.apply(operation);
39784
- }
39785
- }
39786
- serialize() {
39787
- return {
39788
- itemType: "Placeholder",
39789
- backgroundColor: this.backgroundColor,
39790
- icon: this.icon,
39791
- transformation: this.transformation.serialize(),
39792
- miroData: this.miroData
39793
- };
39794
- }
39795
- deserialize(data) {
39796
- this.initPath();
39797
- this.backgroundColor = data.backgroundColor ?? this.backgroundColor;
39798
- this.icon = data.icon ?? this.icon;
39799
- this.miroData = data.miroData;
39800
- if (data.transformation) {
39801
- this.transformation.deserialize(data.transformation);
39802
- this.transformPath();
39803
- }
39804
- this.subject.publish(this);
39805
- return this;
39806
- }
39807
- setId(id) {
39808
- this.id = id;
39809
- this.transformation.setId(id);
39810
- return this;
39811
- }
39812
- getId() {
39813
- return this.id;
39814
- }
39815
- apply(op) {
39816
- switch (op.class) {
39817
- case "Placeholder":
39818
- this.applyPlaceholder(op);
39819
- this.updateMbr();
39820
- break;
39821
- case "Transformation":
39822
- this.transformation.apply(op);
39823
- break;
39824
- default:
39825
- return;
39826
- }
39827
- this.subject.publish(this);
39828
- }
39829
- applyPlaceholder(op) {
39830
- switch (op.method) {
39831
- case "setBackgroundColor":
39832
- this.applyBackgroundColor(op.backgroundColor);
39833
- break;
39834
- case "setIcon":
39835
- this.applyIcon(op.icon);
39836
- break;
39837
- case "setMiroData":
39838
- this.applyMiroData(op.miroData);
39839
- break;
39840
- }
39841
- }
39842
- getBackgroundColor() {
39843
- return this.backgroundColor;
39844
- }
39845
- applyBackgroundColor(backgroundColor) {
39846
- this.backgroundColor = backgroundColor;
39847
- this.path.setBackgroundColor(backgroundColor);
39848
- }
39849
- setBackgroundColor(backgroundColor) {
39850
- this.emit({
39851
- class: "Placeholder",
39852
- method: "setBackgroundColor",
39853
- item: [this.getId()],
39854
- backgroundColor
39855
- });
39856
- }
39857
- getIcon() {
39858
- return this.icon;
39564
+ getIcon() {
39565
+ return this.icon;
39859
39566
  }
39860
39567
  applyIcon(icon) {
39861
39568
  this.icon = icon;
@@ -40099,100 +39806,374 @@ class ImageItem extends BaseItem {
40099
39806
  this.shootLoadCallbacks();
40100
39807
  };
40101
39808
  onError = (_error) => {
40102
- this.image = getPlaceholderImage(this.board);
39809
+ this.image = getPlaceholderImage(this.board);
39810
+ this.updateMbr();
39811
+ this.subject.publish(this);
39812
+ this.shootLoadCallbacks();
39813
+ };
39814
+ onTransform = () => {
39815
+ this.updateMbr();
39816
+ this.subject.publish(this);
39817
+ };
39818
+ updateMbr() {
39819
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
39820
+ this.left = translateX;
39821
+ this.top = translateY;
39822
+ this.right = this.left + this.image.width * scaleX;
39823
+ this.bottom = this.top + this.image.height * scaleY;
39824
+ }
39825
+ doOnceBeforeOnLoad = (callback) => {
39826
+ this.loadCallbacks.push(callback);
39827
+ };
39828
+ doOnceOnLoad = (callback) => {
39829
+ this.loadCallbacks.push(callback);
39830
+ };
39831
+ setId(id) {
39832
+ this.id = id;
39833
+ this.transformation.setId(id);
39834
+ this.linkTo.setId(id);
39835
+ return this;
39836
+ }
39837
+ getId() {
39838
+ return this.id;
39839
+ }
39840
+ serialize() {
39841
+ return {
39842
+ itemType: "Image",
39843
+ storageLink: this.storageLink,
39844
+ imageDimension: this.imageDimension,
39845
+ transformation: this.transformation.serialize(),
39846
+ linkTo: this.linkTo.serialize()
39847
+ };
39848
+ }
39849
+ setCoordinates() {
39850
+ this.left = this.transformation.matrix.translateX;
39851
+ this.top = this.transformation.matrix.translateY;
39852
+ this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
39853
+ this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
39854
+ this.subject.publish(this);
39855
+ }
39856
+ shootBeforeLoadCallbacks() {
39857
+ while (this.beforeLoadCallbacks.length > 0) {
39858
+ this.beforeLoadCallbacks.shift()(this);
39859
+ }
39860
+ }
39861
+ shootLoadCallbacks() {
39862
+ while (this.loadCallbacks.length > 0) {
39863
+ this.loadCallbacks.shift()(this);
39864
+ }
39865
+ }
39866
+ deserialize(data) {
39867
+ if (data.transformation) {
39868
+ this.transformation.deserialize(data.transformation);
39869
+ }
39870
+ this.linkTo.deserialize(data.linkTo);
39871
+ this.image.onload = () => {
39872
+ this.setCoordinates();
39873
+ this.shootLoadCallbacks();
39874
+ };
39875
+ if (data.storageLink) {
39876
+ this.setStorageLink(data.storageLink);
39877
+ }
39878
+ if (this.image.src) {
39879
+ return this;
39880
+ }
39881
+ this.image = getPlaceholderImage(this.board, data.imageDimension);
39882
+ const storageImage = new Image;
39883
+ storageImage.onload = () => {
39884
+ this.image = storageImage;
39885
+ this.onLoad();
39886
+ };
39887
+ storageImage.onerror = this.onError;
39888
+ storageImage.src = this.storageLink;
39889
+ return this;
39890
+ }
39891
+ emit(operation) {
39892
+ if (this.events) {
39893
+ const command = new ImageCommand([this], operation);
39894
+ command.apply();
39895
+ this.events.emit(operation, command);
39896
+ } else {
39897
+ this.apply(operation);
39898
+ }
39899
+ }
39900
+ setDimensions(dim) {
39901
+ this.imageDimension = dim;
39902
+ }
39903
+ apply(op) {
39904
+ switch (op.class) {
39905
+ case "Transformation":
39906
+ this.transformation.apply(op);
39907
+ break;
39908
+ case "LinkTo":
39909
+ this.linkTo.apply(op);
39910
+ break;
39911
+ case "Image":
39912
+ if (op.data.base64) {
39913
+ this.image.src = op.data.base64;
39914
+ }
39915
+ this.setStorageLink(op.data.storageLink);
39916
+ this.setDimensions(op.data.imageDimension);
39917
+ this.subject.publish(this);
39918
+ break;
39919
+ }
39920
+ }
39921
+ render(context) {
39922
+ if (this.transformationRenderBlock) {
39923
+ return;
39924
+ }
39925
+ const ctx = context.ctx;
39926
+ ctx.save();
39927
+ this.transformation.matrix.applyToContext(ctx);
39928
+ ctx.drawImage(this.image, 0, 0);
39929
+ ctx.restore();
39930
+ if (this.getLinkTo()) {
39931
+ const { top, right } = this.getMbr();
39932
+ this.linkTo.render(context, top, right, this.board.camera.getScale());
39933
+ }
39934
+ }
39935
+ renderHTML(documentFactory) {
39936
+ const div = documentFactory.createElement("image-item");
39937
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
39938
+ const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
39939
+ div.style.backgroundImage = `url(${this.storageLink})`;
39940
+ div.id = this.getId();
39941
+ div.style.width = `${this.imageDimension.width}px`;
39942
+ div.style.height = `${this.imageDimension.height}px`;
39943
+ div.style.transformOrigin = "top left";
39944
+ div.style.transform = transform;
39945
+ div.style.position = "absolute";
39946
+ div.style.backgroundSize = "cover";
39947
+ div.setAttribute("data-link-to", this.linkTo.serialize() || "");
39948
+ if (this.getLinkTo()) {
39949
+ const linkElement = this.linkTo.renderHTML(documentFactory);
39950
+ scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
39951
+ translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
39952
+ div.appendChild(linkElement);
39953
+ }
39954
+ return div;
39955
+ }
39956
+ getPath() {
39957
+ const { left, top, right, bottom } = this.getMbr();
39958
+ const leftTop = new Point(left, top);
39959
+ const rightTop = new Point(right, top);
39960
+ const rightBottom = new Point(right, bottom);
39961
+ const leftBottom = new Point(left, bottom);
39962
+ return new Path([
39963
+ new Line(leftTop, rightTop),
39964
+ new Line(rightTop, rightBottom),
39965
+ new Line(rightBottom, leftBottom),
39966
+ new Line(leftBottom, leftTop)
39967
+ ], true);
39968
+ }
39969
+ getSnapAnchorPoints() {
39970
+ const mbr = this.getMbr();
39971
+ const width2 = mbr.getWidth();
39972
+ const height2 = mbr.getHeight();
39973
+ return [
39974
+ new Point(mbr.left + width2 / 2, mbr.top),
39975
+ new Point(mbr.left + width2 / 2, mbr.bottom),
39976
+ new Point(mbr.left, mbr.top + height2 / 2),
39977
+ new Point(mbr.right, mbr.top + height2 / 2)
39978
+ ];
39979
+ }
39980
+ isClosed() {
39981
+ return true;
39982
+ }
39983
+ getRichText() {
39984
+ return null;
39985
+ }
39986
+ getLinkTo() {
39987
+ return this.linkTo.link;
39988
+ }
39989
+ download() {
39990
+ const linkElem = document.createElement("a");
39991
+ linkElem.href = this.storageLink;
39992
+ linkElem.setAttribute("download", "");
39993
+ linkElem.click();
39994
+ }
39995
+ onRemove() {
39996
+ const storageId = this.getStorageId();
39997
+ if (storageId) {
39998
+ deleteMedia([storageId], this.board.getBoardId());
39999
+ }
40000
+ super.onRemove();
40001
+ }
40002
+ }
40003
+ // src/Items/Audio/Audio.ts
40004
+ class AudioItem extends BaseItem {
40005
+ events;
40006
+ extension;
40007
+ itemType = "Audio";
40008
+ parent = "Board";
40009
+ transformation;
40010
+ linkTo;
40011
+ subject = new Subject;
40012
+ loadCallbacks = [];
40013
+ beforeLoadCallbacks = [];
40014
+ transformationRenderBlock = undefined;
40015
+ url = "";
40016
+ isPlaying = false;
40017
+ currentTime = 0;
40018
+ isStorageUrl = true;
40019
+ constructor(board, isStorageUrl, url, events, id = "", extension2) {
40020
+ super(board, id);
40021
+ this.events = events;
40022
+ this.extension = extension2;
40023
+ this.linkTo = new LinkTo(this.id, events);
40024
+ this.board = board;
40025
+ this.isStorageUrl = isStorageUrl;
40026
+ if (url) {
40027
+ this.applyUrl(url);
40028
+ }
40029
+ this.transformation = new Transformation(id, events);
40030
+ this.linkTo.subject.subscribe(() => {
40031
+ this.updateMbr();
40032
+ this.subject.publish(this);
40033
+ });
40034
+ this.transformation.subject.subscribe(this.onTransform);
40035
+ this.right = this.left + conf.AUDIO_DIMENSIONS.width;
40036
+ this.bottom = this.top + conf.AUDIO_DIMENSIONS.height;
40037
+ this.shouldUseCustomRender = true;
40038
+ }
40039
+ setCurrentTime(time) {
40040
+ this.currentTime = time;
40041
+ }
40042
+ getCurrentTime() {
40043
+ return this.currentTime;
40044
+ }
40045
+ getIsStorageUrl() {
40046
+ return this.isStorageUrl;
40047
+ }
40048
+ onTransform = () => {
40049
+ this.updateMbr();
40050
+ this.subject.publish(this);
40051
+ };
40052
+ doOnceBeforeOnLoad = (callback) => {
40053
+ this.loadCallbacks.push(callback);
40054
+ };
40055
+ doOnceOnLoad = (callback) => {
40056
+ this.loadCallbacks.push(callback);
40057
+ };
40058
+ setIsPlaying(isPlaying) {
40059
+ this.isPlaying = isPlaying;
40060
+ this.shouldRenderOutsideViewRect = isPlaying;
40061
+ this.subject.publish(this);
40062
+ }
40063
+ getIsPlaying() {
40064
+ return this.isPlaying;
40065
+ }
40066
+ applyUrl(url) {
40067
+ if (this.isStorageUrl) {
40068
+ try {
40069
+ const newUrl = new URL(url);
40070
+ this.url = `${window.location.origin}${newUrl.pathname}`;
40071
+ } catch (_) {}
40072
+ } else {
40073
+ this.url = url;
40074
+ }
40075
+ }
40076
+ setUrl(url) {
40077
+ this.emit({
40078
+ class: "Audio",
40079
+ method: "setUrl",
40080
+ item: [this.getId()],
40081
+ url
40082
+ });
40083
+ }
40084
+ getStorageId() {
40085
+ if (!this.isStorageUrl) {
40086
+ return;
40087
+ }
40088
+ return this.url.split("/").pop();
40089
+ }
40090
+ getUrl() {
40091
+ return this.url;
40092
+ }
40093
+ onLoad = async () => {
40094
+ this.shootBeforeLoadCallbacks();
40095
+ this.updateMbr();
40096
+ this.subject.publish(this);
40097
+ this.shootLoadCallbacks();
40098
+ };
40099
+ onError = (_error) => {
40103
40100
  this.updateMbr();
40104
40101
  this.subject.publish(this);
40105
40102
  this.shootLoadCallbacks();
40106
40103
  };
40107
- onTransform = () => {
40108
- this.updateMbr();
40109
- this.subject.publish(this);
40110
- };
40111
40104
  updateMbr() {
40112
40105
  const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
40113
40106
  this.left = translateX;
40114
40107
  this.top = translateY;
40115
- this.right = this.left + this.image.width * scaleX;
40116
- this.bottom = this.top + this.image.height * scaleY;
40108
+ this.right = this.left + conf.AUDIO_DIMENSIONS.width * scaleX;
40109
+ this.bottom = this.top + conf.AUDIO_DIMENSIONS.height * scaleY;
40117
40110
  }
40118
- doOnceBeforeOnLoad = (callback) => {
40119
- this.loadCallbacks.push(callback);
40120
- };
40121
- doOnceOnLoad = (callback) => {
40122
- this.loadCallbacks.push(callback);
40123
- };
40124
- setId(id) {
40125
- this.id = id;
40126
- this.transformation.setId(id);
40127
- this.linkTo.setId(id);
40128
- return this;
40111
+ render(context) {
40112
+ if (this.transformationRenderBlock) {
40113
+ return;
40114
+ }
40115
+ const ctx = context.ctx;
40116
+ const radius = 12 * this.transformation.getScale().x;
40117
+ ctx.save();
40118
+ ctx.globalCompositeOperation = "destination-out";
40119
+ ctx.beginPath();
40120
+ ctx.moveTo(this.left + radius, this.top);
40121
+ ctx.lineTo(this.left + this.getWidth() - radius, this.top);
40122
+ ctx.quadraticCurveTo(this.left + this.getWidth(), this.top, this.left + this.getWidth(), this.top + radius);
40123
+ ctx.lineTo(this.left + this.getWidth(), this.top + this.getHeight() - radius);
40124
+ ctx.quadraticCurveTo(this.left + this.getWidth(), this.top + this.getHeight(), this.left + this.getWidth() - radius, this.top + this.getHeight());
40125
+ ctx.lineTo(this.left + radius, this.top + this.getHeight());
40126
+ ctx.quadraticCurveTo(this.left, this.top + this.getHeight(), this.left, this.top + this.getHeight() - radius);
40127
+ ctx.lineTo(this.left, this.top + radius);
40128
+ ctx.quadraticCurveTo(this.left, this.top, this.left + radius, this.top);
40129
+ ctx.closePath();
40130
+ ctx.fill();
40131
+ ctx.restore();
40129
40132
  }
40130
- getId() {
40131
- return this.id;
40133
+ renderHTML(documentFactory) {
40134
+ const div = documentFactory.createElement("audio-item");
40135
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
40136
+ const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
40137
+ div.id = this.getId();
40138
+ div.style.width = `${conf.AUDIO_DIMENSIONS.width}px`;
40139
+ div.style.height = `${conf.AUDIO_DIMENSIONS.height}px`;
40140
+ div.style.transformOrigin = "top left";
40141
+ div.style.transform = transform;
40142
+ div.style.position = "absolute";
40143
+ div.setAttribute("audio-url", this.getUrl());
40144
+ if (this.extension) {
40145
+ div.setAttribute("extension", this.extension);
40146
+ }
40147
+ if (this.isStorageUrl) {
40148
+ div.setAttribute("is-storage-url", "true");
40149
+ }
40150
+ div.setAttribute("data-link-to", "");
40151
+ return div;
40132
40152
  }
40133
40153
  serialize() {
40134
40154
  return {
40135
- itemType: "Image",
40136
- storageLink: this.storageLink,
40137
- imageDimension: this.imageDimension,
40155
+ itemType: "Audio",
40156
+ url: this.url,
40138
40157
  transformation: this.transformation.serialize(),
40139
- linkTo: this.linkTo.serialize()
40158
+ isStorageUrl: this.isStorageUrl,
40159
+ extension: this.extension
40140
40160
  };
40141
40161
  }
40142
- setCoordinates() {
40143
- this.left = this.transformation.matrix.translateX;
40144
- this.top = this.transformation.matrix.translateY;
40145
- this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
40146
- this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
40147
- this.subject.publish(this);
40148
- }
40149
- shootBeforeLoadCallbacks() {
40150
- while (this.beforeLoadCallbacks.length > 0) {
40151
- this.beforeLoadCallbacks.shift()(this);
40152
- }
40153
- }
40154
- shootLoadCallbacks() {
40155
- while (this.loadCallbacks.length > 0) {
40156
- this.loadCallbacks.shift()(this);
40157
- }
40158
- }
40159
40162
  deserialize(data) {
40163
+ if (data.isStorageUrl) {
40164
+ this.isStorageUrl = data.isStorageUrl;
40165
+ }
40160
40166
  if (data.transformation) {
40161
40167
  this.transformation.deserialize(data.transformation);
40162
40168
  }
40163
- this.linkTo.deserialize(data.linkTo);
40164
- this.image.onload = () => {
40165
- this.setCoordinates();
40166
- this.shootLoadCallbacks();
40167
- };
40168
- if (data.storageLink) {
40169
- this.setStorageLink(data.storageLink);
40169
+ if (data.url) {
40170
+ this.setUrl(data.url);
40170
40171
  }
40171
- if (this.image.src) {
40172
- return this;
40172
+ if (data.extension) {
40173
+ this.extension = data.extension;
40173
40174
  }
40174
- this.image = getPlaceholderImage(this.board, data.imageDimension);
40175
- const storageImage = new Image;
40176
- storageImage.onload = () => {
40177
- this.image = storageImage;
40178
- this.onLoad();
40179
- };
40180
- storageImage.onerror = this.onError;
40181
- storageImage.src = this.storageLink;
40182
40175
  return this;
40183
40176
  }
40184
- emit(operation) {
40185
- if (this.events) {
40186
- const command = new ImageCommand([this], operation);
40187
- command.apply();
40188
- this.events.emit(operation, command);
40189
- } else {
40190
- this.apply(operation);
40191
- }
40192
- }
40193
- setDimensions(dim) {
40194
- this.imageDimension = dim;
40195
- }
40196
40177
  apply(op) {
40197
40178
  switch (op.class) {
40198
40179
  case "Transformation":
@@ -40201,50 +40182,40 @@ class ImageItem extends BaseItem {
40201
40182
  case "LinkTo":
40202
40183
  this.linkTo.apply(op);
40203
40184
  break;
40204
- case "Image":
40205
- if (op.data.base64) {
40206
- this.image.src = op.data.base64;
40185
+ case "Audio":
40186
+ if (op.method === "setUrl") {
40187
+ this.applyUrl(op.url);
40207
40188
  }
40208
- this.setStorageLink(op.data.storageLink);
40209
- this.setDimensions(op.data.imageDimension);
40210
40189
  this.subject.publish(this);
40211
40190
  break;
40212
40191
  }
40213
40192
  }
40214
- render(context) {
40215
- if (this.transformationRenderBlock) {
40216
- return;
40193
+ emit(operation) {
40194
+ if (this.events) {
40195
+ const command = new AudioCommand([this], operation);
40196
+ command.apply();
40197
+ this.events.emit(operation, command);
40198
+ } else {
40199
+ this.apply(operation);
40217
40200
  }
40218
- const ctx = context.ctx;
40219
- ctx.save();
40220
- this.transformation.matrix.applyToContext(ctx);
40221
- ctx.drawImage(this.image, 0, 0);
40222
- ctx.restore();
40223
- if (this.getLinkTo()) {
40224
- const { top, right } = this.getMbr();
40225
- this.linkTo.render(context, top, right, this.board.camera.getScale());
40201
+ }
40202
+ setId(id) {
40203
+ this.id = id;
40204
+ this.transformation.setId(id);
40205
+ return this;
40206
+ }
40207
+ getId() {
40208
+ return this.id;
40209
+ }
40210
+ shootLoadCallbacks() {
40211
+ while (this.loadCallbacks.length > 0) {
40212
+ this.loadCallbacks.shift()(this);
40226
40213
  }
40227
40214
  }
40228
- renderHTML(documentFactory) {
40229
- const div = documentFactory.createElement("image-item");
40230
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
40231
- const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
40232
- div.style.backgroundImage = `url(${this.storageLink})`;
40233
- div.id = this.getId();
40234
- div.style.width = `${this.imageDimension.width}px`;
40235
- div.style.height = `${this.imageDimension.height}px`;
40236
- div.style.transformOrigin = "top left";
40237
- div.style.transform = transform;
40238
- div.style.position = "absolute";
40239
- div.style.backgroundSize = "cover";
40240
- div.setAttribute("data-link-to", this.linkTo.serialize() || "");
40241
- if (this.getLinkTo()) {
40242
- const linkElement = this.linkTo.renderHTML(documentFactory);
40243
- scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
40244
- translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
40245
- div.appendChild(linkElement);
40215
+ shootBeforeLoadCallbacks() {
40216
+ while (this.beforeLoadCallbacks.length > 0) {
40217
+ this.beforeLoadCallbacks.shift()(this);
40246
40218
  }
40247
- return div;
40248
40219
  }
40249
40220
  getPath() {
40250
40221
  const { left, top, right, bottom } = this.getMbr();
@@ -40277,15 +40248,78 @@ class ImageItem extends BaseItem {
40277
40248
  return null;
40278
40249
  }
40279
40250
  getLinkTo() {
40280
- return this.linkTo.link;
40251
+ return;
40252
+ }
40253
+ getExtension() {
40254
+ return this.extension;
40281
40255
  }
40282
40256
  download() {
40283
- const linkElem = document.createElement("a");
40284
- linkElem.href = this.storageLink;
40285
- linkElem.setAttribute("download", "");
40286
- linkElem.click();
40257
+ if (this.extension) {
40258
+ const linkElem = conf.documentFactory.createElement("a");
40259
+ linkElem.href = this.url;
40260
+ linkElem.setAttribute("download", `${this.board.getBoardId()}.${this.extension}`);
40261
+ linkElem.click();
40262
+ }
40263
+ }
40264
+ onRemove() {
40265
+ const storageId = this.getStorageId();
40266
+ if (storageId) {
40267
+ deleteMedia([storageId], this.board.getBoardId());
40268
+ }
40269
+ super.onRemove();
40287
40270
  }
40288
40271
  }
40272
+ // src/Items/Audio/AudioHelpers.ts
40273
+ var uploadAudioToStorage = async (hash, audioBlob, accessToken, boardId) => {
40274
+ return new Promise((resolve2, reject) => {
40275
+ fetch(`${window.location.origin}/api/v1/media/audio/${boardId}`, {
40276
+ method: "POST",
40277
+ headers: {
40278
+ "Content-Type": audioBlob.type,
40279
+ "x-audio-id": hash,
40280
+ Authorization: `Bearer ${accessToken}`
40281
+ },
40282
+ body: audioBlob
40283
+ }).then(async (response) => {
40284
+ if (response.status !== 200) {
40285
+ return catchErrorResponse(response, "audio");
40286
+ }
40287
+ return response.json();
40288
+ }).then((data) => {
40289
+ console.log(data);
40290
+ resolve2(data.src);
40291
+ }).catch((error) => {
40292
+ console.error("Media storage error:", error);
40293
+ reject(error);
40294
+ });
40295
+ });
40296
+ };
40297
+ var prepareAudio = (file, accessToken, boardId) => {
40298
+ return new Promise((resolve2, reject) => {
40299
+ const audio = document.createElement("audio");
40300
+ audio.src = URL.createObjectURL(file);
40301
+ audio.onloadedmetadata = () => {
40302
+ fileTosha256(file).then((hash) => {
40303
+ uploadAudioToStorage(hash, file, accessToken, boardId).then((url) => {
40304
+ resolve2(url);
40305
+ }).catch(reject);
40306
+ }).catch(() => {
40307
+ reject(new Error("Failed to generate hash"));
40308
+ });
40309
+ };
40310
+ audio.onerror = () => {
40311
+ reject(new Error("Failed to load audio"));
40312
+ };
40313
+ });
40314
+ };
40315
+ var calculateAudioPosition = (board, audioItem) => {
40316
+ const cameraMbr = board.camera.getMbr();
40317
+ const cameraWidth = cameraMbr.getWidth();
40318
+ const translateX = cameraMbr.left + cameraWidth * 0.34;
40319
+ const translateY = cameraMbr.getCenter().y - audioItem.getHeight() / 2;
40320
+ const scale = cameraWidth * 0.32 / audioItem.getWidth();
40321
+ return new Matrix2(translateX, translateY, scale, scale);
40322
+ };
40289
40323
  // src/isSafari.ts
40290
40324
  function isSafari() {
40291
40325
  if (typeof navigator === "undefined") {
@@ -51983,14 +52017,15 @@ class Board {
51983
52017
  }
51984
52018
  applyAddItems(op) {
51985
52019
  if (Array.isArray(op.item)) {
52020
+ const data = op.data;
51986
52021
  const items = op.item.map((item2) => {
51987
- const created = this.createItem(item2, op.data[item2]);
52022
+ const created = this.createItem(item2, data[item2]);
51988
52023
  this.index.insert(created);
51989
52024
  return created;
51990
52025
  });
51991
52026
  items.forEach((item2) => {
51992
- if (item2.itemType === "Connector" && op.data[item2.getId()]) {
51993
- const connectorData = op.data[item2.getId()];
52027
+ if (item2 instanceof Connector2 && data[item2.getId()]) {
52028
+ const connectorData = data[item2.getId()];
51994
52029
  item2.applyStartPoint(connectorData.startPoint);
51995
52030
  item2.applyEndPoint(connectorData.endPoint);
51996
52031
  }
@@ -52019,7 +52054,7 @@ class Board {
52019
52054
  this.findItemAndApply(op.item, (item) => {
52020
52055
  this.index.remove(item);
52021
52056
  this.selection.remove(item);
52022
- if (item.itemType === "Connector") {
52057
+ if (item instanceof Connector2) {
52023
52058
  item.clearObservedItems();
52024
52059
  }
52025
52060
  removedItems.push(item);
@@ -52027,7 +52062,7 @@ class Board {
52027
52062
  }
52028
52063
  applyRemoveLockedGroupOperation(op) {
52029
52064
  const item = this.index.getById(op.item[0]);
52030
- if (!item || item.itemType !== "Group") {
52065
+ if (!item || !(item instanceof Group)) {
52031
52066
  return;
52032
52067
  }
52033
52068
  item.getChildren().forEach((item2) => {
@@ -52043,9 +52078,11 @@ class Board {
52043
52078
  });
52044
52079
  }
52045
52080
  applyItemOperation(op) {
52046
- this.findItemAndApply(op.item, (item) => {
52047
- item.apply(op);
52048
- });
52081
+ if ("item" in op) {
52082
+ this.findItemAndApply(op.item, (item) => {
52083
+ item.apply(op);
52084
+ });
52085
+ }
52049
52086
  }
52050
52087
  findItemAndApply(item, apply) {
52051
52088
  if (Array.isArray(item)) {
@@ -52134,9 +52171,8 @@ class Board {
52134
52171
  if (withConnectors) {
52135
52172
  connectors = this.items.getLinkedConnectorsById(item.getId()).map((connector) => connector.getId());
52136
52173
  }
52137
- const shouldClearStorageUsage = item.itemType === "Image" || item.itemType === "Video" && item.getIsStorageUrl() || item.itemType === "Audio" && item.getIsStorageUrl();
52138
- if (shouldClearStorageUsage) {
52139
- deleteMedia([item.getStorageId()], this.boardId);
52174
+ if ("onRemove" in item) {
52175
+ item.onRemove();
52140
52176
  }
52141
52177
  this.emit({
52142
52178
  class: "Board",