@fieldnotes/core 0.38.1 → 0.38.2

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/index.cjs CHANGED
@@ -4055,17 +4055,43 @@ var ContextMenu = class {
4055
4055
  }
4056
4056
  };
4057
4057
 
4058
- // src/elements/translate.ts
4059
- function translateElementPatch(el, dx, dy) {
4060
- const position = { x: el.position.x + dx, y: el.position.y + dy };
4061
- if (el.type === "arrow") {
4062
- return {
4063
- position,
4064
- from: { x: el.from.x + dx, y: el.from.y + dy },
4065
- to: { x: el.to.x + dx, y: el.to.y + dy }
4066
- };
4067
- }
4068
- return { position };
4058
+ // src/canvas/viewport-dom.ts
4059
+ function createWrapper() {
4060
+ const el = document.createElement("div");
4061
+ Object.assign(el.style, {
4062
+ position: "relative",
4063
+ width: "100%",
4064
+ height: "100%",
4065
+ overflow: "hidden",
4066
+ overscrollBehavior: "none",
4067
+ userSelect: "none",
4068
+ webkitUserSelect: "none"
4069
+ });
4070
+ return el;
4071
+ }
4072
+ function createCanvas() {
4073
+ const el = document.createElement("canvas");
4074
+ Object.assign(el.style, {
4075
+ position: "absolute",
4076
+ top: "0",
4077
+ left: "0",
4078
+ width: "100%",
4079
+ height: "100%"
4080
+ });
4081
+ return el;
4082
+ }
4083
+ function createDomLayer() {
4084
+ const el = document.createElement("div");
4085
+ Object.assign(el.style, {
4086
+ position: "absolute",
4087
+ top: "0",
4088
+ left: "0",
4089
+ width: "100%",
4090
+ height: "100%",
4091
+ pointerEvents: "none",
4092
+ transformOrigin: "0 0"
4093
+ });
4094
+ return el;
4069
4095
  }
4070
4096
 
4071
4097
  // src/elements/arrow-label-editor.ts
@@ -5689,6 +5715,19 @@ var MarginViewport = class {
5689
5715
  }
5690
5716
  };
5691
5717
 
5718
+ // src/elements/translate.ts
5719
+ function translateElementPatch(el, dx, dy) {
5720
+ const position = { x: el.position.x + dx, y: el.position.y + dy };
5721
+ if (el.type === "arrow") {
5722
+ return {
5723
+ position,
5724
+ from: { x: el.from.x + dx, y: el.from.y + dy },
5725
+ to: { x: el.to.x + dx, y: el.to.y + dy }
5726
+ };
5727
+ }
5728
+ return { position };
5729
+ }
5730
+
5692
5731
  // src/elements/element-style.ts
5693
5732
  function styleToPatch(element, style) {
5694
5733
  const { color, fillColor, strokeWidth, opacity, fontSize } = style;
@@ -5776,7 +5815,7 @@ function getElementStyle(element) {
5776
5815
  }
5777
5816
  }
5778
5817
 
5779
- // src/canvas/viewport.ts
5818
+ // src/canvas/selection-ops.ts
5780
5819
  function unionBounds(list) {
5781
5820
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
5782
5821
  for (const b of list) {
@@ -5787,16 +5826,244 @@ function unionBounds(list) {
5787
5826
  }
5788
5827
  return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };
5789
5828
  }
5790
- var EMPTY_IDS = [];
5791
- var ARROW_HIT_THRESHOLD = 10;
5792
- function noop() {
5793
- }
5794
5829
  function sharedValue(values) {
5795
5830
  const present = values.filter((v) => v !== void 0);
5796
5831
  if (present.length === 0) return void 0;
5797
5832
  const first = present[0];
5798
5833
  return present.every((v) => v === first) ? first : void 0;
5799
5834
  }
5835
+ var SelectionOps = class {
5836
+ constructor(deps) {
5837
+ this.deps = deps;
5838
+ }
5839
+ getStyle() {
5840
+ const ids = this.deps.getSelectedIds();
5841
+ if (ids.length === 0) return null;
5842
+ const styles = [];
5843
+ for (const id of ids) {
5844
+ const el = this.deps.store.getById(id);
5845
+ if (el) styles.push(getElementStyle(el));
5846
+ }
5847
+ if (styles.length === 0) return null;
5848
+ const result = {};
5849
+ const color = sharedValue(styles.map((s) => s.color));
5850
+ if (color !== void 0) result.color = color;
5851
+ const fillColor = sharedValue(styles.map((s) => s.fillColor));
5852
+ if (fillColor !== void 0) result.fillColor = fillColor;
5853
+ const strokeWidth = sharedValue(styles.map((s) => s.strokeWidth));
5854
+ if (strokeWidth !== void 0) result.strokeWidth = strokeWidth;
5855
+ const opacity = sharedValue(styles.map((s) => s.opacity));
5856
+ if (opacity !== void 0) result.opacity = opacity;
5857
+ const fontSize = sharedValue(styles.map((s) => s.fontSize));
5858
+ if (fontSize !== void 0) result.fontSize = fontSize;
5859
+ return result;
5860
+ }
5861
+ applyStyle(style) {
5862
+ const ids = this.deps.getSelectedIds();
5863
+ if (ids.length === 0) return;
5864
+ this.deps.recorder.begin();
5865
+ for (const id of ids) {
5866
+ const el = this.deps.store.getById(id);
5867
+ if (!el) continue;
5868
+ const patch = styleToPatch(el, style);
5869
+ if (Object.keys(patch).length > 0) {
5870
+ this.deps.store.update(id, patch);
5871
+ }
5872
+ }
5873
+ this.deps.recorder.commit();
5874
+ }
5875
+ group() {
5876
+ const ids = this.deps.getSelectedIds();
5877
+ if (ids.length < 2) return;
5878
+ const groupId = createId("group");
5879
+ this.deps.recorder.begin();
5880
+ for (const id of ids) {
5881
+ if (this.deps.store.getById(id)) this.deps.store.update(id, { groupId });
5882
+ }
5883
+ this.deps.recorder.commit();
5884
+ }
5885
+ ungroup() {
5886
+ const ids = this.deps.getSelectedIds();
5887
+ if (ids.length === 0) return;
5888
+ this.deps.recorder.begin();
5889
+ for (const id of ids) {
5890
+ const el = this.deps.store.getById(id);
5891
+ if (el && el.groupId !== void 0) this.deps.store.update(id, { groupId: void 0 });
5892
+ }
5893
+ this.deps.recorder.commit();
5894
+ }
5895
+ toggleLock() {
5896
+ const ids = this.deps.getSelectedIds();
5897
+ if (ids.length === 0) return;
5898
+ const anyUnlocked = ids.some((id) => {
5899
+ const el = this.deps.store.getById(id);
5900
+ return el ? !el.locked : false;
5901
+ });
5902
+ this.deps.recorder.begin();
5903
+ for (const id of ids) {
5904
+ const el = this.deps.store.getById(id);
5905
+ if (el && el.locked !== anyUnlocked) this.deps.store.update(id, { locked: anyUnlocked });
5906
+ }
5907
+ this.deps.recorder.commit();
5908
+ }
5909
+ align(edge) {
5910
+ const bounded = this.boundedSelection();
5911
+ if (bounded.length < 2) return;
5912
+ const B = unionBounds(bounded.map((e) => e.bounds));
5913
+ this.deps.recorder.begin();
5914
+ const moved = [];
5915
+ for (const { id, el, bounds: b } of bounded) {
5916
+ if (!this.isMovable(el)) continue;
5917
+ let dx = 0;
5918
+ let dy = 0;
5919
+ switch (edge) {
5920
+ case "left":
5921
+ dx = B.x - b.x;
5922
+ break;
5923
+ case "right":
5924
+ dx = B.x + B.w - (b.x + b.w);
5925
+ break;
5926
+ case "center-x":
5927
+ dx = B.x + B.w / 2 - (b.x + b.w / 2);
5928
+ break;
5929
+ case "top":
5930
+ dy = B.y - b.y;
5931
+ break;
5932
+ case "bottom":
5933
+ dy = B.y + B.h - (b.y + b.h);
5934
+ break;
5935
+ case "middle":
5936
+ dy = B.y + B.h / 2 - (b.y + b.h / 2);
5937
+ break;
5938
+ }
5939
+ if (dx === 0 && dy === 0) continue;
5940
+ this.deps.store.update(id, translateElementPatch(el, dx, dy));
5941
+ moved.push(id);
5942
+ }
5943
+ updateArrowsBoundToElements(moved, this.deps.store);
5944
+ this.deps.recorder.commit();
5945
+ this.deps.requestRender();
5946
+ }
5947
+ distribute(axis) {
5948
+ const bounded = this.boundedSelection();
5949
+ if (bounded.length < 3) return;
5950
+ const center2 = (b) => axis === "horizontal" ? b.x + b.w / 2 : b.y + b.h / 2;
5951
+ const sorted = [...bounded].sort((p, q) => center2(p.bounds) - center2(q.bounds));
5952
+ const first = sorted[0];
5953
+ const last = sorted[sorted.length - 1];
5954
+ if (!first || !last) return;
5955
+ const c0 = center2(first.bounds);
5956
+ const cN = center2(last.bounds);
5957
+ const n = sorted.length;
5958
+ this.deps.recorder.begin();
5959
+ const moved = [];
5960
+ for (let i = 1; i < n - 1; i++) {
5961
+ const item = sorted[i];
5962
+ if (!item || !this.isMovable(item.el)) continue;
5963
+ const target = c0 + i * (cN - c0) / (n - 1);
5964
+ const delta = target - center2(item.bounds);
5965
+ if (delta === 0) continue;
5966
+ const [dx, dy] = axis === "horizontal" ? [delta, 0] : [0, delta];
5967
+ this.deps.store.update(item.id, translateElementPatch(item.el, dx, dy));
5968
+ moved.push(item.id);
5969
+ }
5970
+ updateArrowsBoundToElements(moved, this.deps.store);
5971
+ this.deps.recorder.commit();
5972
+ this.deps.requestRender();
5973
+ }
5974
+ boundedSelection() {
5975
+ const out = [];
5976
+ for (const id of this.deps.getSelectedIds()) {
5977
+ const el = this.deps.store.getById(id);
5978
+ if (!el) continue;
5979
+ const bounds = getElementBounds(el);
5980
+ if (bounds) out.push({ id, el, bounds });
5981
+ }
5982
+ return out;
5983
+ }
5984
+ isMovable(el) {
5985
+ if (el.locked) return false;
5986
+ if (el.type === "arrow" && (el.fromBinding ?? el.toBinding)) return false;
5987
+ return true;
5988
+ }
5989
+ };
5990
+
5991
+ // src/canvas/grid-controller.ts
5992
+ var GridController = class {
5993
+ constructor(deps) {
5994
+ this.deps = deps;
5995
+ }
5996
+ listeners = /* @__PURE__ */ new Set();
5997
+ add(input) {
5998
+ const existing = this.deps.store.getElementsByType("grid")[0];
5999
+ this.deps.recorder.begin();
6000
+ if (existing) {
6001
+ this.deps.store.remove(existing.id);
6002
+ }
6003
+ const grid = createGrid({ ...input, layerId: this.deps.getActiveLayerId() });
6004
+ this.deps.store.add(grid);
6005
+ this.deps.recorder.commit();
6006
+ this.deps.requestRender();
6007
+ return grid.id;
6008
+ }
6009
+ update(updates) {
6010
+ const grid = this.deps.store.getElementsByType("grid")[0];
6011
+ if (!grid) return;
6012
+ this.deps.recorder.begin();
6013
+ this.deps.store.update(grid.id, updates);
6014
+ this.deps.recorder.commit();
6015
+ this.deps.requestRender();
6016
+ }
6017
+ remove() {
6018
+ const grid = this.deps.store.getElementsByType("grid")[0];
6019
+ if (!grid) return;
6020
+ this.deps.recorder.begin();
6021
+ this.deps.store.remove(grid.id);
6022
+ this.deps.recorder.commit();
6023
+ this.deps.requestRender();
6024
+ }
6025
+ getInfo() {
6026
+ const grid = this.deps.store.getElementsByType("grid")[0];
6027
+ if (!grid) return null;
6028
+ return {
6029
+ gridType: grid.gridType,
6030
+ hexOrientation: grid.hexOrientation,
6031
+ cellSize: grid.cellSize,
6032
+ cellRadius: grid.gridType === "hex" ? grid.cellSize : grid.cellSize / 2
6033
+ };
6034
+ }
6035
+ onChange(listener) {
6036
+ this.listeners.add(listener);
6037
+ return () => {
6038
+ this.listeners.delete(listener);
6039
+ };
6040
+ }
6041
+ syncContext() {
6042
+ const grid = this.deps.store.getElementsByType("grid")[0];
6043
+ if (grid) {
6044
+ this.deps.toolContext.gridSize = grid.cellSize;
6045
+ this.deps.toolContext.gridType = grid.gridType;
6046
+ this.deps.toolContext.hexOrientation = grid.hexOrientation;
6047
+ } else {
6048
+ this.deps.toolContext.gridSize = this.deps.defaultGridSize;
6049
+ this.deps.toolContext.gridType = void 0;
6050
+ this.deps.toolContext.hexOrientation = void 0;
6051
+ }
6052
+ this.notify();
6053
+ }
6054
+ notify() {
6055
+ const info = this.getInfo();
6056
+ for (const listener of this.listeners) {
6057
+ listener(info);
6058
+ }
6059
+ }
6060
+ };
6061
+
6062
+ // src/canvas/viewport.ts
6063
+ var EMPTY_IDS = [];
6064
+ var ARROW_HIT_THRESHOLD = 10;
6065
+ function noop() {
6066
+ }
5800
6067
  var Viewport = class {
5801
6068
  constructor(container, options = {}) {
5802
6069
  this.container = container;
@@ -5839,9 +6106,15 @@ var Viewport = class {
5839
6106
  this.dropHandler = options.onDrop;
5840
6107
  this.history = new HistoryStack();
5841
6108
  this.historyRecorder = new HistoryRecorder(this.store, this.history, this.layerManager);
5842
- this.wrapper = this.createWrapper();
5843
- this.canvasEl = this.createCanvas();
5844
- this.domLayer = this.createDomLayer();
6109
+ this.selectionOps = new SelectionOps({
6110
+ store: this.store,
6111
+ recorder: this.historyRecorder,
6112
+ getSelectedIds: () => this.getSelectedIds(),
6113
+ requestRender: () => this.requestRender()
6114
+ });
6115
+ this.wrapper = createWrapper();
6116
+ this.canvasEl = createCanvas();
6117
+ this.domLayer = createDomLayer();
5845
6118
  this.wrapper.appendChild(this.canvasEl);
5846
6119
  this.wrapper.appendChild(this.domLayer);
5847
6120
  this.container.appendChild(this.wrapper);
@@ -5919,21 +6192,29 @@ var Viewport = class {
5919
6192
  this.contextMenu?.close();
5920
6193
  this.requestRender();
5921
6194
  });
6195
+ this.gridController = new GridController({
6196
+ store: this.store,
6197
+ recorder: this.historyRecorder,
6198
+ requestRender: () => this.requestRender(),
6199
+ getActiveLayerId: () => this.layerManager.activeLayerId,
6200
+ toolContext: this.toolContext,
6201
+ defaultGridSize: this._gridSize
6202
+ });
5922
6203
  this.unsubStore = [
5923
6204
  this.store.on("add", (el) => {
5924
- if (el.type === "grid") this.syncGridContext();
6205
+ if (el.type === "grid") this.gridController.syncContext();
5925
6206
  this.renderLoop.markLayerDirty(el.layerId);
5926
6207
  this.requestRender();
5927
6208
  }),
5928
6209
  this.store.on("remove", (el) => {
5929
- if (el.type === "grid") this.syncGridContext();
6210
+ if (el.type === "grid") this.gridController.syncContext();
5930
6211
  this.unbindArrowsFrom(el);
5931
6212
  this.domNodeManager.removeDomNode(el.id);
5932
6213
  this.renderLoop.markLayerDirty(el.layerId);
5933
6214
  this.requestRender();
5934
6215
  }),
5935
6216
  this.store.on("update", ({ previous, current }) => {
5936
- if (current.type === "grid") this.syncGridContext();
6217
+ if (current.type === "grid") this.gridController.syncContext();
5937
6218
  this.renderLoop.markLayerDirty(current.layerId);
5938
6219
  if (previous.layerId !== current.layerId) {
5939
6220
  this.renderLoop.markLayerDirty(previous.layerId);
@@ -5943,7 +6224,7 @@ var Viewport = class {
5943
6224
  this.store.on("clear", () => {
5944
6225
  this.domNodeManager.clearDomNodes();
5945
6226
  this.renderLoop.markAllLayersDirty();
5946
- this.syncGridContext();
6227
+ this.gridController.syncContext();
5947
6228
  this.requestRender();
5948
6229
  })
5949
6230
  ];
@@ -5958,7 +6239,7 @@ var Viewport = class {
5958
6239
  this.observeResize();
5959
6240
  this.syncCanvasSize();
5960
6241
  this.renderLoop.start();
5961
- this.syncGridContext();
6242
+ this.gridController.syncContext();
5962
6243
  }
5963
6244
  camera;
5964
6245
  store;
@@ -5977,6 +6258,7 @@ var Viewport = class {
5977
6258
  noteEditor;
5978
6259
  arrowLabelEditor;
5979
6260
  historyRecorder;
6261
+ selectionOps;
5980
6262
  toolContext;
5981
6263
  marginViewport;
5982
6264
  resizeObserver = null;
@@ -5988,7 +6270,7 @@ var Viewport = class {
5988
6270
  interactMode;
5989
6271
  onHtmlElementMount;
5990
6272
  dropHandler;
5991
- gridChangeListeners = /* @__PURE__ */ new Set();
6273
+ gridController;
5992
6274
  doubleTapDetector = new DoubleTapDetector();
5993
6275
  tapDownX = 0;
5994
6276
  tapDownY = 0;
@@ -6160,48 +6442,19 @@ var Viewport = class {
6160
6442
  this.requestRender();
6161
6443
  }
6162
6444
  addGrid(input) {
6163
- const existing = this.store.getElementsByType("grid")[0];
6164
- this.historyRecorder.begin();
6165
- if (existing) {
6166
- this.store.remove(existing.id);
6167
- }
6168
- const grid = createGrid({ ...input, layerId: this.layerManager.activeLayerId });
6169
- this.store.add(grid);
6170
- this.historyRecorder.commit();
6171
- this.requestRender();
6172
- return grid.id;
6445
+ return this.gridController.add(input);
6173
6446
  }
6174
6447
  updateGrid(updates) {
6175
- const grid = this.store.getElementsByType("grid")[0];
6176
- if (!grid) return;
6177
- this.historyRecorder.begin();
6178
- this.store.update(grid.id, updates);
6179
- this.historyRecorder.commit();
6180
- this.requestRender();
6448
+ this.gridController.update(updates);
6181
6449
  }
6182
6450
  removeGrid() {
6183
- const grid = this.store.getElementsByType("grid")[0];
6184
- if (!grid) return;
6185
- this.historyRecorder.begin();
6186
- this.store.remove(grid.id);
6187
- this.historyRecorder.commit();
6188
- this.requestRender();
6451
+ this.gridController.remove();
6189
6452
  }
6190
6453
  getGridInfo() {
6191
- const grid = this.store.getElementsByType("grid")[0];
6192
- if (!grid) return null;
6193
- return {
6194
- gridType: grid.gridType,
6195
- hexOrientation: grid.hexOrientation,
6196
- cellSize: grid.cellSize,
6197
- cellRadius: grid.gridType === "hex" ? grid.cellSize : grid.cellSize / 2
6198
- };
6454
+ return this.gridController.getInfo();
6199
6455
  }
6200
6456
  onGridChange(listener) {
6201
- this.gridChangeListeners.add(listener);
6202
- return () => {
6203
- this.gridChangeListeners.delete(listener);
6204
- };
6457
+ return this.gridController.onChange(listener);
6205
6458
  }
6206
6459
  getSelectTool() {
6207
6460
  return this.toolManager.getTool("select");
@@ -6242,154 +6495,25 @@ var Viewport = class {
6242
6495
  return tool ? tool.onSelectionChange(listener) : noop;
6243
6496
  }
6244
6497
  getSelectionStyle() {
6245
- const ids = this.getSelectedIds();
6246
- if (ids.length === 0) return null;
6247
- const styles = [];
6248
- for (const id of ids) {
6249
- const el = this.store.getById(id);
6250
- if (el) styles.push(getElementStyle(el));
6251
- }
6252
- if (styles.length === 0) return null;
6253
- const result = {};
6254
- const color = sharedValue(styles.map((s) => s.color));
6255
- if (color !== void 0) result.color = color;
6256
- const fillColor = sharedValue(styles.map((s) => s.fillColor));
6257
- if (fillColor !== void 0) result.fillColor = fillColor;
6258
- const strokeWidth = sharedValue(styles.map((s) => s.strokeWidth));
6259
- if (strokeWidth !== void 0) result.strokeWidth = strokeWidth;
6260
- const opacity = sharedValue(styles.map((s) => s.opacity));
6261
- if (opacity !== void 0) result.opacity = opacity;
6262
- const fontSize = sharedValue(styles.map((s) => s.fontSize));
6263
- if (fontSize !== void 0) result.fontSize = fontSize;
6264
- return result;
6498
+ return this.selectionOps.getStyle();
6265
6499
  }
6266
6500
  applyStyleToSelection(style) {
6267
- const ids = this.getSelectedIds();
6268
- if (ids.length === 0) return;
6269
- this.historyRecorder.begin();
6270
- for (const id of ids) {
6271
- const el = this.store.getById(id);
6272
- if (!el) continue;
6273
- const patch = styleToPatch(el, style);
6274
- if (Object.keys(patch).length > 0) {
6275
- this.store.update(id, patch);
6276
- }
6277
- }
6278
- this.historyRecorder.commit();
6501
+ this.selectionOps.applyStyle(style);
6279
6502
  }
6280
6503
  groupSelection() {
6281
- const ids = this.getSelectedIds();
6282
- if (ids.length < 2) return;
6283
- const groupId = createId("group");
6284
- this.historyRecorder.begin();
6285
- for (const id of ids) {
6286
- if (this.store.getById(id)) this.store.update(id, { groupId });
6287
- }
6288
- this.historyRecorder.commit();
6504
+ this.selectionOps.group();
6289
6505
  }
6290
6506
  ungroupSelection() {
6291
- const ids = this.getSelectedIds();
6292
- if (ids.length === 0) return;
6293
- this.historyRecorder.begin();
6294
- for (const id of ids) {
6295
- const el = this.store.getById(id);
6296
- if (el && el.groupId !== void 0) this.store.update(id, { groupId: void 0 });
6297
- }
6298
- this.historyRecorder.commit();
6507
+ this.selectionOps.ungroup();
6299
6508
  }
6300
6509
  toggleLockSelection() {
6301
- const ids = this.getSelectedIds();
6302
- if (ids.length === 0) return;
6303
- const anyUnlocked = ids.some((id) => {
6304
- const el = this.store.getById(id);
6305
- return el ? !el.locked : false;
6306
- });
6307
- this.historyRecorder.begin();
6308
- for (const id of ids) {
6309
- const el = this.store.getById(id);
6310
- if (el && el.locked !== anyUnlocked) this.store.update(id, { locked: anyUnlocked });
6311
- }
6312
- this.historyRecorder.commit();
6510
+ this.selectionOps.toggleLock();
6313
6511
  }
6314
6512
  alignSelection(edge) {
6315
- const bounded = this.boundedSelection();
6316
- if (bounded.length < 2) return;
6317
- const B = unionBounds(bounded.map((e) => e.bounds));
6318
- this.historyRecorder.begin();
6319
- const moved = [];
6320
- for (const { id, el, bounds: b } of bounded) {
6321
- if (!this.isMovable(el)) continue;
6322
- let dx = 0;
6323
- let dy = 0;
6324
- switch (edge) {
6325
- case "left":
6326
- dx = B.x - b.x;
6327
- break;
6328
- case "right":
6329
- dx = B.x + B.w - (b.x + b.w);
6330
- break;
6331
- case "center-x":
6332
- dx = B.x + B.w / 2 - (b.x + b.w / 2);
6333
- break;
6334
- case "top":
6335
- dy = B.y - b.y;
6336
- break;
6337
- case "bottom":
6338
- dy = B.y + B.h - (b.y + b.h);
6339
- break;
6340
- case "middle":
6341
- dy = B.y + B.h / 2 - (b.y + b.h / 2);
6342
- break;
6343
- }
6344
- if (dx === 0 && dy === 0) continue;
6345
- this.store.update(id, translateElementPatch(el, dx, dy));
6346
- moved.push(id);
6347
- }
6348
- updateArrowsBoundToElements(moved, this.store);
6349
- this.historyRecorder.commit();
6350
- this.requestRender();
6513
+ this.selectionOps.align(edge);
6351
6514
  }
6352
6515
  distributeSelection(axis) {
6353
- const bounded = this.boundedSelection();
6354
- if (bounded.length < 3) return;
6355
- const center2 = (b) => axis === "horizontal" ? b.x + b.w / 2 : b.y + b.h / 2;
6356
- const sorted = [...bounded].sort((p, q) => center2(p.bounds) - center2(q.bounds));
6357
- const first = sorted[0];
6358
- const last = sorted[sorted.length - 1];
6359
- if (!first || !last) return;
6360
- const c0 = center2(first.bounds);
6361
- const cN = center2(last.bounds);
6362
- const n = sorted.length;
6363
- this.historyRecorder.begin();
6364
- const moved = [];
6365
- for (let i = 1; i < n - 1; i++) {
6366
- const item = sorted[i];
6367
- if (!item || !this.isMovable(item.el)) continue;
6368
- const target = c0 + i * (cN - c0) / (n - 1);
6369
- const delta = target - center2(item.bounds);
6370
- if (delta === 0) continue;
6371
- const [dx, dy] = axis === "horizontal" ? [delta, 0] : [0, delta];
6372
- this.store.update(item.id, translateElementPatch(item.el, dx, dy));
6373
- moved.push(item.id);
6374
- }
6375
- updateArrowsBoundToElements(moved, this.store);
6376
- this.historyRecorder.commit();
6377
- this.requestRender();
6378
- }
6379
- boundedSelection() {
6380
- const out = [];
6381
- for (const id of this.getSelectedIds()) {
6382
- const el = this.store.getById(id);
6383
- if (!el) continue;
6384
- const bounds = getElementBounds(el);
6385
- if (bounds) out.push({ id, el, bounds });
6386
- }
6387
- return out;
6388
- }
6389
- isMovable(el) {
6390
- if (el.locked) return false;
6391
- if (el.type === "arrow" && (el.fromBinding ?? el.toBinding)) return false;
6392
- return true;
6516
+ this.selectionOps.distribute(axis);
6393
6517
  }
6394
6518
  getRenderStats() {
6395
6519
  return this.renderLoop.getStats();
@@ -6598,43 +6722,6 @@ var Viewport = class {
6598
6722
  }
6599
6723
  }
6600
6724
  }
6601
- createWrapper() {
6602
- const el = document.createElement("div");
6603
- Object.assign(el.style, {
6604
- position: "relative",
6605
- width: "100%",
6606
- height: "100%",
6607
- overflow: "hidden",
6608
- overscrollBehavior: "none",
6609
- userSelect: "none",
6610
- webkitUserSelect: "none"
6611
- });
6612
- return el;
6613
- }
6614
- createCanvas() {
6615
- const el = document.createElement("canvas");
6616
- Object.assign(el.style, {
6617
- position: "absolute",
6618
- top: "0",
6619
- left: "0",
6620
- width: "100%",
6621
- height: "100%"
6622
- });
6623
- return el;
6624
- }
6625
- createDomLayer() {
6626
- const el = document.createElement("div");
6627
- Object.assign(el.style, {
6628
- position: "absolute",
6629
- top: "0",
6630
- left: "0",
6631
- width: "100%",
6632
- height: "100%",
6633
- pointerEvents: "none",
6634
- transformOrigin: "0 0"
6635
- });
6636
- return el;
6637
- }
6638
6725
  applyCameraTransform() {
6639
6726
  this.domLayer.style.transform = this.camera.toCSSTransform();
6640
6727
  }
@@ -6644,25 +6731,6 @@ var Viewport = class {
6644
6731
  this.renderLoop.setCanvasSize(rect.width * dpr, rect.height * dpr);
6645
6732
  this.requestRender();
6646
6733
  }
6647
- syncGridContext() {
6648
- const grid = this.store.getElementsByType("grid")[0];
6649
- if (grid) {
6650
- this.toolContext.gridSize = grid.cellSize;
6651
- this.toolContext.gridType = grid.gridType;
6652
- this.toolContext.hexOrientation = grid.hexOrientation;
6653
- } else {
6654
- this.toolContext.gridSize = this._gridSize;
6655
- this.toolContext.gridType = void 0;
6656
- this.toolContext.hexOrientation = void 0;
6657
- }
6658
- this.notifyGridChangeListeners();
6659
- }
6660
- notifyGridChangeListeners() {
6661
- const info = this.getGridInfo();
6662
- for (const listener of this.gridChangeListeners) {
6663
- listener(info);
6664
- }
6665
- }
6666
6734
  observeResize() {
6667
6735
  if (typeof ResizeObserver === "undefined") return;
6668
6736
  this.resizeObserver = new ResizeObserver(() => this.syncCanvasSize());
@@ -8976,7 +9044,7 @@ var TemplateTool = class {
8976
9044
  };
8977
9045
 
8978
9046
  // src/index.ts
8979
- var VERSION = "0.38.0";
9047
+ var VERSION = "0.38.2";
8980
9048
  // Annotate the CommonJS export names for ESM import in node:
8981
9049
  0 && (module.exports = {
8982
9050
  ArrowTool,