@weasel-js/guides 1.10.0 → 1.11.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/index.js CHANGED
@@ -1,16 +1,20 @@
1
- import { pointToGridCell } from './chunk-TLFMAZ6M.js';
2
- export { gridSnapStrategy, pointToGridCell } from './chunk-TLFMAZ6M.js';
3
- export { pointSnapToGrid } from './chunk-B25KFI3I.js';
4
- import { guideOffsetOn } from './chunk-LOFNN7EQ.js';
5
- export { DEFAULT_GUIDE_TOLERANCE_PX, guideSnapStrategy } from './chunk-LOFNN7EQ.js';
6
1
  import { useState, useRef, useCallback, useEffect } from 'react';
7
- import { useLatest, resolveAxes, pxExtent, textCommandFromRuns, AUTO_POSE_DESCRIPTOR, visualBoundsViaDescriptor, rectFromPlane, translatePoseViaDescriptor, unionBounds, fixedCornerOf, createTransformOp, resolveStrokeWidth, screenToWorld, rectToPlane, screenTolerance } from '@weasel-js/core';
8
- import { rectPath, PATH_M, PATH_L } from '@weasel-js/geom';
2
+ import { resolveAxes, useLatest, viewportWorldRect, pxExtent, tickedSegment, measuredSegmentCommands, AUTO_POSE_DESCRIPTOR, visualBoundsViaDescriptor, rectFromPlane, scenePoseFrame, unionAABB, createTransformOp, screenToWorld, nodeGates, resolveStrokeWidth } from '@weasel-js/core';
3
+ import { PATH_M, PATH_L } from '@weasel-js/geom';
9
4
 
10
5
  // src/grid/roundToCell.ts
11
6
  function roundToCell(value, cellSize) {
12
7
  return Math.round(value / cellSize) * cellSize || 0;
13
8
  }
9
+ function pointToGridCell(point, spacing, unitSystem, origin = { x: 0, y: 0 }) {
10
+ const s = resolveAxes(spacing, unitSystem);
11
+ return {
12
+ col: Math.floor((point.x - origin.x) / s.x),
13
+ row: Math.floor((point.y - origin.y) / s.y)
14
+ };
15
+ }
16
+
17
+ // src/grid/useGridCellHover.ts
14
18
  function cellsEqual(a, b) {
15
19
  if (a === b) return true;
16
20
  if (a === null || b === null) return false;
@@ -64,6 +68,7 @@ var DEFAULT_SUB = {
64
68
  paint: { kind: "solid", color: "rgba(255, 255, 255, 0.04)" },
65
69
  width: 1
66
70
  };
71
+ var MIN_SCREEN_SPACING = 4;
67
72
  function createGridLayer(opts) {
68
73
  const line = opts.style?.line ?? DEFAULT_LINE;
69
74
  const accent = opts.style?.accent ?? DEFAULT_ACCENT;
@@ -71,11 +76,11 @@ function createGridLayer(opts) {
71
76
  return {
72
77
  id: "grid",
73
78
  label: "Grid",
74
- draw: (_data, view) => {
75
- const b = opts.bounds();
76
- if (b.width <= 0 || b.height <= 0) return [];
79
+ draw: (_data, view, dims) => {
77
80
  const { accentEvery, subdivisions } = opts;
78
81
  const spacing = resolveAxes(opts.spacing, opts.unitSystem);
82
+ const b = opts.bounds ? opts.bounds(view, dims) : onLattice(viewportWorldRect(view, dims), spacing, accentEvery && accentEvery > 0 ? accentEvery : 1);
83
+ if (!(b.width > 0 && b.height > 0 && Number.isFinite(b.width) && Number.isFinite(b.height))) return [];
79
84
  const x0 = b.x;
80
85
  const y0 = b.y;
81
86
  const x1 = b.x + b.width;
@@ -89,55 +94,47 @@ function createGridLayer(opts) {
89
94
  coords: new Float32Array([sx, sy, ex, ey]),
90
95
  fillRule: "nonzero"
91
96
  };
92
- const across2 = sx === ex ? px.x : px.y;
97
+ const across = sx === ex ? px.x : px.y;
93
98
  children.push({
94
99
  kind: "path",
95
100
  path,
96
- stroke: { ...s, width: resolveStrokeWidth(s.width ?? 1, 1) * across2 }
101
+ stroke: { ...s, width: resolveStrokeWidth(s.width ?? 1, 1) * across }
97
102
  });
98
103
  };
99
- if (subdivisions && subdivisions > 1) {
100
- const stepX = spacing.x / subdivisions;
101
- for (let x = x0; x <= x1 + 1e-9; x += stepX) {
102
- const k = Math.round((x - x0) / stepX);
103
- if (k % subdivisions === 0) continue;
104
- pushSegment(x, y0, x, y1, sub);
105
- }
106
- const stepY = spacing.y / subdivisions;
107
- for (let y = y0; y <= y1 + 1e-9; y += stepY) {
108
- const k = Math.round((y - y0) / stepY);
109
- if (k % subdivisions === 0) continue;
110
- pushSegment(x0, y, x1, y, sub);
104
+ const family = (axis, step, skipEvery, s) => {
105
+ if (!(step * Math.abs(view.scale[axis]) >= MIN_SCREEN_SPACING)) return;
106
+ const [from, to] = axis === "x" ? [x0, x1] : [y0, y1];
107
+ for (let k = 0; from + k * step <= to + 1e-9; k++) {
108
+ if (skipEvery > 0 && k % skipEvery === 0) continue;
109
+ const at = from + k * step;
110
+ if (axis === "x") pushSegment(at, y0, at, y1, s);
111
+ else pushSegment(x0, at, x1, at, s);
111
112
  }
113
+ };
114
+ const accentOn = accentEvery !== void 0 && accentEvery > 0;
115
+ for (const axis of ["x", "y"]) {
116
+ if (subdivisions && subdivisions > 1) family(axis, spacing[axis] / subdivisions, subdivisions, sub);
112
117
  }
113
- let idx = 0;
114
- for (let x = x0; x <= x1 + 1e-9; x += spacing.x) {
115
- const isAccent = !!accentEvery && accentEvery > 0 && idx % accentEvery === 0;
116
- if (!isAccent) pushSegment(x, y0, x, y1, line);
117
- idx++;
118
- }
119
- idx = 0;
120
- for (let y = y0; y <= y1 + 1e-9; y += spacing.y) {
121
- const isAccent = !!accentEvery && accentEvery > 0 && idx % accentEvery === 0;
122
- if (!isAccent) pushSegment(x0, y, x1, y, line);
123
- idx++;
124
- }
125
- if (accentEvery && accentEvery > 0) {
126
- idx = 0;
127
- for (let x = x0; x <= x1 + 1e-9; x += spacing.x) {
128
- if (idx % accentEvery === 0) pushSegment(x, y0, x, y1, accent);
129
- idx++;
130
- }
131
- idx = 0;
132
- for (let y = y0; y <= y1 + 1e-9; y += spacing.y) {
133
- if (idx % accentEvery === 0) pushSegment(x0, y, x1, y, accent);
134
- idx++;
135
- }
118
+ for (const axis of ["x", "y"]) family(axis, spacing[axis], accentOn ? accentEvery : 0, line);
119
+ if (accentOn) {
120
+ for (const axis of ["x", "y"]) family(axis, spacing[axis] * accentEvery, 0, accent);
136
121
  }
137
122
  return children;
138
123
  }
139
124
  };
140
125
  }
126
+ function onLattice(r, spacing, accentEvery) {
127
+ const px = spacing.x * accentEvery;
128
+ const py = spacing.y * accentEvery;
129
+ const x = Math.floor(r.x / px) * px;
130
+ const y = Math.floor(r.y / py) * py;
131
+ return {
132
+ x,
133
+ y,
134
+ width: Math.ceil((r.x + r.width) / px) * px - x,
135
+ height: Math.ceil((r.y + r.height) / py) * py - y
136
+ };
137
+ }
141
138
  var DEFAULT_FILL = { paint: { kind: "solid", color: "rgba(127,176,105,0.15)" } };
142
139
  function createCellHighlightLayer(opts) {
143
140
  const fill = opts.fill ?? DEFAULT_FILL;
@@ -190,24 +187,6 @@ function useGuides(initial = []) {
190
187
  return { guides, getGuides, addGuide, removeGuide, clearGuides };
191
188
  }
192
189
  var DEFAULT_COLOR = "#3aa0ff";
193
- var LABEL_FONT = { fontSize: 10 };
194
- var LABEL_CHAR_W = 6;
195
- var LABEL_H = 14;
196
- var LABEL_PAD_X = 4;
197
- function tickedSegment(x0, y0, x1, y1, t) {
198
- const h = t / 2;
199
- const vertical = x0 === x1;
200
- const ends = t <= 0 ? [] : vertical ? [x0 - h, y0, x0 + h, y0, x1 - h, y1, x1 + h, y1] : [x0, y0 - h, x0, y0 + h, x1, y1 - h, x1, y1 + h];
201
- const coords = [x0, y0, x1, y1, ...ends];
202
- const commands = [];
203
- for (let i = 0; i < coords.length; i += 4) commands.push(PATH_M, PATH_L);
204
- return {
205
- kind: "polygon",
206
- commands: new Uint8Array(commands),
207
- coords: new Float32Array(coords),
208
- fillRule: "nonzero"
209
- };
210
- }
211
190
  function createGuidesLayer(opts) {
212
191
  const lineWidth = opts.lineWidth ?? 1;
213
192
  const color = opts.color ?? DEFAULT_COLOR;
@@ -244,19 +223,7 @@ function createGuidesLayer(opts) {
244
223
  }
245
224
  for (const g of gaps) {
246
225
  const [x0, y0, x1, y1] = g.axis === "x" ? [sx(g.min), sy(g.at), sx(g.max), sy(g.at)] : [sx(g.at), sy(g.min), sx(g.at), sy(g.max)];
247
- out.push({ kind: "path", path: tickedSegment(x0, y0, x1, y1, ticks), stroke: gapStroke });
248
- if (format === null) continue;
249
- const text = format(g.max - g.min);
250
- const w = text.length * LABEL_CHAR_W + LABEL_PAD_X * 2;
251
- const left = (x0 + x1) / 2 - w / 2;
252
- const top = (y0 + y1) / 2 - LABEL_H / 2;
253
- out.push({ kind: "path", path: rectPath(left, top, w, LABEL_H), fill: { paint: { kind: "solid", color: gapColor } } });
254
- out.push(textCommandFromRuns(
255
- left + LABEL_PAD_X,
256
- top + 2,
257
- [{ text, fill: { paint: { kind: "solid", color: "#fff" } } }],
258
- LABEL_FONT
259
- ));
226
+ out.push(...measuredSegmentCommands(x0, y0, x1, y1, ticks, gapStroke, format?.(g.max - g.min) ?? null, gapColor));
260
227
  }
261
228
  return out;
262
229
  }
@@ -302,57 +269,6 @@ function deriveAlignmentGuides(targets, opts = {}) {
302
269
  return [...seenX.values(), ...seenY.values()];
303
270
  }
304
271
 
305
- // src/guides/alignment/match.ts
306
- var MOVE_ANCHORS = {
307
- x: ["min", "center", "max"],
308
- y: ["min", "center", "max"]
309
- };
310
- function featureOffset(b, axis, anchor) {
311
- if (axis === "x") {
312
- if (anchor === "min") return b.x;
313
- if (anchor === "center") return b.x + b.width / 2;
314
- return b.x + b.width;
315
- }
316
- if (anchor === "min") return b.y;
317
- if (anchor === "center") return b.y + b.height / 2;
318
- return b.y + b.height;
319
- }
320
- function bestAxis(b, axis, anchors, candidates, worldTolerance) {
321
- let bestAbs = Infinity;
322
- let bestDelta = 0;
323
- let bestGuide = null;
324
- for (const anchor of anchors) {
325
- const o = featureOffset(b, axis, anchor);
326
- for (const g of candidates) {
327
- if (g.axis !== axis) continue;
328
- const d = g.offset - o;
329
- const ad = Math.abs(d);
330
- if (ad <= worldTolerance && ad < bestAbs) {
331
- bestAbs = ad;
332
- bestDelta = d;
333
- bestGuide = g;
334
- }
335
- }
336
- }
337
- return { delta: bestGuide ? bestDelta : 0, guide: bestGuide };
338
- }
339
- function matchAlignment(bounds, candidates, worldTolerance, anchors) {
340
- const x = bestAxis(bounds, "x", anchors.x, candidates, worldTolerance.x);
341
- const y = bestAxis(bounds, "y", anchors.y, candidates, worldTolerance.y);
342
- const top = bounds.y + y.delta;
343
- const left = bounds.x + x.delta;
344
- return {
345
- dx: x.delta,
346
- dy: y.delta,
347
- activeX: stretchSpan(x.guide, top, top + bounds.height),
348
- activeY: stretchSpan(y.guide, left, left + bounds.width)
349
- };
350
- }
351
- function stretchSpan(g, min, max) {
352
- if (g === null || g.span === void 0) return g;
353
- return { ...g, span: { min: Math.min(g.span.min, min), max: Math.max(g.span.max, max) } };
354
- }
355
-
356
272
  // src/guides/alignment/spacing.ts
357
273
  var EPS2 = 1e-6;
358
274
  var lo = (b, a) => a === "x" ? b.x : b.y;
@@ -373,9 +289,9 @@ function hitsStrip(g, b, span) {
373
289
  return lo(b, g.axis) < g.max - EPS2 && hi(b, g.axis) > g.min + EPS2 && lo(b, c) < span[1] - EPS2 && hi(b, c) > span[0] + EPS2;
374
290
  }
375
291
  function measureGaps(targets, axis) {
376
- return measure(targets, axis).map((m) => m.gap);
292
+ return measureGapSpans(targets, axis).map((m) => m.gap);
377
293
  }
378
- function measure(targets, axis) {
294
+ function measureGapSpans(targets, axis) {
379
295
  const out = [];
380
296
  for (const a of targets) {
381
297
  let next = null;
@@ -392,7 +308,7 @@ function measure(targets, axis) {
392
308
  }
393
309
  return out.sort((p, q) => p.gap.min - q.gap.min || p.gap.at - q.gap.at);
394
310
  }
395
- function bestAxis2(b, axis, edge, targets, refs, tol) {
311
+ function spacingOffers(b, axis, edge, targets, refs) {
396
312
  const bLo = lo(b, axis);
397
313
  const bHi = hi(b, axis);
398
314
  const size = bHi - bLo;
@@ -405,10 +321,9 @@ function bestAxis2(b, axis, edge, targets, refs, tol) {
405
321
  if (lo(t, axis) >= center && (right === null || lo(t, axis) < lo(right, axis))) right = t;
406
322
  }
407
323
  const sizes = refs.map((g) => g.max - g.min);
408
- let best = null;
324
+ const out = [];
409
325
  const offer = (delta, gap) => {
410
- if (gap <= EPS2 || Math.abs(delta) > tol) return;
411
- if (best === null || Math.abs(delta) < Math.abs(best.delta)) best = { delta, size: gap };
326
+ if (gap > EPS2) out.push({ delta, size: gap });
412
327
  };
413
328
  const L = left === null ? null : hi(left, axis);
414
329
  const R = right === null ? null : lo(right, axis);
@@ -428,28 +343,39 @@ function bestAxis2(b, axis, edge, targets, refs, tol) {
428
343
  const own = R !== null ? [R - bHi] : [];
429
344
  for (const g of [...sizes, ...own]) if (L + g < bHi - EPS2) offer(L + g - bLo, g);
430
345
  }
346
+ return out;
347
+ }
348
+ function bestAxis(b, axis, edge, targets, refs, tol) {
349
+ let best = null;
350
+ for (const o of spacingOffers(b, axis, edge, targets, refs)) {
351
+ if (Math.abs(o.delta) > tol) continue;
352
+ if (best === null || Math.abs(o.delta) < Math.abs(best.delta)) best = o;
353
+ }
431
354
  return best;
432
355
  }
433
- function markers(b, axis, size, targets, refs) {
356
+ function equalGaps(b, axis, size, targets, refs) {
434
357
  const eq = (g) => Math.abs(g.max - g.min - size) < 1e-3;
435
358
  const out = refs.filter(eq);
436
- const own = measureGaps([...targets, b], axis).filter((g) => (Math.abs(g.max - lo(b, axis)) < EPS2 || Math.abs(g.min - hi(b, axis)) < EPS2) && eq(g));
359
+ const near = targets.filter((t) => hi(t, axis) > lo(b, axis) - size - EPS2 && lo(t, axis) < hi(b, axis) + size + EPS2);
360
+ const own = measureGaps([...near, b], axis).filter((g) => (Math.abs(g.max - lo(b, axis)) < EPS2 || Math.abs(g.min - hi(b, axis)) < EPS2) && eq(g));
437
361
  return [...out, ...own];
438
362
  }
363
+ function referenceGaps(bounds, measured) {
364
+ return measured.filter((m) => !hitsStrip(m.gap, bounds, m.span)).map((m) => m.gap);
365
+ }
439
366
  function matchSpacing(bounds, targets, worldTolerance, moving = { x: "both", y: "both" }) {
440
- const refsFor = (axis) => measure(targets, axis).filter((m) => !hitsStrip(m.gap, bounds, m.span)).map((m) => m.gap);
441
- const refsX = refsFor("x");
442
- const refsY = refsFor("y");
443
- const x = moving.x === null ? null : bestAxis2(bounds, "x", moving.x, targets, refsX, worldTolerance.x);
444
- const y = moving.y === null ? null : bestAxis2(bounds, "y", moving.y, targets, refsY, worldTolerance.y);
367
+ const refsX = referenceGaps(bounds, measureGapSpans(targets, "x"));
368
+ const refsY = referenceGaps(bounds, measureGapSpans(targets, "y"));
369
+ const x = moving.x === null ? null : bestAxis(bounds, "x", moving.x, targets, refsX, worldTolerance.x);
370
+ const y = moving.y === null ? null : bestAxis(bounds, "y", moving.y, targets, refsY, worldTolerance.y);
445
371
  const dx = x?.delta ?? 0;
446
372
  const dy = y?.delta ?? 0;
447
373
  const final = applyEdges(bounds, dx, dy, moving);
448
374
  return {
449
375
  dx,
450
376
  dy,
451
- gapsX: x === null ? [] : markers(final, "x", x.size, targets, refsX),
452
- gapsY: y === null ? [] : markers(final, "y", y.size, targets, refsY)
377
+ gapsX: x === null ? [] : equalGaps(final, "x", x.size, targets, refsX),
378
+ gapsY: y === null ? [] : equalGaps(final, "y", y.size, targets, refsY)
453
379
  };
454
380
  }
455
381
  function applyEdges(b, dx, dy, moving) {
@@ -466,223 +392,378 @@ function applyEdges(b, dx, dy, moving) {
466
392
  } else if (moving.y === "max") height += dy;
467
393
  return { x, y, width, height };
468
394
  }
469
- var across = (axis) => axis === "x" ? "y" : "x";
470
- var into = (m, axis, v) => v * m.scale[axis] + m.offset[axis];
471
- var outOf = (m, axis, v) => (v - m.offset[axis]) / m.scale[axis];
472
- function range(r, map) {
473
- const a = map(r.min);
474
- const b = map(r.max);
475
- return { ...r, min: Math.min(a, b), max: Math.max(a, b) };
476
- }
477
- function guideToPlane(g, m) {
478
- const span = g.span && range(g.span, (v) => into(m, across(g.axis), v));
479
- return { ...g, offset: guideOffsetOn(g, m), ...span ? { span } : {} };
480
- }
481
- function guideFromPlane(g, m) {
482
- const span = g.span && range(g.span, (v) => outOf(m, across(g.axis), v));
483
- return { ...g, offset: outOf(m, g.axis, g.offset), ...span ? { span } : {} };
484
- }
485
- function gapFromPlane(g, m) {
486
- return { ...range(g, (v) => outOf(m, g.axis, v)), at: outOf(m, across(g.axis), g.at) };
487
- }
488
- function alignmentOnPlane(args, plane) {
489
- if (!plane) return args;
490
- const spacing = args.getSpacingTargets;
491
- const setGaps = args.setActiveGaps;
492
- return {
493
- ...args,
494
- getCandidates: () => args.getCandidates().map((g) => guideToPlane(g, plane)),
495
- setActiveGuides: (guides) => args.setActiveGuides(guides.map((g) => guideFromPlane(g, plane))),
496
- ...spacing ? { getSpacingTargets: () => spacing().map((b) => rectToPlane(plane, b)) } : {},
497
- ...setGaps ? { setActiveGaps: (gaps) => setGaps(gaps.map((g) => gapFromPlane(g, plane))) } : {}
498
- };
395
+ function worldBoundsOf(scene, ids, opts = {}) {
396
+ const d = opts.poseDescriptor ?? AUTO_POSE_DESCRIPTOR;
397
+ const frame = scenePoseFrame(scene);
398
+ const out = [];
399
+ for (const id of ids) {
400
+ if (scene.get(id) === void 0) continue;
401
+ out.push(visualBoundsViaDescriptor(frame.world(id), d));
402
+ }
403
+ return out;
499
404
  }
500
-
501
- // src/guides/alignment/behaviors.ts
502
- var activeList = (m) => [m.activeX, m.activeY].filter((g) => g !== null);
503
- var EXACT = { x: 1e-6, y: 1e-6 };
504
- function resolve(b, args, tol, anchors, edges) {
505
- const candidates = args.getCandidates();
506
- const m = matchAlignment(b, candidates, tol, anchors);
507
- const targets = args.getSpacingTargets?.();
508
- if (targets === void 0) {
509
- if (m.activeX === null && m.activeY === null) return null;
510
- return { dx: m.dx, dy: m.dy, guides: activeList(m), gaps: [] };
405
+ function worldUnionOf(scene, ids, opts = {}) {
406
+ const boxes = worldBoundsOf(scene, ids, opts);
407
+ return boxes.length === 0 ? null : unionAABB(boxes);
408
+ }
409
+ function siblingIds(scene, ids) {
410
+ const moving = new Set(ids);
411
+ const gates = nodeGates(scene);
412
+ const parents = /* @__PURE__ */ new Set();
413
+ for (const id of ids) {
414
+ const node = scene.get(id);
415
+ if (node !== void 0) parents.add(node.parent);
511
416
  }
512
- const s = matchSpacing(b, targets, tol, edges);
513
- const pick = (hit, d, spaced, sd) => hit && (!spaced || Math.abs(d) <= Math.abs(sd)) ? d : spaced ? sd : null;
514
- const dx = pick(m.activeX !== null, m.dx, s.gapsX.length > 0, s.dx);
515
- const dy = pick(m.activeY !== null, m.dy, s.gapsY.length > 0, s.dy);
516
- if (dx === null && dy === null) return null;
517
- const settled = applyEdges(b, dx ?? 0, dy ?? 0, edges);
518
- const shown = matchSpacing(settled, targets, EXACT, edges);
519
- return {
520
- dx: dx ?? 0,
521
- dy: dy ?? 0,
522
- guides: activeList(matchAlignment(settled, candidates, EXACT, anchors)),
523
- gaps: [...shown.gapsX, ...shown.gapsY]
524
- };
417
+ const siblings = [];
418
+ for (const parent of parents) {
419
+ for (const id of parent === null ? scene.roots : scene.childrenOf(parent)) {
420
+ const node = scene.get(id);
421
+ if (moving.has(id) || node === void 0 || gates.hidden(id)) continue;
422
+ siblings.push(id);
423
+ }
424
+ }
425
+ return siblings;
426
+ }
427
+ function siblingBounds(scene, ids, opts = {}) {
428
+ return worldBoundsOf(scene, siblingIds(scene, ids), opts);
429
+ }
430
+
431
+ // src/strategies/onPlane.ts
432
+ function guideOffsetOn(g, plane) {
433
+ return plane ? g.offset * plane.scale[g.axis] + plane.offset[g.axis] : g.offset;
434
+ }
435
+ function roundToGridOn(value, axis, spacing, plane) {
436
+ if (!plane) return Math.round(value / spacing) * spacing;
437
+ const camera = (value - plane.offset[axis]) / plane.scale[axis];
438
+ return Math.round(camera / spacing) * spacing * plane.scale[axis] + plane.offset[axis];
525
439
  }
526
- function publish(args, r) {
527
- args.setActiveGuides(r?.guides ?? []);
528
- args.setActiveGaps?.(r?.gaps ?? []);
440
+
441
+ // src/sources/lines.ts
442
+ function axisLine(axis, offset, near) {
443
+ return axis === "x" ? { at: { x: offset, y: near.y }, dirs: [{ x: 0, y: 1 }] } : { at: { x: near.x, y: offset }, dirs: [{ x: 1, y: 0 }] };
529
444
  }
530
- function worldTol(base, ctx) {
531
- return screenTolerance(base.tolerance ?? 6, ctx);
445
+ function landedShift(q, delta) {
446
+ return { x: delta.x - q.delta0.x, y: delta.y - q.delta0.y };
532
447
  }
533
- function alignMoveBehavior(given) {
534
- const d = given.poseDescriptor ?? AUTO_POSE_DESCRIPTOR;
448
+
449
+ // src/sources/grid.ts
450
+ function gridSnapSource(opts) {
451
+ const pitch = resolveAxes(opts.spacing, opts.unitSystem);
452
+ const o = opts.origin ?? { x: 0, y: 0 };
453
+ const lines = (v, axis, plane) => {
454
+ const s = plane ? plane.scale[axis] : 1;
455
+ const near = roundToGridOn(v - o[axis] * s, axis, pitch[axis], plane) + o[axis] * s;
456
+ const step = pitch[axis] * s;
457
+ return [near, near + (v >= near ? step : -step)];
458
+ };
535
459
  return {
536
- onMove(ctx, transform) {
537
- const args = alignmentOnPlane(given, ctx.plane);
538
- if (args.bypassKey && ctx.modifiers[args.bypassKey]) {
539
- publish(args, null);
540
- return;
541
- }
542
- if (transform.kind !== "translate") return;
543
- const boxes = [];
544
- for (const id of ctx.draggedIds) {
545
- const originPose = ctx.origin.get(id);
546
- if (originPose === void 0) continue;
547
- boxes.push(visualBoundsViaDescriptor(
548
- translatePoseViaDescriptor(originPose, transform.dx, transform.dy, d),
549
- d
550
- ));
460
+ id: "grid",
461
+ tier: "fallback",
462
+ reachPx: Infinity,
463
+ roles: ["origin", "pointer"],
464
+ *collect(q) {
465
+ for (const p of q.probes) {
466
+ for (const axis of ["x", "y"]) {
467
+ for (const at of lines(p.at[axis], axis, q.plane ?? null)) yield { probe: p.id, locus: axisLine(axis, at, p.at) };
468
+ }
551
469
  }
552
- const union = unionBounds(boxes);
553
- if (union === null) return;
554
- const r = resolve(union, args, worldTol(args, ctx), MOVE_ANCHORS, { x: "both", y: "both" });
555
- publish(args, r);
556
- if (r === null) return;
557
- return { transform: { kind: "translate", dx: transform.dx + r.dx, dy: transform.dy + r.dy } };
558
- },
559
- onEnd() {
560
- publish(given, null);
561
- },
562
- onCancel() {
563
- publish(given, null);
564
470
  }
565
471
  };
566
472
  }
567
- function alignInsertBehavior(given) {
568
- const pointAnchors = { x: ["min"], y: ["min"] };
473
+
474
+ // src/sources/guides.ts
475
+ function guideSnapSource(getGuides) {
569
476
  return {
570
- onMove(ctx, { current }) {
571
- const args = alignmentOnPlane(given, ctx.plane);
572
- if (args.bypassKey && ctx.modifiers[args.bypassKey]) {
573
- args.setActiveGuides([]);
574
- return;
575
- }
576
- const box = { x: current.x, y: current.y, width: 0, height: 0 };
577
- const m = matchAlignment(box, args.getCandidates(), worldTol(args, ctx), pointAnchors);
578
- if (m.activeX === null && m.activeY === null) {
579
- args.setActiveGuides([]);
580
- return;
477
+ id: "guides",
478
+ roles: ["origin", "pointer"],
479
+ *collect(q) {
480
+ const guides = getGuides();
481
+ if (guides.length === 0) return;
482
+ const reach = q.reachWorld(q.reachPx);
483
+ for (const p of q.probes) {
484
+ for (const g of guides) {
485
+ const offset = guideOffsetOn(g, q.plane ?? null);
486
+ if (Math.abs(p.at[g.axis] - offset) > reach) continue;
487
+ yield { probe: p.id, locus: axisLine(g.axis, offset, p.at) };
488
+ }
581
489
  }
582
- args.setActiveGuides(activeList(m));
583
- return { current: { x: current.x + m.dx, y: current.y + m.dy } };
584
- },
585
- onEnd() {
586
- given.setActiveGuides([]);
587
- },
588
- onCancel() {
589
- given.setActiveGuides([]);
590
490
  }
591
491
  };
592
492
  }
593
- function alignResizeBehavior(given) {
594
- const d = given.poseDescriptor ?? AUTO_POSE_DESCRIPTOR;
493
+
494
+ // src/guides/alignment/match.ts
495
+ function stretchSpan(g, min, max) {
496
+ if (g === null || g.span === void 0) return g;
497
+ return { ...g, span: { min: Math.min(g.span.min, min), max: Math.max(g.span.max, max) } };
498
+ }
499
+ function targetIds(scene, exclude) {
500
+ if (exclude.length > 0) return siblingIds(scene, exclude);
501
+ const gates = nodeGates(scene);
502
+ return scene.roots.filter((id) => !gates.hidden(id));
503
+ }
504
+ function targetBoxes(q, scene) {
505
+ const drawn = q.drawnBox;
506
+ return drawn ? targetIds(scene, q.exclude).flatMap((id) => drawn(id) ?? []) : [];
507
+ }
508
+ function cachedPerScene(derive) {
509
+ let key = null;
510
+ let value = null;
511
+ return (q) => {
512
+ const scene = q.scene;
513
+ if (!scene) return null;
514
+ const version = scene.getVersion();
515
+ const exclude = q.exclude.join("\n");
516
+ if (key === null || key.scene !== scene || key.version !== version || key.exclude !== exclude) {
517
+ value = derive(targetBoxes(q, scene));
518
+ key = { scene, version, exclude };
519
+ }
520
+ return value;
521
+ };
522
+ }
523
+
524
+ // src/sources/alignment.ts
525
+ function indexLines(lines) {
526
+ const sorted = [...lines].sort((a, b) => a.offset - b.offset);
527
+ return { x: sorted.filter((g) => g.axis === "x"), y: sorted.filter((g) => g.axis === "y") };
528
+ }
529
+ function* inReach(lines, v, reach) {
530
+ let lo3 = 0;
531
+ let hi3 = lines.length;
532
+ while (lo3 < hi3) {
533
+ const mid2 = lo3 + hi3 >> 1;
534
+ if (lines[mid2].offset < v - reach) lo3 = mid2 + 1;
535
+ else hi3 = mid2;
536
+ }
537
+ for (let i = lo3; i < lines.length && lines[i].offset <= v + reach; i++) yield lines[i];
538
+ }
539
+ var cross2 = (a) => a === "x" ? "y" : "x";
540
+ function lineMark(g, extent, color) {
541
+ const span = stretchSpan(g, extent[0], extent[1])?.span ?? { min: extent[0], max: extent[1] };
542
+ const ends = g.axis === "x" ? { from: { x: g.offset, y: span.min }, to: { x: g.offset, y: span.max } } : { from: { x: span.min, y: g.offset }, to: { x: span.max, y: g.offset } };
543
+ return { kind: "line", ...ends, ...color === void 0 ? {} : { color } };
544
+ }
545
+ function alignmentSnapSource(opts = {}) {
546
+ const page = () => (typeof opts.page === "function" ? opts.page() : opts.page) ?? void 0;
547
+ const fromScene = cachedPerScene((boxes) => indexLines(deriveAlignmentGuides(boxes)));
548
+ const linesFor = (q) => {
549
+ const pageBox = page();
550
+ const own = opts.getCandidates ? indexLines(opts.getCandidates()) : fromScene(q);
551
+ return [...own ? [own] : [], ...pageBox ? [indexLines(deriveAlignmentGuides([], { page: pageBox }))] : []];
552
+ };
595
553
  return {
596
- onMove(ctx, { pose, anchor }) {
597
- const args = alignmentOnPlane(given, ctx.plane);
598
- if (args.bypassKey && ctx.modifiers[args.bypassKey]) {
599
- publish(args, null);
600
- return;
601
- }
602
- const origin = ctx.origin.get(ctx.draggedIds[0]);
603
- const rotation = origin === void 0 ? 0 : d.getRotation?.(origin) ?? 0;
604
- const m = rotation === 0 ? matchMovingEdges(pose, anchor, args, worldTol(args, ctx)) : matchRotatedCorners(pose, anchor, d.getBounds(origin), rotation, args.getCandidates(), worldTol(args, ctx));
605
- if (m === null) {
606
- publish(args, null);
607
- return;
608
- }
609
- let { x, y, width, height } = pose;
610
- if (anchor.x === "min") width += m.lx;
611
- else if (anchor.x === "max") {
612
- x += m.lx;
613
- width -= m.lx;
614
- }
615
- if (anchor.y === "min") height += m.ly;
616
- else if (anchor.y === "max") {
617
- y += m.ly;
618
- height -= m.ly;
554
+ id: "alignment",
555
+ ...opts.reachPx === void 0 ? {} : { reachPx: opts.reachPx },
556
+ roles: ["box", "pointer"],
557
+ *collect(q) {
558
+ const indexes = linesFor(q);
559
+ if (indexes.length === 0) return;
560
+ const reach = q.reachWorld(q.reachPx);
561
+ const box = q.box ?? null;
562
+ const probes = q.probes.some((p) => p.role === "box") ? q.probes.filter((p) => p.role === "box") : q.probes;
563
+ for (const p of probes) {
564
+ for (const axis of ["x", "y"]) {
565
+ for (const index of indexes) {
566
+ for (const g of inReach(index[axis], p.at[axis], reach)) {
567
+ yield {
568
+ probe: p.id,
569
+ locus: axisLine(axis, g.offset, p.at),
570
+ mark: (delta) => lineMark(g, extentAcross(p, box, axis, landedShift(q, delta), q.edges), opts.color)
571
+ };
572
+ }
573
+ }
574
+ }
619
575
  }
620
- publish(args, { guides: m.guides, gaps: m.gaps });
621
- return { pose: { ...pose, x, y, width, height } };
622
- },
623
- onEnd() {
624
- publish(given, null);
625
- },
626
- onCancel() {
627
- publish(given, null);
628
576
  }
629
577
  };
630
578
  }
631
- function matchMovingEdges(pose, anchor, args, tol) {
632
- const moving = (a) => a === "min" ? "max" : a === "max" ? "min" : null;
633
- const edges = { x: moving(anchor.x), y: moving(anchor.y) };
634
- const anchors = {
635
- x: edges.x === null ? [] : [edges.x],
636
- y: edges.y === null ? [] : [edges.y]
637
- };
638
- const r = resolve(pose, args, tol, anchors, edges);
639
- return r === null ? null : { lx: r.dx, ly: r.dy, guides: r.guides, gaps: r.gaps };
640
- }
641
- function matchRotatedCorners(pose, anchor, originBox, rotation, candidates, tol) {
642
- const cos = Math.cos(rotation);
643
- const sin = Math.sin(rotation);
644
- const toWorld = (lx, ly) => ({ x: lx * cos - ly * sin, y: lx * sin + ly * cos });
645
- const fixedLocal = fixedCornerOf(pose, anchor);
646
- const f0 = fixedCornerOf(originBox, anchor);
647
- const pivot = toWorld(f0.x - originBox.x - originBox.width / 2, f0.y - originBox.y - originBox.height / 2);
648
- const fixedWorld = { x: originBox.x + originBox.width / 2 + pivot.x, y: originBox.y + originBox.height / 2 + pivot.y };
649
- const drawn = (lx, ly) => {
650
- const o = toWorld(lx - fixedLocal.x, ly - fixedLocal.y);
651
- return { x: fixedWorld.x + o.x, y: fixedWorld.y + o.y };
579
+ function extentAcross(p, box, axis, shift, edges = { x: "both", y: "both" }) {
580
+ const c = cross2(axis);
581
+ if (p.role !== "box" || box === null) return [p.at[c] + shift[c], p.at[c] + shift[c]];
582
+ const landed = applyEdges(box, shift.x, shift.y, edges);
583
+ const lo3 = c === "x" ? landed.x : landed.y;
584
+ return [lo3, lo3 + (c === "x" ? landed.width : landed.height)];
585
+ }
586
+
587
+ // src/sources/spacing.ts
588
+ var measureAll = (boxes) => ({ boxes, x: measureGapSpans(boxes, "x"), y: measureGapSpans(boxes, "y") });
589
+ function gapMark(g, color) {
590
+ const ends = g.axis === "x" ? { from: { x: g.min, y: g.at }, to: { x: g.max, y: g.at } } : { from: { x: g.at, y: g.min }, to: { x: g.at, y: g.max } };
591
+ return { kind: "gap", ...ends, value: g.max - g.min, ...color === void 0 ? {} : { color } };
592
+ }
593
+ function spacingSnapSource(opts = {}) {
594
+ const fromScene = cachedPerScene(measureAll);
595
+ return {
596
+ id: "spacing",
597
+ ...opts.reachPx === void 0 ? {} : { reachPx: opts.reachPx },
598
+ roles: ["box"],
599
+ gestures: ["move", "resize"],
600
+ *collect(q) {
601
+ const box = q.box;
602
+ const probe = q.probes.find((p) => p.role === "box");
603
+ const measured = opts.getTargets ? measureAll(opts.getTargets()) : fromScene(q);
604
+ if (!box || !probe || !measured) return;
605
+ const reach = q.reachWorld(q.reachPx);
606
+ const edges = q.edges ?? { x: "both", y: "both" };
607
+ for (const axis of ["x", "y"]) {
608
+ const edge = edges[axis];
609
+ if (edge === null) continue;
610
+ const refs = referenceGaps(box, measured[axis]);
611
+ const seen = /* @__PURE__ */ new Set();
612
+ for (const o of spacingOffers(box, axis, edge, measured.boxes, refs)) {
613
+ const key = `${o.delta.toFixed(6)}:${o.size.toFixed(6)}`;
614
+ if (Math.abs(o.delta) > reach || seen.has(key)) continue;
615
+ seen.add(key);
616
+ yield {
617
+ probe: probe.id,
618
+ locus: axisLine(axis, probe.at[axis] + o.delta, probe.at),
619
+ mark: (delta) => {
620
+ const shift = landedShift(q, delta);
621
+ const landed = applyEdges(box, shift.x, shift.y, edges);
622
+ return equalGaps(landed, axis, o.size, measured.boxes, refs).map((g) => gapMark(g, opts.color));
623
+ }
624
+ };
625
+ }
626
+ }
627
+ }
652
628
  };
653
- const movingEdge = (axis) => {
654
- const lo2 = axis === "x" ? pose.x : pose.y;
655
- const hi2 = lo2 + (axis === "x" ? pose.width : pose.height);
656
- const a = anchor[axis];
657
- return a === "min" ? [hi2] : a === "max" ? [lo2] : [lo2, hi2];
629
+ }
630
+
631
+ // src/spacingHints/distance.ts
632
+ var EPS3 = 1e-6;
633
+ var lo2 = (b, a) => a === "x" ? b.x : b.y;
634
+ var hi2 = (b, a) => a === "x" ? b.x + b.width : b.y + b.height;
635
+ var mid = (b, a) => (lo2(b, a) + hi2(b, a)) / 2;
636
+ var cross3 = (a) => a === "x" ? "y" : "x";
637
+ function measureDistances(from, to) {
638
+ const out = { gaps: [], leaders: [] };
639
+ for (const axis of ["x", "y"]) measureAxis(from, to, axis, out);
640
+ return out;
641
+ }
642
+ function measureAxis(from, to, axis, out) {
643
+ const c = cross3(axis);
644
+ const sharedMin = Math.max(lo2(from, c), lo2(to, c));
645
+ const sharedMax = Math.min(hi2(from, c), hi2(to, c));
646
+ const shares = sharedMax - sharedMin > EPS3;
647
+ const push = (min, max, at2) => {
648
+ if (max - min > EPS3) out.gaps.push({ axis, min, max, at: at2 });
658
649
  };
659
- if (anchor.x !== "free" && anchor.y !== "free") {
660
- const c = drawn(movingEdge("x")[0], movingEdge("y")[0]);
661
- const m = matchAlignment({ x: c.x, y: c.y, width: 0, height: 0 }, candidates, tol, { x: ["min"], y: ["min"] });
662
- if (m.activeX === null && m.activeY === null) return null;
663
- const lx = m.dx * cos + m.dy * sin;
664
- const ly = -m.dx * sin + m.dy * cos;
665
- return { lx, ly, guides: activeList(m), gaps: [] };
666
- }
667
- if (anchor.x === "free" && anchor.y === "free") return null;
668
- const along = anchor.x === "free" ? "y" : "x";
669
- const dir = along === "x" ? toWorld(1, 0) : toWorld(0, 1);
670
- const edge = movingEdge(along)[0];
671
- let best = null;
672
- for (const across3 of movingEdge(along === "x" ? "y" : "x")) {
673
- const c = along === "x" ? drawn(edge, across3) : drawn(across3, edge);
674
- for (const g of candidates) {
675
- const reach = g.axis === "x" ? dir.x : dir.y;
676
- if (Math.abs(reach) < 1e-9) continue;
677
- const t = (g.offset - (g.axis === "x" ? c.x : c.y)) / reach;
678
- if (Math.abs(t * dir.x) > tol.x || Math.abs(t * dir.y) > tol.y) continue;
679
- if (best === null || Math.abs(t) < Math.abs(best.t)) best = { t, guide: g, at: c };
650
+ const before = hi2(from, axis) <= lo2(to, axis) + EPS3;
651
+ const after = hi2(to, axis) <= lo2(from, axis) + EPS3;
652
+ if (before || after) {
653
+ const [min, max] = before ? [hi2(from, axis), lo2(to, axis)] : [hi2(to, axis), lo2(from, axis)];
654
+ if (max - min <= EPS3) return;
655
+ const at2 = shares ? (sharedMin + sharedMax) / 2 : mid(from, c);
656
+ push(min, max, at2);
657
+ if (!shares) {
658
+ const edge = before ? lo2(to, axis) : hi2(to, axis);
659
+ const span = at2 < lo2(to, c) ? { min: at2, max: lo2(to, c) } : { min: hi2(to, c), max: at2 };
660
+ out.leaders.push({ id: `distance:${axis}`, axis, offset: edge, span });
680
661
  }
662
+ return;
681
663
  }
682
- if (best === null) return null;
683
- const across2 = best.guide.axis === "x" ? best.at.y + best.t * dir.y : best.at.x + best.t * dir.x;
684
- const guides = [stretchSpan(best.guide, across2, across2)];
685
- return along === "x" ? { lx: best.t, ly: 0, guides, gaps: [] } : { lx: 0, ly: best.t, guides, gaps: [] };
664
+ if (!shares) return;
665
+ const [inner, outer] = lo2(from, axis) >= lo2(to, axis) - EPS3 && hi2(from, axis) <= hi2(to, axis) + EPS3 ? [from, to] : lo2(to, axis) >= lo2(from, axis) - EPS3 && hi2(to, axis) <= hi2(from, axis) + EPS3 ? [to, from] : [null, null];
666
+ if (inner === null || outer === null) return;
667
+ const at = mid(inner, c);
668
+ push(lo2(outer, axis), lo2(inner, axis), at);
669
+ push(hi2(inner, axis), hi2(outer, axis), at);
670
+ }
671
+
672
+ // src/spacingHints/distanceReadout.ts
673
+ function marksOf(r, color) {
674
+ const c = color === void 0 ? {} : { color };
675
+ return [
676
+ ...r.gaps.map((g) => g.axis === "x" ? { kind: "distance", from: { x: g.min, y: g.at }, to: { x: g.max, y: g.at }, value: g.max - g.min, ...c } : { kind: "distance", from: { x: g.at, y: g.min }, to: { x: g.at, y: g.max }, value: g.max - g.min, ...c }),
677
+ ...r.leaders.flatMap((l) => {
678
+ if (l.span === void 0) return [];
679
+ return [l.axis === "x" ? { kind: "line", from: { x: l.offset, y: l.span.min }, to: { x: l.offset, y: l.span.max }, ...c } : { kind: "line", from: { x: l.span.min, y: l.offset }, to: { x: l.span.max, y: l.offset }, ...c }];
680
+ })
681
+ ];
682
+ }
683
+ var EMPTY = { gaps: [], leaders: [] };
684
+ var MODIFIERS = ["alt", "ctrl", "meta", "shift"];
685
+ function subtreeOf(scene, ids) {
686
+ const out = /* @__PURE__ */ new Set();
687
+ const stack = [...ids];
688
+ while (stack.length > 0) {
689
+ const id = stack.pop();
690
+ if (out.has(id)) continue;
691
+ out.add(id);
692
+ stack.push(...scene.childrenOf(id));
693
+ }
694
+ return out;
695
+ }
696
+ function distanceReadout(opts = {}) {
697
+ const id = opts.id ?? "distanceReadout";
698
+ const modifier = opts.modifier ?? "alt";
699
+ let shown = EMPTY;
700
+ let store = null;
701
+ const show = (next) => {
702
+ if (next === shown || next.gaps.length === 0 && shown.gaps.length === 0) return;
703
+ shown = next;
704
+ store?.set(marksOf(next, opts.color));
705
+ };
706
+ const action = {
707
+ id: `${id}.measure`,
708
+ label: "Measure distance to the shape under the pointer",
709
+ requires: ["selection", "scene", "nodeAtPoint", "poseDescriptor", "snapReadout"],
710
+ invoker: {
711
+ timing: "immediate",
712
+ run: (deps, params) => {
713
+ const p = params;
714
+ const { selection, scene, nodeAtPoint, poseDescriptor, snapReadout } = deps;
715
+ if (snapReadout !== void 0) store = snapReadout.store;
716
+ const ids = selection?.get() ?? [];
717
+ if (p?.show !== true || p.worldX === void 0 || p.worldY === void 0 || scene === void 0 || nodeAtPoint === void 0 || ids.length === 0) {
718
+ show(EMPTY);
719
+ return;
720
+ }
721
+ const hit = nodeAtPoint({ x: p.worldX, y: p.worldY }, subtreeOf(scene, ids));
722
+ const from = worldUnionOf(scene, ids, { poseDescriptor });
723
+ const [to] = hit === null ? [] : worldBoundsOf(scene, [hit], { poseDescriptor });
724
+ show(from === null || to === void 0 ? EMPTY : measureDistances(from, to));
725
+ }
726
+ }
727
+ };
728
+ const mods = (held) => Object.fromEntries(
729
+ MODIFIERS.map((m) => [m, m === modifier ? held : "optional"])
730
+ );
731
+ const bindings = [
732
+ { spec: { kind: "hover", mods: mods(true) }, actionId: action.id, opts: { params: { show: true } } },
733
+ { spec: { kind: "hover", mods: mods(false) }, actionId: action.id, opts: { params: { show: false } } },
734
+ { spec: { kind: "hover", motion: "leave" }, actionId: action.id, opts: { params: { show: false } } }
735
+ ];
736
+ return {
737
+ id,
738
+ eligibility: { always: true },
739
+ actions: [action],
740
+ bindings,
741
+ attach: (api) => {
742
+ const el = api.element;
743
+ const hide = () => show(EMPTY);
744
+ el?.addEventListener("pointerdown", hide, true);
745
+ return () => {
746
+ el?.removeEventListener("pointerdown", hide, true);
747
+ show(EMPTY);
748
+ store = null;
749
+ };
750
+ },
751
+ read: () => shown
752
+ };
753
+ }
754
+
755
+ // src/spacingHints/preset.ts
756
+ function createSpacingHintsPreset(opts = {}) {
757
+ const id = opts.id ?? "spacingHints";
758
+ const color = opts.color === void 0 ? {} : { color: opts.color };
759
+ const own = { ...color, ...opts.tolerance === void 0 ? {} : { reachPx: opts.tolerance } };
760
+ const snapSources = [
761
+ ...opts.spacing ?? true ? [spacingSnapSource(own)] : [],
762
+ ...opts.align ?? false ? [alignmentSnapSource(own)] : []
763
+ ];
764
+ const contributions = [];
765
+ if (opts.readout !== false) contributions.push(distanceReadout({ ...opts.readout, ...color }));
766
+ return { id, snapSources, contributions };
686
767
  }
687
768
 
688
769
  // src/layout/snaps.ts
@@ -875,7 +956,7 @@ function tileGrid(opts) {
875
956
  if (fromIdx === null || fromIdx === idx) return null;
876
957
  return { occupant: occupant.id, from: occupant.pose, newPose: cellToPose(grid.rectAt(fromIdx), occupant.pose) };
877
958
  }
878
- function pack2(from, into2, children) {
959
+ function pack2(from, into, children) {
879
960
  const ordered = children.map((c) => ({ c, cell: from.indexOf(c.pose) })).sort((a, b) => {
880
961
  if (a.cell !== b.cell) {
881
962
  if (a.cell === null) return 1;
@@ -886,7 +967,7 @@ function tileGrid(opts) {
886
967
  });
887
968
  const out = /* @__PURE__ */ new Map();
888
969
  for (let i = 0; i < ordered.length; i++) {
889
- out.set(ordered[i].c.id, cellToPose(into2.rectAt(i), ordered[i].c.pose));
970
+ out.set(ordered[i].c.id, cellToPose(into.rectAt(i), ordered[i].c.pose));
890
971
  }
891
972
  return out;
892
973
  }
@@ -1457,6 +1538,6 @@ function ringSlots(opts = {}) {
1457
1538
  };
1458
1539
  }
1459
1540
 
1460
- export { MOVE_ANCHORS, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, cellAt, containedThenNearest, createCellHighlightLayer, createGridLayer, createGuidesLayer, deriveAlignmentGuides, freeform, gridSlots, matchAlignment, matchSpacing, measureGaps, nearest, nearestWithin, none, pack, perContainer, quadtree, ringSlots, roundToCell, rowSlots, sequenceLayout, slots, snapPoint, tileGrid, useGridCellHover, useGuides };
1541
+ export { alignmentSnapSource, cellAt, containedThenNearest, createCellHighlightLayer, createGridLayer, createGuidesLayer, createSpacingHintsPreset, deriveAlignmentGuides, distanceReadout, freeform, gridSlots, gridSnapSource, guideSnapSource, matchSpacing, measureDistances, measureGaps, nearest, nearestWithin, none, pack, perContainer, pointToGridCell, quadtree, ringSlots, roundToCell, rowSlots, sequenceLayout, siblingBounds, slots, snapPoint, spacingSnapSource, tileGrid, useGridCellHover, useGuides, worldBoundsOf, worldUnionOf };
1461
1542
  //# sourceMappingURL=index.js.map
1462
1543
  //# sourceMappingURL=index.js.map