{
  "version": 3,
  "sources": ["../../../../../src/lib/editor/managers/SnapManager/BoundsSnaps.ts"],
  "sourcesContent": ["import { computed } from '@tldraw/state'\nimport { TLShape, TLShapeId, VecModel } from '@tldraw/tlschema'\nimport { assertExists, dedupe, uniqueId } from '@tldraw/utils'\nimport {\n\tBox,\n\tSelectionCorner,\n\tSelectionEdge,\n\tflipSelectionHandleX,\n\tflipSelectionHandleY,\n\tisSelectionCorner,\n} from '../../../primitives/Box'\nimport { Mat } from '../../../primitives/Mat'\nimport { Vec } from '../../../primitives/Vec'\nimport { rangeIntersection, rangesOverlap } from '../../../primitives/utils'\nimport type { Editor } from '../../Editor'\nimport type {\n\tGapsSnapIndicator,\n\tPointsSnapIndicator,\n\tSnapData,\n\tSnapIndicator,\n\tSnapManager,\n} from './SnapManager'\n\n/**\n * When moving or resizing shapes, the bounds of the shape can snap to key geometry on other nearby\n * shapes. Customize how a shape snaps to others with {@link ShapeUtil.getBoundsSnapGeometry}.\n *\n * @public\n */\nexport interface BoundsSnapGeometry {\n\t/**\n\t * Points that this shape will snap to. By default, this will be the corners and center of the\n\t * shapes bounding box. To disable snapping to a specific point, use an empty array.\n\t */\n\tpoints?: VecModel[]\n}\n\n/** @public */\nexport interface BoundsSnapPoint {\n\tid: string\n\tx: number\n\ty: number\n\thandle?: SelectionCorner\n}\n\ninterface SnapPair {\n\tthisPoint: BoundsSnapPoint\n\totherPoint: BoundsSnapPoint\n}\n\ninterface NearestPointsSnap {\n\t// selection snaps to a nearby snap point\n\ttype: 'points'\n\tpoints: SnapPair\n\tnudge: number\n}\n\ntype NearestSnap =\n\t| NearestPointsSnap\n\t| {\n\t\t\t// selection snaps to the center of a gap\n\t\t\ttype: 'gap_center'\n\t\t\tgap: Gap\n\t\t\tnudge: number\n\t  }\n\t| {\n\t\t\t// selection snaps to create a new gap of equal size to another gap\n\t\t\t// on the opposite side of some shape\n\t\t\ttype: 'gap_duplicate'\n\t\t\tgap: Gap\n\t\t\tprotrusionDirection: 'left' | 'right' | 'top' | 'bottom'\n\t\t\tnudge: number\n\t  }\n\ninterface GapNode {\n\tid: TLShapeId\n\tpageBounds: Box\n}\n\ninterface Gap {\n\t// e.g.\n\t//      start\n\t//      edge     \u2502         breadth\n\t//               \u2502       intersection\n\t//               \u25BC        [40,100]           end\n\t//                            \u2502            \u2502 edge\n\t// \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 100,0      \u2502            \u2502\n\t// \u2502           \u2502 \u2502            \u25BC            \u25BC\n\t// \u2502           \u2502 \u2502\n\t// \u2502  start    \u2502 \u2502            \u2502     200,40 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\t// \u2502  node     \u2502 \u2502            \u2502            \u2502 \u2502           \u2502\n\t// \u2502           \u2502 \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 \u2502  end      \u2502\n\t// \u2502           \u2502 \u2502            \u2502            \u2502 \u2502  node     \u2502\n\t// \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 100,100    \u2502            \u2502 \u2502           \u2502\n\t//                                         \u2502 \u2502           \u2502\n\t//                                 200,120 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\t//\n\t//                       length 100\n\t//               \u25C4\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25BA\n\tstartNode: GapNode\n\tendNode: GapNode\n\tstartEdge: [Vec, Vec]\n\tendEdge: [Vec, Vec]\n\tlength: number\n\tbreadthIntersection: [number, number]\n}\n\nconst round = (x: number) => {\n\t// round numbers to avoid glitches for floating point rounding errors\n\tconst decimalPlacesTolerance = 8\n\treturn Math.round(x * 10 ** decimalPlacesTolerance) / 10 ** decimalPlacesTolerance\n}\n\nfunction findAdjacentGaps(\n\tgaps: Gap[],\n\tshapeId: TLShapeId,\n\tgapLength: number,\n\tdirection: 'forward' | 'backward',\n\tintersection: [number, number]\n): Gap[] {\n\t// TODO: take advantage of the fact that gaps is sorted by starting position?\n\tconst matches = gaps.filter(\n\t\t(gap) =>\n\t\t\t(direction === 'forward' ? gap.startNode.id === shapeId : gap.endNode.id === shapeId) &&\n\t\t\tround(gap.length) === round(gapLength) &&\n\t\t\trangeIntersection(\n\t\t\t\tgap.breadthIntersection[0],\n\t\t\t\tgap.breadthIntersection[1],\n\t\t\t\tintersection[0],\n\t\t\t\tintersection[1]\n\t\t\t)\n\t)\n\n\tif (matches.length === 0) return []\n\n\tconst nextNodes = new Set<TLShapeId>()\n\n\tmatches.forEach((match) => {\n\t\tconst node = direction === 'forward' ? match.endNode.id : match.startNode.id\n\t\tif (!nextNodes.has(node)) {\n\t\t\tnextNodes.add(node)\n\t\t\tconst foundGaps = findAdjacentGaps(\n\t\t\t\tgaps,\n\t\t\t\tnode,\n\t\t\t\tgapLength,\n\t\t\t\tdirection,\n\t\t\t\trangeIntersection(\n\t\t\t\t\tmatch.breadthIntersection[0],\n\t\t\t\t\tmatch.breadthIntersection[1],\n\t\t\t\t\tintersection[0],\n\t\t\t\t\tintersection[1]\n\t\t\t\t)!\n\t\t\t)\n\n\t\t\tmatches.push(...foundGaps)\n\t\t}\n\t})\n\n\treturn matches\n}\n\nfunction dedupeGapSnaps(snaps: Array<Extract<SnapIndicator, { type: 'gaps' }>>) {\n\t// sort by descending order of number of gaps\n\tsnaps.sort((a, b) => b.gaps.length - a.gaps.length)\n\t// pop off any that are included already\n\tfor (let i = snaps.length - 1; i > 0; i--) {\n\t\tconst snap = snaps[i]\n\t\tfor (let j = i - 1; j >= 0; j--) {\n\t\t\tconst otherSnap = snaps[j]\n\t\t\t// if every edge in this snap is included in the other snap somewhere, then it's redundant\n\t\t\tif (\n\t\t\t\totherSnap.direction === snap.direction &&\n\t\t\t\tsnap.gaps.every(\n\t\t\t\t\t(gap) =>\n\t\t\t\t\t\totherSnap.gaps.some(\n\t\t\t\t\t\t\t(otherGap) =>\n\t\t\t\t\t\t\t\tround(gap.startEdge[0].x) === round(otherGap.startEdge[0].x) &&\n\t\t\t\t\t\t\t\tround(gap.startEdge[0].y) === round(otherGap.startEdge[0].y) &&\n\t\t\t\t\t\t\t\tround(gap.startEdge[1].x) === round(otherGap.startEdge[1].x) &&\n\t\t\t\t\t\t\t\tround(gap.startEdge[1].y) === round(otherGap.startEdge[1].y)\n\t\t\t\t\t\t) &&\n\t\t\t\t\t\totherSnap.gaps.some(\n\t\t\t\t\t\t\t(otherGap) =>\n\t\t\t\t\t\t\t\tround(gap.endEdge[0].x) === round(otherGap.endEdge[0].x) &&\n\t\t\t\t\t\t\t\tround(gap.endEdge[0].y) === round(otherGap.endEdge[0].y) &&\n\t\t\t\t\t\t\t\tround(gap.endEdge[1].x) === round(otherGap.endEdge[1].x) &&\n\t\t\t\t\t\t\t\tround(gap.endEdge[1].y) === round(otherGap.endEdge[1].y)\n\t\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tsnaps.splice(i, 1)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** @public */\nexport class BoundsSnaps {\n\treadonly editor: Editor\n\tconstructor(readonly manager: SnapManager) {\n\t\tthis.editor = manager.editor\n\t}\n\n\t@computed private getSnapPointsCache() {\n\t\tconst { editor } = this\n\t\treturn editor.store.createComputedCache<BoundsSnapPoint[], TLShape>('snapPoints', (shape) => {\n\t\t\tconst pageTransform = editor.getShapePageTransform(shape.id)\n\t\t\tif (!pageTransform) return undefined\n\t\t\tconst boundsSnapGeometry = editor.getShapeUtil(shape).getBoundsSnapGeometry(shape)\n\t\t\tconst snapPoints =\n\t\t\t\tboundsSnapGeometry.points ?? editor.getShapeGeometry(shape).bounds.cornersAndCenter\n\n\t\t\tif (!pageTransform || !snapPoints) return undefined\n\t\t\treturn snapPoints.map((point, i) => {\n\t\t\t\tconst { x, y } = Mat.applyToPoint(pageTransform, point)\n\t\t\t\treturn { x, y, id: `${shape.id}:${i}` }\n\t\t\t})\n\t\t})\n\t}\n\n\tgetSnapPoints(shapeId: TLShapeId) {\n\t\treturn this.getSnapPointsCache().get(shapeId) ?? []\n\t}\n\n\t// Points which belong to snappable shapes\n\t@computed private getSnappablePoints() {\n\t\tconst snapPointsCache = this.getSnapPointsCache()\n\t\tconst snappableShapes = this.manager.getSnappableShapes()\n\t\tconst result: BoundsSnapPoint[] = []\n\n\t\tfor (const shapeId of snappableShapes) {\n\t\t\tconst snapPoints = snapPointsCache.get(shapeId)\n\t\t\tif (snapPoints) {\n\t\t\t\tresult.push(...snapPoints)\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n\n\t@computed private getSnappableGapNodes(): Array<GapNode> {\n\t\treturn Array.from(this.manager.getSnappableShapes(), (shapeId) => ({\n\t\t\tid: shapeId,\n\t\t\tpageBounds: assertExists(this.editor.getShapePageBounds(shapeId)),\n\t\t}))\n\t}\n\n\t@computed private getVisibleGaps(): { horizontal: Gap[]; vertical: Gap[] } {\n\t\tconst horizontal: Gap[] = []\n\t\tconst vertical: Gap[] = []\n\n\t\tlet startNode: GapNode, endNode: GapNode\n\n\t\tconst sortedShapesOnCurrentPageHorizontal = this.getSnappableGapNodes().sort((a, b) => {\n\t\t\treturn a.pageBounds.minX - b.pageBounds.minX\n\t\t})\n\n\t\t// Collect horizontal gaps\n\t\tfor (let i = 0; i < sortedShapesOnCurrentPageHorizontal.length; i++) {\n\t\t\tstartNode = sortedShapesOnCurrentPageHorizontal[i]\n\t\t\tfor (let j = i + 1; j < sortedShapesOnCurrentPageHorizontal.length; j++) {\n\t\t\t\tendNode = sortedShapesOnCurrentPageHorizontal[j]\n\n\t\t\t\tif (\n\t\t\t\t\t// is there space between the boxes\n\t\t\t\t\tstartNode.pageBounds.maxX < endNode.pageBounds.minX &&\n\t\t\t\t\t// and they overlap in the y axis\n\t\t\t\t\trangesOverlap(\n\t\t\t\t\t\tstartNode.pageBounds.minY,\n\t\t\t\t\t\tstartNode.pageBounds.maxY,\n\t\t\t\t\t\tendNode.pageBounds.minY,\n\t\t\t\t\t\tendNode.pageBounds.maxY\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\thorizontal.push({\n\t\t\t\t\t\tstartNode,\n\t\t\t\t\t\tendNode,\n\t\t\t\t\t\tstartEdge: [\n\t\t\t\t\t\t\tnew Vec(startNode.pageBounds.maxX, startNode.pageBounds.minY),\n\t\t\t\t\t\t\tnew Vec(startNode.pageBounds.maxX, startNode.pageBounds.maxY),\n\t\t\t\t\t\t],\n\t\t\t\t\t\tendEdge: [\n\t\t\t\t\t\t\tnew Vec(endNode.pageBounds.minX, endNode.pageBounds.minY),\n\t\t\t\t\t\t\tnew Vec(endNode.pageBounds.minX, endNode.pageBounds.maxY),\n\t\t\t\t\t\t],\n\t\t\t\t\t\tlength: endNode.pageBounds.minX - startNode.pageBounds.maxX,\n\t\t\t\t\t\tbreadthIntersection: rangeIntersection(\n\t\t\t\t\t\t\tstartNode.pageBounds.minY,\n\t\t\t\t\t\t\tstartNode.pageBounds.maxY,\n\t\t\t\t\t\t\tendNode.pageBounds.minY,\n\t\t\t\t\t\t\tendNode.pageBounds.maxY\n\t\t\t\t\t\t)!,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Collect vertical gaps\n\t\tconst sortedShapesOnCurrentPageVertical = sortedShapesOnCurrentPageHorizontal.sort((a, b) => {\n\t\t\treturn a.pageBounds.minY - b.pageBounds.minY\n\t\t})\n\n\t\tfor (let i = 0; i < sortedShapesOnCurrentPageVertical.length; i++) {\n\t\t\tstartNode = sortedShapesOnCurrentPageVertical[i]\n\t\t\tfor (let j = i + 1; j < sortedShapesOnCurrentPageVertical.length; j++) {\n\t\t\t\tendNode = sortedShapesOnCurrentPageVertical[j]\n\n\t\t\t\tif (\n\t\t\t\t\t// is there space between the boxes\n\t\t\t\t\tstartNode.pageBounds.maxY < endNode.pageBounds.minY &&\n\t\t\t\t\t// do they overlap in the x axis\n\t\t\t\t\trangesOverlap(\n\t\t\t\t\t\tstartNode.pageBounds.minX,\n\t\t\t\t\t\tstartNode.pageBounds.maxX,\n\t\t\t\t\t\tendNode.pageBounds.minX,\n\t\t\t\t\t\tendNode.pageBounds.maxX\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tvertical.push({\n\t\t\t\t\t\tstartNode,\n\t\t\t\t\t\tendNode,\n\t\t\t\t\t\tstartEdge: [\n\t\t\t\t\t\t\tnew Vec(startNode.pageBounds.minX, startNode.pageBounds.maxY),\n\t\t\t\t\t\t\tnew Vec(startNode.pageBounds.maxX, startNode.pageBounds.maxY),\n\t\t\t\t\t\t],\n\t\t\t\t\t\tendEdge: [\n\t\t\t\t\t\t\tnew Vec(endNode.pageBounds.minX, endNode.pageBounds.minY),\n\t\t\t\t\t\t\tnew Vec(endNode.pageBounds.maxX, endNode.pageBounds.minY),\n\t\t\t\t\t\t],\n\t\t\t\t\t\tlength: endNode.pageBounds.minY - startNode.pageBounds.maxY,\n\t\t\t\t\t\tbreadthIntersection: rangeIntersection(\n\t\t\t\t\t\t\tstartNode.pageBounds.minX,\n\t\t\t\t\t\t\tstartNode.pageBounds.maxX,\n\t\t\t\t\t\t\tendNode.pageBounds.minX,\n\t\t\t\t\t\t\tendNode.pageBounds.maxX\n\t\t\t\t\t\t)!,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { horizontal, vertical }\n\t}\n\n\tsnapTranslateShapes({\n\t\tlockedAxis,\n\t\tinitialSelectionPageBounds,\n\t\tinitialSelectionSnapPoints,\n\t\tdragDelta,\n\t}: {\n\t\tlockedAxis: 'x' | 'y' | null\n\t\tinitialSelectionSnapPoints: BoundsSnapPoint[]\n\t\tinitialSelectionPageBounds: Box\n\t\tdragDelta: Vec\n\t}): SnapData {\n\t\tconst snapThreshold = this.manager.getSnapThreshold()\n\t\tconst visibleSnapPointsNotInSelection = this.getSnappablePoints()\n\n\t\tconst selectionPageBounds = initialSelectionPageBounds.clone().translate(dragDelta)\n\n\t\tconst selectionSnapPoints: BoundsSnapPoint[] = initialSelectionSnapPoints.map(\n\t\t\t({ x, y }, i) => ({\n\t\t\t\tid: 'selection:' + i,\n\t\t\t\tx: x + dragDelta.x,\n\t\t\t\ty: y + dragDelta.y,\n\t\t\t})\n\t\t)\n\n\t\tconst otherNodeSnapPoints = visibleSnapPointsNotInSelection\n\n\t\tconst nearestSnapsX: NearestSnap[] = []\n\t\tconst nearestSnapsY: NearestSnap[] = []\n\t\tconst minOffset = new Vec(snapThreshold, snapThreshold)\n\n\t\tthis.collectPointSnaps({\n\t\t\tminOffset,\n\t\t\tnearestSnapsX,\n\t\t\tnearestSnapsY,\n\t\t\totherNodeSnapPoints,\n\t\t\tselectionSnapPoints,\n\t\t})\n\n\t\tthis.collectGapSnaps({\n\t\t\tselectionPageBounds,\n\t\t\tnearestSnapsX,\n\t\t\tnearestSnapsY,\n\t\t\tminOffset,\n\t\t})\n\n\t\t// at the same time, calculate how far we need to nudge the shape to 'snap' to the target point(s)\n\t\tconst nudge = new Vec(\n\t\t\tlockedAxis === 'x' ? 0 : (nearestSnapsX[0]?.nudge ?? 0),\n\t\t\tlockedAxis === 'y' ? 0 : (nearestSnapsY[0]?.nudge ?? 0)\n\t\t)\n\n\t\t// ok we've figured out how much the box should be nudged, now let's find all the snap points\n\t\t// that are exact after making that translation, so we can render all of them.\n\t\t// first reset everything and adjust the original shapes to conform to the nudge\n\t\tminOffset.x = 0\n\t\tminOffset.y = 0\n\t\tnearestSnapsX.length = 0\n\t\tnearestSnapsY.length = 0\n\t\tselectionSnapPoints.forEach((s) => {\n\t\t\ts.x += nudge.x\n\t\t\ts.y += nudge.y\n\t\t})\n\t\tselectionPageBounds.translate(nudge)\n\n\t\tthis.collectPointSnaps({\n\t\t\tminOffset,\n\t\t\tnearestSnapsX,\n\t\t\tnearestSnapsY,\n\t\t\totherNodeSnapPoints,\n\t\t\tselectionSnapPoints,\n\t\t})\n\n\t\tthis.collectGapSnaps({\n\t\t\tselectionPageBounds,\n\t\t\tnearestSnapsX,\n\t\t\tnearestSnapsY,\n\t\t\tminOffset,\n\t\t})\n\n\t\tconst pointSnapsLines = this.getPointSnapLines({\n\t\t\tnearestSnapsX,\n\t\t\tnearestSnapsY,\n\t\t})\n\n\t\tconst gapSnapLines = this.getGapSnapLines({\n\t\t\tselectionPageBounds,\n\t\t\tnearestSnapsX,\n\t\t\tnearestSnapsY,\n\t\t})\n\n\t\tthis.manager.setIndicators([...gapSnapLines, ...pointSnapsLines])\n\n\t\treturn { nudge }\n\t}\n\n\tsnapResizeShapes({\n\t\tinitialSelectionPageBounds,\n\t\tdragDelta,\n\t\thandle: originalHandle,\n\t\tisAspectRatioLocked,\n\t\tisResizingFromCenter,\n\t}: {\n\t\t// the page bounds when the pointer went down, before any dragging\n\t\tinitialSelectionPageBounds: Box\n\t\t// how far the pointer has been dragged\n\t\tdragDelta: Vec\n\n\t\thandle: SelectionCorner | SelectionEdge\n\t\tisAspectRatioLocked: boolean\n\t\tisResizingFromCenter: boolean\n\t}): SnapData {\n\t\tconst snapThreshold = this.manager.getSnapThreshold()\n\n\t\t// first figure out the new bounds of the selection\n\t\tconst {\n\t\t\tbox: unsnappedResizedPageBounds,\n\t\t\tscaleX,\n\t\t\tscaleY,\n\t\t} = Box.Resize(\n\t\t\tinitialSelectionPageBounds,\n\t\t\toriginalHandle,\n\t\t\tisResizingFromCenter ? dragDelta.x * 2 : dragDelta.x,\n\t\t\tisResizingFromCenter ? dragDelta.y * 2 : dragDelta.y,\n\t\t\tisAspectRatioLocked\n\t\t)\n\n\t\tlet handle = originalHandle\n\n\t\tif (scaleX < 0) {\n\t\t\thandle = flipSelectionHandleX(handle)\n\t\t}\n\t\tif (scaleY < 0) {\n\t\t\thandle = flipSelectionHandleY(handle)\n\t\t}\n\n\t\tif (isResizingFromCenter) {\n\t\t\t// reposition if resizing from center\n\t\t\tunsnappedResizedPageBounds.center = initialSelectionPageBounds.center\n\t\t}\n\n\t\tconst isXLocked = handle === 'top' || handle === 'bottom'\n\t\tconst isYLocked = handle === 'left' || handle === 'right'\n\n\t\tconst selectionSnapPoints = getResizeSnapPointsForHandle(handle, unsnappedResizedPageBounds)\n\n\t\tconst otherNodeSnapPoints = this.getSnappablePoints()\n\n\t\tconst nearestSnapsX: NearestPointsSnap[] = []\n\t\tconst nearestSnapsY: NearestPointsSnap[] = []\n\t\tconst minOffset = new Vec(snapThreshold, snapThreshold)\n\n\t\tthis.collectPointSnaps({\n\t\t\tminOffset,\n\t\t\tnearestSnapsX,\n\t\t\tnearestSnapsY,\n\t\t\totherNodeSnapPoints,\n\t\t\tselectionSnapPoints,\n\t\t})\n\n\t\t// at the same time, calculate how far we need to nudge the shape to 'snap' to the target point(s)\n\t\tconst nudge = new Vec(\n\t\t\tisXLocked ? 0 : (nearestSnapsX[0]?.nudge ?? 0),\n\t\t\tisYLocked ? 0 : (nearestSnapsY[0]?.nudge ?? 0)\n\t\t)\n\n\t\tif (isAspectRatioLocked && isSelectionCorner(handle) && nudge.len() !== 0) {\n\t\t\t// if the aspect ratio is locked we need to make the nudge diagonal rather than independent in each axis\n\t\t\t// so we use the aspect ratio along with one axis value to set the other axis value, but which axis we use\n\t\t\t// as a source of truth depends what we have snapped to and how far.\n\n\t\t\t// if we found a snap in both axes, pick the closest one and discard the other\n\t\t\tconst primaryNudgeAxis: 'x' | 'y' =\n\t\t\t\tnearestSnapsX.length && nearestSnapsY.length\n\t\t\t\t\t? Math.abs(nudge.x) < Math.abs(nudge.y)\n\t\t\t\t\t\t? 'x'\n\t\t\t\t\t\t: 'y'\n\t\t\t\t\t: nearestSnapsX.length\n\t\t\t\t\t\t? 'x'\n\t\t\t\t\t\t: 'y'\n\n\t\t\tconst ratio = initialSelectionPageBounds.aspectRatio\n\n\t\t\tif (primaryNudgeAxis === 'x') {\n\t\t\t\tnearestSnapsY.length = 0\n\t\t\t\tnudge.y = nudge.x / ratio\n\t\t\t\tif (handle === 'bottom_left' || handle === 'top_right') {\n\t\t\t\t\tnudge.y = -nudge.y\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tnearestSnapsX.length = 0\n\t\t\t\tnudge.x = nudge.y * ratio\n\t\t\t\tif (handle === 'bottom_left' || handle === 'top_right') {\n\t\t\t\t\tnudge.x = -nudge.x\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// now resize the box after nudging, calculate the snaps again, and return the snap lines to match\n\t\t// the fully resized box\n\t\tconst snappedDelta = Vec.Add(dragDelta, nudge)\n\n\t\t// first figure out the new bounds of the selection\n\t\tconst { box: snappedResizedPageBounds } = Box.Resize(\n\t\t\tinitialSelectionPageBounds,\n\t\t\toriginalHandle,\n\t\t\tisResizingFromCenter ? snappedDelta.x * 2 : snappedDelta.x,\n\t\t\tisResizingFromCenter ? snappedDelta.y * 2 : snappedDelta.y,\n\t\t\tisAspectRatioLocked\n\t\t)\n\n\t\tif (isResizingFromCenter) {\n\t\t\t// reposition if resizing from center\n\t\t\tsnappedResizedPageBounds.center = initialSelectionPageBounds.center\n\t\t}\n\n\t\tconst snappedSelectionPoints = getResizeSnapPointsForHandle('any', snappedResizedPageBounds)\n\t\t// calculate snaps again using all points\n\t\tnearestSnapsX.length = 0\n\t\tnearestSnapsY.length = 0\n\t\tminOffset.x = 0\n\t\tminOffset.y = 0\n\n\t\tthis.collectPointSnaps({\n\t\t\tminOffset,\n\t\t\tnearestSnapsX,\n\t\t\tnearestSnapsY,\n\t\t\totherNodeSnapPoints,\n\t\t\tselectionSnapPoints: snappedSelectionPoints,\n\t\t})\n\t\tconst pointSnaps = this.getPointSnapLines({\n\t\t\tnearestSnapsX,\n\t\t\tnearestSnapsY,\n\t\t})\n\n\t\tthis.manager.setIndicators([...pointSnaps])\n\n\t\treturn { nudge }\n\t}\n\n\tprivate collectPointSnaps({\n\t\tselectionSnapPoints,\n\t\totherNodeSnapPoints,\n\t\tminOffset,\n\t\tnearestSnapsX,\n\t\tnearestSnapsY,\n\t}: {\n\t\tselectionSnapPoints: BoundsSnapPoint[]\n\t\totherNodeSnapPoints: BoundsSnapPoint[]\n\t\tminOffset: Vec\n\t\tnearestSnapsX: NearestSnap[]\n\t\tnearestSnapsY: NearestSnap[]\n\t}) {\n\t\t// for each snap point on the bounding box of the selection, find the set of points\n\t\t// which are closest to it in each axis\n\t\tfor (const thisSnapPoint of selectionSnapPoints) {\n\t\t\tfor (const otherSnapPoint of otherNodeSnapPoints) {\n\t\t\t\tconst offset = Vec.Sub(thisSnapPoint, otherSnapPoint)\n\t\t\t\tconst offsetX = Math.abs(offset.x)\n\t\t\t\tconst offsetY = Math.abs(offset.y)\n\n\t\t\t\tif (round(offsetX) <= round(minOffset.x)) {\n\t\t\t\t\tif (round(offsetX) < round(minOffset.x)) {\n\t\t\t\t\t\t// we found a point that is significantly closer than all previous points\n\t\t\t\t\t\t// so wipe the slate clean and start over\n\t\t\t\t\t\tnearestSnapsX.length = 0\n\t\t\t\t\t}\n\n\t\t\t\t\tnearestSnapsX.push({\n\t\t\t\t\t\ttype: 'points',\n\t\t\t\t\t\tpoints: { thisPoint: thisSnapPoint, otherPoint: otherSnapPoint },\n\t\t\t\t\t\tnudge: otherSnapPoint.x - thisSnapPoint.x,\n\t\t\t\t\t})\n\t\t\t\t\tminOffset.x = offsetX\n\t\t\t\t}\n\n\t\t\t\tif (round(offsetY) <= round(minOffset.y)) {\n\t\t\t\t\tif (round(offsetY) < round(minOffset.y)) {\n\t\t\t\t\t\t// we found a point that is significantly closer than all previous points\n\t\t\t\t\t\t// so wipe the slate clean and start over\n\t\t\t\t\t\tnearestSnapsY.length = 0\n\t\t\t\t\t}\n\t\t\t\t\tnearestSnapsY.push({\n\t\t\t\t\t\ttype: 'points',\n\t\t\t\t\t\tpoints: { thisPoint: thisSnapPoint, otherPoint: otherSnapPoint },\n\t\t\t\t\t\tnudge: otherSnapPoint.y - thisSnapPoint.y,\n\t\t\t\t\t})\n\t\t\t\t\tminOffset.y = offsetY\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate collectGapSnaps({\n\t\tselectionPageBounds,\n\t\tminOffset,\n\t\tnearestSnapsX,\n\t\tnearestSnapsY,\n\t}: {\n\t\tselectionPageBounds: Box\n\t\tminOffset: Vec\n\t\tnearestSnapsX: NearestSnap[]\n\t\tnearestSnapsY: NearestSnap[]\n\t}) {\n\t\tconst { horizontal, vertical } = this.getVisibleGaps()\n\n\t\tfor (const gap of horizontal) {\n\t\t\t// ignore this gap if the selection doesn't overlap with it in the y axis\n\t\t\tif (\n\t\t\t\t!rangesOverlap(\n\t\t\t\t\tgap.breadthIntersection[0],\n\t\t\t\t\tgap.breadthIntersection[1],\n\t\t\t\t\tselectionPageBounds.minY,\n\t\t\t\t\tselectionPageBounds.maxY\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// check for center match\n\t\t\tconst gapMidX = gap.startEdge[0].x + gap.length / 2\n\t\t\tconst centerNudge = gapMidX - selectionPageBounds.center.x\n\t\t\tconst gapIsLargerThanSelection = gap.length > selectionPageBounds.width\n\n\t\t\tif (gapIsLargerThanSelection && round(Math.abs(centerNudge)) <= round(minOffset.x)) {\n\t\t\t\tif (round(Math.abs(centerNudge)) < round(minOffset.x)) {\n\t\t\t\t\t// reset if we found a closer snap\n\t\t\t\t\tnearestSnapsX.length = 0\n\t\t\t\t}\n\t\t\t\tminOffset.x = Math.abs(centerNudge)\n\n\t\t\t\tconst snap: NearestSnap = {\n\t\t\t\t\ttype: 'gap_center',\n\t\t\t\t\tgap,\n\t\t\t\t\tnudge: centerNudge,\n\t\t\t\t}\n\n\t\t\t\t// we need to avoid creating visual noise with too many center snaps in situations\n\t\t\t\t// where there are lots of adjacent items with even spacing\n\t\t\t\t// so let's only show other center snaps where the gap's breadth does not overlap with this one\n\t\t\t\t// i.e.\n\t\t\t\t//                \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\t\t\t\t//                \u2502               \u2502\n\t\t\t\t//                \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2518\n\t\t\t\t//                       \u253C    \u2502\n\t\t\t\t//                 \u250C\u2500\u2500\u2500\u2500\u2500\u2534\u2510   \u2502\n\t\t\t\t//                 \u2502      \u2502   \u253C\n\t\t\t\t//                 \u2514\u2500\u2500\u2500\u2500\u2500\u252C\u2518   \u2502\n\t\t\t\t//                       \u253C    \u2502\n\t\t\t\t//                   \u250C\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\t\t\t\t//                   \u2502                \u2502  \u25C4\u2500\u2500\u2500\u2500  i'm dragging this one\n\t\t\t\t//                   \u2514\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\t\t\t\t//            \u2500\u2500\u2500\u2500\u2500\u25BA     \u253C    \u2502\n\t\t\t\t//                 \u250C\u2500\u2500\u2500\u2500\u2500\u2534\u2510   \u2502                don't show these\n\t\t\t\t// show these      \u2502      \u2502   \u253C                larger gaps since\n\t\t\t\t// smaller         \u2514\u2500\u2500\u2500\u2500\u2500\u252C\u2518   \u2502 \u25C4\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 the smaller ones\n\t\t\t\t// gaps                  \u253C    \u2502                cover the same\n\t\t\t\t//              \u2500\u2500\u2500\u2500\u2500\u25BA  \u250C\u2534\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2510          information\n\t\t\t\t//                      \u2502           \u2502\n\t\t\t\t//                      \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\t\t\t\t//\n\t\t\t\t// but we want to show all of these ones since the gap breadths don't overlap\n\t\t\t\t//            \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\t\t\t\t//            \u2502             \u2502\n\t\t\t\t// \u250C\u2500\u2500\u2500\u2500\u2510     \u2514\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\t\t\t\t// \u2502    \u2502         \u2502\n\t\t\t\t// \u2514\u2500\u2500\u252C\u2500\u2518         \u253C\n\t\t\t\t//    \u253C           \u2502\n\t\t\t\t// \u250C\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2510\n\t\t\t\t// \u2502                \u2502 \u25C4\u2500\u2500\u2500\u2500\u2500 i'm dragging this one\n\t\t\t\t// \u2514\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2518\n\t\t\t\t//    \u253C           \u2502\n\t\t\t\t// \u250C\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2510      \u253C\n\t\t\t\t// \u2502       \u2502      \u2502\n\t\t\t\t// \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u250C\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\t\t\t\t//              \u2502         \u2502\n\t\t\t\t//              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\n\t\t\t\tconst otherCenterSnap = nearestSnapsX.find(({ type }) => type === 'gap_center') as\n\t\t\t\t\t| Extract<NearestSnap, { type: 'gap_center' }>\n\t\t\t\t\t| undefined\n\n\t\t\t\tconst gapBreadthsOverlap =\n\t\t\t\t\totherCenterSnap &&\n\t\t\t\t\trangeIntersection(\n\t\t\t\t\t\tgap.breadthIntersection[0],\n\t\t\t\t\t\tgap.breadthIntersection[1],\n\t\t\t\t\t\totherCenterSnap.gap.breadthIntersection[0],\n\t\t\t\t\t\totherCenterSnap.gap.breadthIntersection[1]\n\t\t\t\t\t)\n\n\t\t\t\t// if there is another center snap and it's bigger than this one, and it overlaps with this one, replace it\n\t\t\t\tif (otherCenterSnap && otherCenterSnap.gap.length > gap.length && gapBreadthsOverlap) {\n\t\t\t\t\tnearestSnapsX[nearestSnapsX.indexOf(otherCenterSnap)] = snap\n\t\t\t\t} else if (!otherCenterSnap || !gapBreadthsOverlap) {\n\t\t\t\t\tnearestSnapsX.push(snap)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// check for duplication left match\n\t\t\tconst duplicationLeftX = gap.startNode.pageBounds.minX - gap.length\n\t\t\tconst selectionRightX = selectionPageBounds.maxX\n\n\t\t\tconst duplicationLeftNudge = duplicationLeftX - selectionRightX\n\t\t\tif (round(Math.abs(duplicationLeftNudge)) <= round(minOffset.x)) {\n\t\t\t\tif (round(Math.abs(duplicationLeftNudge)) < round(minOffset.x)) {\n\t\t\t\t\t// reset if we found a closer snap\n\t\t\t\t\tnearestSnapsX.length = 0\n\t\t\t\t}\n\t\t\t\tminOffset.x = Math.abs(duplicationLeftNudge)\n\n\t\t\t\tnearestSnapsX.push({\n\t\t\t\t\ttype: 'gap_duplicate',\n\t\t\t\t\tgap,\n\t\t\t\t\tprotrusionDirection: 'left',\n\t\t\t\t\tnudge: duplicationLeftNudge,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// check for duplication right match\n\t\t\tconst duplicationRightX = gap.endNode.pageBounds.maxX + gap.length\n\t\t\tconst selectionLeftX = selectionPageBounds.minX\n\n\t\t\tconst duplicationRightNudge = duplicationRightX - selectionLeftX\n\t\t\tif (round(Math.abs(duplicationRightNudge)) <= round(minOffset.x)) {\n\t\t\t\tif (round(Math.abs(duplicationRightNudge)) < round(minOffset.x)) {\n\t\t\t\t\t// reset if we found a closer snap\n\t\t\t\t\tnearestSnapsX.length = 0\n\t\t\t\t}\n\t\t\t\tminOffset.x = Math.abs(duplicationRightNudge)\n\n\t\t\t\tnearestSnapsX.push({\n\t\t\t\t\ttype: 'gap_duplicate',\n\t\t\t\t\tgap,\n\t\t\t\t\tprotrusionDirection: 'right',\n\t\t\t\t\tnudge: duplicationRightNudge,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tfor (const gap of vertical) {\n\t\t\t// ignore this gap if the selection doesn't overlap with it in the y axis\n\t\t\tif (\n\t\t\t\t!rangesOverlap(\n\t\t\t\t\tgap.breadthIntersection[0],\n\t\t\t\t\tgap.breadthIntersection[1],\n\t\t\t\t\tselectionPageBounds.minX,\n\t\t\t\t\tselectionPageBounds.maxX\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// check for center match\n\t\t\tconst gapMidY = gap.startEdge[0].y + gap.length / 2\n\t\t\tconst centerNudge = gapMidY - selectionPageBounds.center.y\n\n\t\t\tconst gapIsLargerThanSelection = gap.length > selectionPageBounds.height\n\n\t\t\tif (gapIsLargerThanSelection && round(Math.abs(centerNudge)) <= round(minOffset.y)) {\n\t\t\t\tif (round(Math.abs(centerNudge)) < round(minOffset.y)) {\n\t\t\t\t\t// reset if we found a closer snap\n\t\t\t\t\tnearestSnapsY.length = 0\n\t\t\t\t}\n\t\t\t\tminOffset.y = Math.abs(centerNudge)\n\n\t\t\t\tconst snap: NearestSnap = {\n\t\t\t\t\ttype: 'gap_center',\n\t\t\t\t\tgap,\n\t\t\t\t\tnudge: centerNudge,\n\t\t\t\t}\n\n\t\t\t\t// we need to avoid creating visual noise with too many center snaps in situations\n\t\t\t\t// where there are lots of adjacent items with even spacing\n\t\t\t\t// so let's only show other center snaps where the gap's breadth does not overlap with this one\n\t\t\t\t// i.e.\n\t\t\t\t//                \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\t\t\t\t//                \u2502               \u2502\n\t\t\t\t//                \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2518\n\t\t\t\t//                       \u253C    \u2502\n\t\t\t\t//                 \u250C\u2500\u2500\u2500\u2500\u2500\u2534\u2510   \u2502\n\t\t\t\t//                 \u2502      \u2502   \u253C\n\t\t\t\t//                 \u2514\u2500\u2500\u2500\u2500\u2500\u252C\u2518   \u2502\n\t\t\t\t//                       \u253C    \u2502\n\t\t\t\t//                   \u250C\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\t\t\t\t//                   \u2502                \u2502  \u25C4\u2500\u2500\u2500\u2500  i'm dragging this one\n\t\t\t\t//                   \u2514\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\t\t\t\t//            \u2500\u2500\u2500\u2500\u2500\u25BA     \u253C    \u2502\n\t\t\t\t//                 \u250C\u2500\u2500\u2500\u2500\u2500\u2534\u2510   \u2502                don't show these\n\t\t\t\t// show these      \u2502      \u2502   \u253C                larger gaps since\n\t\t\t\t// smaller         \u2514\u2500\u2500\u2500\u2500\u2500\u252C\u2518   \u2502 \u25C4\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 the smaller ones\n\t\t\t\t// gaps                  \u253C    \u2502                cover the same\n\t\t\t\t//              \u2500\u2500\u2500\u2500\u2500\u25BA  \u250C\u2534\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2510          information\n\t\t\t\t//                      \u2502           \u2502\n\t\t\t\t//                      \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\t\t\t\t//\n\t\t\t\t// but we want to show all of these ones since the gap breadths don't overlap\n\t\t\t\t//            \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\t\t\t\t//            \u2502             \u2502\n\t\t\t\t// \u250C\u2500\u2500\u2500\u2500\u2510     \u2514\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\t\t\t\t// \u2502    \u2502         \u2502\n\t\t\t\t// \u2514\u2500\u2500\u252C\u2500\u2518         \u253C\n\t\t\t\t//    \u253C           \u2502\n\t\t\t\t// \u250C\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2510\n\t\t\t\t// \u2502                \u2502 \u25C4\u2500\u2500\u2500\u2500\u2500 i'm dragging this one\n\t\t\t\t// \u2514\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2518\n\t\t\t\t//    \u253C           \u2502\n\t\t\t\t// \u250C\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2510      \u253C\n\t\t\t\t// \u2502       \u2502      \u2502\n\t\t\t\t// \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u250C\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\t\t\t\t//              \u2502         \u2502\n\t\t\t\t//              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\n\t\t\t\tconst otherCenterSnap = nearestSnapsY.find(({ type }) => type === 'gap_center') as\n\t\t\t\t\t| Extract<NearestSnap, { type: 'gap_center' }>\n\t\t\t\t\t| undefined\n\n\t\t\t\tconst gapBreadthsOverlap =\n\t\t\t\t\totherCenterSnap &&\n\t\t\t\t\trangesOverlap(\n\t\t\t\t\t\totherCenterSnap.gap.breadthIntersection[0],\n\t\t\t\t\t\totherCenterSnap.gap.breadthIntersection[1],\n\t\t\t\t\t\tgap.breadthIntersection[0],\n\t\t\t\t\t\tgap.breadthIntersection[1]\n\t\t\t\t\t)\n\n\t\t\t\t// if there is another center snap and it's bigger than this one, and it overlaps with this one, replace it\n\t\t\t\tif (otherCenterSnap && otherCenterSnap.gap.length > gap.length && gapBreadthsOverlap) {\n\t\t\t\t\tnearestSnapsY[nearestSnapsY.indexOf(otherCenterSnap)] = snap\n\t\t\t\t} else if (!otherCenterSnap || !gapBreadthsOverlap) {\n\t\t\t\t\tnearestSnapsY.push(snap)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// check for duplication top match\n\t\t\tconst duplicationTopY = gap.startNode.pageBounds.minY - gap.length\n\t\t\tconst selectionBottomY = selectionPageBounds.maxY\n\n\t\t\tconst duplicationTopNudge = duplicationTopY - selectionBottomY\n\t\t\tif (round(Math.abs(duplicationTopNudge)) <= round(minOffset.y)) {\n\t\t\t\tif (round(Math.abs(duplicationTopNudge)) < round(minOffset.y)) {\n\t\t\t\t\t// reset if we found a closer snap\n\t\t\t\t\tnearestSnapsY.length = 0\n\t\t\t\t}\n\t\t\t\tminOffset.y = Math.abs(duplicationTopNudge)\n\n\t\t\t\tnearestSnapsY.push({\n\t\t\t\t\ttype: 'gap_duplicate',\n\t\t\t\t\tgap,\n\t\t\t\t\tprotrusionDirection: 'top',\n\t\t\t\t\tnudge: duplicationTopNudge,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// check for duplication bottom match\n\t\t\tconst duplicationBottomY = gap.endNode.pageBounds.maxY + gap.length\n\t\t\tconst selectionTopY = selectionPageBounds.minY\n\n\t\t\tconst duplicationBottomNudge = duplicationBottomY - selectionTopY\n\t\t\tif (round(Math.abs(duplicationBottomNudge)) <= round(minOffset.y)) {\n\t\t\t\tif (round(Math.abs(duplicationBottomNudge)) < round(minOffset.y)) {\n\t\t\t\t\t// reset if we found a closer snap\n\t\t\t\t\tnearestSnapsY.length = 0\n\t\t\t\t}\n\t\t\t\tminOffset.y = Math.abs(duplicationBottomNudge)\n\n\t\t\t\tnearestSnapsY.push({\n\t\t\t\t\ttype: 'gap_duplicate',\n\t\t\t\t\tgap,\n\t\t\t\t\tprotrusionDirection: 'bottom',\n\t\t\t\t\tnudge: duplicationBottomNudge,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getPointSnapLines({\n\t\tnearestSnapsX,\n\t\tnearestSnapsY,\n\t}: {\n\t\tnearestSnapsX: NearestSnap[]\n\t\tnearestSnapsY: NearestSnap[]\n\t}): PointsSnapIndicator[] {\n\t\t// point snaps may align on multiple parallel lines so we need to split the pairs\n\t\t// into groups based on where they are in their their snap axes\n\t\tconst snapGroupsX = {} as { [key: string]: SnapPair[] }\n\t\tconst snapGroupsY = {} as { [key: string]: SnapPair[] }\n\n\t\tif (nearestSnapsX.length > 0) {\n\t\t\tfor (const snap of nearestSnapsX) {\n\t\t\t\tif (snap.type === 'points') {\n\t\t\t\t\tconst key = round(snap.points.otherPoint.x)\n\t\t\t\t\tif (!snapGroupsX[key]) {\n\t\t\t\t\t\tsnapGroupsX[key] = []\n\t\t\t\t\t}\n\t\t\t\t\tsnapGroupsX[key].push(snap.points)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (nearestSnapsY.length > 0) {\n\t\t\tfor (const snap of nearestSnapsY) {\n\t\t\t\tif (snap.type === 'points') {\n\t\t\t\t\tconst key = round(snap.points.otherPoint.y)\n\t\t\t\t\tif (!snapGroupsY[key]) {\n\t\t\t\t\t\tsnapGroupsY[key] = []\n\t\t\t\t\t}\n\t\t\t\t\tsnapGroupsY[key].push(snap.points)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// and finally create all the snap lines for the UI to render\n\t\treturn Object.values(snapGroupsX)\n\t\t\t.concat(Object.values(snapGroupsY))\n\t\t\t.map((snapGroup) => ({\n\t\t\t\tid: uniqueId(),\n\t\t\t\ttype: 'points',\n\t\t\t\tpoints: dedupe(\n\t\t\t\t\tsnapGroup\n\t\t\t\t\t\t.map((snap) => Vec.From(snap.otherPoint))\n\t\t\t\t\t\t// be sure to nudge over the selection snap points\n\t\t\t\t\t\t.concat(snapGroup.map((snap) => Vec.From(snap.thisPoint))),\n\t\t\t\t\t(a: Vec, b: Vec) => a.equals(b)\n\t\t\t\t),\n\t\t\t}))\n\t}\n\n\tprivate getGapSnapLines({\n\t\tselectionPageBounds,\n\t\tnearestSnapsX,\n\t\tnearestSnapsY,\n\t}: {\n\t\tselectionPageBounds: Box\n\t\tnearestSnapsX: NearestSnap[]\n\t\tnearestSnapsY: NearestSnap[]\n\t}): GapsSnapIndicator[] {\n\t\tconst { vertical, horizontal } = this.getVisibleGaps()\n\n\t\tconst selectionSides: Record<SelectionEdge, [Vec, Vec]> = {\n\t\t\ttop: selectionPageBounds.sides[0],\n\t\t\tright: selectionPageBounds.sides[1],\n\t\t\t// need bottom and left to be sorted asc, which .sides is not.\n\t\t\tbottom: [selectionPageBounds.corners[3], selectionPageBounds.corners[2]],\n\t\t\tleft: [selectionPageBounds.corners[0], selectionPageBounds.corners[3]],\n\t\t}\n\n\t\tconst result: GapsSnapIndicator[] = []\n\n\t\tif (nearestSnapsX.length > 0) {\n\t\t\tfor (const snap of nearestSnapsX) {\n\t\t\t\tif (snap.type === 'points') continue\n\n\t\t\t\tconst {\n\t\t\t\t\tgap: { breadthIntersection, startEdge, startNode, endNode, length, endEdge },\n\t\t\t\t} = snap\n\n\t\t\t\tswitch (snap.type) {\n\t\t\t\t\tcase 'gap_center': {\n\t\t\t\t\t\t// create\n\t\t\t\t\t\tconst newGapsLength = (length - selectionPageBounds.width) / 2\n\t\t\t\t\t\tconst gapBreadthIntersection = rangeIntersection(\n\t\t\t\t\t\t\tbreadthIntersection[0],\n\t\t\t\t\t\t\tbreadthIntersection[1],\n\t\t\t\t\t\t\tselectionPageBounds.minY,\n\t\t\t\t\t\t\tselectionPageBounds.maxY\n\t\t\t\t\t\t)!\n\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\ttype: 'gaps',\n\t\t\t\t\t\t\tdirection: 'horizontal',\n\t\t\t\t\t\t\tid: uniqueId(),\n\t\t\t\t\t\t\tgaps: [\n\t\t\t\t\t\t\t\t...findAdjacentGaps(\n\t\t\t\t\t\t\t\t\thorizontal,\n\t\t\t\t\t\t\t\t\tstartNode.id,\n\t\t\t\t\t\t\t\t\tnewGapsLength,\n\t\t\t\t\t\t\t\t\t'backward',\n\t\t\t\t\t\t\t\t\tgapBreadthIntersection\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstartEdge,\n\t\t\t\t\t\t\t\t\tendEdge: selectionSides.left,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstartEdge: selectionSides.right,\n\t\t\t\t\t\t\t\t\tendEdge,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t...findAdjacentGaps(\n\t\t\t\t\t\t\t\t\thorizontal,\n\t\t\t\t\t\t\t\t\tendNode.id,\n\t\t\t\t\t\t\t\t\tnewGapsLength,\n\t\t\t\t\t\t\t\t\t'forward',\n\t\t\t\t\t\t\t\t\tgapBreadthIntersection\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t})\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'gap_duplicate': {\n\t\t\t\t\t\t// create\n\t\t\t\t\t\tconst gapBreadthIntersection = rangeIntersection(\n\t\t\t\t\t\t\tbreadthIntersection[0],\n\t\t\t\t\t\t\tbreadthIntersection[1],\n\t\t\t\t\t\t\tselectionPageBounds.minY,\n\t\t\t\t\t\t\tselectionPageBounds.maxY\n\t\t\t\t\t\t)!\n\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\ttype: 'gaps',\n\t\t\t\t\t\t\tdirection: 'horizontal',\n\t\t\t\t\t\t\tid: uniqueId(),\n\t\t\t\t\t\t\tgaps:\n\t\t\t\t\t\t\t\tsnap.protrusionDirection === 'left'\n\t\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tstartEdge: selectionSides.right,\n\t\t\t\t\t\t\t\t\t\t\t\tendEdge: startEdge.map((v) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\tv.clone().addXY(-startNode.pageBounds.width, 0)\n\t\t\t\t\t\t\t\t\t\t\t\t) as [Vec, Vec],\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{ startEdge, endEdge },\n\t\t\t\t\t\t\t\t\t\t\t...findAdjacentGaps(\n\t\t\t\t\t\t\t\t\t\t\t\thorizontal,\n\t\t\t\t\t\t\t\t\t\t\t\tendNode.id,\n\t\t\t\t\t\t\t\t\t\t\t\tlength,\n\t\t\t\t\t\t\t\t\t\t\t\t'forward',\n\t\t\t\t\t\t\t\t\t\t\t\tgapBreadthIntersection\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\t\t\t\t...findAdjacentGaps(\n\t\t\t\t\t\t\t\t\t\t\t\thorizontal,\n\t\t\t\t\t\t\t\t\t\t\t\tstartNode.id,\n\t\t\t\t\t\t\t\t\t\t\t\tlength,\n\t\t\t\t\t\t\t\t\t\t\t\t'backward',\n\t\t\t\t\t\t\t\t\t\t\t\tgapBreadthIntersection\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t{ startEdge, endEdge },\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tstartEdge: endEdge.map((v) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\tv.clone().addXY(snap.gap.endNode.pageBounds.width, 0)\n\t\t\t\t\t\t\t\t\t\t\t\t) as [Vec, Vec],\n\t\t\t\t\t\t\t\t\t\t\t\tendEdge: selectionSides.left,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t})\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (nearestSnapsY.length > 0) {\n\t\t\tfor (const snap of nearestSnapsY) {\n\t\t\t\tif (snap.type === 'points') continue\n\n\t\t\t\tconst {\n\t\t\t\t\tgap: { breadthIntersection, startEdge, startNode, endNode, length, endEdge },\n\t\t\t\t} = snap\n\n\t\t\t\tswitch (snap.type) {\n\t\t\t\t\tcase 'gap_center': {\n\t\t\t\t\t\tconst newGapsLength = (length - selectionPageBounds.height) / 2\n\t\t\t\t\t\tconst gapBreadthIntersection = rangeIntersection(\n\t\t\t\t\t\t\tbreadthIntersection[0],\n\t\t\t\t\t\t\tbreadthIntersection[1],\n\t\t\t\t\t\t\tselectionPageBounds.minX,\n\t\t\t\t\t\t\tselectionPageBounds.maxX\n\t\t\t\t\t\t)!\n\n\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\ttype: 'gaps',\n\t\t\t\t\t\t\tdirection: 'vertical',\n\t\t\t\t\t\t\tid: uniqueId(),\n\t\t\t\t\t\t\tgaps: [\n\t\t\t\t\t\t\t\t...findAdjacentGaps(\n\t\t\t\t\t\t\t\t\tvertical,\n\t\t\t\t\t\t\t\t\tstartNode.id,\n\t\t\t\t\t\t\t\t\tnewGapsLength,\n\t\t\t\t\t\t\t\t\t'backward',\n\t\t\t\t\t\t\t\t\tgapBreadthIntersection\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstartEdge,\n\t\t\t\t\t\t\t\t\tendEdge: selectionSides.top,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstartEdge: selectionSides.bottom,\n\t\t\t\t\t\t\t\t\tendEdge,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t...findAdjacentGaps(\n\t\t\t\t\t\t\t\t\tvertical,\n\t\t\t\t\t\t\t\t\tsnap.gap.endNode.id,\n\t\t\t\t\t\t\t\t\tnewGapsLength,\n\t\t\t\t\t\t\t\t\t'forward',\n\t\t\t\t\t\t\t\t\tgapBreadthIntersection\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t})\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'gap_duplicate':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst gapBreadthIntersection = rangeIntersection(\n\t\t\t\t\t\t\t\tbreadthIntersection[0],\n\t\t\t\t\t\t\t\tbreadthIntersection[1],\n\t\t\t\t\t\t\t\tselectionPageBounds.minX,\n\t\t\t\t\t\t\t\tselectionPageBounds.maxX\n\t\t\t\t\t\t\t)!\n\n\t\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\t\ttype: 'gaps',\n\t\t\t\t\t\t\t\tdirection: 'vertical',\n\t\t\t\t\t\t\t\tid: uniqueId(),\n\t\t\t\t\t\t\t\tgaps:\n\t\t\t\t\t\t\t\t\tsnap.protrusionDirection === 'top'\n\t\t\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tstartEdge: selectionSides.bottom,\n\t\t\t\t\t\t\t\t\t\t\t\t\tendEdge: startEdge.map((v) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tv.clone().addXY(0, -startNode.pageBounds.height)\n\t\t\t\t\t\t\t\t\t\t\t\t\t) as [Vec, Vec],\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{ startEdge, endEdge },\n\t\t\t\t\t\t\t\t\t\t\t\t...findAdjacentGaps(\n\t\t\t\t\t\t\t\t\t\t\t\t\tvertical,\n\t\t\t\t\t\t\t\t\t\t\t\t\tendNode.id,\n\t\t\t\t\t\t\t\t\t\t\t\t\tlength,\n\t\t\t\t\t\t\t\t\t\t\t\t\t'forward',\n\t\t\t\t\t\t\t\t\t\t\t\t\tgapBreadthIntersection\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\t\t\t\t\t...findAdjacentGaps(\n\t\t\t\t\t\t\t\t\t\t\t\t\tvertical,\n\t\t\t\t\t\t\t\t\t\t\t\t\tstartNode.id,\n\t\t\t\t\t\t\t\t\t\t\t\t\tlength,\n\t\t\t\t\t\t\t\t\t\t\t\t\t'backward',\n\t\t\t\t\t\t\t\t\t\t\t\t\tgapBreadthIntersection\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t{ startEdge, endEdge },\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tstartEdge: endEdge.map((v) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tv.clone().addXY(0, endNode.pageBounds.height)\n\t\t\t\t\t\t\t\t\t\t\t\t\t) as [Vec, Vec],\n\t\t\t\t\t\t\t\t\t\t\t\t\tendEdge: selectionSides.top,\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tdedupeGapSnaps(result)\n\t\treturn result\n\t}\n}\n\nfunction getResizeSnapPointsForHandle(\n\thandle: SelectionCorner | SelectionEdge | 'any',\n\tselectionPageBounds: Box\n): BoundsSnapPoint[] {\n\tconst { minX, maxX, minY, maxY } = selectionPageBounds\n\tconst result: BoundsSnapPoint[] = []\n\n\t// top left corner\n\tswitch (handle) {\n\t\tcase 'top':\n\t\tcase 'left':\n\t\tcase 'top_left':\n\t\tcase 'any':\n\t\t\tresult.push({\n\t\t\t\tid: 'top_left',\n\t\t\t\thandle: 'top_left',\n\t\t\t\tx: minX,\n\t\t\t\ty: minY,\n\t\t\t})\n\t}\n\n\t// top right corner\n\tswitch (handle) {\n\t\tcase 'top':\n\t\tcase 'right':\n\t\tcase 'top_right':\n\t\tcase 'any':\n\t\t\tresult.push({\n\t\t\t\tid: 'top_right',\n\t\t\t\thandle: 'top_right',\n\t\t\t\tx: maxX,\n\t\t\t\ty: minY,\n\t\t\t})\n\t}\n\n\t// bottom right corner\n\tswitch (handle) {\n\t\tcase 'bottom':\n\t\tcase 'right':\n\t\tcase 'bottom_right':\n\t\tcase 'any':\n\t\t\tresult.push({\n\t\t\t\tid: 'bottom_right',\n\t\t\t\thandle: 'bottom_right',\n\t\t\t\tx: maxX,\n\t\t\t\ty: maxY,\n\t\t\t})\n\t}\n\n\t// bottom left corner\n\tswitch (handle) {\n\t\tcase 'bottom':\n\t\tcase 'left':\n\t\tcase 'bottom_left':\n\t\tcase 'any':\n\t\t\tresult.push({\n\t\t\t\tid: 'bottom_left',\n\t\t\t\thandle: 'bottom_left',\n\t\t\t\tx: minX,\n\t\t\t\ty: maxY,\n\t\t\t})\n\t}\n\n\treturn result\n}\n"],
  "mappings": "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",
  "names": []
}
