@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.js CHANGED
@@ -3974,17 +3974,43 @@ var ContextMenu = class {
3974
3974
  }
3975
3975
  };
3976
3976
 
3977
- // src/elements/translate.ts
3978
- function translateElementPatch(el, dx, dy) {
3979
- const position = { x: el.position.x + dx, y: el.position.y + dy };
3980
- if (el.type === "arrow") {
3981
- return {
3982
- position,
3983
- from: { x: el.from.x + dx, y: el.from.y + dy },
3984
- to: { x: el.to.x + dx, y: el.to.y + dy }
3985
- };
3986
- }
3987
- return { position };
3977
+ // src/canvas/viewport-dom.ts
3978
+ function createWrapper() {
3979
+ const el = document.createElement("div");
3980
+ Object.assign(el.style, {
3981
+ position: "relative",
3982
+ width: "100%",
3983
+ height: "100%",
3984
+ overflow: "hidden",
3985
+ overscrollBehavior: "none",
3986
+ userSelect: "none",
3987
+ webkitUserSelect: "none"
3988
+ });
3989
+ return el;
3990
+ }
3991
+ function createCanvas() {
3992
+ const el = document.createElement("canvas");
3993
+ Object.assign(el.style, {
3994
+ position: "absolute",
3995
+ top: "0",
3996
+ left: "0",
3997
+ width: "100%",
3998
+ height: "100%"
3999
+ });
4000
+ return el;
4001
+ }
4002
+ function createDomLayer() {
4003
+ const el = document.createElement("div");
4004
+ Object.assign(el.style, {
4005
+ position: "absolute",
4006
+ top: "0",
4007
+ left: "0",
4008
+ width: "100%",
4009
+ height: "100%",
4010
+ pointerEvents: "none",
4011
+ transformOrigin: "0 0"
4012
+ });
4013
+ return el;
3988
4014
  }
3989
4015
 
3990
4016
  // src/elements/arrow-label-editor.ts
@@ -5608,6 +5634,19 @@ var MarginViewport = class {
5608
5634
  }
5609
5635
  };
5610
5636
 
5637
+ // src/elements/translate.ts
5638
+ function translateElementPatch(el, dx, dy) {
5639
+ const position = { x: el.position.x + dx, y: el.position.y + dy };
5640
+ if (el.type === "arrow") {
5641
+ return {
5642
+ position,
5643
+ from: { x: el.from.x + dx, y: el.from.y + dy },
5644
+ to: { x: el.to.x + dx, y: el.to.y + dy }
5645
+ };
5646
+ }
5647
+ return { position };
5648
+ }
5649
+
5611
5650
  // src/elements/element-style.ts
5612
5651
  function styleToPatch(element, style) {
5613
5652
  const { color, fillColor, strokeWidth, opacity, fontSize } = style;
@@ -5695,7 +5734,7 @@ function getElementStyle(element) {
5695
5734
  }
5696
5735
  }
5697
5736
 
5698
- // src/canvas/viewport.ts
5737
+ // src/canvas/selection-ops.ts
5699
5738
  function unionBounds(list) {
5700
5739
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
5701
5740
  for (const b of list) {
@@ -5706,16 +5745,244 @@ function unionBounds(list) {
5706
5745
  }
5707
5746
  return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };
5708
5747
  }
5709
- var EMPTY_IDS = [];
5710
- var ARROW_HIT_THRESHOLD = 10;
5711
- function noop() {
5712
- }
5713
5748
  function sharedValue(values) {
5714
5749
  const present = values.filter((v) => v !== void 0);
5715
5750
  if (present.length === 0) return void 0;
5716
5751
  const first = present[0];
5717
5752
  return present.every((v) => v === first) ? first : void 0;
5718
5753
  }
5754
+ var SelectionOps = class {
5755
+ constructor(deps) {
5756
+ this.deps = deps;
5757
+ }
5758
+ getStyle() {
5759
+ const ids = this.deps.getSelectedIds();
5760
+ if (ids.length === 0) return null;
5761
+ const styles = [];
5762
+ for (const id of ids) {
5763
+ const el = this.deps.store.getById(id);
5764
+ if (el) styles.push(getElementStyle(el));
5765
+ }
5766
+ if (styles.length === 0) return null;
5767
+ const result = {};
5768
+ const color = sharedValue(styles.map((s) => s.color));
5769
+ if (color !== void 0) result.color = color;
5770
+ const fillColor = sharedValue(styles.map((s) => s.fillColor));
5771
+ if (fillColor !== void 0) result.fillColor = fillColor;
5772
+ const strokeWidth = sharedValue(styles.map((s) => s.strokeWidth));
5773
+ if (strokeWidth !== void 0) result.strokeWidth = strokeWidth;
5774
+ const opacity = sharedValue(styles.map((s) => s.opacity));
5775
+ if (opacity !== void 0) result.opacity = opacity;
5776
+ const fontSize = sharedValue(styles.map((s) => s.fontSize));
5777
+ if (fontSize !== void 0) result.fontSize = fontSize;
5778
+ return result;
5779
+ }
5780
+ applyStyle(style) {
5781
+ const ids = this.deps.getSelectedIds();
5782
+ if (ids.length === 0) return;
5783
+ this.deps.recorder.begin();
5784
+ for (const id of ids) {
5785
+ const el = this.deps.store.getById(id);
5786
+ if (!el) continue;
5787
+ const patch = styleToPatch(el, style);
5788
+ if (Object.keys(patch).length > 0) {
5789
+ this.deps.store.update(id, patch);
5790
+ }
5791
+ }
5792
+ this.deps.recorder.commit();
5793
+ }
5794
+ group() {
5795
+ const ids = this.deps.getSelectedIds();
5796
+ if (ids.length < 2) return;
5797
+ const groupId = createId("group");
5798
+ this.deps.recorder.begin();
5799
+ for (const id of ids) {
5800
+ if (this.deps.store.getById(id)) this.deps.store.update(id, { groupId });
5801
+ }
5802
+ this.deps.recorder.commit();
5803
+ }
5804
+ ungroup() {
5805
+ const ids = this.deps.getSelectedIds();
5806
+ if (ids.length === 0) return;
5807
+ this.deps.recorder.begin();
5808
+ for (const id of ids) {
5809
+ const el = this.deps.store.getById(id);
5810
+ if (el && el.groupId !== void 0) this.deps.store.update(id, { groupId: void 0 });
5811
+ }
5812
+ this.deps.recorder.commit();
5813
+ }
5814
+ toggleLock() {
5815
+ const ids = this.deps.getSelectedIds();
5816
+ if (ids.length === 0) return;
5817
+ const anyUnlocked = ids.some((id) => {
5818
+ const el = this.deps.store.getById(id);
5819
+ return el ? !el.locked : false;
5820
+ });
5821
+ this.deps.recorder.begin();
5822
+ for (const id of ids) {
5823
+ const el = this.deps.store.getById(id);
5824
+ if (el && el.locked !== anyUnlocked) this.deps.store.update(id, { locked: anyUnlocked });
5825
+ }
5826
+ this.deps.recorder.commit();
5827
+ }
5828
+ align(edge) {
5829
+ const bounded = this.boundedSelection();
5830
+ if (bounded.length < 2) return;
5831
+ const B = unionBounds(bounded.map((e) => e.bounds));
5832
+ this.deps.recorder.begin();
5833
+ const moved = [];
5834
+ for (const { id, el, bounds: b } of bounded) {
5835
+ if (!this.isMovable(el)) continue;
5836
+ let dx = 0;
5837
+ let dy = 0;
5838
+ switch (edge) {
5839
+ case "left":
5840
+ dx = B.x - b.x;
5841
+ break;
5842
+ case "right":
5843
+ dx = B.x + B.w - (b.x + b.w);
5844
+ break;
5845
+ case "center-x":
5846
+ dx = B.x + B.w / 2 - (b.x + b.w / 2);
5847
+ break;
5848
+ case "top":
5849
+ dy = B.y - b.y;
5850
+ break;
5851
+ case "bottom":
5852
+ dy = B.y + B.h - (b.y + b.h);
5853
+ break;
5854
+ case "middle":
5855
+ dy = B.y + B.h / 2 - (b.y + b.h / 2);
5856
+ break;
5857
+ }
5858
+ if (dx === 0 && dy === 0) continue;
5859
+ this.deps.store.update(id, translateElementPatch(el, dx, dy));
5860
+ moved.push(id);
5861
+ }
5862
+ updateArrowsBoundToElements(moved, this.deps.store);
5863
+ this.deps.recorder.commit();
5864
+ this.deps.requestRender();
5865
+ }
5866
+ distribute(axis) {
5867
+ const bounded = this.boundedSelection();
5868
+ if (bounded.length < 3) return;
5869
+ const center2 = (b) => axis === "horizontal" ? b.x + b.w / 2 : b.y + b.h / 2;
5870
+ const sorted = [...bounded].sort((p, q) => center2(p.bounds) - center2(q.bounds));
5871
+ const first = sorted[0];
5872
+ const last = sorted[sorted.length - 1];
5873
+ if (!first || !last) return;
5874
+ const c0 = center2(first.bounds);
5875
+ const cN = center2(last.bounds);
5876
+ const n = sorted.length;
5877
+ this.deps.recorder.begin();
5878
+ const moved = [];
5879
+ for (let i = 1; i < n - 1; i++) {
5880
+ const item = sorted[i];
5881
+ if (!item || !this.isMovable(item.el)) continue;
5882
+ const target = c0 + i * (cN - c0) / (n - 1);
5883
+ const delta = target - center2(item.bounds);
5884
+ if (delta === 0) continue;
5885
+ const [dx, dy] = axis === "horizontal" ? [delta, 0] : [0, delta];
5886
+ this.deps.store.update(item.id, translateElementPatch(item.el, dx, dy));
5887
+ moved.push(item.id);
5888
+ }
5889
+ updateArrowsBoundToElements(moved, this.deps.store);
5890
+ this.deps.recorder.commit();
5891
+ this.deps.requestRender();
5892
+ }
5893
+ boundedSelection() {
5894
+ const out = [];
5895
+ for (const id of this.deps.getSelectedIds()) {
5896
+ const el = this.deps.store.getById(id);
5897
+ if (!el) continue;
5898
+ const bounds = getElementBounds(el);
5899
+ if (bounds) out.push({ id, el, bounds });
5900
+ }
5901
+ return out;
5902
+ }
5903
+ isMovable(el) {
5904
+ if (el.locked) return false;
5905
+ if (el.type === "arrow" && (el.fromBinding ?? el.toBinding)) return false;
5906
+ return true;
5907
+ }
5908
+ };
5909
+
5910
+ // src/canvas/grid-controller.ts
5911
+ var GridController = class {
5912
+ constructor(deps) {
5913
+ this.deps = deps;
5914
+ }
5915
+ listeners = /* @__PURE__ */ new Set();
5916
+ add(input) {
5917
+ const existing = this.deps.store.getElementsByType("grid")[0];
5918
+ this.deps.recorder.begin();
5919
+ if (existing) {
5920
+ this.deps.store.remove(existing.id);
5921
+ }
5922
+ const grid = createGrid({ ...input, layerId: this.deps.getActiveLayerId() });
5923
+ this.deps.store.add(grid);
5924
+ this.deps.recorder.commit();
5925
+ this.deps.requestRender();
5926
+ return grid.id;
5927
+ }
5928
+ update(updates) {
5929
+ const grid = this.deps.store.getElementsByType("grid")[0];
5930
+ if (!grid) return;
5931
+ this.deps.recorder.begin();
5932
+ this.deps.store.update(grid.id, updates);
5933
+ this.deps.recorder.commit();
5934
+ this.deps.requestRender();
5935
+ }
5936
+ remove() {
5937
+ const grid = this.deps.store.getElementsByType("grid")[0];
5938
+ if (!grid) return;
5939
+ this.deps.recorder.begin();
5940
+ this.deps.store.remove(grid.id);
5941
+ this.deps.recorder.commit();
5942
+ this.deps.requestRender();
5943
+ }
5944
+ getInfo() {
5945
+ const grid = this.deps.store.getElementsByType("grid")[0];
5946
+ if (!grid) return null;
5947
+ return {
5948
+ gridType: grid.gridType,
5949
+ hexOrientation: grid.hexOrientation,
5950
+ cellSize: grid.cellSize,
5951
+ cellRadius: grid.gridType === "hex" ? grid.cellSize : grid.cellSize / 2
5952
+ };
5953
+ }
5954
+ onChange(listener) {
5955
+ this.listeners.add(listener);
5956
+ return () => {
5957
+ this.listeners.delete(listener);
5958
+ };
5959
+ }
5960
+ syncContext() {
5961
+ const grid = this.deps.store.getElementsByType("grid")[0];
5962
+ if (grid) {
5963
+ this.deps.toolContext.gridSize = grid.cellSize;
5964
+ this.deps.toolContext.gridType = grid.gridType;
5965
+ this.deps.toolContext.hexOrientation = grid.hexOrientation;
5966
+ } else {
5967
+ this.deps.toolContext.gridSize = this.deps.defaultGridSize;
5968
+ this.deps.toolContext.gridType = void 0;
5969
+ this.deps.toolContext.hexOrientation = void 0;
5970
+ }
5971
+ this.notify();
5972
+ }
5973
+ notify() {
5974
+ const info = this.getInfo();
5975
+ for (const listener of this.listeners) {
5976
+ listener(info);
5977
+ }
5978
+ }
5979
+ };
5980
+
5981
+ // src/canvas/viewport.ts
5982
+ var EMPTY_IDS = [];
5983
+ var ARROW_HIT_THRESHOLD = 10;
5984
+ function noop() {
5985
+ }
5719
5986
  var Viewport = class {
5720
5987
  constructor(container, options = {}) {
5721
5988
  this.container = container;
@@ -5758,9 +6025,15 @@ var Viewport = class {
5758
6025
  this.dropHandler = options.onDrop;
5759
6026
  this.history = new HistoryStack();
5760
6027
  this.historyRecorder = new HistoryRecorder(this.store, this.history, this.layerManager);
5761
- this.wrapper = this.createWrapper();
5762
- this.canvasEl = this.createCanvas();
5763
- this.domLayer = this.createDomLayer();
6028
+ this.selectionOps = new SelectionOps({
6029
+ store: this.store,
6030
+ recorder: this.historyRecorder,
6031
+ getSelectedIds: () => this.getSelectedIds(),
6032
+ requestRender: () => this.requestRender()
6033
+ });
6034
+ this.wrapper = createWrapper();
6035
+ this.canvasEl = createCanvas();
6036
+ this.domLayer = createDomLayer();
5764
6037
  this.wrapper.appendChild(this.canvasEl);
5765
6038
  this.wrapper.appendChild(this.domLayer);
5766
6039
  this.container.appendChild(this.wrapper);
@@ -5838,21 +6111,29 @@ var Viewport = class {
5838
6111
  this.contextMenu?.close();
5839
6112
  this.requestRender();
5840
6113
  });
6114
+ this.gridController = new GridController({
6115
+ store: this.store,
6116
+ recorder: this.historyRecorder,
6117
+ requestRender: () => this.requestRender(),
6118
+ getActiveLayerId: () => this.layerManager.activeLayerId,
6119
+ toolContext: this.toolContext,
6120
+ defaultGridSize: this._gridSize
6121
+ });
5841
6122
  this.unsubStore = [
5842
6123
  this.store.on("add", (el) => {
5843
- if (el.type === "grid") this.syncGridContext();
6124
+ if (el.type === "grid") this.gridController.syncContext();
5844
6125
  this.renderLoop.markLayerDirty(el.layerId);
5845
6126
  this.requestRender();
5846
6127
  }),
5847
6128
  this.store.on("remove", (el) => {
5848
- if (el.type === "grid") this.syncGridContext();
6129
+ if (el.type === "grid") this.gridController.syncContext();
5849
6130
  this.unbindArrowsFrom(el);
5850
6131
  this.domNodeManager.removeDomNode(el.id);
5851
6132
  this.renderLoop.markLayerDirty(el.layerId);
5852
6133
  this.requestRender();
5853
6134
  }),
5854
6135
  this.store.on("update", ({ previous, current }) => {
5855
- if (current.type === "grid") this.syncGridContext();
6136
+ if (current.type === "grid") this.gridController.syncContext();
5856
6137
  this.renderLoop.markLayerDirty(current.layerId);
5857
6138
  if (previous.layerId !== current.layerId) {
5858
6139
  this.renderLoop.markLayerDirty(previous.layerId);
@@ -5862,7 +6143,7 @@ var Viewport = class {
5862
6143
  this.store.on("clear", () => {
5863
6144
  this.domNodeManager.clearDomNodes();
5864
6145
  this.renderLoop.markAllLayersDirty();
5865
- this.syncGridContext();
6146
+ this.gridController.syncContext();
5866
6147
  this.requestRender();
5867
6148
  })
5868
6149
  ];
@@ -5877,7 +6158,7 @@ var Viewport = class {
5877
6158
  this.observeResize();
5878
6159
  this.syncCanvasSize();
5879
6160
  this.renderLoop.start();
5880
- this.syncGridContext();
6161
+ this.gridController.syncContext();
5881
6162
  }
5882
6163
  camera;
5883
6164
  store;
@@ -5896,6 +6177,7 @@ var Viewport = class {
5896
6177
  noteEditor;
5897
6178
  arrowLabelEditor;
5898
6179
  historyRecorder;
6180
+ selectionOps;
5899
6181
  toolContext;
5900
6182
  marginViewport;
5901
6183
  resizeObserver = null;
@@ -5907,7 +6189,7 @@ var Viewport = class {
5907
6189
  interactMode;
5908
6190
  onHtmlElementMount;
5909
6191
  dropHandler;
5910
- gridChangeListeners = /* @__PURE__ */ new Set();
6192
+ gridController;
5911
6193
  doubleTapDetector = new DoubleTapDetector();
5912
6194
  tapDownX = 0;
5913
6195
  tapDownY = 0;
@@ -6079,48 +6361,19 @@ var Viewport = class {
6079
6361
  this.requestRender();
6080
6362
  }
6081
6363
  addGrid(input) {
6082
- const existing = this.store.getElementsByType("grid")[0];
6083
- this.historyRecorder.begin();
6084
- if (existing) {
6085
- this.store.remove(existing.id);
6086
- }
6087
- const grid = createGrid({ ...input, layerId: this.layerManager.activeLayerId });
6088
- this.store.add(grid);
6089
- this.historyRecorder.commit();
6090
- this.requestRender();
6091
- return grid.id;
6364
+ return this.gridController.add(input);
6092
6365
  }
6093
6366
  updateGrid(updates) {
6094
- const grid = this.store.getElementsByType("grid")[0];
6095
- if (!grid) return;
6096
- this.historyRecorder.begin();
6097
- this.store.update(grid.id, updates);
6098
- this.historyRecorder.commit();
6099
- this.requestRender();
6367
+ this.gridController.update(updates);
6100
6368
  }
6101
6369
  removeGrid() {
6102
- const grid = this.store.getElementsByType("grid")[0];
6103
- if (!grid) return;
6104
- this.historyRecorder.begin();
6105
- this.store.remove(grid.id);
6106
- this.historyRecorder.commit();
6107
- this.requestRender();
6370
+ this.gridController.remove();
6108
6371
  }
6109
6372
  getGridInfo() {
6110
- const grid = this.store.getElementsByType("grid")[0];
6111
- if (!grid) return null;
6112
- return {
6113
- gridType: grid.gridType,
6114
- hexOrientation: grid.hexOrientation,
6115
- cellSize: grid.cellSize,
6116
- cellRadius: grid.gridType === "hex" ? grid.cellSize : grid.cellSize / 2
6117
- };
6373
+ return this.gridController.getInfo();
6118
6374
  }
6119
6375
  onGridChange(listener) {
6120
- this.gridChangeListeners.add(listener);
6121
- return () => {
6122
- this.gridChangeListeners.delete(listener);
6123
- };
6376
+ return this.gridController.onChange(listener);
6124
6377
  }
6125
6378
  getSelectTool() {
6126
6379
  return this.toolManager.getTool("select");
@@ -6161,154 +6414,25 @@ var Viewport = class {
6161
6414
  return tool ? tool.onSelectionChange(listener) : noop;
6162
6415
  }
6163
6416
  getSelectionStyle() {
6164
- const ids = this.getSelectedIds();
6165
- if (ids.length === 0) return null;
6166
- const styles = [];
6167
- for (const id of ids) {
6168
- const el = this.store.getById(id);
6169
- if (el) styles.push(getElementStyle(el));
6170
- }
6171
- if (styles.length === 0) return null;
6172
- const result = {};
6173
- const color = sharedValue(styles.map((s) => s.color));
6174
- if (color !== void 0) result.color = color;
6175
- const fillColor = sharedValue(styles.map((s) => s.fillColor));
6176
- if (fillColor !== void 0) result.fillColor = fillColor;
6177
- const strokeWidth = sharedValue(styles.map((s) => s.strokeWidth));
6178
- if (strokeWidth !== void 0) result.strokeWidth = strokeWidth;
6179
- const opacity = sharedValue(styles.map((s) => s.opacity));
6180
- if (opacity !== void 0) result.opacity = opacity;
6181
- const fontSize = sharedValue(styles.map((s) => s.fontSize));
6182
- if (fontSize !== void 0) result.fontSize = fontSize;
6183
- return result;
6417
+ return this.selectionOps.getStyle();
6184
6418
  }
6185
6419
  applyStyleToSelection(style) {
6186
- const ids = this.getSelectedIds();
6187
- if (ids.length === 0) return;
6188
- this.historyRecorder.begin();
6189
- for (const id of ids) {
6190
- const el = this.store.getById(id);
6191
- if (!el) continue;
6192
- const patch = styleToPatch(el, style);
6193
- if (Object.keys(patch).length > 0) {
6194
- this.store.update(id, patch);
6195
- }
6196
- }
6197
- this.historyRecorder.commit();
6420
+ this.selectionOps.applyStyle(style);
6198
6421
  }
6199
6422
  groupSelection() {
6200
- const ids = this.getSelectedIds();
6201
- if (ids.length < 2) return;
6202
- const groupId = createId("group");
6203
- this.historyRecorder.begin();
6204
- for (const id of ids) {
6205
- if (this.store.getById(id)) this.store.update(id, { groupId });
6206
- }
6207
- this.historyRecorder.commit();
6423
+ this.selectionOps.group();
6208
6424
  }
6209
6425
  ungroupSelection() {
6210
- const ids = this.getSelectedIds();
6211
- if (ids.length === 0) return;
6212
- this.historyRecorder.begin();
6213
- for (const id of ids) {
6214
- const el = this.store.getById(id);
6215
- if (el && el.groupId !== void 0) this.store.update(id, { groupId: void 0 });
6216
- }
6217
- this.historyRecorder.commit();
6426
+ this.selectionOps.ungroup();
6218
6427
  }
6219
6428
  toggleLockSelection() {
6220
- const ids = this.getSelectedIds();
6221
- if (ids.length === 0) return;
6222
- const anyUnlocked = ids.some((id) => {
6223
- const el = this.store.getById(id);
6224
- return el ? !el.locked : false;
6225
- });
6226
- this.historyRecorder.begin();
6227
- for (const id of ids) {
6228
- const el = this.store.getById(id);
6229
- if (el && el.locked !== anyUnlocked) this.store.update(id, { locked: anyUnlocked });
6230
- }
6231
- this.historyRecorder.commit();
6429
+ this.selectionOps.toggleLock();
6232
6430
  }
6233
6431
  alignSelection(edge) {
6234
- const bounded = this.boundedSelection();
6235
- if (bounded.length < 2) return;
6236
- const B = unionBounds(bounded.map((e) => e.bounds));
6237
- this.historyRecorder.begin();
6238
- const moved = [];
6239
- for (const { id, el, bounds: b } of bounded) {
6240
- if (!this.isMovable(el)) continue;
6241
- let dx = 0;
6242
- let dy = 0;
6243
- switch (edge) {
6244
- case "left":
6245
- dx = B.x - b.x;
6246
- break;
6247
- case "right":
6248
- dx = B.x + B.w - (b.x + b.w);
6249
- break;
6250
- case "center-x":
6251
- dx = B.x + B.w / 2 - (b.x + b.w / 2);
6252
- break;
6253
- case "top":
6254
- dy = B.y - b.y;
6255
- break;
6256
- case "bottom":
6257
- dy = B.y + B.h - (b.y + b.h);
6258
- break;
6259
- case "middle":
6260
- dy = B.y + B.h / 2 - (b.y + b.h / 2);
6261
- break;
6262
- }
6263
- if (dx === 0 && dy === 0) continue;
6264
- this.store.update(id, translateElementPatch(el, dx, dy));
6265
- moved.push(id);
6266
- }
6267
- updateArrowsBoundToElements(moved, this.store);
6268
- this.historyRecorder.commit();
6269
- this.requestRender();
6432
+ this.selectionOps.align(edge);
6270
6433
  }
6271
6434
  distributeSelection(axis) {
6272
- const bounded = this.boundedSelection();
6273
- if (bounded.length < 3) return;
6274
- const center2 = (b) => axis === "horizontal" ? b.x + b.w / 2 : b.y + b.h / 2;
6275
- const sorted = [...bounded].sort((p, q) => center2(p.bounds) - center2(q.bounds));
6276
- const first = sorted[0];
6277
- const last = sorted[sorted.length - 1];
6278
- if (!first || !last) return;
6279
- const c0 = center2(first.bounds);
6280
- const cN = center2(last.bounds);
6281
- const n = sorted.length;
6282
- this.historyRecorder.begin();
6283
- const moved = [];
6284
- for (let i = 1; i < n - 1; i++) {
6285
- const item = sorted[i];
6286
- if (!item || !this.isMovable(item.el)) continue;
6287
- const target = c0 + i * (cN - c0) / (n - 1);
6288
- const delta = target - center2(item.bounds);
6289
- if (delta === 0) continue;
6290
- const [dx, dy] = axis === "horizontal" ? [delta, 0] : [0, delta];
6291
- this.store.update(item.id, translateElementPatch(item.el, dx, dy));
6292
- moved.push(item.id);
6293
- }
6294
- updateArrowsBoundToElements(moved, this.store);
6295
- this.historyRecorder.commit();
6296
- this.requestRender();
6297
- }
6298
- boundedSelection() {
6299
- const out = [];
6300
- for (const id of this.getSelectedIds()) {
6301
- const el = this.store.getById(id);
6302
- if (!el) continue;
6303
- const bounds = getElementBounds(el);
6304
- if (bounds) out.push({ id, el, bounds });
6305
- }
6306
- return out;
6307
- }
6308
- isMovable(el) {
6309
- if (el.locked) return false;
6310
- if (el.type === "arrow" && (el.fromBinding ?? el.toBinding)) return false;
6311
- return true;
6435
+ this.selectionOps.distribute(axis);
6312
6436
  }
6313
6437
  getRenderStats() {
6314
6438
  return this.renderLoop.getStats();
@@ -6517,43 +6641,6 @@ var Viewport = class {
6517
6641
  }
6518
6642
  }
6519
6643
  }
6520
- createWrapper() {
6521
- const el = document.createElement("div");
6522
- Object.assign(el.style, {
6523
- position: "relative",
6524
- width: "100%",
6525
- height: "100%",
6526
- overflow: "hidden",
6527
- overscrollBehavior: "none",
6528
- userSelect: "none",
6529
- webkitUserSelect: "none"
6530
- });
6531
- return el;
6532
- }
6533
- createCanvas() {
6534
- const el = document.createElement("canvas");
6535
- Object.assign(el.style, {
6536
- position: "absolute",
6537
- top: "0",
6538
- left: "0",
6539
- width: "100%",
6540
- height: "100%"
6541
- });
6542
- return el;
6543
- }
6544
- createDomLayer() {
6545
- const el = document.createElement("div");
6546
- Object.assign(el.style, {
6547
- position: "absolute",
6548
- top: "0",
6549
- left: "0",
6550
- width: "100%",
6551
- height: "100%",
6552
- pointerEvents: "none",
6553
- transformOrigin: "0 0"
6554
- });
6555
- return el;
6556
- }
6557
6644
  applyCameraTransform() {
6558
6645
  this.domLayer.style.transform = this.camera.toCSSTransform();
6559
6646
  }
@@ -6563,25 +6650,6 @@ var Viewport = class {
6563
6650
  this.renderLoop.setCanvasSize(rect.width * dpr, rect.height * dpr);
6564
6651
  this.requestRender();
6565
6652
  }
6566
- syncGridContext() {
6567
- const grid = this.store.getElementsByType("grid")[0];
6568
- if (grid) {
6569
- this.toolContext.gridSize = grid.cellSize;
6570
- this.toolContext.gridType = grid.gridType;
6571
- this.toolContext.hexOrientation = grid.hexOrientation;
6572
- } else {
6573
- this.toolContext.gridSize = this._gridSize;
6574
- this.toolContext.gridType = void 0;
6575
- this.toolContext.hexOrientation = void 0;
6576
- }
6577
- this.notifyGridChangeListeners();
6578
- }
6579
- notifyGridChangeListeners() {
6580
- const info = this.getGridInfo();
6581
- for (const listener of this.gridChangeListeners) {
6582
- listener(info);
6583
- }
6584
- }
6585
6653
  observeResize() {
6586
6654
  if (typeof ResizeObserver === "undefined") return;
6587
6655
  this.resizeObserver = new ResizeObserver(() => this.syncCanvasSize());
@@ -8895,7 +8963,7 @@ var TemplateTool = class {
8895
8963
  };
8896
8964
 
8897
8965
  // src/index.ts
8898
- var VERSION = "0.38.0";
8966
+ var VERSION = "0.38.2";
8899
8967
  export {
8900
8968
  ArrowTool,
8901
8969
  AutoSave,