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/node.js CHANGED
@@ -35930,6 +35930,7 @@ class BaseItem extends Mbr {
35930
35930
  transformationRenderBlock = undefined;
35931
35931
  board;
35932
35932
  id;
35933
+ onRemoveCallbacks = [];
35933
35934
  shouldUseCustomRender = false;
35934
35935
  shouldRenderOutsideViewRect = true;
35935
35936
  itemType = "";
@@ -36007,6 +36008,12 @@ class BaseItem extends Mbr {
36007
36008
  break;
36008
36009
  }
36009
36010
  }
36011
+ addOnRemoveCallback(cb) {
36012
+ this.onRemoveCallbacks.push(cb);
36013
+ }
36014
+ onRemove() {
36015
+ this.onRemoveCallbacks.forEach((cb) => cb());
36016
+ }
36010
36017
  render(context) {}
36011
36018
  renderHTML(documentFactory) {
36012
36019
  return documentFactory.createElement("div");
@@ -41263,6 +41270,9 @@ class VideoItem extends BaseItem {
41263
41270
  this.loadCallbacks.push(callback);
41264
41271
  };
41265
41272
  getStorageId() {
41273
+ if (!this.isStorageUrl) {
41274
+ return;
41275
+ }
41266
41276
  return this.url.split("/").pop();
41267
41277
  }
41268
41278
  getIsStorageUrl() {
@@ -41535,6 +41545,13 @@ class VideoItem extends BaseItem {
41535
41545
  linkElem.click();
41536
41546
  }
41537
41547
  }
41548
+ onRemove() {
41549
+ const storageId = this.getStorageId();
41550
+ if (storageId) {
41551
+ deleteMedia([storageId], this.board.getBoardId());
41552
+ }
41553
+ super.onRemove();
41554
+ }
41538
41555
  }
41539
41556
  // src/Items/Image/calculatePosition.ts
41540
41557
  function calculatePosition(boardImage, board) {
@@ -41965,432 +41982,122 @@ var captureFrame = (frameTime, video) => {
41965
41982
  return null;
41966
41983
  }
41967
41984
  };
41968
- // src/Items/Audio/Audio.ts
41969
- class AudioItem extends BaseItem {
41985
+ // src/Items/Placeholder/Placeholder.ts
41986
+ var PlaceholderImg = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
41987
+ <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"/>
41988
+ </svg>`;
41989
+
41990
+ class Placeholder extends BaseItem {
41970
41991
  events;
41971
- extension;
41972
- itemType = "Audio";
41992
+ miroData;
41993
+ backgroundColor;
41994
+ icon;
41995
+ itemType = "Placeholder";
41996
+ shapeType = "Rectangle";
41973
41997
  parent = "Board";
41974
41998
  transformation;
41975
- linkTo;
41999
+ path = Shapes[this.shapeType].path.copy();
42000
+ mbr = Shapes[this.shapeType].path.getMbr().copy();
41976
42001
  subject = new Subject;
41977
- loadCallbacks = [];
41978
- beforeLoadCallbacks = [];
41979
42002
  transformationRenderBlock = undefined;
41980
- url = "";
41981
- isPlaying = false;
41982
- currentTime = 0;
41983
- isStorageUrl = true;
41984
- constructor(board, isStorageUrl, url, events, id = "", extension2) {
42003
+ iconImage;
42004
+ constructor(board, events, miroData, id = "", backgroundColor = "#E5E5EA", icon = PlaceholderImg?.toString() || "") {
41985
42005
  super(board, id);
41986
42006
  this.events = events;
41987
- this.extension = extension2;
41988
- this.linkTo = new LinkTo(this.id, events);
41989
- this.board = board;
41990
- this.isStorageUrl = isStorageUrl;
41991
- if (url) {
41992
- this.applyUrl(url);
41993
- }
41994
- this.transformation = new Transformation(id, events);
41995
- this.linkTo.subject.subscribe(() => {
42007
+ this.miroData = miroData;
42008
+ this.backgroundColor = backgroundColor;
42009
+ this.icon = icon;
42010
+ this.transformation = new Transformation(this.id, this.events);
42011
+ this.transformation.subject.subscribe((_subject) => {
42012
+ this.transformPath();
41996
42013
  this.updateMbr();
41997
42014
  this.subject.publish(this);
41998
42015
  });
41999
- this.transformation.subject.subscribe(this.onTransform);
42000
- this.right = this.left + conf.AUDIO_DIMENSIONS.width;
42001
- this.bottom = this.top + conf.AUDIO_DIMENSIONS.height;
42002
- this.shouldUseCustomRender = true;
42003
- }
42004
- setCurrentTime(time) {
42005
- this.currentTime = time;
42006
- }
42007
- getCurrentTime() {
42008
- return this.currentTime;
42009
- }
42010
- getIsStorageUrl() {
42011
- return this.isStorageUrl;
42012
- }
42013
- onTransform = () => {
42014
42016
  this.updateMbr();
42015
- this.subject.publish(this);
42016
- };
42017
- doOnceBeforeOnLoad = (callback) => {
42018
- this.loadCallbacks.push(callback);
42019
- };
42020
- doOnceOnLoad = (callback) => {
42021
- this.loadCallbacks.push(callback);
42022
- };
42023
- setIsPlaying(isPlaying) {
42024
- this.isPlaying = isPlaying;
42025
- this.shouldRenderOutsideViewRect = isPlaying;
42026
- this.subject.publish(this);
42027
- }
42028
- getIsPlaying() {
42029
- return this.isPlaying;
42017
+ this.loadIconImage();
42030
42018
  }
42031
- applyUrl(url) {
42032
- if (this.isStorageUrl) {
42033
- try {
42034
- const newUrl = new URL(url);
42035
- this.url = `${window.location.origin}${newUrl.pathname}`;
42036
- } catch (_) {}
42019
+ emit(operation) {
42020
+ if (this.events) {
42021
+ const command = new PlaceholderCommand([this], operation);
42022
+ command.apply();
42023
+ this.events.emit(operation, command);
42037
42024
  } else {
42038
- this.url = url;
42039
- }
42040
- }
42041
- setUrl(url) {
42042
- this.emit({
42043
- class: "Audio",
42044
- method: "setUrl",
42045
- item: [this.getId()],
42046
- url
42047
- });
42048
- }
42049
- getStorageId() {
42050
- return this.url.split("/").pop();
42051
- }
42052
- getUrl() {
42053
- return this.url;
42054
- }
42055
- onLoad = async () => {
42056
- this.shootBeforeLoadCallbacks();
42057
- this.updateMbr();
42058
- this.subject.publish(this);
42059
- this.shootLoadCallbacks();
42060
- };
42061
- onError = (_error) => {
42062
- this.updateMbr();
42063
- this.subject.publish(this);
42064
- this.shootLoadCallbacks();
42065
- };
42066
- updateMbr() {
42067
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42068
- this.left = translateX;
42069
- this.top = translateY;
42070
- this.right = this.left + conf.AUDIO_DIMENSIONS.width * scaleX;
42071
- this.bottom = this.top + conf.AUDIO_DIMENSIONS.height * scaleY;
42072
- }
42073
- render(context) {
42074
- if (this.transformationRenderBlock) {
42075
- return;
42076
- }
42077
- const ctx = context.ctx;
42078
- const radius = 12 * this.transformation.getScale().x;
42079
- ctx.save();
42080
- ctx.globalCompositeOperation = "destination-out";
42081
- ctx.beginPath();
42082
- ctx.moveTo(this.left + radius, this.top);
42083
- ctx.lineTo(this.left + this.getWidth() - radius, this.top);
42084
- ctx.quadraticCurveTo(this.left + this.getWidth(), this.top, this.left + this.getWidth(), this.top + radius);
42085
- ctx.lineTo(this.left + this.getWidth(), this.top + this.getHeight() - radius);
42086
- ctx.quadraticCurveTo(this.left + this.getWidth(), this.top + this.getHeight(), this.left + this.getWidth() - radius, this.top + this.getHeight());
42087
- ctx.lineTo(this.left + radius, this.top + this.getHeight());
42088
- ctx.quadraticCurveTo(this.left, this.top + this.getHeight(), this.left, this.top + this.getHeight() - radius);
42089
- ctx.lineTo(this.left, this.top + radius);
42090
- ctx.quadraticCurveTo(this.left, this.top, this.left + radius, this.top);
42091
- ctx.closePath();
42092
- ctx.fill();
42093
- ctx.restore();
42094
- }
42095
- renderHTML(documentFactory) {
42096
- const div = documentFactory.createElement("audio-item");
42097
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42098
- const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42099
- div.id = this.getId();
42100
- div.style.width = `${conf.AUDIO_DIMENSIONS.width}px`;
42101
- div.style.height = `${conf.AUDIO_DIMENSIONS.height}px`;
42102
- div.style.transformOrigin = "top left";
42103
- div.style.transform = transform;
42104
- div.style.position = "absolute";
42105
- div.setAttribute("audio-url", this.getUrl());
42106
- if (this.extension) {
42107
- div.setAttribute("extension", this.extension);
42108
- }
42109
- if (this.isStorageUrl) {
42110
- div.setAttribute("is-storage-url", "true");
42025
+ this.apply(operation);
42111
42026
  }
42112
- div.setAttribute("data-link-to", "");
42113
- return div;
42114
42027
  }
42115
42028
  serialize() {
42116
42029
  return {
42117
- itemType: "Audio",
42118
- url: this.url,
42030
+ itemType: "Placeholder",
42031
+ backgroundColor: this.backgroundColor,
42032
+ icon: this.icon,
42119
42033
  transformation: this.transformation.serialize(),
42120
- isStorageUrl: this.isStorageUrl,
42121
- extension: this.extension
42034
+ miroData: this.miroData
42122
42035
  };
42123
42036
  }
42124
42037
  deserialize(data) {
42125
- if (data.isStorageUrl) {
42126
- this.isStorageUrl = data.isStorageUrl;
42127
- }
42038
+ this.initPath();
42039
+ this.backgroundColor = data.backgroundColor ?? this.backgroundColor;
42040
+ this.icon = data.icon ?? this.icon;
42041
+ this.miroData = data.miroData;
42128
42042
  if (data.transformation) {
42129
42043
  this.transformation.deserialize(data.transformation);
42044
+ this.transformPath();
42130
42045
  }
42131
- if (data.url) {
42132
- this.setUrl(data.url);
42133
- }
42134
- if (data.extension) {
42135
- this.extension = data.extension;
42136
- }
42046
+ this.subject.publish(this);
42047
+ return this;
42048
+ }
42049
+ setId(id) {
42050
+ this.id = id;
42051
+ this.transformation.setId(id);
42137
42052
  return this;
42138
42053
  }
42054
+ getId() {
42055
+ return this.id;
42056
+ }
42139
42057
  apply(op) {
42140
42058
  switch (op.class) {
42059
+ case "Placeholder":
42060
+ this.applyPlaceholder(op);
42061
+ this.updateMbr();
42062
+ break;
42141
42063
  case "Transformation":
42142
42064
  this.transformation.apply(op);
42143
42065
  break;
42144
- case "LinkTo":
42145
- this.linkTo.apply(op);
42066
+ default:
42067
+ return;
42068
+ }
42069
+ this.subject.publish(this);
42070
+ }
42071
+ applyPlaceholder(op) {
42072
+ switch (op.method) {
42073
+ case "setBackgroundColor":
42074
+ this.applyBackgroundColor(op.backgroundColor);
42146
42075
  break;
42147
- case "Audio":
42148
- if (op.method === "setUrl") {
42149
- this.applyUrl(op.url);
42150
- }
42151
- this.subject.publish(this);
42076
+ case "setIcon":
42077
+ this.applyIcon(op.icon);
42078
+ break;
42079
+ case "setMiroData":
42080
+ this.applyMiroData(op.miroData);
42152
42081
  break;
42153
42082
  }
42154
42083
  }
42155
- emit(operation) {
42156
- if (this.events) {
42157
- const command = new AudioCommand([this], operation);
42158
- command.apply();
42159
- this.events.emit(operation, command);
42160
- } else {
42161
- this.apply(operation);
42162
- }
42084
+ getBackgroundColor() {
42085
+ return this.backgroundColor;
42163
42086
  }
42164
- setId(id) {
42165
- this.id = id;
42166
- this.transformation.setId(id);
42167
- return this;
42087
+ applyBackgroundColor(backgroundColor) {
42088
+ this.backgroundColor = backgroundColor;
42089
+ this.path.setBackgroundColor(backgroundColor);
42168
42090
  }
42169
- getId() {
42170
- return this.id;
42091
+ setBackgroundColor(backgroundColor) {
42092
+ this.emit({
42093
+ class: "Placeholder",
42094
+ method: "setBackgroundColor",
42095
+ item: [this.getId()],
42096
+ backgroundColor
42097
+ });
42171
42098
  }
42172
- shootLoadCallbacks() {
42173
- while (this.loadCallbacks.length > 0) {
42174
- this.loadCallbacks.shift()(this);
42175
- }
42176
- }
42177
- shootBeforeLoadCallbacks() {
42178
- while (this.beforeLoadCallbacks.length > 0) {
42179
- this.beforeLoadCallbacks.shift()(this);
42180
- }
42181
- }
42182
- getPath() {
42183
- const { left, top, right, bottom } = this.getMbr();
42184
- const leftTop = new Point(left, top);
42185
- const rightTop = new Point(right, top);
42186
- const rightBottom = new Point(right, bottom);
42187
- const leftBottom = new Point(left, bottom);
42188
- return new Path([
42189
- new Line(leftTop, rightTop),
42190
- new Line(rightTop, rightBottom),
42191
- new Line(rightBottom, leftBottom),
42192
- new Line(leftBottom, leftTop)
42193
- ], true);
42194
- }
42195
- getSnapAnchorPoints() {
42196
- const mbr = this.getMbr();
42197
- const width2 = mbr.getWidth();
42198
- const height2 = mbr.getHeight();
42199
- return [
42200
- new Point(mbr.left + width2 / 2, mbr.top),
42201
- new Point(mbr.left + width2 / 2, mbr.bottom),
42202
- new Point(mbr.left, mbr.top + height2 / 2),
42203
- new Point(mbr.right, mbr.top + height2 / 2)
42204
- ];
42205
- }
42206
- isClosed() {
42207
- return true;
42208
- }
42209
- getRichText() {
42210
- return null;
42211
- }
42212
- getLinkTo() {
42213
- return;
42214
- }
42215
- getExtension() {
42216
- return this.extension;
42217
- }
42218
- download() {
42219
- if (this.extension) {
42220
- const linkElem = conf.documentFactory.createElement("a");
42221
- linkElem.href = this.url;
42222
- linkElem.setAttribute("download", `${this.board.getBoardId()}.${this.extension}`);
42223
- linkElem.click();
42224
- }
42225
- }
42226
- }
42227
- // src/Items/Audio/AudioHelpers.ts
42228
- var uploadAudioToStorage = async (hash, audioBlob, accessToken, boardId) => {
42229
- return new Promise((resolve2, reject) => {
42230
- fetch(`${window.location.origin}/api/v1/media/audio/${boardId}`, {
42231
- method: "POST",
42232
- headers: {
42233
- "Content-Type": audioBlob.type,
42234
- "x-audio-id": hash,
42235
- Authorization: `Bearer ${accessToken}`
42236
- },
42237
- body: audioBlob
42238
- }).then(async (response) => {
42239
- if (response.status !== 200) {
42240
- return catchErrorResponse(response, "audio");
42241
- }
42242
- return response.json();
42243
- }).then((data) => {
42244
- console.log(data);
42245
- resolve2(data.src);
42246
- }).catch((error) => {
42247
- console.error("Media storage error:", error);
42248
- reject(error);
42249
- });
42250
- });
42251
- };
42252
- var prepareAudio = (file, accessToken, boardId) => {
42253
- return new Promise((resolve2, reject) => {
42254
- const audio = document.createElement("audio");
42255
- audio.src = URL.createObjectURL(file);
42256
- audio.onloadedmetadata = () => {
42257
- fileTosha256(file).then((hash) => {
42258
- uploadAudioToStorage(hash, file, accessToken, boardId).then((url) => {
42259
- resolve2(url);
42260
- }).catch(reject);
42261
- }).catch(() => {
42262
- reject(new Error("Failed to generate hash"));
42263
- });
42264
- };
42265
- audio.onerror = () => {
42266
- reject(new Error("Failed to load audio"));
42267
- };
42268
- });
42269
- };
42270
- var calculateAudioPosition = (board, audioItem) => {
42271
- const cameraMbr = board.camera.getMbr();
42272
- const cameraWidth = cameraMbr.getWidth();
42273
- const translateX = cameraMbr.left + cameraWidth * 0.34;
42274
- const translateY = cameraMbr.getCenter().y - audioItem.getHeight() / 2;
42275
- const scale = cameraWidth * 0.32 / audioItem.getWidth();
42276
- return new Matrix2(translateX, translateY, scale, scale);
42277
- };
42278
- // src/Items/Placeholder/Placeholder.ts
42279
- var PlaceholderImg = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
42280
- <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"/>
42281
- </svg>`;
42282
-
42283
- class Placeholder extends BaseItem {
42284
- events;
42285
- miroData;
42286
- backgroundColor;
42287
- icon;
42288
- itemType = "Placeholder";
42289
- shapeType = "Rectangle";
42290
- parent = "Board";
42291
- transformation;
42292
- path = Shapes[this.shapeType].path.copy();
42293
- mbr = Shapes[this.shapeType].path.getMbr().copy();
42294
- subject = new Subject;
42295
- transformationRenderBlock = undefined;
42296
- iconImage;
42297
- constructor(board, events, miroData, id = "", backgroundColor = "#E5E5EA", icon = PlaceholderImg?.toString() || "") {
42298
- super(board, id);
42299
- this.events = events;
42300
- this.miroData = miroData;
42301
- this.backgroundColor = backgroundColor;
42302
- this.icon = icon;
42303
- this.transformation = new Transformation(this.id, this.events);
42304
- this.transformation.subject.subscribe((_subject) => {
42305
- this.transformPath();
42306
- this.updateMbr();
42307
- this.subject.publish(this);
42308
- });
42309
- this.updateMbr();
42310
- this.loadIconImage();
42311
- }
42312
- emit(operation) {
42313
- if (this.events) {
42314
- const command = new PlaceholderCommand([this], operation);
42315
- command.apply();
42316
- this.events.emit(operation, command);
42317
- } else {
42318
- this.apply(operation);
42319
- }
42320
- }
42321
- serialize() {
42322
- return {
42323
- itemType: "Placeholder",
42324
- backgroundColor: this.backgroundColor,
42325
- icon: this.icon,
42326
- transformation: this.transformation.serialize(),
42327
- miroData: this.miroData
42328
- };
42329
- }
42330
- deserialize(data) {
42331
- this.initPath();
42332
- this.backgroundColor = data.backgroundColor ?? this.backgroundColor;
42333
- this.icon = data.icon ?? this.icon;
42334
- this.miroData = data.miroData;
42335
- if (data.transformation) {
42336
- this.transformation.deserialize(data.transformation);
42337
- this.transformPath();
42338
- }
42339
- this.subject.publish(this);
42340
- return this;
42341
- }
42342
- setId(id) {
42343
- this.id = id;
42344
- this.transformation.setId(id);
42345
- return this;
42346
- }
42347
- getId() {
42348
- return this.id;
42349
- }
42350
- apply(op) {
42351
- switch (op.class) {
42352
- case "Placeholder":
42353
- this.applyPlaceholder(op);
42354
- this.updateMbr();
42355
- break;
42356
- case "Transformation":
42357
- this.transformation.apply(op);
42358
- break;
42359
- default:
42360
- return;
42361
- }
42362
- this.subject.publish(this);
42363
- }
42364
- applyPlaceholder(op) {
42365
- switch (op.method) {
42366
- case "setBackgroundColor":
42367
- this.applyBackgroundColor(op.backgroundColor);
42368
- break;
42369
- case "setIcon":
42370
- this.applyIcon(op.icon);
42371
- break;
42372
- case "setMiroData":
42373
- this.applyMiroData(op.miroData);
42374
- break;
42375
- }
42376
- }
42377
- getBackgroundColor() {
42378
- return this.backgroundColor;
42379
- }
42380
- applyBackgroundColor(backgroundColor) {
42381
- this.backgroundColor = backgroundColor;
42382
- this.path.setBackgroundColor(backgroundColor);
42383
- }
42384
- setBackgroundColor(backgroundColor) {
42385
- this.emit({
42386
- class: "Placeholder",
42387
- method: "setBackgroundColor",
42388
- item: [this.getId()],
42389
- backgroundColor
42390
- });
42391
- }
42392
- getIcon() {
42393
- return this.icon;
42099
+ getIcon() {
42100
+ return this.icon;
42394
42101
  }
42395
42102
  applyIcon(icon) {
42396
42103
  this.icon = icon;
@@ -42634,100 +42341,374 @@ class ImageItem extends BaseItem {
42634
42341
  this.shootLoadCallbacks();
42635
42342
  };
42636
42343
  onError = (_error) => {
42637
- this.image = getPlaceholderImage(this.board);
42344
+ this.image = getPlaceholderImage(this.board);
42345
+ this.updateMbr();
42346
+ this.subject.publish(this);
42347
+ this.shootLoadCallbacks();
42348
+ };
42349
+ onTransform = () => {
42350
+ this.updateMbr();
42351
+ this.subject.publish(this);
42352
+ };
42353
+ updateMbr() {
42354
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42355
+ this.left = translateX;
42356
+ this.top = translateY;
42357
+ this.right = this.left + this.image.width * scaleX;
42358
+ this.bottom = this.top + this.image.height * scaleY;
42359
+ }
42360
+ doOnceBeforeOnLoad = (callback) => {
42361
+ this.loadCallbacks.push(callback);
42362
+ };
42363
+ doOnceOnLoad = (callback) => {
42364
+ this.loadCallbacks.push(callback);
42365
+ };
42366
+ setId(id) {
42367
+ this.id = id;
42368
+ this.transformation.setId(id);
42369
+ this.linkTo.setId(id);
42370
+ return this;
42371
+ }
42372
+ getId() {
42373
+ return this.id;
42374
+ }
42375
+ serialize() {
42376
+ return {
42377
+ itemType: "Image",
42378
+ storageLink: this.storageLink,
42379
+ imageDimension: this.imageDimension,
42380
+ transformation: this.transformation.serialize(),
42381
+ linkTo: this.linkTo.serialize()
42382
+ };
42383
+ }
42384
+ setCoordinates() {
42385
+ this.left = this.transformation.matrix.translateX;
42386
+ this.top = this.transformation.matrix.translateY;
42387
+ this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
42388
+ this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
42389
+ this.subject.publish(this);
42390
+ }
42391
+ shootBeforeLoadCallbacks() {
42392
+ while (this.beforeLoadCallbacks.length > 0) {
42393
+ this.beforeLoadCallbacks.shift()(this);
42394
+ }
42395
+ }
42396
+ shootLoadCallbacks() {
42397
+ while (this.loadCallbacks.length > 0) {
42398
+ this.loadCallbacks.shift()(this);
42399
+ }
42400
+ }
42401
+ deserialize(data) {
42402
+ if (data.transformation) {
42403
+ this.transformation.deserialize(data.transformation);
42404
+ }
42405
+ this.linkTo.deserialize(data.linkTo);
42406
+ this.image.onload = () => {
42407
+ this.setCoordinates();
42408
+ this.shootLoadCallbacks();
42409
+ };
42410
+ if (data.storageLink) {
42411
+ this.setStorageLink(data.storageLink);
42412
+ }
42413
+ if (this.image.src) {
42414
+ return this;
42415
+ }
42416
+ this.image = getPlaceholderImage(this.board, data.imageDimension);
42417
+ const storageImage = new Image;
42418
+ storageImage.onload = () => {
42419
+ this.image = storageImage;
42420
+ this.onLoad();
42421
+ };
42422
+ storageImage.onerror = this.onError;
42423
+ storageImage.src = this.storageLink;
42424
+ return this;
42425
+ }
42426
+ emit(operation) {
42427
+ if (this.events) {
42428
+ const command = new ImageCommand([this], operation);
42429
+ command.apply();
42430
+ this.events.emit(operation, command);
42431
+ } else {
42432
+ this.apply(operation);
42433
+ }
42434
+ }
42435
+ setDimensions(dim) {
42436
+ this.imageDimension = dim;
42437
+ }
42438
+ apply(op) {
42439
+ switch (op.class) {
42440
+ case "Transformation":
42441
+ this.transformation.apply(op);
42442
+ break;
42443
+ case "LinkTo":
42444
+ this.linkTo.apply(op);
42445
+ break;
42446
+ case "Image":
42447
+ if (op.data.base64) {
42448
+ this.image.src = op.data.base64;
42449
+ }
42450
+ this.setStorageLink(op.data.storageLink);
42451
+ this.setDimensions(op.data.imageDimension);
42452
+ this.subject.publish(this);
42453
+ break;
42454
+ }
42455
+ }
42456
+ render(context) {
42457
+ if (this.transformationRenderBlock) {
42458
+ return;
42459
+ }
42460
+ const ctx = context.ctx;
42461
+ ctx.save();
42462
+ this.transformation.matrix.applyToContext(ctx);
42463
+ ctx.drawImage(this.image, 0, 0);
42464
+ ctx.restore();
42465
+ if (this.getLinkTo()) {
42466
+ const { top, right } = this.getMbr();
42467
+ this.linkTo.render(context, top, right, this.board.camera.getScale());
42468
+ }
42469
+ }
42470
+ renderHTML(documentFactory) {
42471
+ const div = documentFactory.createElement("image-item");
42472
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42473
+ const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42474
+ div.style.backgroundImage = `url(${this.storageLink})`;
42475
+ div.id = this.getId();
42476
+ div.style.width = `${this.imageDimension.width}px`;
42477
+ div.style.height = `${this.imageDimension.height}px`;
42478
+ div.style.transformOrigin = "top left";
42479
+ div.style.transform = transform;
42480
+ div.style.position = "absolute";
42481
+ div.style.backgroundSize = "cover";
42482
+ div.setAttribute("data-link-to", this.linkTo.serialize() || "");
42483
+ if (this.getLinkTo()) {
42484
+ const linkElement = this.linkTo.renderHTML(documentFactory);
42485
+ scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
42486
+ translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
42487
+ div.appendChild(linkElement);
42488
+ }
42489
+ return div;
42490
+ }
42491
+ getPath() {
42492
+ const { left, top, right, bottom } = this.getMbr();
42493
+ const leftTop = new Point(left, top);
42494
+ const rightTop = new Point(right, top);
42495
+ const rightBottom = new Point(right, bottom);
42496
+ const leftBottom = new Point(left, bottom);
42497
+ return new Path([
42498
+ new Line(leftTop, rightTop),
42499
+ new Line(rightTop, rightBottom),
42500
+ new Line(rightBottom, leftBottom),
42501
+ new Line(leftBottom, leftTop)
42502
+ ], true);
42503
+ }
42504
+ getSnapAnchorPoints() {
42505
+ const mbr = this.getMbr();
42506
+ const width2 = mbr.getWidth();
42507
+ const height2 = mbr.getHeight();
42508
+ return [
42509
+ new Point(mbr.left + width2 / 2, mbr.top),
42510
+ new Point(mbr.left + width2 / 2, mbr.bottom),
42511
+ new Point(mbr.left, mbr.top + height2 / 2),
42512
+ new Point(mbr.right, mbr.top + height2 / 2)
42513
+ ];
42514
+ }
42515
+ isClosed() {
42516
+ return true;
42517
+ }
42518
+ getRichText() {
42519
+ return null;
42520
+ }
42521
+ getLinkTo() {
42522
+ return this.linkTo.link;
42523
+ }
42524
+ download() {
42525
+ const linkElem = document.createElement("a");
42526
+ linkElem.href = this.storageLink;
42527
+ linkElem.setAttribute("download", "");
42528
+ linkElem.click();
42529
+ }
42530
+ onRemove() {
42531
+ const storageId = this.getStorageId();
42532
+ if (storageId) {
42533
+ deleteMedia([storageId], this.board.getBoardId());
42534
+ }
42535
+ super.onRemove();
42536
+ }
42537
+ }
42538
+ // src/Items/Audio/Audio.ts
42539
+ class AudioItem extends BaseItem {
42540
+ events;
42541
+ extension;
42542
+ itemType = "Audio";
42543
+ parent = "Board";
42544
+ transformation;
42545
+ linkTo;
42546
+ subject = new Subject;
42547
+ loadCallbacks = [];
42548
+ beforeLoadCallbacks = [];
42549
+ transformationRenderBlock = undefined;
42550
+ url = "";
42551
+ isPlaying = false;
42552
+ currentTime = 0;
42553
+ isStorageUrl = true;
42554
+ constructor(board, isStorageUrl, url, events, id = "", extension2) {
42555
+ super(board, id);
42556
+ this.events = events;
42557
+ this.extension = extension2;
42558
+ this.linkTo = new LinkTo(this.id, events);
42559
+ this.board = board;
42560
+ this.isStorageUrl = isStorageUrl;
42561
+ if (url) {
42562
+ this.applyUrl(url);
42563
+ }
42564
+ this.transformation = new Transformation(id, events);
42565
+ this.linkTo.subject.subscribe(() => {
42566
+ this.updateMbr();
42567
+ this.subject.publish(this);
42568
+ });
42569
+ this.transformation.subject.subscribe(this.onTransform);
42570
+ this.right = this.left + conf.AUDIO_DIMENSIONS.width;
42571
+ this.bottom = this.top + conf.AUDIO_DIMENSIONS.height;
42572
+ this.shouldUseCustomRender = true;
42573
+ }
42574
+ setCurrentTime(time) {
42575
+ this.currentTime = time;
42576
+ }
42577
+ getCurrentTime() {
42578
+ return this.currentTime;
42579
+ }
42580
+ getIsStorageUrl() {
42581
+ return this.isStorageUrl;
42582
+ }
42583
+ onTransform = () => {
42584
+ this.updateMbr();
42585
+ this.subject.publish(this);
42586
+ };
42587
+ doOnceBeforeOnLoad = (callback) => {
42588
+ this.loadCallbacks.push(callback);
42589
+ };
42590
+ doOnceOnLoad = (callback) => {
42591
+ this.loadCallbacks.push(callback);
42592
+ };
42593
+ setIsPlaying(isPlaying) {
42594
+ this.isPlaying = isPlaying;
42595
+ this.shouldRenderOutsideViewRect = isPlaying;
42596
+ this.subject.publish(this);
42597
+ }
42598
+ getIsPlaying() {
42599
+ return this.isPlaying;
42600
+ }
42601
+ applyUrl(url) {
42602
+ if (this.isStorageUrl) {
42603
+ try {
42604
+ const newUrl = new URL(url);
42605
+ this.url = `${window.location.origin}${newUrl.pathname}`;
42606
+ } catch (_) {}
42607
+ } else {
42608
+ this.url = url;
42609
+ }
42610
+ }
42611
+ setUrl(url) {
42612
+ this.emit({
42613
+ class: "Audio",
42614
+ method: "setUrl",
42615
+ item: [this.getId()],
42616
+ url
42617
+ });
42618
+ }
42619
+ getStorageId() {
42620
+ if (!this.isStorageUrl) {
42621
+ return;
42622
+ }
42623
+ return this.url.split("/").pop();
42624
+ }
42625
+ getUrl() {
42626
+ return this.url;
42627
+ }
42628
+ onLoad = async () => {
42629
+ this.shootBeforeLoadCallbacks();
42630
+ this.updateMbr();
42631
+ this.subject.publish(this);
42632
+ this.shootLoadCallbacks();
42633
+ };
42634
+ onError = (_error) => {
42638
42635
  this.updateMbr();
42639
42636
  this.subject.publish(this);
42640
42637
  this.shootLoadCallbacks();
42641
42638
  };
42642
- onTransform = () => {
42643
- this.updateMbr();
42644
- this.subject.publish(this);
42645
- };
42646
42639
  updateMbr() {
42647
42640
  const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42648
42641
  this.left = translateX;
42649
42642
  this.top = translateY;
42650
- this.right = this.left + this.image.width * scaleX;
42651
- this.bottom = this.top + this.image.height * scaleY;
42643
+ this.right = this.left + conf.AUDIO_DIMENSIONS.width * scaleX;
42644
+ this.bottom = this.top + conf.AUDIO_DIMENSIONS.height * scaleY;
42652
42645
  }
42653
- doOnceBeforeOnLoad = (callback) => {
42654
- this.loadCallbacks.push(callback);
42655
- };
42656
- doOnceOnLoad = (callback) => {
42657
- this.loadCallbacks.push(callback);
42658
- };
42659
- setId(id) {
42660
- this.id = id;
42661
- this.transformation.setId(id);
42662
- this.linkTo.setId(id);
42663
- return this;
42646
+ render(context) {
42647
+ if (this.transformationRenderBlock) {
42648
+ return;
42649
+ }
42650
+ const ctx = context.ctx;
42651
+ const radius = 12 * this.transformation.getScale().x;
42652
+ ctx.save();
42653
+ ctx.globalCompositeOperation = "destination-out";
42654
+ ctx.beginPath();
42655
+ ctx.moveTo(this.left + radius, this.top);
42656
+ ctx.lineTo(this.left + this.getWidth() - radius, this.top);
42657
+ ctx.quadraticCurveTo(this.left + this.getWidth(), this.top, this.left + this.getWidth(), this.top + radius);
42658
+ ctx.lineTo(this.left + this.getWidth(), this.top + this.getHeight() - radius);
42659
+ ctx.quadraticCurveTo(this.left + this.getWidth(), this.top + this.getHeight(), this.left + this.getWidth() - radius, this.top + this.getHeight());
42660
+ ctx.lineTo(this.left + radius, this.top + this.getHeight());
42661
+ ctx.quadraticCurveTo(this.left, this.top + this.getHeight(), this.left, this.top + this.getHeight() - radius);
42662
+ ctx.lineTo(this.left, this.top + radius);
42663
+ ctx.quadraticCurveTo(this.left, this.top, this.left + radius, this.top);
42664
+ ctx.closePath();
42665
+ ctx.fill();
42666
+ ctx.restore();
42664
42667
  }
42665
- getId() {
42666
- return this.id;
42668
+ renderHTML(documentFactory) {
42669
+ const div = documentFactory.createElement("audio-item");
42670
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42671
+ const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42672
+ div.id = this.getId();
42673
+ div.style.width = `${conf.AUDIO_DIMENSIONS.width}px`;
42674
+ div.style.height = `${conf.AUDIO_DIMENSIONS.height}px`;
42675
+ div.style.transformOrigin = "top left";
42676
+ div.style.transform = transform;
42677
+ div.style.position = "absolute";
42678
+ div.setAttribute("audio-url", this.getUrl());
42679
+ if (this.extension) {
42680
+ div.setAttribute("extension", this.extension);
42681
+ }
42682
+ if (this.isStorageUrl) {
42683
+ div.setAttribute("is-storage-url", "true");
42684
+ }
42685
+ div.setAttribute("data-link-to", "");
42686
+ return div;
42667
42687
  }
42668
42688
  serialize() {
42669
42689
  return {
42670
- itemType: "Image",
42671
- storageLink: this.storageLink,
42672
- imageDimension: this.imageDimension,
42690
+ itemType: "Audio",
42691
+ url: this.url,
42673
42692
  transformation: this.transformation.serialize(),
42674
- linkTo: this.linkTo.serialize()
42693
+ isStorageUrl: this.isStorageUrl,
42694
+ extension: this.extension
42675
42695
  };
42676
42696
  }
42677
- setCoordinates() {
42678
- this.left = this.transformation.matrix.translateX;
42679
- this.top = this.transformation.matrix.translateY;
42680
- this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
42681
- this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
42682
- this.subject.publish(this);
42683
- }
42684
- shootBeforeLoadCallbacks() {
42685
- while (this.beforeLoadCallbacks.length > 0) {
42686
- this.beforeLoadCallbacks.shift()(this);
42687
- }
42688
- }
42689
- shootLoadCallbacks() {
42690
- while (this.loadCallbacks.length > 0) {
42691
- this.loadCallbacks.shift()(this);
42692
- }
42693
- }
42694
42697
  deserialize(data) {
42698
+ if (data.isStorageUrl) {
42699
+ this.isStorageUrl = data.isStorageUrl;
42700
+ }
42695
42701
  if (data.transformation) {
42696
42702
  this.transformation.deserialize(data.transformation);
42697
42703
  }
42698
- this.linkTo.deserialize(data.linkTo);
42699
- this.image.onload = () => {
42700
- this.setCoordinates();
42701
- this.shootLoadCallbacks();
42702
- };
42703
- if (data.storageLink) {
42704
- this.setStorageLink(data.storageLink);
42704
+ if (data.url) {
42705
+ this.setUrl(data.url);
42705
42706
  }
42706
- if (this.image.src) {
42707
- return this;
42707
+ if (data.extension) {
42708
+ this.extension = data.extension;
42708
42709
  }
42709
- this.image = getPlaceholderImage(this.board, data.imageDimension);
42710
- const storageImage = new Image;
42711
- storageImage.onload = () => {
42712
- this.image = storageImage;
42713
- this.onLoad();
42714
- };
42715
- storageImage.onerror = this.onError;
42716
- storageImage.src = this.storageLink;
42717
42710
  return this;
42718
42711
  }
42719
- emit(operation) {
42720
- if (this.events) {
42721
- const command = new ImageCommand([this], operation);
42722
- command.apply();
42723
- this.events.emit(operation, command);
42724
- } else {
42725
- this.apply(operation);
42726
- }
42727
- }
42728
- setDimensions(dim) {
42729
- this.imageDimension = dim;
42730
- }
42731
42712
  apply(op) {
42732
42713
  switch (op.class) {
42733
42714
  case "Transformation":
@@ -42736,50 +42717,40 @@ class ImageItem extends BaseItem {
42736
42717
  case "LinkTo":
42737
42718
  this.linkTo.apply(op);
42738
42719
  break;
42739
- case "Image":
42740
- if (op.data.base64) {
42741
- this.image.src = op.data.base64;
42720
+ case "Audio":
42721
+ if (op.method === "setUrl") {
42722
+ this.applyUrl(op.url);
42742
42723
  }
42743
- this.setStorageLink(op.data.storageLink);
42744
- this.setDimensions(op.data.imageDimension);
42745
42724
  this.subject.publish(this);
42746
42725
  break;
42747
42726
  }
42748
42727
  }
42749
- render(context) {
42750
- if (this.transformationRenderBlock) {
42751
- return;
42728
+ emit(operation) {
42729
+ if (this.events) {
42730
+ const command = new AudioCommand([this], operation);
42731
+ command.apply();
42732
+ this.events.emit(operation, command);
42733
+ } else {
42734
+ this.apply(operation);
42752
42735
  }
42753
- const ctx = context.ctx;
42754
- ctx.save();
42755
- this.transformation.matrix.applyToContext(ctx);
42756
- ctx.drawImage(this.image, 0, 0);
42757
- ctx.restore();
42758
- if (this.getLinkTo()) {
42759
- const { top, right } = this.getMbr();
42760
- this.linkTo.render(context, top, right, this.board.camera.getScale());
42736
+ }
42737
+ setId(id) {
42738
+ this.id = id;
42739
+ this.transformation.setId(id);
42740
+ return this;
42741
+ }
42742
+ getId() {
42743
+ return this.id;
42744
+ }
42745
+ shootLoadCallbacks() {
42746
+ while (this.loadCallbacks.length > 0) {
42747
+ this.loadCallbacks.shift()(this);
42761
42748
  }
42762
42749
  }
42763
- renderHTML(documentFactory) {
42764
- const div = documentFactory.createElement("image-item");
42765
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42766
- const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42767
- div.style.backgroundImage = `url(${this.storageLink})`;
42768
- div.id = this.getId();
42769
- div.style.width = `${this.imageDimension.width}px`;
42770
- div.style.height = `${this.imageDimension.height}px`;
42771
- div.style.transformOrigin = "top left";
42772
- div.style.transform = transform;
42773
- div.style.position = "absolute";
42774
- div.style.backgroundSize = "cover";
42775
- div.setAttribute("data-link-to", this.linkTo.serialize() || "");
42776
- if (this.getLinkTo()) {
42777
- const linkElement = this.linkTo.renderHTML(documentFactory);
42778
- scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
42779
- translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
42780
- div.appendChild(linkElement);
42750
+ shootBeforeLoadCallbacks() {
42751
+ while (this.beforeLoadCallbacks.length > 0) {
42752
+ this.beforeLoadCallbacks.shift()(this);
42781
42753
  }
42782
- return div;
42783
42754
  }
42784
42755
  getPath() {
42785
42756
  const { left, top, right, bottom } = this.getMbr();
@@ -42812,15 +42783,78 @@ class ImageItem extends BaseItem {
42812
42783
  return null;
42813
42784
  }
42814
42785
  getLinkTo() {
42815
- return this.linkTo.link;
42786
+ return;
42787
+ }
42788
+ getExtension() {
42789
+ return this.extension;
42816
42790
  }
42817
42791
  download() {
42818
- const linkElem = document.createElement("a");
42819
- linkElem.href = this.storageLink;
42820
- linkElem.setAttribute("download", "");
42821
- linkElem.click();
42792
+ if (this.extension) {
42793
+ const linkElem = conf.documentFactory.createElement("a");
42794
+ linkElem.href = this.url;
42795
+ linkElem.setAttribute("download", `${this.board.getBoardId()}.${this.extension}`);
42796
+ linkElem.click();
42797
+ }
42798
+ }
42799
+ onRemove() {
42800
+ const storageId = this.getStorageId();
42801
+ if (storageId) {
42802
+ deleteMedia([storageId], this.board.getBoardId());
42803
+ }
42804
+ super.onRemove();
42822
42805
  }
42823
42806
  }
42807
+ // src/Items/Audio/AudioHelpers.ts
42808
+ var uploadAudioToStorage = async (hash, audioBlob, accessToken, boardId) => {
42809
+ return new Promise((resolve2, reject) => {
42810
+ fetch(`${window.location.origin}/api/v1/media/audio/${boardId}`, {
42811
+ method: "POST",
42812
+ headers: {
42813
+ "Content-Type": audioBlob.type,
42814
+ "x-audio-id": hash,
42815
+ Authorization: `Bearer ${accessToken}`
42816
+ },
42817
+ body: audioBlob
42818
+ }).then(async (response) => {
42819
+ if (response.status !== 200) {
42820
+ return catchErrorResponse(response, "audio");
42821
+ }
42822
+ return response.json();
42823
+ }).then((data) => {
42824
+ console.log(data);
42825
+ resolve2(data.src);
42826
+ }).catch((error) => {
42827
+ console.error("Media storage error:", error);
42828
+ reject(error);
42829
+ });
42830
+ });
42831
+ };
42832
+ var prepareAudio = (file, accessToken, boardId) => {
42833
+ return new Promise((resolve2, reject) => {
42834
+ const audio = document.createElement("audio");
42835
+ audio.src = URL.createObjectURL(file);
42836
+ audio.onloadedmetadata = () => {
42837
+ fileTosha256(file).then((hash) => {
42838
+ uploadAudioToStorage(hash, file, accessToken, boardId).then((url) => {
42839
+ resolve2(url);
42840
+ }).catch(reject);
42841
+ }).catch(() => {
42842
+ reject(new Error("Failed to generate hash"));
42843
+ });
42844
+ };
42845
+ audio.onerror = () => {
42846
+ reject(new Error("Failed to load audio"));
42847
+ };
42848
+ });
42849
+ };
42850
+ var calculateAudioPosition = (board, audioItem) => {
42851
+ const cameraMbr = board.camera.getMbr();
42852
+ const cameraWidth = cameraMbr.getWidth();
42853
+ const translateX = cameraMbr.left + cameraWidth * 0.34;
42854
+ const translateY = cameraMbr.getCenter().y - audioItem.getHeight() / 2;
42855
+ const scale = cameraWidth * 0.32 / audioItem.getWidth();
42856
+ return new Matrix2(translateX, translateY, scale, scale);
42857
+ };
42824
42858
  // src/isSafari.ts
42825
42859
  function isSafari() {
42826
42860
  if (typeof navigator === "undefined") {
@@ -54451,14 +54485,15 @@ class Board {
54451
54485
  }
54452
54486
  applyAddItems(op) {
54453
54487
  if (Array.isArray(op.item)) {
54488
+ const data = op.data;
54454
54489
  const items = op.item.map((item2) => {
54455
- const created = this.createItem(item2, op.data[item2]);
54490
+ const created = this.createItem(item2, data[item2]);
54456
54491
  this.index.insert(created);
54457
54492
  return created;
54458
54493
  });
54459
54494
  items.forEach((item2) => {
54460
- if (item2.itemType === "Connector" && op.data[item2.getId()]) {
54461
- const connectorData = op.data[item2.getId()];
54495
+ if (item2 instanceof Connector2 && data[item2.getId()]) {
54496
+ const connectorData = data[item2.getId()];
54462
54497
  item2.applyStartPoint(connectorData.startPoint);
54463
54498
  item2.applyEndPoint(connectorData.endPoint);
54464
54499
  }
@@ -54487,7 +54522,7 @@ class Board {
54487
54522
  this.findItemAndApply(op.item, (item) => {
54488
54523
  this.index.remove(item);
54489
54524
  this.selection.remove(item);
54490
- if (item.itemType === "Connector") {
54525
+ if (item instanceof Connector2) {
54491
54526
  item.clearObservedItems();
54492
54527
  }
54493
54528
  removedItems.push(item);
@@ -54495,7 +54530,7 @@ class Board {
54495
54530
  }
54496
54531
  applyRemoveLockedGroupOperation(op) {
54497
54532
  const item = this.index.getById(op.item[0]);
54498
- if (!item || item.itemType !== "Group") {
54533
+ if (!item || !(item instanceof Group)) {
54499
54534
  return;
54500
54535
  }
54501
54536
  item.getChildren().forEach((item2) => {
@@ -54511,9 +54546,11 @@ class Board {
54511
54546
  });
54512
54547
  }
54513
54548
  applyItemOperation(op) {
54514
- this.findItemAndApply(op.item, (item) => {
54515
- item.apply(op);
54516
- });
54549
+ if ("item" in op) {
54550
+ this.findItemAndApply(op.item, (item) => {
54551
+ item.apply(op);
54552
+ });
54553
+ }
54517
54554
  }
54518
54555
  findItemAndApply(item, apply) {
54519
54556
  if (Array.isArray(item)) {
@@ -54602,9 +54639,8 @@ class Board {
54602
54639
  if (withConnectors) {
54603
54640
  connectors = this.items.getLinkedConnectorsById(item.getId()).map((connector) => connector.getId());
54604
54641
  }
54605
- const shouldClearStorageUsage = item.itemType === "Image" || item.itemType === "Video" && item.getIsStorageUrl() || item.itemType === "Audio" && item.getIsStorageUrl();
54606
- if (shouldClearStorageUsage) {
54607
- deleteMedia([item.getStorageId()], this.boardId);
54642
+ if ("onRemove" in item) {
54643
+ item.onRemove();
54608
54644
  }
54609
54645
  this.emit({
54610
54646
  class: "Board",