UNPKG

@tldraw/editor

Version:

tldraw infinite canvas SDK (editor).

872 lines (871 loc) • 30.4 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __decorateClass = (decorators, target, key, kind) => { var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target; for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result; if (kind && result) __defProp(target, key, result); return result; }; var BoundsSnaps_exports = {}; __export(BoundsSnaps_exports, { BoundsSnaps: () => BoundsSnaps }); module.exports = __toCommonJS(BoundsSnaps_exports); var import_state = require("@tldraw/state"); var import_utils = require("@tldraw/utils"); var import_Box = require("../../../primitives/Box"); var import_Mat = require("../../../primitives/Mat"); var import_utils2 = require("../../../primitives/utils"); var import_Vec = require("../../../primitives/Vec"); const round = (x) => { const decimalPlacesTolerance = 8; return Math.round(x * 10 ** decimalPlacesTolerance) / 10 ** decimalPlacesTolerance; }; function findAdjacentGaps(gaps, shapeId, gapLength, direction, intersection) { const matches = gaps.filter( (gap) => (direction === "forward" ? gap.startNode.id === shapeId : gap.endNode.id === shapeId) && round(gap.length) === round(gapLength) && (0, import_utils2.rangeIntersection)( gap.breadthIntersection[0], gap.breadthIntersection[1], intersection[0], intersection[1] ) ); if (matches.length === 0) return []; const nextNodes = /* @__PURE__ */ new Set(); matches.forEach((match) => { const node = direction === "forward" ? match.endNode.id : match.startNode.id; if (!nextNodes.has(node)) { nextNodes.add(node); const foundGaps = findAdjacentGaps( gaps, node, gapLength, direction, (0, import_utils2.rangeIntersection)( match.breadthIntersection[0], match.breadthIntersection[1], intersection[0], intersection[1] ) ); matches.push(...foundGaps); } }); return matches; } function dedupeGapSnaps(snaps) { snaps.sort((a, b) => b.gaps.length - a.gaps.length); for (let i = snaps.length - 1; i > 0; i--) { const snap = snaps[i]; for (let j = i - 1; j >= 0; j--) { const otherSnap = snaps[j]; if (otherSnap.direction === snap.direction && snap.gaps.every( (gap) => otherSnap.gaps.some( (otherGap) => round(gap.startEdge[0].x) === round(otherGap.startEdge[0].x) && round(gap.startEdge[0].y) === round(otherGap.startEdge[0].y) && round(gap.startEdge[1].x) === round(otherGap.startEdge[1].x) && round(gap.startEdge[1].y) === round(otherGap.startEdge[1].y) ) && otherSnap.gaps.some( (otherGap) => round(gap.endEdge[0].x) === round(otherGap.endEdge[0].x) && round(gap.endEdge[0].y) === round(otherGap.endEdge[0].y) && round(gap.endEdge[1].x) === round(otherGap.endEdge[1].x) && round(gap.endEdge[1].y) === round(otherGap.endEdge[1].y) ) )) { snaps.splice(i, 1); break; } } } } class BoundsSnaps { constructor(manager) { this.manager = manager; this.editor = manager.editor; } manager; editor; getSnapPointsCache() { const { editor } = this; return editor.store.createComputedCache("snapPoints", (shape) => { const pageTransform = editor.getShapePageTransform(shape.id); if (!pageTransform) return void 0; const boundsSnapGeometry = editor.getShapeUtil(shape).getBoundsSnapGeometry(shape); const snapPoints = boundsSnapGeometry.points ?? editor.getShapeGeometry(shape).bounds.cornersAndCenter; if (!pageTransform || !snapPoints) return void 0; return snapPoints.map((point, i) => { const { x, y } = import_Mat.Mat.applyToPoint(pageTransform, point); return { x, y, id: `${shape.id}:${i}` }; }); }); } getSnapPoints(shapeId) { return this.getSnapPointsCache().get(shapeId) ?? []; } getSnappablePoints() { const snapPointsCache = this.getSnapPointsCache(); const snappableShapes = this.manager.getSnappableShapes(); const result = []; for (const shapeId of snappableShapes) { const snapPoints = snapPointsCache.get(shapeId); if (snapPoints) { result.push(...snapPoints); } } return result; } getSnappableGapNodes() { return Array.from(this.manager.getSnappableShapes(), (shapeId) => ({ id: shapeId, pageBounds: (0, import_utils.assertExists)(this.editor.getShapePageBounds(shapeId)) })); } getVisibleGaps() { const horizontal = []; const vertical = []; let startNode, endNode; const sortedShapesOnCurrentPageHorizontal = this.getSnappableGapNodes().sort((a, b) => { return a.pageBounds.minX - b.pageBounds.minX; }); for (let i = 0; i < sortedShapesOnCurrentPageHorizontal.length; i++) { startNode = sortedShapesOnCurrentPageHorizontal[i]; for (let j = i + 1; j < sortedShapesOnCurrentPageHorizontal.length; j++) { endNode = sortedShapesOnCurrentPageHorizontal[j]; if ( // is there space between the boxes startNode.pageBounds.maxX < endNode.pageBounds.minX && // and they overlap in the y axis (0, import_utils2.rangesOverlap)( startNode.pageBounds.minY, startNode.pageBounds.maxY, endNode.pageBounds.minY, endNode.pageBounds.maxY ) ) { horizontal.push({ startNode, endNode, startEdge: [ new import_Vec.Vec(startNode.pageBounds.maxX, startNode.pageBounds.minY), new import_Vec.Vec(startNode.pageBounds.maxX, startNode.pageBounds.maxY) ], endEdge: [ new import_Vec.Vec(endNode.pageBounds.minX, endNode.pageBounds.minY), new import_Vec.Vec(endNode.pageBounds.minX, endNode.pageBounds.maxY) ], length: endNode.pageBounds.minX - startNode.pageBounds.maxX, breadthIntersection: (0, import_utils2.rangeIntersection)( startNode.pageBounds.minY, startNode.pageBounds.maxY, endNode.pageBounds.minY, endNode.pageBounds.maxY ) }); } } } const sortedShapesOnCurrentPageVertical = sortedShapesOnCurrentPageHorizontal.sort((a, b) => { return a.pageBounds.minY - b.pageBounds.minY; }); for (let i = 0; i < sortedShapesOnCurrentPageVertical.length; i++) { startNode = sortedShapesOnCurrentPageVertical[i]; for (let j = i + 1; j < sortedShapesOnCurrentPageVertical.length; j++) { endNode = sortedShapesOnCurrentPageVertical[j]; if ( // is there space between the boxes startNode.pageBounds.maxY < endNode.pageBounds.minY && // do they overlap in the x axis (0, import_utils2.rangesOverlap)( startNode.pageBounds.minX, startNode.pageBounds.maxX, endNode.pageBounds.minX, endNode.pageBounds.maxX ) ) { vertical.push({ startNode, endNode, startEdge: [ new import_Vec.Vec(startNode.pageBounds.minX, startNode.pageBounds.maxY), new import_Vec.Vec(startNode.pageBounds.maxX, startNode.pageBounds.maxY) ], endEdge: [ new import_Vec.Vec(endNode.pageBounds.minX, endNode.pageBounds.minY), new import_Vec.Vec(endNode.pageBounds.maxX, endNode.pageBounds.minY) ], length: endNode.pageBounds.minY - startNode.pageBounds.maxY, breadthIntersection: (0, import_utils2.rangeIntersection)( startNode.pageBounds.minX, startNode.pageBounds.maxX, endNode.pageBounds.minX, endNode.pageBounds.maxX ) }); } } } return { horizontal, vertical }; } snapTranslateShapes({ lockedAxis, initialSelectionPageBounds, initialSelectionSnapPoints, dragDelta }) { const snapThreshold = this.manager.getSnapThreshold(); const visibleSnapPointsNotInSelection = this.getSnappablePoints(); const selectionPageBounds = initialSelectionPageBounds.clone().translate(dragDelta); const selectionSnapPoints = initialSelectionSnapPoints.map( ({ x, y }, i) => ({ id: "selection:" + i, x: x + dragDelta.x, y: y + dragDelta.y }) ); const otherNodeSnapPoints = visibleSnapPointsNotInSelection; const nearestSnapsX = []; const nearestSnapsY = []; const minOffset = new import_Vec.Vec(snapThreshold, snapThreshold); this.collectPointSnaps({ minOffset, nearestSnapsX, nearestSnapsY, otherNodeSnapPoints, selectionSnapPoints }); this.collectGapSnaps({ selectionPageBounds, nearestSnapsX, nearestSnapsY, minOffset }); const nudge = new import_Vec.Vec( lockedAxis === "x" ? 0 : nearestSnapsX[0]?.nudge ?? 0, lockedAxis === "y" ? 0 : nearestSnapsY[0]?.nudge ?? 0 ); minOffset.x = 0; minOffset.y = 0; nearestSnapsX.length = 0; nearestSnapsY.length = 0; selectionSnapPoints.forEach((s) => { s.x += nudge.x; s.y += nudge.y; }); selectionPageBounds.translate(nudge); this.collectPointSnaps({ minOffset, nearestSnapsX, nearestSnapsY, otherNodeSnapPoints, selectionSnapPoints }); this.collectGapSnaps({ selectionPageBounds, nearestSnapsX, nearestSnapsY, minOffset }); const pointSnapsLines = this.getPointSnapLines({ nearestSnapsX, nearestSnapsY }); const gapSnapLines = this.getGapSnapLines({ selectionPageBounds, nearestSnapsX, nearestSnapsY }); this.manager.setIndicators([...gapSnapLines, ...pointSnapsLines]); return { nudge }; } snapResizeShapes({ initialSelectionPageBounds, dragDelta, handle: originalHandle, isAspectRatioLocked, isResizingFromCenter }) { const snapThreshold = this.manager.getSnapThreshold(); const { box: unsnappedResizedPageBounds, scaleX, scaleY } = import_Box.Box.Resize( initialSelectionPageBounds, originalHandle, isResizingFromCenter ? dragDelta.x * 2 : dragDelta.x, isResizingFromCenter ? dragDelta.y * 2 : dragDelta.y, isAspectRatioLocked ); let handle = originalHandle; if (scaleX < 0) { handle = (0, import_Box.flipSelectionHandleX)(handle); } if (scaleY < 0) { handle = (0, import_Box.flipSelectionHandleY)(handle); } if (isResizingFromCenter) { unsnappedResizedPageBounds.center = initialSelectionPageBounds.center; } const isXLocked = handle === "top" || handle === "bottom"; const isYLocked = handle === "left" || handle === "right"; const selectionSnapPoints = getResizeSnapPointsForHandle(handle, unsnappedResizedPageBounds); const otherNodeSnapPoints = this.getSnappablePoints(); const nearestSnapsX = []; const nearestSnapsY = []; const minOffset = new import_Vec.Vec(snapThreshold, snapThreshold); this.collectPointSnaps({ minOffset, nearestSnapsX, nearestSnapsY, otherNodeSnapPoints, selectionSnapPoints }); const nudge = new import_Vec.Vec( isXLocked ? 0 : nearestSnapsX[0]?.nudge ?? 0, isYLocked ? 0 : nearestSnapsY[0]?.nudge ?? 0 ); if (isAspectRatioLocked && (0, import_Box.isSelectionCorner)(handle) && nudge.len() !== 0) { const primaryNudgeAxis = nearestSnapsX.length && nearestSnapsY.length ? Math.abs(nudge.x) < Math.abs(nudge.y) ? "x" : "y" : nearestSnapsX.length ? "x" : "y"; const ratio = initialSelectionPageBounds.aspectRatio; if (primaryNudgeAxis === "x") { nearestSnapsY.length = 0; nudge.y = nudge.x / ratio; if (handle === "bottom_left" || handle === "top_right") { nudge.y = -nudge.y; } } else { nearestSnapsX.length = 0; nudge.x = nudge.y * ratio; if (handle === "bottom_left" || handle === "top_right") { nudge.x = -nudge.x; } } } const snappedDelta = import_Vec.Vec.Add(dragDelta, nudge); const { box: snappedResizedPageBounds } = import_Box.Box.Resize( initialSelectionPageBounds, originalHandle, isResizingFromCenter ? snappedDelta.x * 2 : snappedDelta.x, isResizingFromCenter ? snappedDelta.y * 2 : snappedDelta.y, isAspectRatioLocked ); if (isResizingFromCenter) { snappedResizedPageBounds.center = initialSelectionPageBounds.center; } const snappedSelectionPoints = getResizeSnapPointsForHandle("any", snappedResizedPageBounds); nearestSnapsX.length = 0; nearestSnapsY.length = 0; minOffset.x = 0; minOffset.y = 0; this.collectPointSnaps({ minOffset, nearestSnapsX, nearestSnapsY, otherNodeSnapPoints, selectionSnapPoints: snappedSelectionPoints }); const pointSnaps = this.getPointSnapLines({ nearestSnapsX, nearestSnapsY }); this.manager.setIndicators([...pointSnaps]); return { nudge }; } collectPointSnaps({ selectionSnapPoints, otherNodeSnapPoints, minOffset, nearestSnapsX, nearestSnapsY }) { for (const thisSnapPoint of selectionSnapPoints) { for (const otherSnapPoint of otherNodeSnapPoints) { const offset = import_Vec.Vec.Sub(thisSnapPoint, otherSnapPoint); const offsetX = Math.abs(offset.x); const offsetY = Math.abs(offset.y); if (round(offsetX) <= round(minOffset.x)) { if (round(offsetX) < round(minOffset.x)) { nearestSnapsX.length = 0; } nearestSnapsX.push({ type: "points", points: { thisPoint: thisSnapPoint, otherPoint: otherSnapPoint }, nudge: otherSnapPoint.x - thisSnapPoint.x }); minOffset.x = offsetX; } if (round(offsetY) <= round(minOffset.y)) { if (round(offsetY) < round(minOffset.y)) { nearestSnapsY.length = 0; } nearestSnapsY.push({ type: "points", points: { thisPoint: thisSnapPoint, otherPoint: otherSnapPoint }, nudge: otherSnapPoint.y - thisSnapPoint.y }); minOffset.y = offsetY; } } } } collectGapSnaps({ selectionPageBounds, minOffset, nearestSnapsX, nearestSnapsY }) { const { horizontal, vertical } = this.getVisibleGaps(); for (const gap of horizontal) { if (!(0, import_utils2.rangesOverlap)( gap.breadthIntersection[0], gap.breadthIntersection[1], selectionPageBounds.minY, selectionPageBounds.maxY )) { continue; } const gapMidX = gap.startEdge[0].x + gap.length / 2; const centerNudge = gapMidX - selectionPageBounds.center.x; const gapIsLargerThanSelection = gap.length > selectionPageBounds.width; if (gapIsLargerThanSelection && round(Math.abs(centerNudge)) <= round(minOffset.x)) { if (round(Math.abs(centerNudge)) < round(minOffset.x)) { nearestSnapsX.length = 0; } minOffset.x = Math.abs(centerNudge); const snap = { type: "gap_center", gap, nudge: centerNudge }; const otherCenterSnap = nearestSnapsX.find(({ type }) => type === "gap_center"); const gapBreadthsOverlap = otherCenterSnap && (0, import_utils2.rangeIntersection)( gap.breadthIntersection[0], gap.breadthIntersection[1], otherCenterSnap.gap.breadthIntersection[0], otherCenterSnap.gap.breadthIntersection[1] ); if (otherCenterSnap && otherCenterSnap.gap.length > gap.length && gapBreadthsOverlap) { nearestSnapsX[nearestSnapsX.indexOf(otherCenterSnap)] = snap; } else if (!otherCenterSnap || !gapBreadthsOverlap) { nearestSnapsX.push(snap); } } const duplicationLeftX = gap.startNode.pageBounds.minX - gap.length; const selectionRightX = selectionPageBounds.maxX; const duplicationLeftNudge = duplicationLeftX - selectionRightX; if (round(Math.abs(duplicationLeftNudge)) <= round(minOffset.x)) { if (round(Math.abs(duplicationLeftNudge)) < round(minOffset.x)) { nearestSnapsX.length = 0; } minOffset.x = Math.abs(duplicationLeftNudge); nearestSnapsX.push({ type: "gap_duplicate", gap, protrusionDirection: "left", nudge: duplicationLeftNudge }); } const duplicationRightX = gap.endNode.pageBounds.maxX + gap.length; const selectionLeftX = selectionPageBounds.minX; const duplicationRightNudge = duplicationRightX - selectionLeftX; if (round(Math.abs(duplicationRightNudge)) <= round(minOffset.x)) { if (round(Math.abs(duplicationRightNudge)) < round(minOffset.x)) { nearestSnapsX.length = 0; } minOffset.x = Math.abs(duplicationRightNudge); nearestSnapsX.push({ type: "gap_duplicate", gap, protrusionDirection: "right", nudge: duplicationRightNudge }); } } for (const gap of vertical) { if (!(0, import_utils2.rangesOverlap)( gap.breadthIntersection[0], gap.breadthIntersection[1], selectionPageBounds.minX, selectionPageBounds.maxX )) { continue; } const gapMidY = gap.startEdge[0].y + gap.length / 2; const centerNudge = gapMidY - selectionPageBounds.center.y; const gapIsLargerThanSelection = gap.length > selectionPageBounds.height; if (gapIsLargerThanSelection && round(Math.abs(centerNudge)) <= round(minOffset.y)) { if (round(Math.abs(centerNudge)) < round(minOffset.y)) { nearestSnapsY.length = 0; } minOffset.y = Math.abs(centerNudge); const snap = { type: "gap_center", gap, nudge: centerNudge }; const otherCenterSnap = nearestSnapsY.find(({ type }) => type === "gap_center"); const gapBreadthsOverlap = otherCenterSnap && (0, import_utils2.rangesOverlap)( otherCenterSnap.gap.breadthIntersection[0], otherCenterSnap.gap.breadthIntersection[1], gap.breadthIntersection[0], gap.breadthIntersection[1] ); if (otherCenterSnap && otherCenterSnap.gap.length > gap.length && gapBreadthsOverlap) { nearestSnapsY[nearestSnapsY.indexOf(otherCenterSnap)] = snap; } else if (!otherCenterSnap || !gapBreadthsOverlap) { nearestSnapsY.push(snap); } continue; } const duplicationTopY = gap.startNode.pageBounds.minY - gap.length; const selectionBottomY = selectionPageBounds.maxY; const duplicationTopNudge = duplicationTopY - selectionBottomY; if (round(Math.abs(duplicationTopNudge)) <= round(minOffset.y)) { if (round(Math.abs(duplicationTopNudge)) < round(minOffset.y)) { nearestSnapsY.length = 0; } minOffset.y = Math.abs(duplicationTopNudge); nearestSnapsY.push({ type: "gap_duplicate", gap, protrusionDirection: "top", nudge: duplicationTopNudge }); } const duplicationBottomY = gap.endNode.pageBounds.maxY + gap.length; const selectionTopY = selectionPageBounds.minY; const duplicationBottomNudge = duplicationBottomY - selectionTopY; if (round(Math.abs(duplicationBottomNudge)) <= round(minOffset.y)) { if (round(Math.abs(duplicationBottomNudge)) < round(minOffset.y)) { nearestSnapsY.length = 0; } minOffset.y = Math.abs(duplicationBottomNudge); nearestSnapsY.push({ type: "gap_duplicate", gap, protrusionDirection: "bottom", nudge: duplicationBottomNudge }); } } } getPointSnapLines({ nearestSnapsX, nearestSnapsY }) { const snapGroupsX = {}; const snapGroupsY = {}; if (nearestSnapsX.length > 0) { for (const snap of nearestSnapsX) { if (snap.type === "points") { const key = round(snap.points.otherPoint.x); if (!snapGroupsX[key]) { snapGroupsX[key] = []; } snapGroupsX[key].push(snap.points); } } } if (nearestSnapsY.length > 0) { for (const snap of nearestSnapsY) { if (snap.type === "points") { const key = round(snap.points.otherPoint.y); if (!snapGroupsY[key]) { snapGroupsY[key] = []; } snapGroupsY[key].push(snap.points); } } } return Object.values(snapGroupsX).concat(Object.values(snapGroupsY)).map((snapGroup) => ({ id: (0, import_utils.uniqueId)(), type: "points", points: (0, import_utils.dedupe)( snapGroup.map((snap) => import_Vec.Vec.From(snap.otherPoint)).concat(snapGroup.map((snap) => import_Vec.Vec.From(snap.thisPoint))), (a, b) => a.equals(b) ) })); } getGapSnapLines({ selectionPageBounds, nearestSnapsX, nearestSnapsY }) { const { vertical, horizontal } = this.getVisibleGaps(); const selectionSides = { top: selectionPageBounds.sides[0], right: selectionPageBounds.sides[1], // need bottom and left to be sorted asc, which .sides is not. bottom: [selectionPageBounds.corners[3], selectionPageBounds.corners[2]], left: [selectionPageBounds.corners[0], selectionPageBounds.corners[3]] }; const result = []; if (nearestSnapsX.length > 0) { for (const snap of nearestSnapsX) { if (snap.type === "points") continue; const { gap: { breadthIntersection, startEdge, startNode, endNode, length, endEdge } } = snap; switch (snap.type) { case "gap_center": { const newGapsLength = (length - selectionPageBounds.width) / 2; const gapBreadthIntersection = (0, import_utils2.rangeIntersection)( breadthIntersection[0], breadthIntersection[1], selectionPageBounds.minY, selectionPageBounds.maxY ); result.push({ type: "gaps", direction: "horizontal", id: (0, import_utils.uniqueId)(), gaps: [ ...findAdjacentGaps( horizontal, startNode.id, newGapsLength, "backward", gapBreadthIntersection ), { startEdge, endEdge: selectionSides.left }, { startEdge: selectionSides.right, endEdge }, ...findAdjacentGaps( horizontal, endNode.id, newGapsLength, "forward", gapBreadthIntersection ) ] }); break; } case "gap_duplicate": { const gapBreadthIntersection = (0, import_utils2.rangeIntersection)( breadthIntersection[0], breadthIntersection[1], selectionPageBounds.minY, selectionPageBounds.maxY ); result.push({ type: "gaps", direction: "horizontal", id: (0, import_utils.uniqueId)(), gaps: snap.protrusionDirection === "left" ? [ { startEdge: selectionSides.right, endEdge: startEdge.map( (v) => v.clone().addXY(-startNode.pageBounds.width, 0) ) }, { startEdge, endEdge }, ...findAdjacentGaps( horizontal, endNode.id, length, "forward", gapBreadthIntersection ) ] : [ ...findAdjacentGaps( horizontal, startNode.id, length, "backward", gapBreadthIntersection ), { startEdge, endEdge }, { startEdge: endEdge.map( (v) => v.clone().addXY(snap.gap.endNode.pageBounds.width, 0) ), endEdge: selectionSides.left } ] }); break; } } } } if (nearestSnapsY.length > 0) { for (const snap of nearestSnapsY) { if (snap.type === "points") continue; const { gap: { breadthIntersection, startEdge, startNode, endNode, length, endEdge } } = snap; switch (snap.type) { case "gap_center": { const newGapsLength = (length - selectionPageBounds.height) / 2; const gapBreadthIntersection = (0, import_utils2.rangeIntersection)( breadthIntersection[0], breadthIntersection[1], selectionPageBounds.minX, selectionPageBounds.maxX ); result.push({ type: "gaps", direction: "vertical", id: (0, import_utils.uniqueId)(), gaps: [ ...findAdjacentGaps( vertical, startNode.id, newGapsLength, "backward", gapBreadthIntersection ), { startEdge, endEdge: selectionSides.top }, { startEdge: selectionSides.bottom, endEdge }, ...findAdjacentGaps( vertical, snap.gap.endNode.id, newGapsLength, "forward", gapBreadthIntersection ) ] }); break; } case "gap_duplicate": { const gapBreadthIntersection = (0, import_utils2.rangeIntersection)( breadthIntersection[0], breadthIntersection[1], selectionPageBounds.minX, selectionPageBounds.maxX ); result.push({ type: "gaps", direction: "vertical", id: (0, import_utils.uniqueId)(), gaps: snap.protrusionDirection === "top" ? [ { startEdge: selectionSides.bottom, endEdge: startEdge.map( (v) => v.clone().addXY(0, -startNode.pageBounds.height) ) }, { startEdge, endEdge }, ...findAdjacentGaps( vertical, endNode.id, length, "forward", gapBreadthIntersection ) ] : [ ...findAdjacentGaps( vertical, startNode.id, length, "backward", gapBreadthIntersection ), { startEdge, endEdge }, { startEdge: endEdge.map( (v) => v.clone().addXY(0, endNode.pageBounds.height) ), endEdge: selectionSides.top } ] }); } break; } } } dedupeGapSnaps(result); return result; } } __decorateClass([ import_state.computed ], BoundsSnaps.prototype, "getSnapPointsCache", 1); __decorateClass([ import_state.computed ], BoundsSnaps.prototype, "getSnappablePoints", 1); __decorateClass([ import_state.computed ], BoundsSnaps.prototype, "getSnappableGapNodes", 1); __decorateClass([ import_state.computed ], BoundsSnaps.prototype, "getVisibleGaps", 1); function getResizeSnapPointsForHandle(handle, selectionPageBounds) { const { minX, maxX, minY, maxY } = selectionPageBounds; const result = []; switch (handle) { case "top": case "left": case "top_left": case "any": result.push({ id: "top_left", handle: "top_left", x: minX, y: minY }); } switch (handle) { case "top": case "right": case "top_right": case "any": result.push({ id: "top_right", handle: "top_right", x: maxX, y: minY }); } switch (handle) { case "bottom": case "right": case "bottom_right": case "any": result.push({ id: "bottom_right", handle: "bottom_right", x: maxX, y: maxY }); } switch (handle) { case "bottom": case "left": case "bottom_left": case "any": result.push({ id: "bottom_left", handle: "bottom_left", x: minX, y: maxY }); } return result; } //# sourceMappingURL=BoundsSnaps.js.map