@netless/forge-slide 1.2.0-beta.3 → 1.3.0-beta.1

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/slide.esm.js CHANGED
@@ -61103,6 +61103,8 @@ function me(e, t = {}) {
61103
61103
  function ae(e, t = {}) {
61104
61104
  return ce(me(e, t), t);
61105
61105
  }
61106
+ var elementsUndoOrigin = "elementsUndoOrigin";
61107
+ var backgroundElementsUndoOrigin = "backgroundElementsUndoOrigin";
61106
61108
  function _defineProperty(e, r, t) {
61107
61109
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e;
61108
61110
  }
@@ -61132,6 +61134,12 @@ var ElementModel = class _ElementModel {
61132
61134
  get type() {
61133
61135
  return this.root.get("type");
61134
61136
  }
61137
+ get role() {
61138
+ return this.root.get("role") ?? "normal";
61139
+ }
61140
+ get isBackground() {
61141
+ return this.role === "background";
61142
+ }
61135
61143
  get strokeWidth() {
61136
61144
  return this.root.get(_ElementModel.KEYS.strokeWidth);
61137
61145
  }
@@ -61190,6 +61198,9 @@ var ElementModel = class _ElementModel {
61190
61198
  get isPerformanceEnvironment() {
61191
61199
  return this.isPerformanceMode() && this.shouldUseLocalPoints;
61192
61200
  }
61201
+ isAttached() {
61202
+ return this.root.has(_ElementModel.KEYS.uuid);
61203
+ }
61193
61204
  constructor(root, scope, liveCursor, isPerformanceMode) {
61194
61205
  _defineProperty(this, "shadowEmitter", null);
61195
61206
  _defineProperty(this, "root", void 0);
@@ -61275,16 +61286,12 @@ var ElementModel = class _ElementModel {
61275
61286
  }
61276
61287
  }
61277
61288
  bindObserver() {
61278
- const beforeL = this.root._eH?.l?.length ?? -1;
61279
- const beforeDL = this.root._dEH?.l?.length ?? -1;
61280
61289
  removeDeepObserver(this.root, this.handlePropChange);
61281
61290
  this.subBindObserver();
61282
- const afterRemoveL = this.root._eH?.l?.length ?? -1;
61283
- const afterRemoveDL = this.root._dEH?.l?.length ?? -1;
61284
61291
  this.root.observeDeep(this.handlePropChange);
61285
- const afterAddL = this.root._eH?.l?.length ?? -1;
61286
- const afterAddDL = this.root._dEH?.l?.length ?? -1;
61287
- console.log(`[][][] bindObserver uuid=${this.uuid} doc=${!!this.root.doc} _eH: ${beforeL}->${afterRemoveL}->${afterAddL} _dEH: ${beforeDL}->${afterRemoveDL}->${afterAddDL}`);
61292
+ }
61293
+ mutationOrigin() {
61294
+ return elementsUndoOrigin;
61288
61295
  }
61289
61296
  subBindObserver() {
61290
61297
  }
@@ -61323,62 +61330,81 @@ var ElementModel = class _ElementModel {
61323
61330
  this.item.data.uuid = this.uuid;
61324
61331
  this.item.data.index = this.index;
61325
61332
  this.item.data.type = this.root.get("type");
61333
+ this.item.data.role = this.role;
61326
61334
  this.item.data.ownerId = this.ownerId;
61327
61335
  this.item.applyMatrix = false;
61328
61336
  }
61329
61337
  }
61330
61338
  appendPoints(points) {
61331
61339
  if (this.isPerformanceEnvironment) {
61332
- this.appendPointsPerformance(points);
61340
+ return this.appendPointsPerformance(points);
61333
61341
  } else {
61334
- this.appendPointsDirect(points);
61342
+ return this.appendPointsDirect(points);
61335
61343
  }
61336
61344
  }
61345
+ getPointsArray() {
61346
+ const yArray = this.root.get(_ElementModel.KEYS.points);
61347
+ return yArray instanceof Y.Array ? yArray : null;
61348
+ }
61337
61349
  appendPointsDirect(points) {
61338
- this.root.get(_ElementModel.KEYS.points).push(points);
61350
+ const yArray = this.getPointsArray();
61351
+ if (!yArray) {
61352
+ return false;
61353
+ }
61354
+ yArray.push(points);
61355
+ return true;
61339
61356
  }
61340
61357
  appendPointsPerformance(points) {
61358
+ const yArray = this.getPointsArray();
61359
+ if (!yArray) {
61360
+ return false;
61361
+ }
61341
61362
  this.localPoints = this.localPoints.concat(points);
61342
61363
  this.onVectorUpdate();
61343
61364
  if (this.appendPointsTimer) {
61344
61365
  window.clearTimeout(this.appendPointsTimer);
61345
61366
  }
61346
61367
  if (this.localPoints.length % 80 === 0) {
61347
- const yArray = this.root.get(_ElementModel.KEYS.points);
61348
61368
  yArray?.push(this.localPoints.slice(yArray.length));
61349
61369
  }
61350
61370
  this.appendPointsTimer = window.setTimeout(() => {
61351
61371
  this.appendPointsTimer = null;
61352
61372
  if (this.localPoints.length > 0) {
61353
- const yArray = this.root.get(_ElementModel.KEYS.points);
61354
- yArray?.push(this.localPoints.slice(yArray.length));
61373
+ const nextArray = this.getPointsArray();
61374
+ nextArray?.push(this.localPoints.slice(nextArray.length));
61355
61375
  }
61356
61376
  }, 100);
61377
+ return true;
61357
61378
  }
61358
61379
  setPoints(points) {
61359
61380
  if (this.isPerformanceEnvironment) {
61360
- this.setPointsPerformance(points);
61381
+ return this.setPointsPerformance(points);
61361
61382
  } else {
61362
- this.setPointsDirect(points);
61383
+ return this.setPointsDirect(points);
61363
61384
  }
61364
61385
  }
61365
61386
  setPointsDirect(points) {
61366
61387
  if (this.root.doc) {
61388
+ const yArray = this.getPointsArray();
61389
+ if (!yArray) {
61390
+ return false;
61391
+ }
61367
61392
  this.root.doc.transact(() => {
61368
- const yArray = this.root.get(_ElementModel.KEYS.points);
61369
- if (yArray) {
61370
- yArray.delete(0, yArray.length);
61371
- yArray.push(points);
61372
- }
61373
- });
61393
+ yArray.delete(0, yArray.length);
61394
+ yArray.push(points);
61395
+ }, this.mutationOrigin());
61374
61396
  } else {
61375
- const yArray = this.root.get(_ElementModel.KEYS.points) || new Y.Array();
61397
+ const yArray = this.getPointsArray() || new Y.Array();
61376
61398
  yArray.delete(0, yArray.length);
61377
61399
  yArray.push(points);
61378
61400
  this.root.set(_ElementModel.KEYS.points, yArray);
61379
61401
  }
61402
+ return true;
61380
61403
  }
61381
61404
  setPointsPerformance(points) {
61405
+ if (this.root.doc && !this.getPointsArray()) {
61406
+ return false;
61407
+ }
61382
61408
  this.localPoints = points;
61383
61409
  this.onVectorUpdate();
61384
61410
  if (this.setPointsTimer) {
@@ -61386,25 +61412,33 @@ var ElementModel = class _ElementModel {
61386
61412
  }
61387
61413
  this.setPointsTimer = window.setTimeout(() => {
61388
61414
  if (this.root.doc) {
61415
+ const yArray = this.getPointsArray();
61416
+ if (!yArray) {
61417
+ return;
61418
+ }
61389
61419
  this.root.doc.transact(() => {
61390
- const yArray = this.root.get(_ElementModel.KEYS.points);
61391
- if (yArray) {
61392
- yArray.delete(0, yArray.length);
61393
- yArray.push(points);
61394
- }
61395
- });
61420
+ yArray.delete(0, yArray.length);
61421
+ yArray.push(points);
61422
+ }, this.mutationOrigin());
61396
61423
  } else {
61397
- const yArray = this.root.get(_ElementModel.KEYS.points) || new Y.Array();
61424
+ const yArray = this.getPointsArray() || new Y.Array();
61398
61425
  yArray.delete(0, yArray.length);
61399
61426
  yArray.push(points);
61400
61427
  this.root.set(_ElementModel.KEYS.points, yArray);
61401
61428
  }
61402
61429
  }, 100);
61430
+ return true;
61403
61431
  }
61404
61432
  appendPointsMatrix(matrix) {
61405
61433
  const current = new this.scope.Matrix(this.pointsMatrix);
61406
61434
  const next = matrix.appended(current);
61407
- this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61435
+ if (this.root.doc) {
61436
+ this.root.doc.transact(() => {
61437
+ this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61438
+ }, this.mutationOrigin());
61439
+ } else {
61440
+ this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61441
+ }
61408
61442
  }
61409
61443
  rotateByOffset(angle, centerX, centerY) {
61410
61444
  const current = new this.scope.Matrix(this.pointsMatrix);
@@ -61418,7 +61452,13 @@ var ElementModel = class _ElementModel {
61418
61452
  matrix2.rotate(delta, centerX, centerY);
61419
61453
  next = matrix2.appended(next);
61420
61454
  }
61421
- this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61455
+ if (this.root.doc) {
61456
+ this.root.doc.transact(() => {
61457
+ this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61458
+ }, this.mutationOrigin());
61459
+ } else {
61460
+ this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61461
+ }
61422
61462
  return next.rotation;
61423
61463
  }
61424
61464
  getStyleKeys() {
@@ -61429,7 +61469,6 @@ var ElementModel = class _ElementModel {
61429
61469
  this.subDispose();
61430
61470
  }
61431
61471
  disposeObserver() {
61432
- console.log(`[][][] disposeObserver uuid=${this.uuid}`);
61433
61472
  removeDeepObserver(this.root, this.handlePropChange);
61434
61473
  }
61435
61474
  };
@@ -61468,6 +61507,7 @@ var EditorConfig = class _EditorConfig {
61468
61507
  constructor() {
61469
61508
  _defineProperty2(this, "resizeModel", () => "eight");
61470
61509
  _defineProperty2(this, "uniformScale", () => false);
61510
+ _defineProperty2(this, "translatable", () => true);
61471
61511
  _defineProperty2(this, "controlPoints", []);
61472
61512
  }
61473
61513
  merge(other) {
@@ -61476,6 +61516,7 @@ var EditorConfig = class _EditorConfig {
61476
61516
  const j = RESIZE_MODEL_LEVEL.findIndex((v) => v === other.resizeModel());
61477
61517
  next.resizeModel = () => RESIZE_MODEL_LEVEL[Math.max(i, j)];
61478
61518
  next.uniformScale = this.uniformScale || other.uniformScale;
61519
+ next.translatable = () => this.translatable() && other.translatable();
61479
61520
  next.controlPoints = [];
61480
61521
  return next;
61481
61522
  }
@@ -61926,7 +61967,14 @@ var WhiteboardTool = class {
61926
61967
  }
61927
61968
  this.pendingDragEvent = null;
61928
61969
  this.shadowEmitter.setActive(true);
61929
- this.onMouseDown(event);
61970
+ try {
61971
+ this.onMouseDown(event);
61972
+ } catch (error) {
61973
+ this.cancelCurrentAction();
61974
+ this.eventAvailable = false;
61975
+ this.shadowEmitter.setActive(false);
61976
+ throw error;
61977
+ }
61930
61978
  });
61931
61979
  _defineProperty7(this, "flushPendingDrag", () => {
61932
61980
  this.dragRafId = 0;
@@ -61934,7 +61982,14 @@ var WhiteboardTool = class {
61934
61982
  this.lastDragTime = performance.now();
61935
61983
  const event = this.pendingDragEvent;
61936
61984
  this.pendingDragEvent = null;
61937
- this.onMouseDrag(event);
61985
+ try {
61986
+ this.onMouseDrag(event);
61987
+ } catch (error) {
61988
+ this.cancelCurrentAction();
61989
+ this.eventAvailable = false;
61990
+ this.shadowEmitter.setActive(false);
61991
+ throw error;
61992
+ }
61938
61993
  }
61939
61994
  });
61940
61995
  _defineProperty7(this, "onMouseDragSelf", (event) => {
@@ -61945,7 +62000,14 @@ var WhiteboardTool = class {
61945
62000
  if (now - this.lastDragTime >= DRAG_FRAME_MS) {
61946
62001
  this.lastDragTime = now;
61947
62002
  this.pendingDragEvent = null;
61948
- this.onMouseDrag(event);
62003
+ try {
62004
+ this.onMouseDrag(event);
62005
+ } catch (error) {
62006
+ this.cancelCurrentAction();
62007
+ this.eventAvailable = false;
62008
+ this.shadowEmitter.setActive(false);
62009
+ throw error;
62010
+ }
61949
62011
  } else {
61950
62012
  this.pendingDragEvent = event;
61951
62013
  if (!this.dragRafId) {
@@ -61962,11 +62024,26 @@ var WhiteboardTool = class {
61962
62024
  this.dragRafId = 0;
61963
62025
  }
61964
62026
  if (this.pendingDragEvent) {
61965
- this.onMouseDrag(this.pendingDragEvent);
61966
- this.pendingDragEvent = null;
62027
+ try {
62028
+ this.onMouseDrag(this.pendingDragEvent);
62029
+ this.pendingDragEvent = null;
62030
+ } catch (error) {
62031
+ this.pendingDragEvent = null;
62032
+ this.cancelCurrentAction();
62033
+ this.eventAvailable = false;
62034
+ this.shadowEmitter.setActive(false);
62035
+ throw error;
62036
+ }
62037
+ }
62038
+ try {
62039
+ this.onMouseUp(event);
62040
+ } catch (error) {
62041
+ this.cancelCurrentAction();
62042
+ this.eventAvailable = false;
62043
+ throw error;
62044
+ } finally {
62045
+ this.shadowEmitter.setActive(false);
61967
62046
  }
61968
- this.onMouseUp(event);
61969
- this.shadowEmitter.setActive(false);
61970
62047
  });
61971
62048
  this.modelGetter = modelGetter;
61972
62049
  this.enableToolEvent = enableToolEvent;
@@ -61977,6 +62054,8 @@ var WhiteboardTool = class {
61977
62054
  this.tool.onMouseDrag = this.onMouseDragSelf;
61978
62055
  this.tool.onMouseUp = this.onMouseUpSelf;
61979
62056
  }
62057
+ cancelCurrentAction() {
62058
+ }
61980
62059
  };
61981
62060
  var import_lodash3 = __toESM2(require_lodash(), 1);
61982
62061
  function _defineProperty8(e, r, t) {
@@ -62349,7 +62428,6 @@ var PointTextModel = class extends ElementModel {
62349
62428
  if (!this.item) {
62350
62429
  return null;
62351
62430
  }
62352
- console.log("[][][] drawPoints", this.drawPoints);
62353
62431
  const bounds = this.item.internalBounds;
62354
62432
  const matrix = new this.scope.Matrix(this.pointsMatrix);
62355
62433
  const topLeft = new this.scope.Point(this.drawPoints[0], this.drawPoints[1]).transform(matrix);
@@ -62713,7 +62791,6 @@ var RectangleModel = class extends ElementModel {
62713
62791
  onStyleKeyUpdate(_key) {
62714
62792
  }
62715
62793
  };
62716
- var elementsUndoOrigin = "elementsUndoOrigin";
62717
62794
  var import_lodash5 = __toESM2(require_lodash(), 1);
62718
62795
  function _defineProperty13(e, r, t) {
62719
62796
  return (r = _toPropertyKey13(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e;
@@ -62988,7 +63065,6 @@ var LaserPointerModel = class extends ElementModel {
62988
63065
  matrixedPoints() {
62989
63066
  const matrix = new this.scope.Matrix(this.pointsMatrix);
62990
63067
  const points = this.cachedPoints || this.points;
62991
- console.log("[][][] ,", this.points.length, this.cachedPoints?.length, this.localPoints.length);
62992
63068
  const groupPoints = (0, import_lodash6.chunk)(points, 2).slice(this.sliceBegin);
62993
63069
  return groupPoints.map((_ref) => {
62994
63070
  let [x, y] = _ref;
@@ -63250,6 +63326,7 @@ var ImageModel = class extends ElementModel {
63250
63326
  this.item = new this.scope.Raster(this.uuid);
63251
63327
  const matrix = new this.scope.Matrix(this.pointsMatrix);
63252
63328
  this.item.matrix = matrix;
63329
+ this.item.data.role = this.role;
63253
63330
  }
63254
63331
  onVectorUpdate() {
63255
63332
  const matrix = new this.scope.Matrix(this.pointsMatrix);
@@ -63278,8 +63355,12 @@ var ImageModel = class extends ElementModel {
63278
63355
  const cfg = new EditorConfig();
63279
63356
  cfg.resizeModel = () => "four-corner";
63280
63357
  cfg.uniformScale = () => true;
63358
+ cfg.translatable = () => !this.isBackground;
63281
63359
  return cfg;
63282
63360
  }
63361
+ mutationOrigin() {
63362
+ return this.isBackground ? backgroundElementsUndoOrigin : elementsUndoOrigin;
63363
+ }
63283
63364
  liveCursorPoint() {
63284
63365
  return null;
63285
63366
  }
@@ -63360,6 +63441,7 @@ var RenderableModel = class extends EventEmitter {
63360
63441
  flushRenderables() {
63361
63442
  this.emit("elementClear");
63362
63443
  const elements = Array.from(this.elements.values()).map((v) => this.convertToModel(v)).filter((v) => !!v);
63444
+ elements.sort((a2, b2) => this.compareElements(a2, b2));
63363
63445
  this.maxIndex = elements.reduce((r, n) => Math.max(r, n.index), -1);
63364
63446
  const clearIds = [];
63365
63447
  elements.forEach((model) => {
@@ -63421,7 +63503,32 @@ var RenderableModel = class extends EventEmitter {
63421
63503
  initElement(element) {
63422
63504
  element.shadowEmitter = this.shadowEmitter;
63423
63505
  }
63506
+ compareElementRole(roleA, roleB) {
63507
+ const a2 = roleA === "background" ? 0 : 1;
63508
+ const b2 = roleB === "background" ? 0 : 1;
63509
+ return a2 - b2;
63510
+ }
63511
+ compareElements(a2, b2) {
63512
+ const roleCompare = this.compareElementRole(a2.role, b2.role);
63513
+ if (roleCompare !== 0) {
63514
+ return roleCompare;
63515
+ }
63516
+ if (a2.index !== b2.index) {
63517
+ return a2.index - b2.index;
63518
+ }
63519
+ return a2.uuid.localeCompare(b2.uuid);
63520
+ }
63521
+ isBackgroundElement(uuid) {
63522
+ const element = this.elements.get(uuid);
63523
+ if (!element) {
63524
+ return false;
63525
+ }
63526
+ return (element.get("role") ?? "normal") === "background";
63527
+ }
63424
63528
  removeElementItem(uuid) {
63529
+ if (this.isBackgroundElement(uuid)) {
63530
+ return;
63531
+ }
63425
63532
  this.elements.delete(uuid);
63426
63533
  }
63427
63534
  confirmPermission() {
@@ -63432,15 +63539,21 @@ var RenderableModel = class extends EventEmitter {
63432
63539
  return hasPermission;
63433
63540
  }
63434
63541
  createImage(src) {
63542
+ let fit = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "legacy";
63543
+ let role = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "normal";
63435
63544
  if (!this.confirmPermission()) {
63436
63545
  return;
63437
63546
  }
63547
+ if (role === "background") {
63548
+ return this.upsertBackgroundImage(src, fit);
63549
+ }
63438
63550
  const yMap = new Y12.Map();
63439
63551
  this.elements.doc?.transact(() => {
63440
63552
  const uuid = this.uuid;
63441
63553
  yMap.set(ElementModel.KEYS.index, ++this.maxIndex);
63442
63554
  yMap.set(ElementModel.KEYS.uuid, uuid);
63443
63555
  yMap.set("type", "image");
63556
+ yMap.set("role", role);
63444
63557
  yMap.set(ElementModel.KEYS.ownerId, this.userManager.selfId);
63445
63558
  this.elements.set(uuid, yMap);
63446
63559
  }, elementsUndoOrigin);
@@ -63448,9 +63561,47 @@ var RenderableModel = class extends EventEmitter {
63448
63561
  model.bindObserver();
63449
63562
  model.root.set("src", src);
63450
63563
  model.ownerId = this.userManager.selfId;
63451
- this.fitImageToViewport(src, model);
63564
+ this.fitImageToViewport(src, model, fit);
63452
63565
  }
63453
- fitImageToViewport(src, model) {
63566
+ upsertBackgroundImage(src, fit) {
63567
+ const backgroundEntries = Array.from(this.elements.entries()).filter((_ref) => {
63568
+ let [, elementMap] = _ref;
63569
+ return elementMap.get("type") === "image" && (elementMap.get("role") ?? "normal") === "background";
63570
+ });
63571
+ let targetMap = backgroundEntries[0]?.[1] ?? null;
63572
+ if (this.elements.doc) {
63573
+ this.elements.doc.transact(() => {
63574
+ backgroundEntries.slice(1).forEach((_ref2) => {
63575
+ let [key] = _ref2;
63576
+ return this.elements.delete(key);
63577
+ });
63578
+ if (!targetMap) {
63579
+ targetMap = new Y12.Map();
63580
+ const uuid = this.uuid;
63581
+ targetMap.set(ElementModel.KEYS.index, -1);
63582
+ targetMap.set(ElementModel.KEYS.uuid, uuid);
63583
+ targetMap.set("type", "image");
63584
+ targetMap.set("role", "background");
63585
+ targetMap.set(ElementModel.KEYS.ownerId, this.userManager.selfId);
63586
+ this.elements.set(uuid, targetMap);
63587
+ } else {
63588
+ targetMap.set("role", "background");
63589
+ targetMap.set(ElementModel.KEYS.ownerId, this.userManager.selfId);
63590
+ }
63591
+ }, backgroundElementsUndoOrigin);
63592
+ }
63593
+ if (!targetMap) {
63594
+ return;
63595
+ }
63596
+ const model = this.convertToModel(targetMap);
63597
+ if (!model || !(model instanceof ImageModel)) {
63598
+ return;
63599
+ }
63600
+ model.root.set("src", src);
63601
+ model.ownerId = this.userManager.selfId;
63602
+ this.fitImageToViewport(src, model, fit);
63603
+ }
63604
+ fitImageToViewport(src, model, fit) {
63454
63605
  const center = this.scope.project.view.center;
63455
63606
  const fallbackMatrix = new this.scope.Matrix();
63456
63607
  fallbackMatrix.translate({
@@ -63467,9 +63618,9 @@ var RenderableModel = class extends EventEmitter {
63467
63618
  return;
63468
63619
  }
63469
63620
  const viewportBounds = this.scope.project.view.bounds;
63470
- const maxWidth = viewportBounds.width * 2 / 3;
63471
- const maxHeight = viewportBounds.height * 2 / 3;
63472
- const fitScale = Math.min(maxWidth / naturalWidth, maxHeight / naturalHeight, 1);
63621
+ const maxWidth = fit === "contain" ? viewportBounds.width : viewportBounds.width * 2 / 3;
63622
+ const maxHeight = fit === "contain" ? viewportBounds.height : viewportBounds.height * 2 / 3;
63623
+ const fitScale = fit === "contain" ? Math.min(maxWidth / naturalWidth, maxHeight / naturalHeight) : Math.min(maxWidth / naturalWidth, maxHeight / naturalHeight, 1);
63473
63624
  const nextMatrix = new this.scope.Matrix();
63474
63625
  nextMatrix.translate({
63475
63626
  x: center.x,
@@ -63492,7 +63643,7 @@ var RenderableModel = class extends EventEmitter {
63492
63643
  if (model.root.doc) {
63493
63644
  model.root.doc.transact(() => {
63494
63645
  model.root.set(ElementModel.KEYS.pointsMatrix, values);
63495
- }, elementsUndoOrigin);
63646
+ }, model.isBackground ? backgroundElementsUndoOrigin : elementsUndoOrigin);
63496
63647
  } else {
63497
63648
  model.root.set(ElementModel.KEYS.pointsMatrix, values);
63498
63649
  }
@@ -64082,22 +64233,33 @@ var CurveTool = class extends WhiteboardTool {
64082
64233
  _defineProperty19(this, "flushPendingPoints", () => {
64083
64234
  this.flushRafId = 0;
64084
64235
  if (this.elementModel && this.pendingPoints.length > 0) {
64085
- this.elementModel.appendPoints(this.pendingPoints);
64236
+ const appended = this.elementModel.appendPoints(this.pendingPoints);
64237
+ if (!appended) {
64238
+ this.resetStrokeState();
64239
+ return;
64240
+ }
64086
64241
  this.pendingPoints = [];
64087
64242
  }
64088
64243
  });
64089
64244
  }
64090
- onMouseDown(_event) {
64245
+ resetStrokeState() {
64091
64246
  this.pointCount = 0;
64092
64247
  this.pendingPoints = [];
64093
64248
  if (this.flushRafId) {
64094
64249
  cancelAnimationFrame(this.flushRafId);
64095
64250
  this.flushRafId = 0;
64096
64251
  }
64097
- if (this.elementModel) {
64098
- this.elementModel.dispose();
64099
- }
64100
64252
  this.elementModel = null;
64253
+ }
64254
+ cancelCurrentAction() {
64255
+ this.resetStrokeState();
64256
+ }
64257
+ onMouseDown(_event) {
64258
+ const previousElement = this.elementModel;
64259
+ this.resetStrokeState();
64260
+ if (previousElement) {
64261
+ previousElement.dispose();
64262
+ }
64101
64263
  this.modelGetter().then((model) => {
64102
64264
  if (model) {
64103
64265
  this.elementModel = model.createCurve(true);
@@ -64110,6 +64272,10 @@ var CurveTool = class extends WhiteboardTool {
64110
64272
  }
64111
64273
  const MIN_DISTANCE = 2;
64112
64274
  if (this.elementModel) {
64275
+ if (!this.elementModel.isAttached()) {
64276
+ this.resetStrokeState();
64277
+ return;
64278
+ }
64113
64279
  let lastX = 0;
64114
64280
  let lastY = 0;
64115
64281
  if (this.pendingPoints.length >= 2) {
@@ -64138,22 +64304,27 @@ var CurveTool = class extends WhiteboardTool {
64138
64304
  this.flushRafId = 0;
64139
64305
  }
64140
64306
  this.flushPendingPoints();
64307
+ if (!this.elementModel || !this.elementModel.isAttached()) {
64308
+ this.resetStrokeState();
64309
+ return;
64310
+ }
64311
+ const currentElement = this.elementModel;
64312
+ const currentUuid = currentElement.uuid;
64313
+ const currentPointCount = this.pointCount;
64141
64314
  this.modelGetter().then((model) => {
64142
64315
  if (!model) {
64143
64316
  return;
64144
64317
  }
64145
- if (this.pointCount < 3 && this.elementModel) {
64146
- if (this.elementModel) {
64147
- model.removeElementItem(this.elementModel.uuid);
64148
- }
64318
+ if (currentPointCount < 3) {
64319
+ model.removeElementItem(currentUuid);
64149
64320
  }
64150
- if (this.elementModel) {
64151
- this.elementModel.shadow = "";
64321
+ if (currentElement.isAttached()) {
64322
+ currentElement.shadow = "";
64152
64323
  }
64153
- if (this.elementModel && event.event.metaKey) {
64154
- const result = this.recognizer.recognize(this.elementModel.points);
64324
+ if (currentElement.isAttached() && event.event.metaKey) {
64325
+ const result = this.recognizer.recognize(currentElement.points);
64155
64326
  if (result) {
64156
- model.removeElementItem(this.elementModel.uuid);
64327
+ model.removeElementItem(currentUuid);
64157
64328
  if (/^rectangle/.test(result.shape)) {
64158
64329
  const rect = model.createRectangle(false);
64159
64330
  rect?.setPoints([result.minX, result.minY, result.maxX, result.maxY]);
@@ -64172,6 +64343,9 @@ var CurveTool = class extends WhiteboardTool {
64172
64343
  }
64173
64344
  }
64174
64345
  }
64346
+ if (this.elementModel === currentElement) {
64347
+ this.resetStrokeState();
64348
+ }
64175
64349
  });
64176
64350
  }
64177
64351
  };
@@ -64361,6 +64535,9 @@ var SelectorTool = class extends WhiteboardTool {
64361
64535
  _defineProperty22(this, "showLiveCursor", false);
64362
64536
  this.selectElementsModel = selectElementsModel;
64363
64537
  }
64538
+ isSelectableItem(item) {
64539
+ return !!item.data.type && ["selector", "eraser", "laser"].indexOf(item.data.type) < 0 && item.data.role !== "background";
64540
+ }
64364
64541
  onMouseDown(event) {
64365
64542
  this.from = null;
64366
64543
  this.to = null;
@@ -64386,7 +64563,7 @@ var SelectorTool = class extends WhiteboardTool {
64386
64563
  this.elementModel.setPoints([rect.topLeft.x, rect.topLeft.y, rect.size.width, rect.size.height]);
64387
64564
  this.selectElementsModel.clearSelectElementForSelf();
64388
64565
  this.scope.project.activeLayer.children.forEach((item) => {
64389
- if (item.data.type && ["selector", "eraser", "laser"].indexOf(item.data.type) < 0) {
64566
+ if (this.isSelectableItem(item)) {
64390
64567
  if (rect.contains(item.bounds)) {
64391
64568
  this.selectElements.set(item.data.uuid, item.data.ownerId);
64392
64569
  } else {
@@ -64412,7 +64589,7 @@ var SelectorTool = class extends WhiteboardTool {
64412
64589
  return result;
64413
64590
  }, []);
64414
64591
  const hitResult = this.scope.project.hitTest(event.point);
64415
- if (hitResult && hitResult.item.data.uuid) {
64592
+ if (hitResult && hitResult.item.data.uuid && this.isSelectableItem(hitResult.item)) {
64416
64593
  elements.push({
64417
64594
  elementId: hitResult.item.data.uuid,
64418
64595
  ownerId: hitResult.item.data.ownerId
@@ -64939,7 +65116,7 @@ var Editor = class extends EventEmitter5 {
64939
65116
  };
64940
65117
  this.rootView.style.opacity = "0";
64941
65118
  }
64942
- if (target === this.frame) {
65119
+ if (target === this.frame && this.editorConfig?.translatable()) {
64943
65120
  evt.preventDefault();
64944
65121
  this.editMode = "translate";
64945
65122
  this.lastEditPoint = {
@@ -65244,7 +65421,6 @@ var Editor = class extends EventEmitter5 {
65244
65421
  this.shadowContainer.remove();
65245
65422
  this.shadowScope.project.activeLayer.addChild(this.shadowContainer);
65246
65423
  this.targets.forEach((model) => {
65247
- console.log("[][][] translateShadow model", model.root._dEH);
65248
65424
  model.shadow = this.shadowContainer.data.uuid;
65249
65425
  });
65250
65426
  }
@@ -66105,6 +66281,9 @@ var EraserTool = class extends WhiteboardTool {
66105
66281
  this.elementModel.appendPoints([event.point.x, event.point.y]);
66106
66282
  }
66107
66283
  this.scope.project.activeLayer.children.forEach((item) => {
66284
+ if (item.data.role === "background") {
66285
+ return;
66286
+ }
66108
66287
  if (item.data.type && ["selector", "eraser", "laser"].indexOf(item.data.type) < 0 && item.hitTest(event.point, {
66109
66288
  segments: true,
66110
66289
  stroke: true,
@@ -66115,6 +66294,9 @@ var EraserTool = class extends WhiteboardTool {
66115
66294
  }
66116
66295
  });
66117
66296
  this.shadowScope.project.activeLayer.children.forEach((item) => {
66297
+ if (item.data.role === "background") {
66298
+ return;
66299
+ }
66118
66300
  if (item.data.type && ["selector", "eraser", "laser"].indexOf(item.data.type) < 0 && item.hitTest(event.point, {
66119
66301
  segments: true,
66120
66302
  stroke: true,
@@ -66556,16 +66738,7 @@ var IndexedNavigation = class extends EventEmitter11 {
66556
66738
  return this.pageModel.pageList().filter((id) => /^_i_/.test(id));
66557
66739
  }
66558
66740
  get head() {
66559
- const headId = Object.keys(this.list).find((key) => {
66560
- return this.list[key] && this.list[key].prev === "";
66561
- });
66562
- if (!headId) {
66563
- log3("indexed navigation confusion", {
66564
- list: JSON.stringify(this.list)
66565
- }, "error");
66566
- throw new Error("indexed navigation confusion");
66567
- }
66568
- return headId;
66741
+ return this.ensureValidList().head;
66569
66742
  }
66570
66743
  get lastNodeId() {
66571
66744
  let currentId = this.head;
@@ -66585,7 +66758,8 @@ var IndexedNavigation = class extends EventEmitter11 {
66585
66758
  _defineProperty36(this, "list", {});
66586
66759
  _defineProperty36(this, "hasPermission", void 0);
66587
66760
  _defineProperty36(this, "handleIndexedPageMapUpdate", (_evt) => {
66588
- this.list = this.indexedPageMap.get("list");
66761
+ this.list = this.normalizeList(this.indexedPageMap.get("list")) ?? {};
66762
+ this.ensureValidList("update");
66589
66763
  const needRemoveList = this.pageModel.pageList().filter((v) => /^_i_/.test(v) && Object.keys(this.list).indexOf(v) < 0);
66590
66764
  const needAddList = Object.keys(this.list).filter((v) => this.pageModel.pageList().indexOf(v) < 0);
66591
66765
  this.indexedPageMap.doc.transact(() => {
@@ -66618,11 +66792,156 @@ var IndexedNavigation = class extends EventEmitter11 {
66618
66792
  this.indexedPageMap.set("list", this.list);
66619
66793
  this.idPool.add("_i_");
66620
66794
  } else {
66621
- this.list = this.indexedPageMap.get("list");
66795
+ this.list = this.normalizeList(this.indexedPageMap.get("list")) ?? {};
66622
66796
  Object.keys(this.list).forEach((id) => this.idPool.add(id));
66797
+ this.ensureValidList("constructor");
66623
66798
  }
66624
66799
  this.indexedPageMap.observe(this.handleIndexedPageMapUpdate);
66625
66800
  }
66801
+ normalizeList(list) {
66802
+ if (!list || typeof list !== "object" || Array.isArray(list)) {
66803
+ return null;
66804
+ }
66805
+ const nextList = {};
66806
+ for (const [id, node] of Object.entries(list)) {
66807
+ if (!/^_i_/.test(id) || !node || typeof node !== "object") {
66808
+ return null;
66809
+ }
66810
+ const {
66811
+ prev,
66812
+ next
66813
+ } = node;
66814
+ if (typeof prev !== "string" || typeof next !== "string") {
66815
+ return null;
66816
+ }
66817
+ nextList[id] = {
66818
+ prev,
66819
+ next
66820
+ };
66821
+ }
66822
+ return nextList;
66823
+ }
66824
+ validateList(list) {
66825
+ const ids = Object.keys(list);
66826
+ if (ids.length === 0) {
66827
+ return {
66828
+ valid: false,
66829
+ reason: "empty list"
66830
+ };
66831
+ }
66832
+ const heads = ids.filter((id) => list[id].prev === "");
66833
+ if (heads.length !== 1) {
66834
+ return {
66835
+ valid: false,
66836
+ reason: `expected one head, got ${heads.length}`
66837
+ };
66838
+ }
66839
+ for (const id of ids) {
66840
+ const node = list[id];
66841
+ if (node.prev && !list[node.prev]) {
66842
+ return {
66843
+ valid: false,
66844
+ reason: `missing prev node ${node.prev}`
66845
+ };
66846
+ }
66847
+ if (node.next && !list[node.next]) {
66848
+ return {
66849
+ valid: false,
66850
+ reason: `missing next node ${node.next}`
66851
+ };
66852
+ }
66853
+ if (node.prev && list[node.prev].next !== id) {
66854
+ return {
66855
+ valid: false,
66856
+ reason: `prev link mismatch for ${id}`
66857
+ };
66858
+ }
66859
+ if (node.next && list[node.next].prev !== id) {
66860
+ return {
66861
+ valid: false,
66862
+ reason: `next link mismatch for ${id}`
66863
+ };
66864
+ }
66865
+ }
66866
+ const visited = /* @__PURE__ */ new Set();
66867
+ let currentId = heads[0];
66868
+ while (currentId) {
66869
+ if (visited.has(currentId)) {
66870
+ return {
66871
+ valid: false,
66872
+ reason: `cycle at ${currentId}`
66873
+ };
66874
+ }
66875
+ visited.add(currentId);
66876
+ currentId = list[currentId].next;
66877
+ }
66878
+ if (visited.size !== ids.length) {
66879
+ return {
66880
+ valid: false,
66881
+ reason: "detached nodes"
66882
+ };
66883
+ }
66884
+ return {
66885
+ valid: true,
66886
+ head: heads[0]
66887
+ };
66888
+ }
66889
+ createList(ids) {
66890
+ return ids.reduce((list, id, index) => {
66891
+ list[id] = {
66892
+ prev: ids[index - 1] ?? "",
66893
+ next: ids[index + 1] ?? ""
66894
+ };
66895
+ return list;
66896
+ }, {});
66897
+ }
66898
+ repairList(reason) {
66899
+ const pageIds = this.idList;
66900
+ const ids = pageIds.length > 0 ? pageIds : Object.keys(this.list).filter((id) => /^_i_/.test(id));
66901
+ const nextIds = ids.length > 0 ? ids : ["_i_"];
66902
+ const nextList = this.createList(nextIds);
66903
+ log3("indexed navigation recovered", {
66904
+ reason,
66905
+ pageList: JSON.stringify(this.pageModel.pageList()),
66906
+ list: JSON.stringify(this.list),
66907
+ nextList: JSON.stringify(nextList)
66908
+ }, "warn");
66909
+ const apply = () => {
66910
+ for (const id of nextIds) {
66911
+ if (this.pageModel.pageList().indexOf(id) < 0) {
66912
+ this.pageModel.addPage(id);
66913
+ }
66914
+ }
66915
+ this.list = nextList;
66916
+ this.indexedPageMap.set("list", nextList);
66917
+ };
66918
+ if (this.indexedPageMap.doc) {
66919
+ this.indexedPageMap.doc.transact(apply);
66920
+ } else {
66921
+ apply();
66922
+ }
66923
+ nextIds.forEach((id) => this.idPool.add(id));
66924
+ return nextIds[0];
66925
+ }
66926
+ ensureValidList() {
66927
+ let context = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "read";
66928
+ const normalized = this.normalizeList(this.list);
66929
+ if (!normalized) {
66930
+ return {
66931
+ head: this.repairList(`${context}: invalid list`)
66932
+ };
66933
+ }
66934
+ this.list = normalized;
66935
+ const validation = this.validateList(this.list);
66936
+ if (!validation.valid) {
66937
+ return {
66938
+ head: this.repairList(`${context}: ${validation.reason}`)
66939
+ };
66940
+ }
66941
+ return {
66942
+ head: validation.head
66943
+ };
66944
+ }
66626
66945
  getNextId() {
66627
66946
  const cache = Array.from(this.idPool).filter((id) => this.idList.indexOf(id) < 0);
66628
66947
  if (cache.length > 0) {
@@ -67554,7 +67873,6 @@ var WhiteboardApplication = class _WhiteboardApplication extends AbstractApplica
67554
67873
  this.emitter.emit("elementDeselected", userId);
67555
67874
  return;
67556
67875
  }
67557
- editor.show();
67558
67876
  const targetLayerId = this.userMap(userId).get(WhiteboardKeys.currentPage);
67559
67877
  const selfLayerId = this.userMap(this.userId).get(WhiteboardKeys.currentPage);
67560
67878
  if (targetLayerId !== selfLayerId || !this.layers.has(targetLayerId)) {
@@ -67562,7 +67880,13 @@ var WhiteboardApplication = class _WhiteboardApplication extends AbstractApplica
67562
67880
  }
67563
67881
  const elementModels = elements.map((id) => {
67564
67882
  return this.layers.get(targetLayerId).elementModels.get(id);
67565
- }).filter((v) => !!v);
67883
+ }).filter((model) => !!model && !model.isBackground);
67884
+ if (elementModels.length === 0) {
67885
+ editor.hidden();
67886
+ this.emitter.emit("elementDeselected", userId);
67887
+ return;
67888
+ }
67889
+ editor.show();
67566
67890
  editor.setTargets(elementModels);
67567
67891
  if (elementModels.length === 1) {
67568
67892
  const model = elementModels[0];
@@ -67754,14 +68078,17 @@ var WhiteboardApplication = class _WhiteboardApplication extends AbstractApplica
67754
68078
  this.camera.resetViewMatrixToMain();
67755
68079
  }
67756
68080
  };
67757
- this.emitter.insertImage = (src, pageId) => {
68081
+ this.emitter.insertImage = (src, options) => {
67758
68082
  if (!/https/.test(src)) {
67759
68083
  log4("[@netless/forge-whiteboard] invalid image url, src needs to be in the HTTPS protocol.", {
67760
68084
  src
67761
68085
  }, "warn");
67762
68086
  return;
67763
68087
  }
67764
- let targetPageId = pageId;
68088
+ const normalizedOptions = typeof options === "string" ? {
68089
+ pageId: options
68090
+ } : options ?? {};
68091
+ let targetPageId = normalizedOptions.pageId;
67765
68092
  if (!targetPageId) {
67766
68093
  targetPageId = this.pageModel.getCurrentPage(this.userManager.selfId);
67767
68094
  }
@@ -67769,13 +68096,16 @@ var WhiteboardApplication = class _WhiteboardApplication extends AbstractApplica
67769
68096
  log4("[@netless/forge-whiteboard] page not found", {}, "warn");
67770
68097
  return;
67771
68098
  }
67772
- this.layers.get(targetPageId)?.createImage(src);
68099
+ this.layers.get(targetPageId)?.createImage(src, normalizedOptions.fit ?? "legacy", normalizedOptions.role ?? "normal");
67773
68100
  };
67774
68101
  this.emitter.removeElement = (pageId, elementId) => {
67775
68102
  if (!this.layers.has(pageId)) {
67776
68103
  log4("[@netless/forge-whiteboard] page not found", {}, "warn");
67777
68104
  return;
67778
68105
  }
68106
+ if (this.layers.get(pageId)?.isBackgroundElement(elementId)) {
68107
+ return;
68108
+ }
67779
68109
  this.layers.get(pageId)?.removeElementItem(elementId);
67780
68110
  };
67781
68111
  this.emitter.getViewModel = (userId) => {
@@ -67826,7 +68156,11 @@ var WhiteboardApplication = class _WhiteboardApplication extends AbstractApplica
67826
68156
  if (model) {
67827
68157
  if (model.elements.doc) {
67828
68158
  model.elements.doc.transact(() => {
67829
- model.elements.clear();
68159
+ for (const key of Array.from(model.elements.keys())) {
68160
+ if (!model.isBackgroundElement(key)) {
68161
+ model.elements.delete(key);
68162
+ }
68163
+ }
67830
68164
  }, elementsUndoOrigin);
67831
68165
  } else {
67832
68166
  model.elementModels.clear();
@@ -68238,7 +68572,9 @@ var WhiteboardApplication = class _WhiteboardApplication extends AbstractApplica
68238
68572
  const at = this.findElementIndex(element.data.index, parent);
68239
68573
  for (let i = at; i >= 0; i--) {
68240
68574
  const child = children[i - 1];
68241
- if (!child || child.data.index < element.data.index || child.data.uuid < element.data.uuid) {
68575
+ const childRole = child?.data.role === "background" ? 0 : 1;
68576
+ const elementRole = element.data.role === "background" ? 0 : 1;
68577
+ if (!child || childRole < elementRole || childRole === elementRole && child.data.index < element.data.index || childRole === elementRole && child.data.index === element.data.index && child.data.uuid < element.data.uuid) {
68242
68578
  parent.insertChild(i, element);
68243
68579
  break;
68244
68580
  }