sliced-areas 1.0.2 → 1.0.4
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/README.md +39 -51
- package/dist/index.js +1 -1
- package/dist/{sliced-areas-DS_2BRnf.js → sliced-areas-rZ_V6Je7.js} +8 -3
- package/dist/sliced-areas-rZ_V6Je7.js.map +1 -0
- package/dist/sliced-areas.d.ts +8 -0
- package/dist/vue.d.ts +1 -0
- package/dist/vue.js +2 -2
- package/dist/vue.js.map +1 -1
- package/package.json +8 -5
- package/dist/sliced-areas-DS_2BRnf.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sliced-areas-DS_2BRnf.js","names":["next: AreasGraph","rects: Array<{ id: AreaId; rect: Rect }>","verts: Record<VertId, GraphVert>","edges: Record<EdgeId, GraphEdge>","areas: Record<AreaId, GraphArea>","keep: 'min' | 'max'","bottomArea: GraphArea","topArea: GraphArea","leftArea: GraphArea","rightArea: GraphArea","created: RemainderInfo[]","handles: HTMLDivElement[]","events: Array<{ pos: number; delta: number }>","result: Array<{ start: number; end: number }>","activeStart: number | null","verts: AreasGraph['verts']","edges: AreasGraph['edges']","areas: AreasGraph['areas']","secondary: Rect","best: { target: GraphArea; rect: Rect; distance: number; orientation: JoinDir } | null","rects: Rect[]","remap: Record<VertId, VertId>","pairs: [VertId, VertId][]","filteredEdges: Record<EdgeId, GraphEdge>","filteredVerts: Record<VertId, GraphVert>","holes: Rect[]","cell: Rect","coords: number[]","merged: number[]","mergedRect: Rect","sides: Array<'west' | 'east' | 'south' | 'north'>","neighbors: Array<{ areaId: AreaId; rect: Rect }>","segments: Array<{ start: number; end: number }>","merged: Array<{ start: number; end: number }>","overlaps: Array<{ a: AreaId; b: AreaId; rect: Rect }>","queue: VertId[]"],"sources":["../src/plugin/sliced-areas.ts"],"sourcesContent":["/**\n * Stable identifier used by the layout graph to reference an area.\n */\nexport type AreaId = string\n\n/**\n * External tag used by the host to map content into areas.\n */\nexport type AreaTag = string\n\n/**\n * Corner identifiers used for drag docking gestures.\n */\nexport type CornerId = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'\n\n/**\n * Normalized rectangle in layout space (0..1).\n */\nexport type AreaRect = {\n left: number\n right: number\n top: number\n bottom: number\n}\n\n/**\n * Internal vertex identifier in the planar graph.\n */\ntype VertId = string\n\n/**\n * Internal edge identifier in the planar graph.\n */\ntype EdgeId = string\n\n/**\n * Graph vertex with normalized coordinates.\n */\nexport type GraphVert = {\n id: VertId\n x: number\n y: number\n}\n\n/**\n * Graph edge connecting two vertices, optionally on the border.\n */\nexport type GraphEdge = {\n id: EdgeId\n v1: VertId\n v2: VertId\n border: boolean\n}\n\n/**\n * Area represented by four ordered vertices.\n */\nexport type GraphArea = {\n id: AreaId\n v1: VertId\n v2: VertId\n v3: VertId\n v4: VertId\n}\n\n/**\n * Full planar graph for the layout.\n */\nexport type AreasGraph = {\n verts: Record<VertId, GraphVert>\n edges: Record<EdgeId, GraphEdge>\n areas: Record<AreaId, GraphArea>\n}\n\n/**\n * Serializable layout payload used by the host.\n */\nexport type AreasLayout = {\n areas: Array<{ tag: AreaTag; rect: AreaRect }>\n}\n\n/**\n * Payload emitted when a corner click is detected.\n */\nexport type CornerClickDetail = {\n areaId: AreaId\n corner: CornerId\n clientX: number\n clientY: number\n}\n\n/**\n * Alias for normalized rectangle geometry.\n */\ntype Rect = AreaRect\n\n/**\n * Axis used for splits and edge moves.\n */\ntype SplitAxis = 'horizontal' | 'vertical'\n\n/**\n * Direction describing adjacency between two areas.\n */\ntype JoinDir = 'west' | 'east' | 'north' | 'south' | 'none'\n\n/**\n * Tracks areas created while trimming to overlap ranges.\n */\ntype RemainderInfo = { id: AreaId; sourceAreaId: AreaId }\n\n/**\n * Resolves host content for an area tag.\n */\nexport type AreaResolver = (tag: AreaTag) => HTMLElement | null | undefined\n\n/**\n * State for resizing drag handles.\n */\ntype DragState = {\n axis: SplitAxis\n coord: number\n start: number\n end: number\n min: number\n max: number\n pointerId: number\n originX: number\n originY: number\n}\n\n/**\n * State for area move/split/join/swap gestures.\n */\ntype AreaDragState = {\n sourceAreaId: AreaId\n pointerId: number\n startX: number\n startY: number\n lastX: number\n lastY: number\n axis: SplitAxis | null\n swapMode: boolean\n originCorner?: CornerId\n moved?: boolean\n}\n\n/**\n * Attribute used to mark internal plugin nodes.\n */\nconst INTERNAL_ATTR = 'data-sliced-areas-internal'\n\n/**\n * Attribute marking auto-generated area nodes.\n */\nconst AUTO_ATTR = 'data-sliced-areas-auto'\n\n/**\n * Default split ratio when splitting without a pointer.\n */\nconst DEFAULT_RATIO = 0.5\n\n/**\n * Minimum allowed area ratio per axis.\n */\nconst MIN_RATIO = 0.08\n\n/**\n * Floating-point epsilon for geometry comparisons.\n */\nconst EPS = 1e-6\n\n/**\n * Tolerance used for alignment and grid merging.\n */\nconst ALIGN_TOLERANCE = 1e-4\n\n/**\n * Tolerance used for area joining alignment.\n */\nconst JOIN_TOLERANCE = 0.02\n\n/**\n * Visible splitter thickness in pixels.\n */\nconst DEFAULT_SPLITTER_SIZE = 2\n\n/**\n * Depth of the join target zone relative to the area size.\n */\nconst JOIN_ZONE_DEPTH = 0.18\n\n/**\n * Movement threshold to start split gesture detection.\n */\nconst SPLIT_GESTURE_THRESHOLD_PX = 6\n\n/**\n * Axis dominance threshold for split gesture classification.\n */\nconst SPLIT_AXIS_TOLERANCE_PX = 12\n\n/**\n * Radius in pixels to treat drag as parked (no action).\n */\nconst DRAG_PARK_TOLERANCE_PX = 20\n\n/**\n * Movement threshold in pixels to treat as a click.\n */\nconst CLICK_TOLERANCE_PX = 4\n\n/**\n * Pixel snap tolerance for move preview.\n */\nconst MOVE_SNAP_PX = 12\n\n/**\n * Minimum center zone size for replace action.\n */\nconst REPLACE_THRESHOLD_RATIO = MIN_RATIO * 3\n\n/**\n * Web component implementing Blender-like area layout behavior.\n */\nexport class SlicedAreasElement extends HTMLElement {\n /**\n * Current graph model, or null when no layout is active.\n */\n private graph: AreasGraph | null = null\n\n /**\n * Root container for generated layout nodes.\n */\n private rootEl: HTMLDivElement | null = null\n\n /**\n * Hidden container used to stash detached area nodes.\n */\n private stashEl: HTMLDivElement | null = null\n\n /**\n * Resize observer to re-render on host size changes.\n */\n private resizeObserver: ResizeObserver | null = null\n\n /**\n * Active resize drag state for splitters.\n */\n private dragState: DragState | null = null\n\n /**\n * Active area drag state for move/split/join/swap.\n */\n private areaDragState: AreaDragState | null = null\n\n /**\n * Last pointer position seen during area drag.\n */\n private lastPointer: { x: number; y: number } | null = null\n\n /**\n * Overlay element used to preview drop zones.\n */\n private dropOverlay: HTMLDivElement | null = null\n\n /**\n * Dimmed overlay used to preview join results.\n */\n private dropShade: HTMLDivElement | null = null\n\n /**\n * Floating label used during drag interactions.\n */\n private dragLabel: HTMLDivElement | null = null\n\n /**\n * Snapshot used to revert canceled resize drags.\n */\n private dragSnapshot: AreasGraph | null = null\n\n /**\n * Cached cursor style so it can be restored.\n */\n private dragCursor: string | null = null\n\n /**\n * Stored graph when an area is maximized.\n */\n private storedGraph: AreasGraph | null = null\n\n /**\n * Stored tag mapping when an area is maximized.\n */\n private storedTags: Map<AreaId, AreaTag> | null = null\n\n /**\n * Resolver used to materialize area content.\n */\n private areaResolver: AreaResolver | null = null\n\n /**\n * Cache of resolved area nodes by id.\n */\n private resolvedNodes = new Map<AreaId, HTMLElement>()\n\n /**\n * Tag mapping for areas in the current graph.\n */\n private areaTags = new Map<AreaId, AreaTag>()\n\n /**\n * Counter for generating unique vertex ids.\n */\n private vertCounter = 0\n\n /**\n * Counter for generating unique edge ids.\n */\n private edgeCounter = 0\n\n /**\n * Counter for generating unique area ids.\n */\n private areaCounter = 0\n\n /**\n * Returns the current serialized layout.\n *\n * @returns Current layout or null when empty.\n */\n get layout(): AreasLayout | null {\n if (!this.graph) return null\n return this.serializeLayout(this.graph)\n }\n\n /**\n * Applies a serialized layout to the component.\n *\n * @param value Layout to apply, or null to clear.\n */\n set layout(value: AreasLayout | null) {\n if (!value) {\n this.graph = null\n this.areaTags.clear()\n this.storedGraph = null\n this.storedTags = null\n this.resolvedNodes.clear()\n this.render()\n return\n }\n if (value.areas.length === 0) {\n this.graph = null\n this.areaTags.clear()\n this.storedGraph = null\n this.storedTags = null\n this.resolvedNodes.clear()\n this.render()\n return\n }\n this.storedGraph = null\n this.storedTags = null\n this.graph = this.buildGraphFromLayout(value)\n this.resolvedNodes.clear()\n this.render()\n }\n\n /**\n * Sets a resolver for auto-providing area content.\n *\n * @param resolver Callback for resolving an area tag to a node.\n */\n setResolver(resolver: AreaResolver | null): void {\n this.areaResolver = resolver\n this.resolvedNodes.clear()\n if (resolver) {\n this.render()\n }\n }\n\n /**\n * Initializes internal DOM and observers when connected.\n */\n connectedCallback(): void {\n this.ensureRoot()\n this.addEventListener('sliced-areas:retag', this.onRetagRequest as EventListener)\n this.ensureResizeObserver()\n this.render()\n }\n\n /**\n * Cleans up observers and listeners when disconnected.\n */\n disconnectedCallback(): void {\n if (this.resizeObserver) {\n this.resizeObserver.disconnect()\n this.resizeObserver = null\n }\n this.detachDragListeners()\n this.removeEventListener('sliced-areas:retag', this.onRetagRequest as EventListener)\n }\n\n /**\n * Splits an area by zone, optionally using a pointer position.\n *\n * @param sourceAreaId Area to split.\n * @param zone Split direction.\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n */\n split(\n sourceAreaId: AreaId,\n zone: 'left' | 'right' | 'top' | 'bottom' = 'right',\n clientX = 0,\n clientY = 0,\n ): void {\n if (!this.graph) return\n const newAreaId = this.nextAreaId()\n const updated =\n Number.isFinite(clientX) && Number.isFinite(clientY) && this.rootEl\n ? this.splitAreaAtPointer(this.graph, sourceAreaId, zone, clientX, clientY, newAreaId)\n : this.splitAreaByZone(this.graph, sourceAreaId, zone, DEFAULT_RATIO, newAreaId)\n if (!updated) return\n this.ensureAreaNode(newAreaId, sourceAreaId, true)\n this.graph = this.normalizeGraph(updated)\n this.emitLayoutChange()\n this.render()\n }\n\n /**\n * Joins two adjacent areas when alignment permits.\n *\n * @param sourceAreaId Area being merged into the target.\n * @param targetAreaId Area that remains after the join.\n */\n join(sourceAreaId: AreaId, targetAreaId: AreaId): void {\n if (!this.graph) return\n if (!this.canJoin(sourceAreaId, targetAreaId)) return\n const updated = this.joinAreas(this.graph, sourceAreaId, targetAreaId)\n if (!updated) return\n this.graph = this.normalizeGraph(updated)\n this.pruneAreaTags(this.graph)\n this.emitLayoutChange()\n this.render()\n }\n\n /**\n * Replaces the target area with the source area content.\n *\n * @param sourceAreaId Area providing the content.\n * @param targetAreaId Area to remove.\n */\n replace(sourceAreaId: AreaId, targetAreaId: AreaId): void {\n if (!this.graph) return\n const updated = this.replaceArea(this.graph, sourceAreaId, targetAreaId)\n if (!updated) return\n this.graph = this.normalizeGraph(updated)\n this.removeAreaNode(targetAreaId)\n this.pruneAreaTags(this.graph)\n this.emitLayoutChange()\n this.render()\n }\n\n /**\n * Swaps the ids (and therefore content) between two areas.\n *\n * @param sourceAreaId First area id.\n * @param targetAreaId Second area id.\n */\n swap(sourceAreaId: AreaId, targetAreaId: AreaId): void {\n if (!this.graph) return\n const updated = this.swapAreaIds(this.graph, sourceAreaId, targetAreaId)\n if (!updated) return\n this.graph = updated\n this.emitLayoutChange()\n this.render()\n }\n\n /**\n * Moves one area into another, producing overlay and remainder areas.\n *\n * @param sourceAreaId Area being moved.\n * @param targetAreaId Area being split to receive the move.\n * @param overlay Target rectangle for the moved area.\n * @param remainder Remaining rectangle for the target area.\n */\n move(sourceAreaId: AreaId, targetAreaId: AreaId, overlay: Rect, remainder: Rect): void {\n if (!this.graph) return\n const updated = this.moveArea(this.graph, sourceAreaId, targetAreaId, overlay, remainder)\n if (!updated) return\n this.graph = this.normalizeGraph(updated)\n this.emitLayoutChange()\n this.render()\n }\n\n /**\n * Removes an area from the layout if possible.\n *\n * @param areaId Area to close.\n */\n close(areaId: AreaId): void {\n if (!this.graph) return\n if (!this.graph.areas[areaId]) return\n if (Object.keys(this.graph.areas).length <= 1) return\n\n const next: AreasGraph = {\n verts: { ...this.graph.verts },\n edges: { ...this.graph.edges },\n areas: { ...this.graph.areas },\n }\n\n delete next.areas[areaId]\n this.graph = this.normalizeGraph(next)\n this.removeAreaNode(areaId)\n this.pruneAreaTags(this.graph)\n this.emitLayoutChange()\n this.render()\n }\n\n /**\n * Updates the tag for a specific area.\n *\n * @param areaId Area to retag.\n * @param tag New tag value.\n */\n retag(areaId: AreaId, tag: AreaTag): void {\n if (!this.graph) return\n if (!this.graph.areas[areaId]) return\n if (this.areaTags.get(areaId) === tag) return\n this.areaTags.set(areaId, tag)\n this.resolvedNodes.delete(areaId)\n this.detachAreaNode(areaId)\n this.emitLayoutChange()\n this.render()\n }\n\n /**\n * Maximizes a single area and stores the previous layout.\n *\n * @param areaId Area to maximize.\n */\n maximize(areaId: AreaId): void {\n if (!this.graph) return\n if (this.storedGraph) return\n if (!this.graph.areas[areaId]) return\n this.storedGraph = this.graph\n this.storedTags = new Map(this.areaTags)\n this.graph = this.createBaseGraph(areaId)\n this.areaTags = new Map()\n const tag = this.storedTags.get(areaId)\n if (tag) {\n this.areaTags.set(areaId, tag)\n }\n this.emitLayoutChange()\n this.render()\n }\n\n /**\n * Restores the layout from a previous maximize action.\n */\n restore(): void {\n if (!this.storedGraph) return\n this.graph = this.storedGraph\n if (this.storedTags) {\n this.areaTags = new Map(this.storedTags)\n }\n this.storedGraph = null\n this.storedTags = null\n this.emitLayoutChange()\n this.render()\n }\n\n /**\n * Creates the root container element if it does not exist.\n */\n private ensureRoot(): void {\n if (this.rootEl) return\n\n const existing = this.querySelector<HTMLDivElement>(':scope > .sliced-areas-root')\n this.rootEl = existing ?? document.createElement('div')\n this.rootEl.classList.add('sliced-areas-root')\n this.rootEl.setAttribute(INTERNAL_ATTR, 'true')\n\n if (!existing) {\n this.appendChild(this.rootEl)\n }\n\n this.rootEl.addEventListener('pointerdown', this.onPointerDown)\n this.ensureStash()\n }\n\n /**\n * Creates the stash container used to hold detached nodes.\n */\n private ensureStash(): void {\n if (this.stashEl) return\n const existing = this.querySelector<HTMLDivElement>(':scope > .sliced-areas-stash')\n this.stashEl = existing ?? document.createElement('div')\n this.stashEl.classList.add('sliced-areas-stash')\n this.stashEl.setAttribute(INTERNAL_ATTR, 'true')\n if (!existing) {\n this.appendChild(this.stashEl)\n }\n }\n\n /**\n * Attaches a ResizeObserver to trigger re-rendering.\n */\n private ensureResizeObserver(): void {\n if (this.resizeObserver) return\n\n this.resizeObserver = new ResizeObserver(() => {\n this.render()\n })\n this.resizeObserver.observe(this)\n }\n\n /**\n * Emits a layout change event with serialized data.\n */\n private emitLayoutChange(): void {\n if (!this.graph) return\n this.dispatchEvent(\n new CustomEvent('sliced-areas:layoutchange', {\n detail: { layout: this.serializeLayout(this.graph) },\n }),\n )\n }\n\n /**\n * Emits a corner click event for docking actions.\n *\n * @param detail Corner click payload.\n */\n private emitCornerClick(detail: CornerClickDetail): void {\n if (detail.corner !== 'top-left') return\n this.dispatchEvent(new CustomEvent('sliced-areas:cornerclick', { detail }))\n }\n\n /**\n * Renders the current graph into positioned DOM nodes.\n */\n private render(): void {\n if (!this.rootEl || !this.graph) return\n\n const areaNodes = this.collectAreaNodes()\n this.ensureStash()\n if (this.stashEl) {\n this.stashEl.innerHTML = ''\n }\n let missing = Object.values(this.graph.areas).filter((area) => !areaNodes.has(area.id))\n if (missing.length > 0 && this.areaResolver) {\n for (const area of missing) {\n const cached = this.resolvedNodes.get(area.id)\n if (cached) {\n areaNodes.set(area.id, cached)\n continue\n }\n const tag = this.areaTags.get(area.id) ?? area.id\n const resolved = this.areaResolver(tag)\n if (resolved) {\n resolved.dataset.areaId = area.id\n resolved.setAttribute(AUTO_ATTR, 'true')\n this.resolvedNodes.set(area.id, resolved)\n areaNodes.set(area.id, resolved)\n }\n }\n missing = Object.values(this.graph.areas).filter((area) => !areaNodes.has(area.id))\n }\n if (missing.length > 0) {\n const detail = {\n missing: missing.map((area) => area.id),\n areas: Object.values(this.graph.areas).map((area) => ({\n id: area.id,\n rect: this.formatRect(this.getAreaRect(this.graph as AreasGraph, area)),\n })),\n }\n throw new Error(`Missing area content detected: ${JSON.stringify(detail)}`)\n }\n const rect = this.rootEl.getBoundingClientRect()\n const width = Math.max(rect.width, 1)\n const height = Math.max(rect.height, 1)\n const splitterInset = DEFAULT_SPLITTER_SIZE / 2\n\n this.rootEl.innerHTML = ''\n\n for (const area of Object.values(this.graph.areas)) {\n const areaRect = this.getAreaRect(this.graph, area)\n const wrapper = document.createElement('div')\n wrapper.classList.add('sliced-areas-area')\n wrapper.setAttribute(INTERNAL_ATTR, 'true')\n const left = areaRect.left * width + splitterInset\n const top = (1 - areaRect.top) * height + splitterInset\n const areaWidth = (areaRect.right - areaRect.left) * width - splitterInset * 2\n const areaHeight = (areaRect.top - areaRect.bottom) * height - splitterInset * 2\n wrapper.style.left = `${left}px`\n wrapper.style.top = `${top}px`\n wrapper.style.width = `${Math.max(areaWidth, 0)}px`\n wrapper.style.height = `${Math.max(areaHeight, 0)}px`\n\n const overlay = document.createElement('div')\n overlay.classList.add('sliced-areas-overlay')\n overlay.setAttribute(INTERNAL_ATTR, 'true')\n wrapper.appendChild(overlay)\n\n const corners = ['top-left', 'top-right', 'bottom-left', 'bottom-right'] as const\n for (const corner of corners) {\n const handle = document.createElement('div')\n handle.classList.add('sliced-areas-corner')\n handle.classList.add(`is-${corner}`)\n handle.setAttribute(INTERNAL_ATTR, 'true')\n handle.dataset.areaId = area.id\n handle.dataset.corner = corner\n overlay.appendChild(handle)\n }\n\n const areaNode = areaNodes.get(area.id)\n if (areaNode) {\n wrapper.appendChild(areaNode)\n } else {\n throw new Error(`Missing area content for ${area.id}`)\n }\n\n this.rootEl.appendChild(wrapper)\n }\n\n if (this.stashEl) {\n for (const [areaId, node] of areaNodes.entries()) {\n if (!this.graph.areas[areaId]) {\n this.stashEl.appendChild(node)\n }\n }\n }\n\n for (const handle of this.buildResizeHandles(this.graph, width, height)) {\n this.rootEl.appendChild(handle)\n }\n }\n\n /**\n * Collects host-provided area nodes keyed by area id.\n *\n * @returns Map of area ids to nodes.\n */\n private collectAreaNodes(): Map<AreaId, HTMLElement> {\n const map = new Map<AreaId, HTMLElement>()\n const candidates = Array.from(this.querySelectorAll<HTMLElement>('[data-area-id]'))\n\n for (const node of candidates) {\n if (node.hasAttribute(INTERNAL_ATTR)) continue\n const id = node.dataset.areaId\n if (!id) continue\n const isAuto = node.hasAttribute(AUTO_ATTR)\n const existing = map.get(id)\n if (existing) {\n const existingIsAuto = existing.hasAttribute(AUTO_ATTR)\n if (existingIsAuto && !isAuto) {\n existing.remove()\n map.set(id, node)\n }\n continue\n }\n map.set(id, node)\n }\n\n return map\n }\n\n /**\n * Ensures a DOM node exists for a newly created area.\n *\n * @param newAreaId Area id needing a node.\n * @param sourceAreaId Area id to clone or inherit from.\n * @param cloneSource Whether to clone the source node when possible.\n */\n private ensureAreaNode(newAreaId: AreaId, sourceAreaId: AreaId, cloneSource = true): void {\n const existing = Array.from(\n this.querySelectorAll<HTMLElement>(`[data-area-id=\"${newAreaId}\"]`),\n ).find((node) => !node.hasAttribute(INTERNAL_ATTR))\n if (existing) return\n\n this.inheritAreaTag(newAreaId, sourceAreaId)\n const sourceTag = this.areaTags.get(sourceAreaId) ?? this.areaTags.get(newAreaId)\n\n const source = Array.from(\n this.querySelectorAll<HTMLElement>(`[data-area-id=\"${sourceAreaId}\"]`),\n ).find((node) => !node.hasAttribute(INTERNAL_ATTR))\n const sourceIsAuto = source?.hasAttribute(AUTO_ATTR) ?? false\n if (cloneSource && source && (!sourceIsAuto || !this.areaResolver)) {\n const clone = source.cloneNode(true) as HTMLElement\n clone.dataset.areaId = newAreaId\n clone.setAttribute(AUTO_ATTR, 'true')\n this.appendChild(clone)\n return\n }\n\n if (sourceTag && this.areaResolver) {\n const resolved = this.areaResolver(sourceTag)\n if (resolved) {\n resolved.dataset.areaId = newAreaId\n resolved.setAttribute(AUTO_ATTR, 'true')\n this.appendChild(resolved)\n return\n }\n }\n\n const placeholder = document.createElement('div')\n placeholder.dataset.areaId = newAreaId\n placeholder.classList.add('sliced-areas-auto-content')\n placeholder.setAttribute(AUTO_ATTR, 'true')\n placeholder.textContent = sourceTag ?? 'Area'\n this.appendChild(placeholder)\n }\n\n /**\n * Copies a tag from an existing area when creating a new one.\n *\n * @param newAreaId Area id to assign a tag to.\n * @param sourceAreaId Area id to inherit the tag from.\n */\n private inheritAreaTag(newAreaId: AreaId, sourceAreaId: AreaId): void {\n if (this.areaTags.has(newAreaId)) return\n const tag = this.areaTags.get(sourceAreaId)\n if (tag) {\n this.areaTags.set(newAreaId, tag)\n return\n }\n this.areaTags.set(newAreaId, sourceAreaId)\n }\n\n /**\n * Builds a graph from a serialized layout payload.\n *\n * @param layout Serialized layout data.\n * @returns Graph representation of the layout.\n */\n private buildGraphFromLayout(layout: AreasLayout): AreasGraph {\n this.areaTags.clear()\n const rects: Array<{ id: AreaId; rect: Rect }> = []\n for (const area of layout.areas) {\n const id = this.nextAreaId()\n rects.push({ id, rect: area.rect })\n this.areaTags.set(id, area.tag)\n }\n const graph = this.buildGraphFromRects(rects)\n return this.normalizeGraph(graph)\n }\n\n /**\n * Converts the graph into a serialized layout payload.\n *\n * @param graph Graph to serialize.\n * @returns Layout payload for events.\n */\n private serializeLayout(graph: AreasGraph): AreasLayout {\n return {\n areas: Object.values(graph.areas).map((area) => ({\n tag: this.areaTags.get(area.id) ?? area.id,\n rect: this.formatRect(this.getAreaRect(graph, area)),\n })),\n }\n }\n\n /**\n * Removes tags for areas that no longer exist.\n *\n * @param graph Current graph for validation.\n */\n private pruneAreaTags(graph: AreasGraph): void {\n for (const areaId of this.areaTags.keys()) {\n if (!graph.areas[areaId]) {\n this.areaTags.delete(areaId)\n this.resolvedNodes.delete(areaId)\n }\n }\n }\n\n /**\n * Handles bubbled retag events from area content.\n *\n * @param event Retag event from child content.\n */\n private onRetagRequest = (event: Event): void => {\n const detail = (event as CustomEvent<{ tag?: AreaTag }>).detail\n const nextTag = detail?.tag\n if (!nextTag || typeof nextTag !== 'string') return\n const target = event.target\n if (!(target instanceof HTMLElement)) return\n const areaNode = target.closest('[data-area-id]')\n if (!areaNode || !(areaNode instanceof HTMLElement)) return\n const areaId = areaNode.dataset.areaId\n if (!areaId) return\n if (!this.graph?.areas[areaId]) return\n event.stopPropagation()\n this.retag(areaId, nextTag)\n }\n\n /**\n * Normalizes rectangles so the layout spans the unit square.\n *\n * @param rects Rectangles to normalize.\n * @returns Normalized rectangles.\n */\n private normalizeRectsToUnit(\n rects: Array<{ id: AreaId; rect: Rect }>,\n ): Array<{ id: AreaId; rect: Rect }> {\n let minLeft = Infinity\n let maxRight = -Infinity\n let minBottom = Infinity\n let maxTop = -Infinity\n\n for (const item of rects) {\n minLeft = Math.min(minLeft, item.rect.left)\n maxRight = Math.max(maxRight, item.rect.right)\n minBottom = Math.min(minBottom, item.rect.bottom)\n maxTop = Math.max(maxTop, item.rect.top)\n }\n\n if (\n !Number.isFinite(minLeft) ||\n !Number.isFinite(maxRight) ||\n !Number.isFinite(minBottom) ||\n !Number.isFinite(maxTop)\n ) {\n return rects\n }\n\n const spanX = maxRight - minLeft\n const spanY = maxTop - minBottom\n if (spanX <= EPS || spanY <= EPS) return rects\n\n if (\n Math.abs(minLeft) <= EPS &&\n Math.abs(maxRight - 1) <= EPS &&\n Math.abs(minBottom) <= EPS &&\n Math.abs(maxTop - 1) <= EPS\n ) {\n return rects\n }\n\n return rects.map((item) => ({\n id: item.id,\n rect: {\n left: (item.rect.left - minLeft) / spanX,\n right: (item.rect.right - minLeft) / spanX,\n bottom: (item.rect.bottom - minBottom) / spanY,\n top: (item.rect.top - minBottom) / spanY,\n },\n }))\n }\n\n /**\n * Builds a graph from normalized rectangles.\n *\n * @param rects Rectangles that describe areas.\n * @returns Graph built from the rectangles.\n */\n private buildGraphFromRects(rects: Array<{ id: AreaId; rect: Rect }>): AreasGraph {\n const verts: Record<VertId, GraphVert> = {}\n const edges: Record<EdgeId, GraphEdge> = {}\n const areas: Record<AreaId, GraphArea> = {}\n const vertMap = new Map<string, VertId>()\n\n const getVert = (x: number, y: number): VertId => {\n const key = `${x.toFixed(6)}|${y.toFixed(6)}`\n const existing = vertMap.get(key)\n if (existing) return existing\n const id = this.addVert(verts, x, y)\n vertMap.set(key, id)\n return id\n }\n\n for (const item of rects) {\n const rect = item.rect\n const v1 = getVert(rect.left, rect.bottom)\n const v2 = getVert(rect.left, rect.top)\n const v3 = getVert(rect.right, rect.top)\n const v4 = getVert(rect.right, rect.bottom)\n areas[item.id] = { id: item.id, v1, v2, v3, v4 }\n this.addEdge(edges, v1, v2)\n this.addEdge(edges, v2, v3)\n this.addEdge(edges, v3, v4)\n this.addEdge(edges, v4, v1)\n }\n\n return { verts, edges, areas }\n }\n\n /**\n * Creates a single-area graph spanning the full layout.\n *\n * @param areaId Area id for the base graph.\n * @returns Graph with a single area.\n */\n private createBaseGraph(areaId: AreaId): AreasGraph {\n const verts: Record<VertId, GraphVert> = {}\n const edges: Record<EdgeId, GraphEdge> = {}\n const areas: Record<AreaId, GraphArea> = {}\n\n const v1 = this.addVert(verts, 0, 0)\n const v2 = this.addVert(verts, 0, 1)\n const v3 = this.addVert(verts, 1, 1)\n const v4 = this.addVert(verts, 1, 0)\n\n const e1 = this.nextEdgeId(edges)\n edges[e1] = { id: e1, v1, v2, border: true }\n const e2 = this.nextEdgeId(edges)\n edges[e2] = { id: e2, v1: v2, v2: v3, border: true }\n const e3 = this.nextEdgeId(edges)\n edges[e3] = { id: e3, v1: v3, v2: v4, border: true }\n const e4 = this.nextEdgeId(edges)\n edges[e4] = { id: e4, v1: v4, v2: v1, border: true }\n\n areas[areaId] = { id: areaId, v1, v2, v3, v4 }\n\n return { verts, edges, areas }\n }\n\n /**\n * Splits an area by a zone using a ratio.\n *\n * @param graph Graph to update.\n * @param areaId Area to split.\n * @param zone Split direction.\n * @param ratio Split ratio within the area.\n * @param newAreaId Id for the new area.\n * @returns Updated graph or null when split is invalid.\n */\n private splitAreaByZone(\n graph: AreasGraph,\n areaId: AreaId,\n zone: 'left' | 'right' | 'top' | 'bottom',\n ratio: number,\n newAreaId: AreaId,\n ): AreasGraph | null {\n const area = graph.areas[areaId]\n if (!area) return null\n\n const rect = this.getAreaRect(graph, area)\n const clampedRatio = Math.max(MIN_RATIO, Math.min(1 - MIN_RATIO, ratio))\n\n if (zone === 'left' || zone === 'right') {\n const width = rect.right - rect.left\n const splitX =\n zone === 'left' ? rect.left + width * clampedRatio : rect.left + width * (1 - clampedRatio)\n const keep: 'min' | 'max' = zone === 'left' ? 'max' : 'min'\n return this.splitAreaAt(graph, areaId, 'vertical', splitX, newAreaId, keep)\n }\n\n const height = rect.top - rect.bottom\n const splitY =\n zone === 'bottom'\n ? rect.bottom + height * clampedRatio\n : rect.bottom + height * (1 - clampedRatio)\n const keep: 'min' | 'max' = zone === 'bottom' ? 'max' : 'min'\n return this.splitAreaAt(graph, areaId, 'horizontal', splitY, newAreaId, keep)\n }\n\n /**\n * Splits an area using a pointer position inside the component.\n *\n * @param graph Graph to update.\n * @param areaId Area to split.\n * @param zone Split direction.\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n * @param newAreaId Id for the new area.\n * @returns Updated graph or null when split is invalid.\n */\n private splitAreaAtPointer(\n graph: AreasGraph,\n areaId: AreaId,\n zone: 'left' | 'right' | 'top' | 'bottom',\n clientX: number,\n clientY: number,\n newAreaId: AreaId,\n ): AreasGraph | null {\n const area = graph.areas[areaId]\n if (!area || !this.rootEl) return null\n\n const rect = this.rootEl.getBoundingClientRect()\n const x = (clientX - rect.left) / rect.width\n const y = 1 - (clientY - rect.top) / rect.height\n const areaRect = this.getAreaRect(graph, area)\n\n const clampedX = Math.min(Math.max(x, areaRect.left + MIN_RATIO), areaRect.right - MIN_RATIO)\n const clampedY = Math.min(Math.max(y, areaRect.bottom + MIN_RATIO), areaRect.top - MIN_RATIO)\n\n if (zone === 'left' || zone === 'right') {\n const keep: 'min' | 'max' = zone === 'left' ? 'max' : 'min'\n return this.splitAreaAt(graph, areaId, 'vertical', clampedX, newAreaId, keep)\n }\n\n const keep: 'min' | 'max' = zone === 'bottom' ? 'max' : 'min'\n return this.splitAreaAt(graph, areaId, 'horizontal', clampedY, newAreaId, keep)\n }\n\n /**\n * Splits an area along a coordinate on a given axis.\n *\n * @param graph Graph to update.\n * @param areaId Area to split.\n * @param axis Axis to split along.\n * @param splitCoord Coordinate for the split.\n * @param newAreaId Id for the new area.\n * @param keep Which side keeps the original area id.\n * @returns Updated graph or null when split is invalid.\n */\n private splitAreaAt(\n graph: AreasGraph,\n areaId: AreaId,\n axis: SplitAxis,\n splitCoord: number,\n newAreaId: AreaId,\n keep: 'min' | 'max',\n ): AreasGraph | null {\n const area = graph.areas[areaId]\n if (!area) return null\n\n const rect = this.getAreaRect(graph, area)\n if (axis === 'vertical') {\n if (splitCoord <= rect.left + EPS || splitCoord >= rect.right - EPS) return null\n } else if (splitCoord <= rect.bottom + EPS || splitCoord >= rect.top - EPS) {\n return null\n }\n\n const next: AreasGraph = {\n verts: { ...graph.verts },\n edges: { ...graph.edges },\n areas: { ...graph.areas },\n }\n\n if (axis === 'horizontal') {\n const sv1 = this.addVert(next.verts, rect.left, splitCoord)\n const sv2 = this.addVert(next.verts, rect.right, splitCoord)\n this.addEdge(next.edges, area.v1, sv1)\n this.addEdge(next.edges, sv1, area.v2)\n this.addEdge(next.edges, area.v3, sv2)\n this.addEdge(next.edges, sv2, area.v4)\n this.addEdge(next.edges, sv1, sv2)\n\n const bottomArea: GraphArea = {\n id: keep === 'min' ? area.id : newAreaId,\n v1: area.v1,\n v2: sv1,\n v3: sv2,\n v4: area.v4,\n }\n const topArea: GraphArea = {\n id: keep === 'max' ? area.id : newAreaId,\n v1: sv1,\n v2: area.v2,\n v3: area.v3,\n v4: sv2,\n }\n\n next.areas[bottomArea.id] = bottomArea\n next.areas[topArea.id] = topArea\n if (bottomArea.id !== area.id && topArea.id !== area.id) {\n delete next.areas[area.id]\n }\n } else {\n const sv1 = this.addVert(next.verts, splitCoord, rect.bottom)\n const sv2 = this.addVert(next.verts, splitCoord, rect.top)\n this.addEdge(next.edges, area.v1, sv1)\n this.addEdge(next.edges, sv1, area.v4)\n this.addEdge(next.edges, area.v2, sv2)\n this.addEdge(next.edges, sv2, area.v3)\n this.addEdge(next.edges, sv1, sv2)\n\n const leftArea: GraphArea = {\n id: keep === 'min' ? area.id : newAreaId,\n v1: area.v1,\n v2: area.v2,\n v3: sv2,\n v4: sv1,\n }\n const rightArea: GraphArea = {\n id: keep === 'max' ? area.id : newAreaId,\n v1: sv1,\n v2: sv2,\n v3: area.v3,\n v4: area.v4,\n }\n\n next.areas[leftArea.id] = leftArea\n next.areas[rightArea.id] = rightArea\n if (leftArea.id !== area.id && rightArea.id !== area.id) {\n delete next.areas[area.id]\n }\n }\n\n return next\n }\n\n /**\n * Joins two areas, trimming to overlapping ranges as needed.\n *\n * @param graph Graph to update.\n * @param areaAId First area id.\n * @param areaBId Second area id.\n * @returns Updated graph or null when join is invalid.\n */\n private joinAreas(graph: AreasGraph, areaAId: AreaId, areaBId: AreaId): AreasGraph | null {\n let next = graph\n let areaA = next.areas[areaAId]\n let areaB = next.areas[areaBId]\n if (!areaA || !areaB) return null\n\n const dir = this.getOrientation(next, areaA, areaB)\n if (dir === 'none') return null\n\n const rectA = this.getAreaRect(next, areaA)\n const rectB = this.getAreaRect(next, areaB)\n\n let created: RemainderInfo[] = []\n if (dir === 'west' || dir === 'east') {\n const overlapBottom = Math.max(rectA.bottom, rectB.bottom)\n const overlapTop = Math.min(rectA.top, rectB.top)\n if (overlapTop - overlapBottom <= EPS) return null\n\n const trimA = this.trimAreaToRange(next, areaAId, 'horizontal', overlapBottom, overlapTop)\n next = trimA.graph\n areaA = next.areas[trimA.keptAreaId]\n if (!areaA) return null\n created = created.concat(trimA.created)\n\n const trimB = this.trimAreaToRange(next, areaBId, 'horizontal', overlapBottom, overlapTop)\n next = trimB.graph\n areaB = next.areas[trimB.keptAreaId]\n if (!areaB) return null\n created = created.concat(trimB.created)\n } else {\n const overlapLeft = Math.max(rectA.left, rectB.left)\n const overlapRight = Math.min(rectA.right, rectB.right)\n if (overlapRight - overlapLeft <= EPS) return null\n\n const trimA = this.trimAreaToRange(next, areaAId, 'vertical', overlapLeft, overlapRight)\n next = trimA.graph\n areaA = next.areas[trimA.keptAreaId]\n if (!areaA) return null\n created = created.concat(trimA.created)\n\n const trimB = this.trimAreaToRange(next, areaBId, 'vertical', overlapLeft, overlapRight)\n next = trimB.graph\n areaB = next.areas[trimB.keptAreaId]\n if (!areaB) return null\n created = created.concat(trimB.created)\n }\n\n const aligned = this.joinAreasAligned(next, areaAId, areaBId)\n if (!aligned) return null\n if (created.length === 0) return aligned\n return this.processRemainders(aligned, created, areaBId)\n }\n\n /**\n * Trims an area to a range and records created remainder areas.\n *\n * @param graph Graph to update.\n * @param areaId Area to trim.\n * @param axis Axis to trim along.\n * @param rangeStart Range start coordinate.\n * @param rangeEnd Range end coordinate.\n * @returns Updated graph, kept area id, and created remainders.\n */\n private trimAreaToRange(\n graph: AreasGraph,\n areaId: AreaId,\n axis: SplitAxis,\n rangeStart: number,\n rangeEnd: number,\n ): { graph: AreasGraph; keptAreaId: AreaId; created: RemainderInfo[] } {\n let next = graph\n const keptAreaId = areaId\n const created: RemainderInfo[] = []\n\n const area = next.areas[keptAreaId]\n if (!area) return { graph: next, keptAreaId, created }\n\n const rect = this.getAreaRect(next, area)\n\n if (axis === 'horizontal') {\n if (rect.bottom < rangeStart - EPS) {\n const newId = this.nextAreaId()\n const split = this.splitAreaAt(next, keptAreaId, axis, rangeStart, newId, 'max')\n if (split) {\n next = split\n created.push({ id: newId, sourceAreaId: areaId })\n }\n }\n\n const updated = next.areas[keptAreaId]\n if (updated) {\n const updatedRect = this.getAreaRect(next, updated)\n if (updatedRect.top > rangeEnd + EPS) {\n const newId = this.nextAreaId()\n const split = this.splitAreaAt(next, keptAreaId, axis, rangeEnd, newId, 'min')\n if (split) {\n next = split\n created.push({ id: newId, sourceAreaId: areaId })\n }\n }\n }\n } else {\n if (rect.left < rangeStart - EPS) {\n const newId = this.nextAreaId()\n const split = this.splitAreaAt(next, keptAreaId, axis, rangeStart, newId, 'max')\n if (split) {\n next = split\n created.push({ id: newId, sourceAreaId: areaId })\n }\n }\n\n const updated = next.areas[keptAreaId]\n if (updated) {\n const updatedRect = this.getAreaRect(next, updated)\n if (updatedRect.right > rangeEnd + EPS) {\n const newId = this.nextAreaId()\n const split = this.splitAreaAt(next, keptAreaId, axis, rangeEnd, newId, 'min')\n if (split) {\n next = split\n created.push({ id: newId, sourceAreaId: areaId })\n }\n }\n }\n }\n\n return { graph: next, keptAreaId, created }\n }\n\n /**\n * Applies remainder areas created during a join.\n *\n * @param graph Graph to update.\n * @param remainders Remainder areas created during trimming.\n * @param targetAreaId Target area being joined.\n * @returns Updated graph with remainders processed.\n */\n private processRemainders(\n graph: AreasGraph,\n remainders: RemainderInfo[],\n targetAreaId: AreaId,\n ): AreasGraph {\n let next = graph\n const targetRemainders = remainders.filter((item) => item.sourceAreaId === targetAreaId)\n const sourceRemainders = remainders.filter((item) => item.sourceAreaId !== targetAreaId)\n\n if (targetRemainders.length > 0) {\n const primary = targetRemainders[0]\n const rest = targetRemainders.slice(1)\n if (primary && next.areas[primary.id] && !next.areas[targetAreaId]) {\n next = this.renameAreaId(next, primary.id, targetAreaId)\n }\n this.ensureAreaNode(targetAreaId, targetAreaId, true)\n for (const remainder of rest) {\n this.ensureAreaNode(remainder.id, targetAreaId, true)\n }\n } else {\n this.removeAreaNode(targetAreaId)\n }\n\n for (const remainder of sourceRemainders) {\n delete next.areas[remainder.id]\n this.removeAreaNode(remainder.id)\n }\n\n return next\n }\n\n /**\n * Replaces an area with a new rectangle in the graph.\n *\n * @param graph Graph to update.\n * @param areaId Area to update.\n * @param rect New rectangle.\n * @returns Updated graph.\n */\n private setAreaRect(graph: AreasGraph, areaId: AreaId, rect: Rect): AreasGraph {\n const area = graph.areas[areaId]\n if (!area) return graph\n\n const next: AreasGraph = {\n verts: { ...graph.verts },\n edges: { ...graph.edges },\n areas: { ...graph.areas },\n }\n\n const v1 = this.addVert(next.verts, rect.left, rect.bottom)\n const v2 = this.addVert(next.verts, rect.left, rect.top)\n const v3 = this.addVert(next.verts, rect.right, rect.top)\n const v4 = this.addVert(next.verts, rect.right, rect.bottom)\n\n this.addEdge(next.edges, v1, v2)\n this.addEdge(next.edges, v2, v3)\n this.addEdge(next.edges, v3, v4)\n this.addEdge(next.edges, v4, v1)\n\n next.areas[areaId] = { id: areaId, v1, v2, v3, v4 }\n return next\n }\n\n /**\n * Moves an area into an overlay region and shrinks the target.\n *\n * @param graph Graph to update.\n * @param sourceAreaId Area being moved.\n * @param targetAreaId Area receiving the move.\n * @param overlay Rectangle for the moved area.\n * @param remainder Rectangle for the remainder of target.\n * @returns Updated graph or null when invalid.\n */\n private moveArea(\n graph: AreasGraph,\n sourceAreaId: AreaId,\n targetAreaId: AreaId,\n overlay: Rect,\n remainder: Rect,\n ): AreasGraph | null {\n const sourceArea = graph.areas[sourceAreaId]\n const targetArea = graph.areas[targetAreaId]\n if (!sourceArea || !targetArea) return null\n if (sourceAreaId === targetAreaId) return null\n\n const next: AreasGraph = {\n verts: { ...graph.verts },\n edges: { ...graph.edges },\n areas: { ...graph.areas },\n }\n\n const overlayWidth = overlay.right - overlay.left\n const overlayHeight = overlay.top - overlay.bottom\n const remainderWidth = remainder.right - remainder.left\n const remainderHeight = remainder.top - remainder.bottom\n if (\n overlayWidth <= EPS ||\n overlayHeight <= EPS ||\n remainderWidth <= EPS ||\n remainderHeight <= EPS\n ) {\n return null\n }\n\n const moved = this.setAreaRect(next, sourceAreaId, overlay)\n const updated = this.setAreaRect(moved, targetAreaId, remainder)\n return updated\n }\n\n /**\n * Replaces the target area with the source area rectangle.\n *\n * @param graph Graph to update.\n * @param sourceAreaId Area providing the rectangle.\n * @param targetAreaId Area to remove.\n * @returns Updated graph or null when invalid.\n */\n private replaceArea(\n graph: AreasGraph,\n sourceAreaId: AreaId,\n targetAreaId: AreaId,\n ): AreasGraph | null {\n const sourceArea = graph.areas[sourceAreaId]\n const targetArea = graph.areas[targetAreaId]\n if (!sourceArea || !targetArea) return null\n if (sourceAreaId === targetAreaId) return null\n\n const targetRect = this.getAreaRect(graph, targetArea)\n\n const next: AreasGraph = {\n verts: { ...graph.verts },\n edges: { ...graph.edges },\n areas: { ...graph.areas },\n }\n\n const moved = this.setAreaRect(next, sourceAreaId, targetRect)\n delete moved.areas[targetAreaId]\n\n return moved\n }\n\n /**\n * Renames an area id and updates DOM references.\n *\n * @param graph Graph to update.\n * @param fromId Existing area id.\n * @param toId New area id.\n * @returns Updated graph.\n */\n private renameAreaId(graph: AreasGraph, fromId: AreaId, toId: AreaId): AreasGraph {\n if (fromId === toId) return graph\n const area = graph.areas[fromId]\n if (!area) return graph\n if (graph.areas[toId]) {\n throw new Error(`Cannot rename area ${fromId} to ${toId}: target id already exists`)\n }\n\n const next: AreasGraph = {\n verts: { ...graph.verts },\n edges: { ...graph.edges },\n areas: { ...graph.areas },\n }\n next.areas[toId] = { ...area, id: toId }\n delete next.areas[fromId]\n\n const targetNode = Array.from(\n this.querySelectorAll<HTMLElement>(`[data-area-id=\"${toId}\"]`),\n ).find((item) => !item.hasAttribute(INTERNAL_ATTR))\n const node = Array.from(this.querySelectorAll<HTMLElement>(`[data-area-id=\"${fromId}\"]`)).find(\n (item) => !item.hasAttribute(INTERNAL_ATTR),\n )\n if (node) {\n if (targetNode) {\n node.remove()\n } else {\n node.dataset.areaId = toId\n }\n }\n\n const tag = this.areaTags.get(fromId)\n if (tag) {\n this.areaTags.set(toId, tag)\n this.areaTags.delete(fromId)\n }\n\n const resolved = this.resolvedNodes.get(fromId)\n if (resolved) {\n this.resolvedNodes.set(toId, resolved)\n this.resolvedNodes.delete(fromId)\n }\n\n return next\n }\n\n /**\n * Removes an area node and its cached metadata.\n *\n * @param areaId Area to remove.\n */\n private removeAreaNode(areaId: AreaId): void {\n const node = Array.from(this.querySelectorAll<HTMLElement>(`[data-area-id=\"${areaId}\"]`)).find(\n (item) => !item.hasAttribute(INTERNAL_ATTR),\n )\n if (node) {\n node.remove()\n }\n this.areaTags.delete(areaId)\n this.resolvedNodes.delete(areaId)\n }\n\n /**\n * Detaches an area node without altering tags.\n *\n * @param areaId Area to detach.\n */\n private detachAreaNode(areaId: AreaId): void {\n const node = Array.from(this.querySelectorAll<HTMLElement>(`[data-area-id=\"${areaId}\"]`)).find(\n (item) => !item.hasAttribute(INTERNAL_ATTR),\n )\n if (node) {\n node.remove()\n }\n this.resolvedNodes.delete(areaId)\n }\n\n /**\n * Joins two areas that are already aligned.\n *\n * @param graph Graph to update.\n * @param areaAId First area id.\n * @param areaBId Second area id.\n * @returns Updated graph or null when join is invalid.\n */\n private joinAreasAligned(graph: AreasGraph, areaAId: AreaId, areaBId: AreaId): AreasGraph | null {\n const areaA = graph.areas[areaAId]\n const areaB = graph.areas[areaBId]\n if (!areaA || !areaB) return null\n\n const dir = this.getOrientation(graph, areaA, areaB)\n if (dir === 'none') return null\n\n if (!this.areAreasAligned(graph, areaA, areaB, dir)) {\n return null\n }\n\n const next: AreasGraph = {\n verts: { ...graph.verts },\n edges: { ...graph.edges },\n areas: { ...graph.areas },\n }\n\n const merged = { ...areaA }\n if (dir === 'west') {\n merged.v1 = areaB.v1\n merged.v2 = areaB.v2\n this.addEdge(next.edges, merged.v2, merged.v3)\n this.addEdge(next.edges, merged.v1, merged.v4)\n } else if (dir === 'north') {\n merged.v2 = areaB.v2\n merged.v3 = areaB.v3\n this.addEdge(next.edges, merged.v1, merged.v2)\n this.addEdge(next.edges, merged.v3, merged.v4)\n } else if (dir === 'east') {\n merged.v3 = areaB.v3\n merged.v4 = areaB.v4\n this.addEdge(next.edges, merged.v2, merged.v3)\n this.addEdge(next.edges, merged.v1, merged.v4)\n } else if (dir === 'south') {\n merged.v1 = areaB.v1\n merged.v4 = areaB.v4\n this.addEdge(next.edges, merged.v1, merged.v2)\n this.addEdge(next.edges, merged.v3, merged.v4)\n }\n\n next.areas[areaAId] = merged\n delete next.areas[areaBId]\n\n return next\n }\n\n /**\n * Swaps the ids of two areas in the graph.\n *\n * @param graph Graph to update.\n * @param areaAId First area id.\n * @param areaBId Second area id.\n * @returns Updated graph or null when invalid.\n */\n private swapAreaIds(graph: AreasGraph, areaAId: AreaId, areaBId: AreaId): AreasGraph | null {\n const areaA = graph.areas[areaAId]\n const areaB = graph.areas[areaBId]\n if (!areaA || !areaB) return null\n\n const next: AreasGraph = {\n verts: { ...graph.verts },\n edges: { ...graph.edges },\n areas: { ...graph.areas },\n }\n\n next.areas[areaAId] = { ...areaB, id: areaAId }\n next.areas[areaBId] = { ...areaA, id: areaBId }\n\n return next\n }\n\n /**\n * Checks whether two areas can be joined.\n *\n * @param areaAId First area id.\n * @param areaBId Second area id.\n * @returns True when join is possible.\n */\n private canJoin(areaAId: AreaId, areaBId: AreaId): boolean {\n if (!this.graph) return false\n const areaA = this.graph.areas[areaAId]\n const areaB = this.graph.areas[areaBId]\n if (!areaA || !areaB) return false\n const dir = this.getOrientation(this.graph, areaA, areaB)\n if (dir === 'none') return false\n const rectA = this.getAreaRect(this.graph, areaA)\n const rectB = this.getAreaRect(this.graph, areaB)\n if (dir === 'west' || dir === 'east') {\n const overlap = Math.min(rectA.top, rectB.top) - Math.max(rectA.bottom, rectB.bottom)\n return overlap > EPS\n }\n const overlap = Math.min(rectA.right, rectB.right) - Math.max(rectA.left, rectB.left)\n return overlap > EPS\n }\n\n /**\n * Checks if two areas align for a join operation.\n *\n * @param graph Graph containing the areas.\n * @param areaA First area.\n * @param areaB Second area.\n * @param dir Expected orientation between areas.\n * @returns True when aligned within tolerance.\n */\n private areAreasAligned(\n graph: AreasGraph,\n areaA: GraphArea,\n areaB: GraphArea,\n dir: JoinDir,\n ): boolean {\n const offset = this.getOffsets(graph, areaA, areaB, dir)\n if (!offset) return false\n return Math.abs(offset.offset1) <= JOIN_TOLERANCE && Math.abs(offset.offset2) <= JOIN_TOLERANCE\n }\n\n /**\n * Determines the orientation between two areas.\n *\n * @param graph Graph containing the areas.\n * @param areaA First area.\n * @param areaB Second area.\n * @returns Orientation of areaB relative to areaA.\n */\n private getOrientation(graph: AreasGraph, areaA: GraphArea, areaB: GraphArea): JoinDir {\n const rectA = this.getAreaRect(graph, areaA)\n const rectB = this.getAreaRect(graph, areaB)\n\n const overlapX = Math.min(rectA.right, rectB.right) - Math.max(rectA.left, rectB.left)\n const overlapY = Math.min(rectA.top, rectB.top) - Math.max(rectA.bottom, rectB.bottom)\n\n const minX = Math.min(JOIN_TOLERANCE, rectA.right - rectA.left, rectB.right - rectB.left)\n const minY = Math.min(JOIN_TOLERANCE, rectA.top - rectA.bottom, rectB.top - rectB.bottom)\n\n if (Math.abs(rectA.top - rectB.bottom) <= EPS && overlapX >= minX) {\n return 'north'\n }\n if (Math.abs(rectA.bottom - rectB.top) <= EPS && overlapX >= minX) {\n return 'south'\n }\n if (Math.abs(rectA.left - rectB.right) <= EPS && overlapY >= minY) {\n return 'west'\n }\n if (Math.abs(rectA.right - rectB.left) <= EPS && overlapY >= minY) {\n return 'east'\n }\n\n return 'none'\n }\n\n /**\n * Computes alignment offsets between two areas by orientation.\n *\n * @param graph Graph containing the areas.\n * @param areaA First area.\n * @param areaB Second area.\n * @param dir Orientation between the areas.\n * @returns Offset values or null when invalid.\n */\n private getOffsets(\n graph: AreasGraph,\n areaA: GraphArea,\n areaB: GraphArea,\n dir: JoinDir,\n ): { offset1: number; offset2: number } | null {\n const vA1 = graph.verts[areaA.v1]\n const vA2 = graph.verts[areaA.v2]\n const vA3 = graph.verts[areaA.v3]\n const vA4 = graph.verts[areaA.v4]\n const vB1 = graph.verts[areaB.v1]\n const vB2 = graph.verts[areaB.v2]\n const vB3 = graph.verts[areaB.v3]\n const vB4 = graph.verts[areaB.v4]\n if (!vA1 || !vA2 || !vA3 || !vA4 || !vB1 || !vB2 || !vB3 || !vB4) return null\n if (dir === 'west') {\n return {\n offset1: vB3.y - vA2.y,\n offset2: vB4.y - vA1.y,\n }\n }\n if (dir === 'north') {\n return {\n offset1: vA2.x - vB1.x,\n offset2: vA3.x - vB4.x,\n }\n }\n if (dir === 'east') {\n return {\n offset1: vB2.y - vA3.y,\n offset2: vB1.y - vA4.y,\n }\n }\n if (dir === 'south') {\n return {\n offset1: vA1.x - vB2.x,\n offset2: vA4.x - vB3.x,\n }\n }\n\n return null\n }\n\n /**\n * Builds draggable splitter handles for shared edges.\n *\n * @param graph Graph to inspect.\n * @param width Render width in pixels.\n * @param height Render height in pixels.\n * @returns Array of handle elements.\n */\n private buildResizeHandles(graph: AreasGraph, width: number, height: number): HTMLDivElement[] {\n const handles: HTMLDivElement[] = []\n const splitterSize = DEFAULT_SPLITTER_SIZE\n const hitSize = splitterSize + 2\n const edgeMap = new Map<\n string,\n { axis: SplitAxis; coord: number; segments: Array<{ start: number; end: number }> }\n >()\n\n for (const area of Object.values(graph.areas)) {\n const rect = this.getAreaRect(graph, area)\n this.registerEdge(edgeMap, 'vertical', rect.left, rect.bottom, rect.top)\n this.registerEdge(edgeMap, 'vertical', rect.right, rect.bottom, rect.top)\n this.registerEdge(edgeMap, 'horizontal', rect.bottom, rect.left, rect.right)\n this.registerEdge(edgeMap, 'horizontal', rect.top, rect.left, rect.right)\n }\n\n for (const edge of edgeMap.values()) {\n if (edge.axis === 'vertical' && (edge.coord <= EPS || edge.coord >= 1 - EPS)) continue\n if (edge.axis === 'horizontal' && (edge.coord <= EPS || edge.coord >= 1 - EPS)) continue\n\n const sharedSegments = this.computeSharedSegments(edge.segments)\n for (const segment of sharedSegments) {\n const handle = document.createElement('div')\n handle.classList.add('sliced-areas-handle')\n handle.setAttribute(INTERNAL_ATTR, 'true')\n handle.dataset.axis = edge.axis\n handle.dataset.coord = edge.coord.toFixed(6)\n handle.dataset.start = segment.start.toFixed(6)\n handle.dataset.end = segment.end.toFixed(6)\n\n if (edge.axis === 'vertical') {\n handle.classList.add('is-vertical')\n handle.style.left = `${edge.coord * width - hitSize / 2}px`\n handle.style.top = `${(1 - segment.end) * height}px`\n handle.style.width = `${hitSize}px`\n handle.style.height = `${(segment.end - segment.start) * height}px`\n } else {\n handle.classList.add('is-horizontal')\n handle.style.left = `${segment.start * width}px`\n handle.style.top = `${(1 - edge.coord) * height - hitSize / 2}px`\n handle.style.width = `${(segment.end - segment.start) * width}px`\n handle.style.height = `${hitSize}px`\n }\n\n handles.push(handle)\n }\n }\n\n return handles\n }\n\n /**\n * Registers an edge segment for shared edge detection.\n *\n * @param map Edge aggregation map.\n * @param axis Axis of the edge.\n * @param coord Constant coordinate for the edge.\n * @param start Segment start.\n * @param end Segment end.\n */\n private registerEdge(\n map: Map<\n string,\n { axis: SplitAxis; coord: number; segments: Array<{ start: number; end: number }> }\n >,\n axis: SplitAxis,\n coord: number,\n start: number,\n end: number,\n ): void {\n const min = Math.min(start, end)\n const max = Math.max(start, end)\n const key = `${axis}|${coord.toFixed(6)}`\n const existing = map.get(key)\n const entry = existing ?? { axis, coord, segments: [] }\n entry.segments.push({ start: min, end: max })\n if (!existing) {\n map.set(key, entry)\n }\n }\n\n /**\n * Computes overlapping segments shared by at least two areas.\n *\n * @param segments Segments to analyze.\n * @returns Shared segments.\n */\n private computeSharedSegments(\n segments: Array<{ start: number; end: number }>,\n ): Array<{ start: number; end: number }> {\n const events: Array<{ pos: number; delta: number }> = []\n for (const segment of segments) {\n const min = Math.min(segment.start, segment.end)\n const max = Math.max(segment.start, segment.end)\n if (max - min <= EPS) continue\n events.push({ pos: min, delta: 1 })\n events.push({ pos: max, delta: -1 })\n }\n\n events.sort((a, b) => {\n if (Math.abs(a.pos - b.pos) > EPS) return a.pos - b.pos\n return a.delta - b.delta\n })\n\n const result: Array<{ start: number; end: number }> = []\n let count = 0\n let activeStart: number | null = null\n\n for (const event of events) {\n const prevCount = count\n count += event.delta\n if (prevCount < 2 && count >= 2) {\n activeStart = event.pos\n } else if (prevCount >= 2 && count < 2 && activeStart !== null) {\n if (event.pos - activeStart > EPS) {\n result.push({ start: activeStart, end: event.pos })\n }\n activeStart = null\n }\n }\n\n return result\n }\n\n /**\n * Handles pointer down on resize handles and drag targets.\n *\n * @param event Pointer event.\n */\n private onPointerDown = (event: PointerEvent): void => {\n if (!this.rootEl || !this.graph) return\n const target = event.target\n if (!(target instanceof HTMLElement)) return\n if (target.classList.contains('sliced-areas-grab')) {\n const areaId = target.dataset.areaId\n if (!areaId) return\n event.preventDefault()\n this.startAreaDrag(event, areaId)\n return\n }\n if (target.classList.contains('sliced-areas-corner')) {\n const areaId = target.dataset.areaId\n if (!areaId) return\n const corner = target.dataset.corner as CornerId | undefined\n event.preventDefault()\n this.startAreaDrag(event, areaId, corner)\n return\n }\n if (!target.classList.contains('sliced-areas-handle')) return\n event.preventDefault()\n\n const axis = (target.dataset.axis ?? '') as SplitAxis\n const coord = Number(target.dataset.coord)\n const start = Number(target.dataset.start)\n const end = Number(target.dataset.end)\n if (!axis || !Number.isFinite(coord) || !Number.isFinite(start) || !Number.isFinite(end)) return\n\n const bounds = this.getEdgeDragBounds(this.graph, axis, coord, start, end)\n if (!bounds) return\n\n target.setPointerCapture(event.pointerId)\n this.dragState = {\n axis,\n coord,\n start,\n end,\n min: bounds.min,\n max: bounds.max,\n pointerId: event.pointerId,\n originX: event.clientX,\n originY: event.clientY,\n }\n this.dragSnapshot = this.cloneGraph(this.graph)\n\n window.addEventListener('pointermove', this.onPointerMove)\n window.addEventListener('pointerup', this.onPointerUp)\n window.addEventListener('keydown', this.onKeyDown)\n window.addEventListener('keyup', this.onKeyUp)\n }\n\n /**\n * Handles pointer movement for resize and area drag operations.\n *\n * @param event Pointer event.\n */\n private onPointerMove = (event: PointerEvent): void => {\n if (this.areaDragState) {\n this.updateAreaDrag(event)\n return\n }\n if (!this.rootEl || !this.graph || !this.dragState) return\n\n const rect = this.rootEl.getBoundingClientRect()\n const width = Math.max(rect.width, 1)\n const height = Math.max(rect.height, 1)\n const deltaX = event.clientX - this.dragState.originX\n const deltaY = event.clientY - this.dragState.originY\n\n const delta = this.dragState.axis === 'vertical' ? deltaX / width : -deltaY / height\n const nextCoord = Math.max(\n this.dragState.min,\n Math.min(this.dragState.max, this.dragState.coord + delta),\n )\n\n const updated = this.moveEdge(\n this.graph,\n this.dragState.axis,\n this.dragState.coord,\n nextCoord,\n this.dragState.start,\n this.dragState.end,\n )\n if (!updated) return\n\n this.graph = updated\n this.dragState.coord = nextCoord\n this.dragState.originX = event.clientX\n this.dragState.originY = event.clientY\n this.render()\n }\n\n /**\n * Finalizes drag operations on pointer release.\n *\n * @param event Pointer event.\n */\n private onPointerUp = (event: PointerEvent): void => {\n if (this.areaDragState) {\n const corner = this.areaDragState.originCorner\n const moved = this.areaDragState.moved ?? false\n if (corner === 'top-left' && !moved) {\n this.emitCornerClick({\n areaId: this.areaDragState.sourceAreaId,\n corner,\n clientX: event.clientX,\n clientY: event.clientY,\n })\n }\n this.finishAreaDrag()\n return\n }\n if (!this.dragState) return\n this.dragState = null\n this.detachDragListeners()\n this.detachKeyListener()\n this.dragSnapshot = null\n if (this.graph) {\n this.graph = this.normalizeGraph(this.graph)\n }\n this.emitLayoutChange()\n }\n\n /**\n * Handles key presses for drag modifiers and cancel.\n *\n * @param event Keyboard event.\n */\n private onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Control') {\n if (this.areaDragState) {\n this.areaDragState.swapMode = true\n this.refreshAreaDrag()\n }\n return\n }\n if (event.key !== 'Escape') return\n if (this.areaDragState) {\n event.preventDefault()\n this.cancelAreaDrag()\n return\n }\n if (this.dragState) {\n event.preventDefault()\n this.cancelResizeDrag()\n }\n }\n\n /**\n * Handles key releases for drag modifiers.\n *\n * @param event Keyboard event.\n */\n private onKeyUp = (event: KeyboardEvent): void => {\n if (event.key !== 'Control') return\n if (!this.areaDragState) return\n this.areaDragState.swapMode = false\n this.refreshAreaDrag()\n }\n\n /**\n * Cancels an area drag and resets UI state.\n */\n private cancelAreaDrag(): void {\n this.areaDragState = null\n this.hideDropOverlay()\n this.hideJoinShade()\n this.hideDragLabel()\n this.detachDragListeners()\n this.detachKeyListener()\n this.resetDragCursor(true)\n this.lastPointer = null\n }\n\n /**\n * Cancels a resize drag and restores the snapshot.\n */\n private cancelResizeDrag(): void {\n if (this.dragSnapshot) {\n this.graph = this.dragSnapshot\n this.dragSnapshot = null\n this.render()\n }\n this.dragState = null\n this.detachDragListeners()\n this.detachKeyListener()\n }\n\n /**\n * Re-evaluates the area drag UI at the last pointer.\n */\n private refreshAreaDrag(): void {\n if (!this.areaDragState || !this.lastPointer) return\n this.updateAreaDragAt(this.lastPointer.x, this.lastPointer.y)\n }\n\n /**\n * Sets a temporary cursor during drag operations.\n *\n * @param cursor CSS cursor value.\n */\n private setDragCursor(cursor: string): void {\n if (!this.rootEl) return\n if (this.dragCursor === null) {\n this.dragCursor = this.rootEl.style.cursor || ''\n }\n this.rootEl.style.cursor = cursor\n }\n\n /**\n * Restores the cursor to its previous value.\n *\n * @param force Whether to restore even if no cursor is tracked.\n */\n private resetDragCursor(force = false): void {\n if (!this.rootEl) return\n if (this.dragCursor !== null || force) {\n this.rootEl.style.cursor = this.dragCursor ?? ''\n this.dragCursor = null\n }\n }\n\n /**\n * Deep clones the graph for safe mutation.\n *\n * @param graph Graph to clone.\n * @returns Cloned graph.\n */\n private cloneGraph(graph: AreasGraph): AreasGraph {\n const verts: AreasGraph['verts'] = {}\n for (const [id, vert] of Object.entries(graph.verts)) {\n verts[id] = { ...vert }\n }\n const edges: AreasGraph['edges'] = {}\n for (const [id, edge] of Object.entries(graph.edges)) {\n edges[id] = { ...edge }\n }\n const areas: AreasGraph['areas'] = {}\n for (const [id, area] of Object.entries(graph.areas)) {\n areas[id] = { ...area }\n }\n return { verts, edges, areas }\n }\n\n /**\n * Detaches pointer drag listeners.\n */\n private detachDragListeners(): void {\n window.removeEventListener('pointermove', this.onPointerMove)\n window.removeEventListener('pointerup', this.onPointerUp)\n }\n\n /**\n * Detaches keyboard listeners used during drag.\n */\n private detachKeyListener(): void {\n window.removeEventListener('keydown', this.onKeyDown)\n window.removeEventListener('keyup', this.onKeyUp)\n }\n\n /**\n * Starts an area drag for move/split/join actions.\n *\n * @param event Pointer event.\n * @param areaId Source area id.\n * @param corner Optional corner id for corner drag.\n */\n private startAreaDrag(event: PointerEvent, areaId: AreaId, corner?: CornerId): void {\n if (!this.rootEl) return\n this.areaDragState = {\n sourceAreaId: areaId,\n pointerId: event.pointerId,\n startX: event.clientX,\n startY: event.clientY,\n lastX: event.clientX,\n lastY: event.clientY,\n axis: null,\n swapMode: event.ctrlKey,\n originCorner: corner,\n moved: false,\n }\n if (event.target instanceof HTMLElement) {\n event.target.setPointerCapture(event.pointerId)\n }\n window.addEventListener('pointermove', this.onPointerMove)\n window.addEventListener('pointerup', this.onPointerUp)\n window.addEventListener('keydown', this.onKeyDown)\n window.addEventListener('keyup', this.onKeyUp)\n }\n\n /**\n * Updates area drag state from a pointer event.\n *\n * @param event Pointer event.\n */\n private updateAreaDrag(event: PointerEvent): void {\n if (!this.rootEl || !this.graph || !this.areaDragState) return\n this.areaDragState.swapMode = event.ctrlKey\n this.updateAreaDragAt(event.clientX, event.clientY)\n }\n\n /**\n * Updates area drag state at a specific pointer position.\n *\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n */\n private updateAreaDragAt(clientX: number, clientY: number): void {\n if (!this.rootEl || !this.graph || !this.areaDragState) return\n this.lastPointer = { x: clientX, y: clientY }\n const startDx = clientX - this.areaDragState.startX\n const startDy = clientY - this.areaDragState.startY\n if (Math.hypot(startDx, startDy) > CLICK_TOLERANCE_PX) {\n this.areaDragState.moved = true\n }\n const parked = Math.hypot(startDx, startDy) <= DRAG_PARK_TOLERANCE_PX\n if (parked) {\n this.hideDropOverlay()\n this.hideJoinShade()\n this.hideDragLabel()\n this.resetDragCursor()\n return\n }\n const sourceAreaId = this.areaDragState.sourceAreaId\n const hit = this.findAreaAtPoint(clientX, clientY)\n if (!hit) {\n this.hideDropOverlay()\n this.hideJoinShade()\n this.hideDragLabel()\n this.resetDragCursor()\n return\n }\n\n if (hit.areaId === sourceAreaId) {\n const canSplitVertical = this.canSplitRect(hit.rect, 'vertical')\n const canSplitHorizontal = this.canSplitRect(hit.rect, 'horizontal')\n if (!canSplitVertical && !canSplitHorizontal) {\n this.hideDropOverlay()\n this.hideDragLabel()\n this.resetDragCursor()\n return\n }\n\n if (canSplitVertical !== canSplitHorizontal) {\n const axis = canSplitVertical ? 'vertical' : 'horizontal'\n const zone = this.getSplitZoneByAxis(hit.rect, clientX, clientY, axis)\n const overlayRect = this.getSplitOverlayRect(hit.rect, zone, clientX, clientY)\n this.showSplitOverlay(hit, zone, overlayRect)\n this.hideJoinShade()\n this.hideDragLabel()\n this.setDragCursor(axis === 'vertical' ? 'col-resize' : 'row-resize')\n return\n }\n\n const gesture = this.resolveSplitGesture(this.areaDragState, clientX, clientY)\n if (!gesture) {\n this.hideDropOverlay()\n this.hideDragLabel()\n this.resetDragCursor()\n return\n }\n const zone = this.getSplitZone(hit.rect, clientX, clientY, gesture)\n const overlayRect = this.getSplitOverlayRect(hit.rect, zone, clientX, clientY)\n this.showSplitOverlay(hit, zone, overlayRect)\n this.hideJoinShade()\n this.hideDragLabel()\n this.setDragCursor(gesture.axis === 'vertical' ? 'col-resize' : 'row-resize')\n return\n }\n\n if (this.areaDragState.swapMode) {\n this.showDropOverlay({ areaId: hit.areaId, rect: hit.rect }, 'center', 'swap', hit.rect)\n this.hideJoinShade()\n this.showDragLabel(clientX, clientY, 'Swap')\n this.setDragCursor('copy')\n this.lastDropTarget = { areaId: hit.areaId, rect: hit.rect, zone: 'center', mode: 'swap' }\n return\n }\n\n const joinTarget = this.findJoinTargetAtPoint(sourceAreaId, clientX, clientY)\n if (!joinTarget) {\n const zone = this.getMoveZone(hit.rect, clientX, clientY)\n if (zone === 'center') {\n this.hideDropOverlay()\n this.hideJoinShade()\n this.hideDragLabel()\n this.resetDragCursor()\n return\n }\n const preview = this.getMovePreview(hit.rect, zone, clientX, clientY)\n if (preview.replace) {\n this.showDropOverlay({ areaId: hit.areaId, rect: hit.rect }, zone, 'replace', hit.rect)\n this.hideJoinShade()\n this.showDragLabel(clientX, clientY, 'Replace')\n this.setDragCursor('alias')\n this.lastDropTarget = { areaId: hit.areaId, rect: hit.rect, zone, mode: 'replace' }\n return\n }\n this.showDropOverlay({ areaId: hit.areaId, rect: hit.rect }, zone, 'move', preview.overlay)\n this.hideJoinShade()\n this.showDragLabel(clientX, clientY, 'Move')\n this.setDragCursor('move')\n this.lastDropTarget = {\n areaId: hit.areaId,\n rect: hit.rect,\n zone,\n mode: 'move',\n moveRect: preview.overlay,\n remainderRect: preview.remainder,\n }\n return\n }\n\n this.showDropOverlay(\n { areaId: joinTarget.areaId, rect: joinTarget.rect },\n joinTarget.zone,\n 'join',\n joinTarget.result,\n joinTarget.direction,\n )\n this.showJoinShade(joinTarget.result, joinTarget.sourceRect, joinTarget.rect)\n this.showDragLabel(clientX, clientY, this.getJoinLabel(joinTarget.direction))\n this.setDragCursor('pointer')\n }\n\n /**\n * Commits the last area drag action if valid.\n */\n private finishAreaDrag(): void {\n if (!this.areaDragState || !this.graph) return\n const { sourceAreaId } = this.areaDragState\n const lastPointer = this.lastPointer\n const hit = this.lastDropTarget\n this.areaDragState = null\n this.hideDropOverlay()\n this.hideJoinShade()\n this.hideDragLabel()\n this.detachDragListeners()\n this.detachKeyListener()\n this.resetDragCursor(true)\n this.lastPointer = null\n\n if (!hit) return\n\n if (hit.mode === 'split') {\n if (hit.zone !== 'center') {\n const axis = hit.zone === 'left' || hit.zone === 'right' ? 'vertical' : 'horizontal'\n if (!this.canSplitRect(hit.rect, axis)) {\n return\n }\n this.split(sourceAreaId, hit.zone, lastPointer?.x ?? 0, lastPointer?.y ?? 0)\n }\n return\n }\n\n if (hit.mode === 'replace') {\n this.replace(sourceAreaId, hit.areaId)\n return\n }\n\n if (hit.mode === 'move') {\n if (!hit.moveRect || !hit.remainderRect) return\n if (hit.zone === 'center') return\n this.move(sourceAreaId, hit.areaId, hit.moveRect, hit.remainderRect)\n return\n }\n\n if (hit.mode === 'swap') {\n this.swap(sourceAreaId, hit.areaId)\n return\n }\n\n if (hit.areaId === sourceAreaId) return\n\n if (hit.zone === 'center') {\n this.swap(sourceAreaId, hit.areaId)\n return\n }\n\n if (\n hit.zone === 'left' ||\n hit.zone === 'right' ||\n hit.zone === 'top' ||\n hit.zone === 'bottom'\n ) {\n this.join(sourceAreaId, hit.areaId)\n }\n }\n\n /**\n * Tracks the latest drop target preview for area drag.\n */\n private lastDropTarget: {\n areaId: AreaId\n rect: Rect\n zone: 'left' | 'right' | 'top' | 'bottom' | 'center'\n mode: 'join' | 'split' | 'move' | 'replace' | 'swap'\n direction?: 'left' | 'right' | 'up' | 'down'\n result?: Rect\n moveRect?: Rect\n remainderRect?: Rect\n } | null = null\n\n /**\n * Shows the drop overlay for join/split/move/replace/swap.\n *\n * @param target Target area and rect.\n * @param zone Zone to highlight.\n * @param mode Drop mode being previewed.\n * @param overlayRect Optional overlay rect override.\n * @param direction Optional join direction.\n */\n private showDropOverlay(\n target: { areaId: AreaId; rect: Rect },\n zone: 'left' | 'right' | 'top' | 'bottom' | 'center',\n mode: 'join' | 'split' | 'move' | 'replace' | 'swap',\n overlayRect?: Rect,\n direction?: 'left' | 'right' | 'up' | 'down',\n ): void {\n if (!this.rootEl) return\n const rect = this.rootEl.getBoundingClientRect()\n const width = Math.max(rect.width, 1)\n const height = Math.max(rect.height, 1)\n const zoneRect = overlayRect ?? this.getZoneRect(target.rect, zone, mode)\n\n if (!this.dropOverlay) {\n this.dropOverlay = document.createElement('div')\n this.dropOverlay.classList.add('sliced-areas-drop')\n this.dropOverlay.setAttribute(INTERNAL_ATTR, 'true')\n }\n if (!this.dropOverlay.isConnected) {\n this.rootEl.appendChild(this.dropOverlay)\n }\n this.dropOverlay.innerHTML = ''\n\n this.dropOverlay.style.left = `${zoneRect.left * width}px`\n this.dropOverlay.style.top = `${(1 - zoneRect.top) * height}px`\n this.dropOverlay.style.width = `${(zoneRect.right - zoneRect.left) * width}px`\n this.dropOverlay.style.height = `${(zoneRect.top - zoneRect.bottom) * height}px`\n this.dropOverlay.dataset.zone = zone\n this.dropOverlay.dataset.mode = mode\n delete this.dropOverlay.dataset.splitMode\n this.dropOverlay.style.display = 'block'\n this.lastDropTarget = { areaId: target.areaId, rect: target.rect, zone, mode, direction }\n }\n\n /**\n * Shows a split overlay with both resulting regions.\n *\n * @param target Target area and rect.\n * @param zone Split zone.\n * @param overlayRect Primary overlay rectangle.\n */\n private showSplitOverlay(\n target: { areaId: AreaId; rect: Rect },\n zone: 'left' | 'right' | 'top' | 'bottom' | 'center',\n overlayRect: Rect,\n ): void {\n if (!this.rootEl) return\n const rect = this.rootEl.getBoundingClientRect()\n const width = Math.max(rect.width, 1)\n const height = Math.max(rect.height, 1)\n\n if (!this.dropOverlay) {\n this.dropOverlay = document.createElement('div')\n this.dropOverlay.classList.add('sliced-areas-drop')\n this.dropOverlay.setAttribute(INTERNAL_ATTR, 'true')\n }\n if (!this.dropOverlay.isConnected) {\n this.rootEl.appendChild(this.dropOverlay)\n }\n\n this.dropOverlay.style.left = '0px'\n this.dropOverlay.style.top = '0px'\n this.dropOverlay.style.width = `${width}px`\n this.dropOverlay.style.height = `${height}px`\n this.dropOverlay.dataset.zone = 'split'\n this.dropOverlay.dataset.mode = 'split'\n this.dropOverlay.dataset.splitMode = 'true'\n this.dropOverlay.innerHTML = ''\n\n const primary = overlayRect\n let secondary: Rect\n if (zone === 'left') {\n secondary = {\n left: overlayRect.right,\n right: target.rect.right,\n top: target.rect.top,\n bottom: target.rect.bottom,\n }\n } else if (zone === 'right') {\n secondary = {\n left: target.rect.left,\n right: overlayRect.left,\n top: target.rect.top,\n bottom: target.rect.bottom,\n }\n } else if (zone === 'bottom') {\n secondary = {\n left: target.rect.left,\n right: target.rect.right,\n top: target.rect.top,\n bottom: overlayRect.top,\n }\n } else {\n secondary = {\n left: target.rect.left,\n right: target.rect.right,\n top: overlayRect.bottom,\n bottom: target.rect.bottom,\n }\n }\n\n for (const rect of [primary, secondary]) {\n const piece = document.createElement('div')\n piece.classList.add('sliced-areas-drop-piece')\n piece.style.left = `${rect.left * width}px`\n piece.style.top = `${(1 - rect.top) * height}px`\n piece.style.width = `${(rect.right - rect.left) * width}px`\n piece.style.height = `${(rect.top - rect.bottom) * height}px`\n this.dropOverlay.appendChild(piece)\n }\n this.dropOverlay.style.display = 'block'\n this.lastDropTarget = { areaId: target.areaId, rect: target.rect, zone, mode: 'split' }\n }\n\n /**\n * Computes overlay and remainder rectangles for move preview.\n *\n * @param targetRect Target area rectangle.\n * @param zone Move zone.\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n * @returns Overlay and remainder rectangles plus replace flag.\n */\n private getMovePreview(\n targetRect: Rect,\n zone: 'left' | 'right' | 'top' | 'bottom',\n clientX: number,\n clientY: number,\n ): { overlay: Rect; remainder: Rect; replace: boolean } {\n if (!this.rootEl) {\n return { overlay: targetRect, remainder: targetRect, replace: true }\n }\n const bounds = this.rootEl.getBoundingClientRect()\n const x = (clientX - bounds.left) / bounds.width\n const y = 1 - (clientY - bounds.top) / bounds.height\n const snapX = MOVE_SNAP_PX / Math.max(bounds.width, 1)\n const snapY = MOVE_SNAP_PX / Math.max(bounds.height, 1)\n const centerX = (targetRect.left + targetRect.right) / 2\n const centerY = (targetRect.bottom + targetRect.top) / 2\n const targetWidth = targetRect.right - targetRect.left\n const targetHeight = targetRect.top - targetRect.bottom\n const replaceSize = Math.min(targetWidth, targetHeight) * REPLACE_THRESHOLD_RATIO\n const replaceHalf = replaceSize / 2\n const replaceLeft = centerX - replaceHalf\n const replaceRight = centerX + replaceHalf\n const replaceBottom = centerY - replaceHalf\n const replaceTop = centerY + replaceHalf\n const replace = x >= replaceLeft && x <= replaceRight && y >= replaceBottom && y <= replaceTop\n\n if (zone === 'left' || zone === 'right') {\n let split = zone === 'left' ? 2 * x - targetRect.left : 2 * x - targetRect.right\n if (Math.abs(split - centerX) <= snapX) {\n split = centerX\n }\n split = Math.min(Math.max(split, targetRect.left + MIN_RATIO), targetRect.right - MIN_RATIO)\n const overlay =\n zone === 'left'\n ? { left: targetRect.left, right: split, top: targetRect.top, bottom: targetRect.bottom }\n : { left: split, right: targetRect.right, top: targetRect.top, bottom: targetRect.bottom }\n const remainder =\n zone === 'left'\n ? { left: split, right: targetRect.right, top: targetRect.top, bottom: targetRect.bottom }\n : { left: targetRect.left, right: split, top: targetRect.top, bottom: targetRect.bottom }\n const tooSmall = targetWidth <= MIN_RATIO * 2 + EPS\n const finalReplace = replace || tooSmall\n return {\n overlay: finalReplace ? targetRect : overlay,\n remainder: finalReplace ? targetRect : remainder,\n replace: finalReplace,\n }\n }\n\n let split = zone === 'bottom' ? 2 * y - targetRect.bottom : 2 * y - targetRect.top\n if (Math.abs(split - centerY) <= snapY) {\n split = centerY\n }\n split = Math.min(Math.max(split, targetRect.bottom + MIN_RATIO), targetRect.top - MIN_RATIO)\n const overlay =\n zone === 'bottom'\n ? { left: targetRect.left, right: targetRect.right, top: split, bottom: targetRect.bottom }\n : { left: targetRect.left, right: targetRect.right, top: targetRect.top, bottom: split }\n const remainder =\n zone === 'bottom'\n ? { left: targetRect.left, right: targetRect.right, top: targetRect.top, bottom: split }\n : { left: targetRect.left, right: targetRect.right, top: split, bottom: targetRect.bottom }\n const tooSmall = targetHeight <= MIN_RATIO * 2 + EPS\n const finalReplace = replace || tooSmall\n return {\n overlay: finalReplace ? targetRect : overlay,\n remainder: finalReplace ? targetRect : remainder,\n replace: finalReplace,\n }\n }\n\n /**\n * Hides the drop overlay and clears target state.\n */\n private hideDropOverlay(): void {\n if (this.dropOverlay) {\n this.dropOverlay.style.display = 'none'\n }\n this.lastDropTarget = null\n }\n\n /**\n * Shows shaded regions that would be removed after a join.\n *\n * @param result Resulting rectangle after join.\n * @param sourceRect Source area rectangle.\n * @param targetRect Target area rectangle.\n */\n private showJoinShade(result: Rect, sourceRect: Rect, targetRect: Rect): void {\n if (!this.rootEl) return\n\n if (!this.dropShade) {\n this.dropShade = document.createElement('div')\n this.dropShade.classList.add('sliced-areas-drop-dim')\n this.dropShade.setAttribute(INTERNAL_ATTR, 'true')\n }\n if (!this.dropShade.isConnected) {\n this.rootEl.appendChild(this.dropShade)\n }\n\n const rect = this.rootEl.getBoundingClientRect()\n const width = Math.max(rect.width, 1)\n const height = Math.max(rect.height, 1)\n\n this.dropShade.innerHTML = ''\n const shadeRects = [\n ...this.subtractRect(sourceRect, result),\n ...this.subtractRect(targetRect, result),\n ]\n for (const shade of shadeRects) {\n const piece = document.createElement('div')\n piece.classList.add('sliced-areas-drop-dim-piece')\n piece.style.left = `${shade.left * width}px`\n piece.style.top = `${(1 - shade.top) * height}px`\n piece.style.width = `${(shade.right - shade.left) * width}px`\n piece.style.height = `${(shade.top - shade.bottom) * height}px`\n this.dropShade.appendChild(piece)\n }\n this.dropShade.style.display = shadeRects.length > 0 ? 'block' : 'none'\n }\n\n /**\n * Hides the join shading overlay.\n */\n private hideJoinShade(): void {\n if (this.dropShade) {\n this.dropShade.style.display = 'none'\n }\n }\n\n /**\n * Displays a drag label at the pointer.\n *\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n * @param label Label text.\n */\n private showDragLabel(clientX: number, clientY: number, label: string): void {\n if (!this.rootEl) return\n if (!this.dragLabel) {\n this.dragLabel = document.createElement('div')\n this.dragLabel.classList.add('sliced-areas-drag-label')\n this.dragLabel.setAttribute(INTERNAL_ATTR, 'true')\n }\n if (!this.dragLabel.isConnected) {\n this.rootEl.appendChild(this.dragLabel)\n }\n\n this.dragLabel.textContent = label\n this.dragLabel.style.left = `${clientX}px`\n this.dragLabel.style.top = `${clientY}px`\n this.dragLabel.style.display = 'block'\n }\n\n /**\n * Hides the drag label.\n */\n private hideDragLabel(): void {\n if (this.dragLabel) {\n this.dragLabel.style.display = 'none'\n }\n }\n\n /**\n * Returns the split label for a given zone.\n *\n * @param zone Split zone.\n * @returns Label text.\n */\n private getSplitLabel(zone: 'left' | 'right' | 'top' | 'bottom' | 'center'): string {\n if (zone === 'left') return 'Split Left'\n if (zone === 'right') return 'Split Right'\n if (zone === 'top') return 'Split Top'\n if (zone === 'bottom') return 'Split Bottom'\n return 'Split'\n }\n\n /**\n * Returns the join label for a given direction.\n *\n * @param direction Join direction.\n * @returns Label text.\n */\n private getJoinLabel(direction: 'left' | 'right' | 'up' | 'down'): string {\n if (direction === 'left') return 'Join Left'\n if (direction === 'right') return 'Join Right'\n if (direction === 'up') return 'Join Up'\n return 'Join Down'\n }\n\n /**\n * Finds a join target under the pointer, if any.\n *\n * @param sourceAreaId Source area id.\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n * @returns Join target details or null.\n */\n private findJoinTargetAtPoint(\n sourceAreaId: AreaId,\n clientX: number,\n clientY: number,\n ): {\n areaId: AreaId\n rect: Rect\n zone: 'left' | 'right' | 'top' | 'bottom'\n direction: 'left' | 'right' | 'up' | 'down'\n overlay: Rect\n result: Rect\n sourceRect: Rect\n } | null {\n if (!this.graph || !this.rootEl) return null\n const sourceArea = this.graph.areas[sourceAreaId]\n if (!sourceArea) return null\n\n const rect = this.rootEl.getBoundingClientRect()\n const x = (clientX - rect.left) / rect.width\n const y = 1 - (clientY - rect.top) / rect.height\n\n const sourceRect = this.getAreaRect(this.graph, sourceArea)\n let best: { target: GraphArea; rect: Rect; distance: number; orientation: JoinDir } | null =\n null\n\n for (const area of Object.values(this.graph.areas)) {\n if (area.id === sourceAreaId) continue\n const targetRect = this.getAreaRect(this.graph, area)\n if (\n x < targetRect.left ||\n x > targetRect.right ||\n y < targetRect.bottom ||\n y > targetRect.top\n ) {\n continue\n }\n\n const orientation = this.getOrientation(this.graph, sourceArea, area)\n if (orientation === 'none') continue\n\n if (orientation === 'east' || orientation === 'west') {\n const overlapBottom = Math.max(sourceRect.bottom, targetRect.bottom)\n const overlapTop = Math.min(sourceRect.top, targetRect.top)\n if (y < overlapBottom || y > overlapTop) continue\n const depth = (targetRect.right - targetRect.left) * JOIN_ZONE_DEPTH\n const distance = orientation === 'east' ? x - targetRect.left : targetRect.right - x\n if (distance < 0 || distance > depth) continue\n if (!best || distance < best.distance) {\n best = { target: area, rect: targetRect, distance, orientation }\n }\n } else {\n const overlapLeft = Math.max(sourceRect.left, targetRect.left)\n const overlapRight = Math.min(sourceRect.right, targetRect.right)\n if (x < overlapLeft || x > overlapRight) continue\n const depth = (targetRect.top - targetRect.bottom) * JOIN_ZONE_DEPTH\n const distance = orientation === 'north' ? y - targetRect.bottom : targetRect.top - y\n if (distance < 0 || distance > depth) continue\n if (!best || distance < best.distance) {\n best = { target: area, rect: targetRect, distance, orientation }\n }\n }\n }\n\n if (!best) return null\n\n const orientation = best.orientation\n const zone =\n orientation === 'east'\n ? 'left'\n : orientation === 'west'\n ? 'right'\n : orientation === 'north'\n ? 'bottom'\n : 'top'\n const direction =\n orientation === 'east'\n ? 'right'\n : orientation === 'west'\n ? 'left'\n : orientation === 'north'\n ? 'up'\n : 'down'\n const overlay = this.getJoinOverlayRect(sourceRect, best.rect, orientation)\n const result = this.getJoinResultRect(sourceRect, best.rect, orientation)\n\n return { areaId: best.target.id, rect: best.rect, zone, direction, overlay, result, sourceRect }\n }\n\n /**\n * Computes the overlay rectangle for a join preview.\n *\n * @param source Source area rectangle.\n * @param target Target area rectangle.\n * @param orientation Orientation between the areas.\n * @returns Overlay rectangle.\n */\n private getJoinOverlayRect(source: Rect, target: Rect, orientation: JoinDir): Rect {\n const overlapBottom = Math.max(source.bottom, target.bottom)\n const overlapTop = Math.min(source.top, target.top)\n const overlapLeft = Math.max(source.left, target.left)\n const overlapRight = Math.min(source.right, target.right)\n\n if (orientation === 'east') {\n return { left: target.left, right: target.right, top: overlapTop, bottom: overlapBottom }\n }\n if (orientation === 'west') {\n return { left: target.left, right: target.right, top: overlapTop, bottom: overlapBottom }\n }\n if (orientation === 'north') {\n return { left: overlapLeft, right: overlapRight, top: target.top, bottom: target.bottom }\n }\n return { left: overlapLeft, right: overlapRight, top: target.top, bottom: target.bottom }\n }\n\n /**\n * Computes the resulting rectangle of a join.\n *\n * @param source Source area rectangle.\n * @param target Target area rectangle.\n * @param orientation Orientation between the areas.\n * @returns Result rectangle.\n */\n private getJoinResultRect(source: Rect, target: Rect, orientation: JoinDir): Rect {\n const overlapBottom = Math.max(source.bottom, target.bottom)\n const overlapTop = Math.min(source.top, target.top)\n const overlapLeft = Math.max(source.left, target.left)\n const overlapRight = Math.min(source.right, target.right)\n\n if (orientation === 'east' || orientation === 'west') {\n return {\n left: Math.min(source.left, target.left),\n right: Math.max(source.right, target.right),\n top: overlapTop,\n bottom: overlapBottom,\n }\n }\n\n return {\n left: overlapLeft,\n right: overlapRight,\n top: Math.max(source.top, target.top),\n bottom: Math.min(source.bottom, target.bottom),\n }\n }\n\n /**\n * Subtracts a rectangle from another and returns remaining pieces.\n *\n * @param outer Outer rectangle.\n * @param inner Inner rectangle to subtract.\n * @returns Remaining rectangles.\n */\n private subtractRect(outer: Rect, inner: Rect): Rect[] {\n const overlapLeft = Math.max(outer.left, inner.left)\n const overlapRight = Math.min(outer.right, inner.right)\n const overlapBottom = Math.max(outer.bottom, inner.bottom)\n const overlapTop = Math.min(outer.top, inner.top)\n\n if (overlapLeft >= overlapRight || overlapBottom >= overlapTop) {\n return [outer]\n }\n\n const rects: Rect[] = []\n if (outer.top > overlapTop) {\n rects.push({ left: outer.left, right: outer.right, top: outer.top, bottom: overlapTop })\n }\n if (outer.bottom < overlapBottom) {\n rects.push({ left: outer.left, right: outer.right, top: overlapBottom, bottom: outer.bottom })\n }\n if (outer.left < overlapLeft) {\n rects.push({ left: outer.left, right: overlapLeft, top: overlapTop, bottom: overlapBottom })\n }\n if (outer.right > overlapRight) {\n rects.push({ left: overlapRight, right: outer.right, top: overlapTop, bottom: overlapBottom })\n }\n\n return rects\n }\n\n /**\n * Finds the area under the given pointer coordinates.\n *\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n * @returns Area id and rect or null when not found.\n */\n private findAreaAtPoint(clientX: number, clientY: number): { areaId: AreaId; rect: Rect } | null {\n if (!this.rootEl || !this.graph) return null\n const rect = this.rootEl.getBoundingClientRect()\n const x = (clientX - rect.left) / rect.width\n const y = 1 - (clientY - rect.top) / rect.height\n\n for (const area of Object.values(this.graph.areas)) {\n const areaRect = this.getAreaRect(this.graph, area)\n if (x >= areaRect.left && x <= areaRect.right && y >= areaRect.bottom && y <= areaRect.top) {\n return { areaId: area.id, rect: areaRect }\n }\n }\n\n return null\n }\n\n /**\n * Resolves the move zone inside a rectangle by pointer position.\n *\n * @param rect Target rectangle.\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n * @returns Move zone.\n */\n private getMoveZone(\n rect: Rect,\n clientX: number,\n clientY: number,\n ): 'left' | 'right' | 'top' | 'bottom' | 'center' {\n if (!this.rootEl) return 'center'\n const bounds = this.rootEl.getBoundingClientRect()\n const x = (clientX - bounds.left) / bounds.width\n const y = 1 - (clientY - bounds.top) / bounds.height\n const relX = (x - rect.left) / Math.max(rect.right - rect.left, EPS)\n const relY = (y - rect.bottom) / Math.max(rect.top - rect.bottom, EPS)\n\n if (relY >= relX && relY >= 1 - relX) return 'top'\n if (relY <= relX && relY <= 1 - relX) return 'bottom'\n if (relY >= relX && relY <= 1 - relX) return 'left'\n return 'right'\n }\n\n /**\n * Determines split axis from a drag gesture.\n *\n * @param state Area drag state.\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n * @returns Gesture axis or null when undecided.\n */\n private resolveSplitGesture(\n state: AreaDragState,\n clientX: number,\n clientY: number,\n ): { axis: SplitAxis } | null {\n const fromStartDx = clientX - state.startX\n const fromStartDy = clientY - state.startY\n const absStartDx = Math.abs(fromStartDx)\n const absStartDy = Math.abs(fromStartDy)\n\n if (!state.axis) {\n if (Math.max(absStartDx, absStartDy) < SPLIT_GESTURE_THRESHOLD_PX) return null\n if (absStartDx - absStartDy >= SPLIT_AXIS_TOLERANCE_PX) {\n state.axis = 'vertical'\n } else if (absStartDy - absStartDx >= SPLIT_AXIS_TOLERANCE_PX) {\n state.axis = 'horizontal'\n } else {\n return null\n }\n } else {\n const dx = clientX - state.lastX\n const dy = clientY - state.lastY\n const absDx = Math.abs(dx)\n const absDy = Math.abs(dy)\n if (Math.max(absDx, absDy) >= SPLIT_GESTURE_THRESHOLD_PX) {\n if (state.axis === 'vertical' && absDy - absDx >= SPLIT_AXIS_TOLERANCE_PX) {\n state.axis = 'horizontal'\n } else if (state.axis === 'horizontal' && absDx - absDy >= SPLIT_AXIS_TOLERANCE_PX) {\n state.axis = 'vertical'\n }\n }\n }\n\n state.lastX = clientX\n state.lastY = clientY\n\n return { axis: state.axis }\n }\n\n /**\n * Determines the split zone from a resolved gesture.\n *\n * @param rect Target rectangle.\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n * @param gesture Resolved split gesture.\n * @returns Split zone.\n */\n private getSplitZone(\n rect: Rect,\n clientX: number,\n clientY: number,\n gesture: { axis: SplitAxis },\n ): 'left' | 'right' | 'top' | 'bottom' {\n if (!this.rootEl) return gesture.axis === 'vertical' ? 'right' : 'top'\n const bounds = this.rootEl.getBoundingClientRect()\n const x = (clientX - bounds.left) / bounds.width\n const y = 1 - (clientY - bounds.top) / bounds.height\n const relX = (x - rect.left) / Math.max(rect.right - rect.left, EPS)\n const relY = (y - rect.bottom) / Math.max(rect.top - rect.bottom, EPS)\n const factorV = relY\n const factorH = relX\n const isLeft = factorV < 0.5\n const isBottom = factorH < 0.5\n const isRight = !isLeft\n const isTop = !isBottom\n\n let factor = gesture.axis === 'horizontal' ? factorH : factorV\n if ((isTop && isLeft) || (isBottom && isRight)) {\n factor = 1 - factor\n }\n\n if (gesture.axis === 'vertical') {\n return factor > 0.5 ? 'right' : 'left'\n }\n return factor > 0.5 ? 'top' : 'bottom'\n }\n\n /**\n * Determines the split zone given a fixed axis.\n *\n * @param rect Target rectangle.\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n * @param axis Split axis.\n * @returns Split zone.\n */\n private getSplitZoneByAxis(\n rect: Rect,\n clientX: number,\n clientY: number,\n axis: SplitAxis,\n ): 'left' | 'right' | 'top' | 'bottom' {\n if (!this.rootEl) return axis === 'vertical' ? 'right' : 'top'\n const bounds = this.rootEl.getBoundingClientRect()\n const x = (clientX - bounds.left) / bounds.width\n const y = 1 - (clientY - bounds.top) / bounds.height\n const relX = (x - rect.left) / Math.max(rect.right - rect.left, EPS)\n const relY = (y - rect.bottom) / Math.max(rect.top - rect.bottom, EPS)\n\n if (axis === 'vertical') {\n return relX < 0.5 ? 'left' : 'right'\n }\n return relY < 0.5 ? 'bottom' : 'top'\n }\n\n /**\n * Checks if a rectangle can be split along an axis.\n *\n * @param rect Target rectangle.\n * @param axis Split axis.\n * @returns True when split is possible.\n */\n private canSplitRect(rect: Rect, axis: SplitAxis): boolean {\n const width = rect.right - rect.left\n const height = rect.top - rect.bottom\n\n if (axis === 'vertical') {\n return width > MIN_RATIO * 2\n }\n return height > MIN_RATIO * 2\n }\n\n /**\n * Returns the zone rectangle for previews.\n *\n * @param rect Target rectangle.\n * @param zone Zone to extract.\n * @param mode Drop mode.\n * @returns Zone rectangle.\n */\n private getZoneRect(\n rect: Rect,\n zone: 'left' | 'right' | 'top' | 'bottom' | 'center',\n mode: 'join' | 'split' | 'move' | 'replace' | 'swap',\n ): Rect {\n const threshold = mode === 'join' ? 0.25 : 0.5\n if (zone === 'left') {\n return {\n left: rect.left,\n right: rect.left + (rect.right - rect.left) * threshold,\n top: rect.top,\n bottom: rect.bottom,\n }\n }\n if (zone === 'right') {\n return {\n left: rect.right - (rect.right - rect.left) * threshold,\n right: rect.right,\n top: rect.top,\n bottom: rect.bottom,\n }\n }\n if (zone === 'bottom') {\n return {\n left: rect.left,\n right: rect.right,\n top: rect.bottom + (rect.top - rect.bottom) * threshold,\n bottom: rect.bottom,\n }\n }\n if (zone === 'top') {\n return {\n left: rect.left,\n right: rect.right,\n top: rect.top,\n bottom: rect.top - (rect.top - rect.bottom) * threshold,\n }\n }\n return rect\n }\n\n /**\n * Computes the overlay rectangle for a split preview.\n *\n * @param rect Target rectangle.\n * @param zone Split zone.\n * @param clientX Pointer X position.\n * @param clientY Pointer Y position.\n * @returns Overlay rectangle.\n */\n private getSplitOverlayRect(\n rect: Rect,\n zone: 'left' | 'right' | 'top' | 'bottom' | 'center',\n clientX: number,\n clientY: number,\n ): Rect {\n if (!this.rootEl) return rect\n const bounds = this.rootEl.getBoundingClientRect()\n const x = (clientX - bounds.left) / bounds.width\n const y = 1 - (clientY - bounds.top) / bounds.height\n const clampedX = Math.min(Math.max(x, rect.left + MIN_RATIO), rect.right - MIN_RATIO)\n const clampedY = Math.min(Math.max(y, rect.bottom + MIN_RATIO), rect.top - MIN_RATIO)\n\n if (zone === 'left') {\n return { left: rect.left, right: clampedX, top: rect.top, bottom: rect.bottom }\n }\n if (zone === 'right') {\n return { left: clampedX, right: rect.right, top: rect.top, bottom: rect.bottom }\n }\n if (zone === 'bottom') {\n return { left: rect.left, right: rect.right, top: clampedY, bottom: rect.bottom }\n }\n if (zone === 'top') {\n return { left: rect.left, right: rect.right, top: rect.top, bottom: clampedY }\n }\n return rect\n }\n\n /**\n * Moves all connected vertices on an edge to a new coordinate.\n *\n * @param graph Graph to update.\n * @param axis Axis of movement.\n * @param fromCoord Current coordinate.\n * @param toCoord Target coordinate.\n * @param rangeStart Range start.\n * @param rangeEnd Range end.\n * @returns Updated graph or null when no movement.\n */\n private moveEdge(\n graph: AreasGraph,\n axis: SplitAxis,\n fromCoord: number,\n toCoord: number,\n rangeStart: number,\n rangeEnd: number,\n ): AreasGraph | null {\n if (Math.abs(fromCoord - toCoord) <= EPS) return null\n\n const next: AreasGraph = {\n verts: { ...graph.verts },\n edges: { ...graph.edges },\n areas: { ...graph.areas },\n }\n\n const connected = this.collectConnectedVerts(next, axis, fromCoord, rangeStart, rangeEnd)\n for (const vertId of connected) {\n const vert = next.verts[vertId]\n if (!vert) continue\n if (axis === 'vertical') {\n vert.x = toCoord\n } else {\n vert.y = toCoord\n }\n }\n\n return next\n }\n\n /**\n * Computes min/max bounds for a draggable edge segment.\n *\n * @param graph Graph to inspect.\n * @param axis Axis of the edge.\n * @param coord Edge coordinate.\n * @param rangeStart Segment start.\n * @param rangeEnd Segment end.\n * @returns Bounds or null when invalid.\n */\n private getEdgeDragBounds(\n graph: AreasGraph,\n axis: SplitAxis,\n coord: number,\n rangeStart: number,\n rangeEnd: number,\n ): { min: number; max: number } | null {\n let min = 0\n let max = 1\n const start = Math.min(rangeStart, rangeEnd) - EPS\n const end = Math.max(rangeStart, rangeEnd) + EPS\n let hasMatch = false\n\n for (const area of Object.values(graph.areas)) {\n const rect = this.getAreaRect(graph, area)\n if (axis === 'vertical') {\n const overlaps = rect.bottom <= end && rect.top >= start\n if (!overlaps) continue\n if (Math.abs(rect.right - coord) <= EPS) {\n min = Math.max(min, rect.left + MIN_RATIO)\n hasMatch = true\n }\n if (Math.abs(rect.left - coord) <= EPS) {\n max = Math.min(max, rect.right - MIN_RATIO)\n hasMatch = true\n }\n } else {\n const overlaps = rect.left <= end && rect.right >= start\n if (!overlaps) continue\n if (Math.abs(rect.top - coord) <= EPS) {\n min = Math.max(min, rect.bottom + MIN_RATIO)\n hasMatch = true\n }\n if (Math.abs(rect.bottom - coord) <= EPS) {\n max = Math.min(max, rect.top - MIN_RATIO)\n hasMatch = true\n }\n }\n }\n\n if (!hasMatch || min >= max) return null\n return { min, max }\n }\n\n /**\n * Computes the rectangle for a graph area.\n *\n * @param graph Graph containing the area.\n * @param area Area to compute.\n * @returns Normalized rectangle.\n */\n private getAreaRect(graph: AreasGraph, area: GraphArea): Rect {\n const v1 = graph.verts[area.v1]\n const v2 = graph.verts[area.v2]\n const v3 = graph.verts[area.v3]\n const v4 = graph.verts[area.v4]\n if (!v1 || !v2 || !v3 || !v4) {\n throw new Error(`Invalid area vertices for ${area.id}`)\n }\n\n return {\n left: Math.min(v1.x, v2.x, v3.x, v4.x),\n right: Math.max(v1.x, v2.x, v3.x, v4.x),\n bottom: Math.min(v1.y, v2.y, v3.y, v4.y),\n top: Math.max(v1.y, v2.y, v3.y, v4.y),\n }\n }\n\n /**\n * Adds a vertex to the vertex map.\n *\n * @param verts Vertex map to update.\n * @param x X coordinate.\n * @param y Y coordinate.\n * @returns New vertex id.\n */\n private addVert(verts: Record<VertId, GraphVert>, x: number, y: number): VertId {\n const id = this.nextVertId(verts)\n verts[id] = { id, x, y }\n return id\n }\n\n /**\n * Adds an edge to the edge map.\n *\n * @param edges Edge map to update.\n * @param v1 First vertex id.\n * @param v2 Second vertex id.\n * @returns New edge id.\n */\n private addEdge(edges: Record<EdgeId, GraphEdge>, v1: VertId, v2: VertId): EdgeId {\n const id = this.nextEdgeId(edges)\n edges[id] = { id, v1, v2, border: false }\n return id\n }\n\n /**\n * Generates the next unique vertex id.\n *\n * @param verts Existing vertex map.\n * @returns Unique vertex id.\n */\n private nextVertId(verts: Record<VertId, GraphVert>): VertId {\n let id = ''\n do {\n this.vertCounter += 1\n id = `v${this.vertCounter}`\n } while (verts[id])\n return id\n }\n\n /**\n * Generates the next unique edge id.\n *\n * @param edges Existing edge map.\n * @returns Unique edge id.\n */\n private nextEdgeId(edges: Record<EdgeId, GraphEdge>): EdgeId {\n let id = ''\n do {\n this.edgeCounter += 1\n id = `e${this.edgeCounter}`\n } while (edges[id])\n return id\n }\n\n /**\n * Generates the next unique area id.\n *\n * @returns Unique area id.\n */\n private nextAreaId(): AreaId {\n let id = ''\n do {\n this.areaCounter += 1\n id = `area-${this.areaCounter}`\n } while (this.graph?.areas[id] || this.querySelector(`[data-area-id=\"${id}\"]`))\n return id\n }\n\n /**\n * Normalizes the graph and fills any holes.\n *\n * @param graph Graph to normalize.\n * @returns Normalized graph.\n */\n private normalizeGraph(graph: AreasGraph): AreasGraph {\n const normalized = this.normalizeGraphInternal(graph)\n const filled = this.fillHoles(normalized)\n return this.normalizeGraphInternal(filled)\n }\n\n /**\n * Normalizes vertices and edges by merging duplicates.\n *\n * @param graph Graph to normalize.\n * @returns Normalized graph.\n */\n private normalizeGraphInternal(graph: AreasGraph): AreasGraph {\n const vertKey = (vert: GraphVert) => `${vert.x.toFixed(6)}|${vert.y.toFixed(6)}`\n const vertMap = new Map<string, VertId>()\n const remap: Record<VertId, VertId> = {}\n const verts: Record<VertId, GraphVert> = {}\n\n for (const vert of Object.values(graph.verts)) {\n const key = vertKey(vert)\n const existing = vertMap.get(key)\n if (existing) {\n remap[vert.id] = existing\n } else {\n vertMap.set(key, vert.id)\n verts[vert.id] = { ...vert }\n }\n }\n\n const edges: Record<EdgeId, GraphEdge> = {}\n const edgeMap = new Map<string, EdgeId>()\n\n for (const edge of Object.values(graph.edges)) {\n const v1 = remap[edge.v1] ?? edge.v1\n const v2 = remap[edge.v2] ?? edge.v2\n const ordered = v1 < v2 ? `${v1}|${v2}` : `${v2}|${v1}`\n if (edgeMap.has(ordered)) continue\n const id = this.nextEdgeId(edges)\n edges[id] = { id, v1, v2, border: edge.border }\n edgeMap.set(ordered, id)\n }\n\n const areas: Record<AreaId, GraphArea> = {}\n for (const area of Object.values(graph.areas)) {\n areas[area.id] = {\n id: area.id,\n v1: remap[area.v1] ?? area.v1,\n v2: remap[area.v2] ?? area.v2,\n v3: remap[area.v3] ?? area.v3,\n v4: remap[area.v4] ?? area.v4,\n }\n }\n\n const usedEdges = new Set<EdgeId>()\n const areaEdges = new Set<string>()\n for (const area of Object.values(areas)) {\n const pairs: [VertId, VertId][] = [\n [area.v1, area.v2],\n [area.v2, area.v3],\n [area.v3, area.v4],\n [area.v4, area.v1],\n ]\n for (const [a, b] of pairs) {\n areaEdges.add(a < b ? `${a}|${b}` : `${b}|${a}`)\n }\n }\n\n for (const edge of Object.values(edges)) {\n const key = edge.v1 < edge.v2 ? `${edge.v1}|${edge.v2}` : `${edge.v2}|${edge.v1}`\n if (areaEdges.has(key)) {\n usedEdges.add(edge.id)\n }\n }\n\n const filteredEdges: Record<EdgeId, GraphEdge> = {}\n for (const edge of Object.values(edges)) {\n if (usedEdges.has(edge.id)) {\n filteredEdges[edge.id] = edge\n }\n }\n\n const usedVerts = new Set<VertId>()\n for (const edge of Object.values(filteredEdges)) {\n usedVerts.add(edge.v1)\n usedVerts.add(edge.v2)\n }\n\n const filteredVerts: Record<VertId, GraphVert> = {}\n for (const vert of Object.values(verts)) {\n if (usedVerts.has(vert.id)) {\n filteredVerts[vert.id] = vert\n }\n }\n\n return { verts: filteredVerts, edges: filteredEdges, areas }\n }\n\n /**\n * Attempts to fill any uncovered holes in the layout.\n *\n * @param graph Graph to update.\n * @returns Graph with holes filled.\n */\n private fillHoles(graph: AreasGraph): AreasGraph {\n let next = graph\n let guard = 0\n while (guard < 50) {\n const holes = this.findHoleCells(next)\n if (holes.length === 0) {\n const overlaps = this.findOverlaps(next)\n if (overlaps.length > 0) {\n this.throwOverlapError(next, overlaps)\n }\n return next\n }\n\n let progress = false\n for (const hole of holes) {\n const plan = this.findHoleFillPlan(next, hole)\n if (!plan) {\n const aligned = this.tryAlignHoleNeighbors(next, hole)\n if (aligned.changed) {\n next = aligned.graph\n progress = true\n break\n }\n continue\n }\n for (const neighbor of plan.neighbors) {\n const merged = this.expandRectIntoHole(neighbor.rect, hole, plan.side)\n next = this.setAreaRect(next, neighbor.areaId, merged)\n }\n progress = true\n }\n\n if (!progress) {\n this.throwHoleError(next, holes)\n }\n\n guard += 1\n }\n\n this.throwHoleError(next, this.findHoleCells(next))\n }\n\n /**\n * Finds uncovered grid cells in the layout.\n *\n * @param graph Graph to inspect.\n * @returns Hole rectangles.\n */\n private findHoleCells(graph: AreasGraph): Rect[] {\n const rects = Object.values(graph.areas).map((area) => this.getAreaRect(graph, area))\n const xs = this.collectAxisCoords(rects, 'x')\n const ys = this.collectAxisCoords(rects, 'y')\n const holes: Rect[] = []\n\n for (let xi = 0; xi < xs.length - 1; xi += 1) {\n const left = xs[xi]\n const right = xs[xi + 1]\n if (left === undefined || right === undefined) continue\n for (let yi = 0; yi < ys.length - 1; yi += 1) {\n const bottom = ys[yi]\n const top = ys[yi + 1]\n if (bottom === undefined || top === undefined) continue\n const cell: Rect = { left, right, bottom, top }\n if (cell.right - cell.left <= EPS || cell.top - cell.bottom <= EPS) continue\n if (!this.isCellCovered(rects, cell)) {\n holes.push(cell)\n }\n }\n }\n\n return this.mergeHoleCells(holes)\n }\n\n /**\n * Collects and de-duplicates axis coordinates for grid scan.\n *\n * @param rects Rectangles to inspect.\n * @param axis Axis to collect.\n * @returns Sorted coordinates.\n */\n private collectAxisCoords(rects: Rect[], axis: 'x' | 'y'): number[] {\n const coords: number[] = [0, 1]\n for (const rect of rects) {\n if (axis === 'x') {\n coords.push(rect.left, rect.right)\n } else {\n coords.push(rect.bottom, rect.top)\n }\n }\n coords.sort((a, b) => a - b)\n const merged: number[] = []\n for (const value of coords) {\n const last = merged[merged.length - 1]\n if (last === undefined || Math.abs(value - last) > ALIGN_TOLERANCE) {\n merged.push(value)\n }\n }\n return merged\n }\n\n /**\n * Merges adjacent hole cells into larger rectangles.\n *\n * @param cells Hole cells to merge.\n * @returns Merged hole rectangles.\n */\n private mergeHoleCells(cells: Rect[]): Rect[] {\n const merged = [...cells]\n let changed = true\n while (changed) {\n changed = false\n outer: for (let i = 0; i < merged.length; i += 1) {\n for (let j = i + 1; j < merged.length; j += 1) {\n const a = merged[i]\n const b = merged[j]\n if (!a || !b) continue\n const canMergeVertical =\n Math.abs(a.left - b.left) <= ALIGN_TOLERANCE &&\n Math.abs(a.right - b.right) <= ALIGN_TOLERANCE &&\n (Math.abs(a.top - b.bottom) <= ALIGN_TOLERANCE ||\n Math.abs(b.top - a.bottom) <= ALIGN_TOLERANCE)\n const canMergeHorizontal =\n Math.abs(a.bottom - b.bottom) <= ALIGN_TOLERANCE &&\n Math.abs(a.top - b.top) <= ALIGN_TOLERANCE &&\n (Math.abs(a.right - b.left) <= ALIGN_TOLERANCE ||\n Math.abs(b.right - a.left) <= ALIGN_TOLERANCE)\n\n if (canMergeVertical || canMergeHorizontal) {\n const mergedRect: Rect = {\n left: Math.min(a.left, b.left),\n right: Math.max(a.right, b.right),\n bottom: Math.min(a.bottom, b.bottom),\n top: Math.max(a.top, b.top),\n }\n merged.splice(j, 1)\n merged.splice(i, 1, mergedRect)\n changed = true\n break outer\n }\n }\n }\n }\n\n return merged\n }\n\n /**\n * Attempts to align neighbors to cover a hole.\n *\n * @param graph Graph to update.\n * @param hole Hole rectangle.\n * @returns Updated graph and change flag.\n */\n private tryAlignHoleNeighbors(\n graph: AreasGraph,\n hole: Rect,\n ): { graph: AreasGraph; changed: boolean } {\n let next = graph\n let changed = false\n const sides: Array<'west' | 'east' | 'south' | 'north'> = ['west', 'east', 'south', 'north']\n\n for (const side of sides) {\n const neighbors = this.collectAdjacentNeighbors(next, hole, side)\n for (const neighbor of neighbors) {\n const result = this.alignNeighborToHole(next, neighbor.areaId, hole, side)\n if (result.changed) {\n next = result.graph\n changed = true\n }\n }\n }\n\n return { graph: next, changed }\n }\n\n /**\n * Collects adjacent neighbors along one side of a hole.\n *\n * @param graph Graph to inspect.\n * @param hole Hole rectangle.\n * @param side Side to check.\n * @returns Neighbor areas and rectangles.\n */\n private collectAdjacentNeighbors(\n graph: AreasGraph,\n hole: Rect,\n side: 'west' | 'east' | 'south' | 'north',\n ): Array<{ areaId: AreaId; rect: Rect }> {\n const neighbors: Array<{ areaId: AreaId; rect: Rect }> = []\n for (const area of Object.values(graph.areas)) {\n const rect = this.getAreaRect(graph, area)\n if (side === 'west') {\n if (Math.abs(rect.right - hole.left) > ALIGN_TOLERANCE) continue\n const overlap = Math.min(rect.top, hole.top) - Math.max(rect.bottom, hole.bottom)\n if (overlap <= EPS) continue\n neighbors.push({ areaId: area.id, rect })\n } else if (side === 'east') {\n if (Math.abs(rect.left - hole.right) > ALIGN_TOLERANCE) continue\n const overlap = Math.min(rect.top, hole.top) - Math.max(rect.bottom, hole.bottom)\n if (overlap <= EPS) continue\n neighbors.push({ areaId: area.id, rect })\n } else if (side === 'south') {\n if (Math.abs(rect.top - hole.bottom) > ALIGN_TOLERANCE) continue\n const overlap = Math.min(rect.right, hole.right) - Math.max(rect.left, hole.left)\n if (overlap <= EPS) continue\n neighbors.push({ areaId: area.id, rect })\n } else {\n if (Math.abs(rect.bottom - hole.top) > ALIGN_TOLERANCE) continue\n const overlap = Math.min(rect.right, hole.right) - Math.max(rect.left, hole.left)\n if (overlap <= EPS) continue\n neighbors.push({ areaId: area.id, rect })\n }\n }\n\n return neighbors\n }\n\n /**\n * Splits or trims a neighbor to align with a hole.\n *\n * @param graph Graph to update.\n * @param areaId Neighbor area id.\n * @param hole Hole rectangle.\n * @param side Side of the hole.\n * @returns Updated graph and change flag.\n */\n private alignNeighborToHole(\n graph: AreasGraph,\n areaId: AreaId,\n hole: Rect,\n side: 'west' | 'east' | 'south' | 'north',\n ): { graph: AreasGraph; changed: boolean } {\n let next = graph\n let changed = false\n let area = next.areas[areaId]\n if (!area) return { graph: next, changed }\n let rect = this.getAreaRect(next, area)\n\n if (side === 'west' || side === 'east') {\n if (rect.bottom < hole.bottom - ALIGN_TOLERANCE) {\n const newId = this.nextAreaId()\n const split = this.splitAreaAt(next, areaId, 'horizontal', hole.bottom, newId, 'max')\n if (split) {\n next = split\n this.ensureAreaNode(newId, areaId, true)\n changed = true\n area = next.areas[areaId]\n if (!area) return { graph: next, changed }\n rect = this.getAreaRect(next, area)\n }\n }\n if (rect.top > hole.top + ALIGN_TOLERANCE) {\n const newId = this.nextAreaId()\n const split = this.splitAreaAt(next, areaId, 'horizontal', hole.top, newId, 'min')\n if (split) {\n next = split\n this.ensureAreaNode(newId, areaId, true)\n changed = true\n }\n }\n } else {\n if (rect.left < hole.left - ALIGN_TOLERANCE) {\n const newId = this.nextAreaId()\n const split = this.splitAreaAt(next, areaId, 'vertical', hole.left, newId, 'max')\n if (split) {\n next = split\n this.ensureAreaNode(newId, areaId, true)\n changed = true\n area = next.areas[areaId]\n if (!area) return { graph: next, changed }\n rect = this.getAreaRect(next, area)\n }\n }\n if (rect.right > hole.right + ALIGN_TOLERANCE) {\n const newId = this.nextAreaId()\n const split = this.splitAreaAt(next, areaId, 'vertical', hole.right, newId, 'min')\n if (split) {\n next = split\n this.ensureAreaNode(newId, areaId, true)\n changed = true\n }\n }\n }\n\n return { graph: next, changed }\n }\n\n /**\n * Checks if a cell is covered by any rectangle.\n *\n * @param rects Rectangles to check.\n * @param cell Cell rectangle.\n * @returns True when covered.\n */\n private isCellCovered(rects: Rect[], cell: Rect): boolean {\n const cx = (cell.left + cell.right) / 2\n const cy = (cell.bottom + cell.top) / 2\n for (const rect of rects) {\n if (\n cx >= rect.left - ALIGN_TOLERANCE &&\n cx <= rect.right + ALIGN_TOLERANCE &&\n cy >= rect.bottom - ALIGN_TOLERANCE &&\n cy <= rect.top + ALIGN_TOLERANCE\n ) {\n return true\n }\n }\n return false\n }\n\n /**\n * Finds a plan to fill a hole by expanding neighbors.\n *\n * @param graph Graph to inspect.\n * @param hole Hole rectangle.\n * @returns Fill plan or null when impossible.\n */\n private findHoleFillPlan(\n graph: AreasGraph,\n hole: Rect,\n ): {\n side: 'west' | 'east' | 'north' | 'south'\n neighbors: Array<{ areaId: AreaId; rect: Rect }>\n } | null {\n const candidates = [\n this.collectHoleNeighbors(graph, hole, 'west'),\n this.collectHoleNeighbors(graph, hole, 'east'),\n this.collectHoleNeighbors(graph, hole, 'south'),\n this.collectHoleNeighbors(graph, hole, 'north'),\n ]\n\n for (const candidate of candidates) {\n if (!candidate) continue\n if (this.isHoleSideCovered(hole, candidate.side, candidate.segments)) {\n return { side: candidate.side, neighbors: candidate.neighbors }\n }\n }\n\n return null\n }\n\n /**\n * Collects neighbor areas that fully cover one side of a hole.\n *\n * @param graph Graph to inspect.\n * @param hole Hole rectangle.\n * @param side Side to check.\n * @returns Neighbor data or null when none found.\n */\n private collectHoleNeighbors(\n graph: AreasGraph,\n hole: Rect,\n side: 'west' | 'east' | 'north' | 'south',\n ): {\n side: 'west' | 'east' | 'north' | 'south'\n neighbors: Array<{ areaId: AreaId; rect: Rect }>\n segments: Array<{ start: number; end: number }>\n } | null {\n const neighbors: Array<{ areaId: AreaId; rect: Rect }> = []\n const segments: Array<{ start: number; end: number }> = []\n\n for (const area of Object.values(graph.areas)) {\n const rect = this.getAreaRect(graph, area)\n if (side === 'west') {\n if (Math.abs(rect.right - hole.left) > ALIGN_TOLERANCE) continue\n if (rect.bottom < hole.bottom - ALIGN_TOLERANCE || rect.top > hole.top + ALIGN_TOLERANCE)\n continue\n const start = Math.max(rect.bottom, hole.bottom)\n const end = Math.min(rect.top, hole.top)\n if (end - start <= EPS) continue\n neighbors.push({ areaId: area.id, rect })\n segments.push({ start, end })\n } else if (side === 'east') {\n if (Math.abs(rect.left - hole.right) > ALIGN_TOLERANCE) continue\n if (rect.bottom < hole.bottom - ALIGN_TOLERANCE || rect.top > hole.top + ALIGN_TOLERANCE)\n continue\n const start = Math.max(rect.bottom, hole.bottom)\n const end = Math.min(rect.top, hole.top)\n if (end - start <= EPS) continue\n neighbors.push({ areaId: area.id, rect })\n segments.push({ start, end })\n } else if (side === 'south') {\n if (Math.abs(rect.top - hole.bottom) > ALIGN_TOLERANCE) continue\n if (rect.left < hole.left - ALIGN_TOLERANCE || rect.right > hole.right + ALIGN_TOLERANCE)\n continue\n const start = Math.max(rect.left, hole.left)\n const end = Math.min(rect.right, hole.right)\n if (end - start <= EPS) continue\n neighbors.push({ areaId: area.id, rect })\n segments.push({ start, end })\n } else {\n if (Math.abs(rect.bottom - hole.top) > ALIGN_TOLERANCE) continue\n if (rect.left < hole.left - ALIGN_TOLERANCE || rect.right > hole.right + ALIGN_TOLERANCE)\n continue\n const start = Math.max(rect.left, hole.left)\n const end = Math.min(rect.right, hole.right)\n if (end - start <= EPS) continue\n neighbors.push({ areaId: area.id, rect })\n segments.push({ start, end })\n }\n }\n\n if (neighbors.length === 0) return null\n return { side, neighbors, segments }\n }\n\n /**\n * Checks whether a hole side is fully covered by segments.\n *\n * @param hole Hole rectangle.\n * @param side Side to check.\n * @param segments Coverage segments.\n * @returns True when side is covered.\n */\n private isHoleSideCovered(\n hole: Rect,\n side: 'west' | 'east' | 'north' | 'south',\n segments: Array<{ start: number; end: number }>,\n ): boolean {\n const spanStart = side === 'west' || side === 'east' ? hole.bottom : hole.left\n const spanEnd = side === 'west' || side === 'east' ? hole.top : hole.right\n const merged = this.mergeSegments(segments)\n if (merged.length === 0) return false\n const first = merged[0]\n if (!first) return false\n if (first.start > spanStart + ALIGN_TOLERANCE) return false\n let coverageEnd = first.end\n for (let i = 1; i < merged.length; i += 1) {\n const segment = merged[i]\n if (!segment) continue\n if (segment.start > coverageEnd + ALIGN_TOLERANCE) return false\n coverageEnd = Math.max(coverageEnd, segment.end)\n }\n return coverageEnd >= spanEnd - ALIGN_TOLERANCE\n }\n\n /**\n * Merges overlapping or touching segments.\n *\n * @param segments Segments to merge.\n * @returns Merged segments.\n */\n private mergeSegments(\n segments: Array<{ start: number; end: number }>,\n ): Array<{ start: number; end: number }> {\n const sorted = segments\n .map((seg) => ({ start: Math.min(seg.start, seg.end), end: Math.max(seg.start, seg.end) }))\n .sort((a, b) => a.start - b.start)\n const merged: Array<{ start: number; end: number }> = []\n for (const seg of sorted) {\n const last = merged[merged.length - 1]\n if (!last || seg.start > last.end + ALIGN_TOLERANCE) {\n merged.push({ ...seg })\n } else {\n last.end = Math.max(last.end, seg.end)\n }\n }\n return merged\n }\n\n /**\n * Expands a rectangle into a hole from a given side.\n *\n * @param rect Neighbor rectangle.\n * @param hole Hole rectangle.\n * @param side Side to expand from.\n * @returns Expanded rectangle.\n */\n private expandRectIntoHole(\n rect: Rect,\n hole: Rect,\n side: 'west' | 'east' | 'north' | 'south',\n ): Rect {\n if (side === 'west') {\n return { ...rect, right: hole.right }\n }\n if (side === 'east') {\n return { ...rect, left: hole.left }\n }\n if (side === 'south') {\n return { ...rect, top: hole.top }\n }\n return { ...rect, bottom: hole.bottom }\n }\n\n /**\n * Detects overlapping areas in the graph.\n *\n * @param graph Graph to inspect.\n * @returns List of overlaps.\n */\n private findOverlaps(graph: AreasGraph): Array<{ a: AreaId; b: AreaId; rect: Rect }> {\n const areas = Object.values(graph.areas)\n const overlaps: Array<{ a: AreaId; b: AreaId; rect: Rect }> = []\n for (let i = 0; i < areas.length; i += 1) {\n const areaA = areas[i]\n if (!areaA) continue\n const rectA = this.getAreaRect(graph, areaA)\n for (let j = i + 1; j < areas.length; j += 1) {\n const areaB = areas[j]\n if (!areaB) continue\n const rectB = this.getAreaRect(graph, areaB)\n const left = Math.max(rectA.left, rectB.left)\n const right = Math.min(rectA.right, rectB.right)\n const bottom = Math.max(rectA.bottom, rectB.bottom)\n const top = Math.min(rectA.top, rectB.top)\n if (right - left > ALIGN_TOLERANCE && top - bottom > ALIGN_TOLERANCE) {\n overlaps.push({ a: areaA.id, b: areaB.id, rect: { left, right, bottom, top } })\n }\n }\n }\n return overlaps\n }\n\n /**\n * Throws a detailed error for overlapping areas.\n *\n * @param graph Graph containing overlaps.\n * @param overlaps Overlap data.\n * @throws Error when overlaps are found.\n */\n private throwOverlapError(\n graph: AreasGraph,\n overlaps: Array<{ a: AreaId; b: AreaId; rect: Rect }>,\n ): never {\n const detail = {\n overlaps: overlaps.map((item) => ({\n a: item.a,\n b: item.b,\n rect: this.formatRect(item.rect),\n })),\n areas: Object.values(graph.areas).map((area) => ({\n id: area.id,\n rect: this.formatRect(this.getAreaRect(graph, area)),\n })),\n }\n throw new Error(`Overlapping areas detected in layout: ${JSON.stringify(detail)}`)\n }\n\n /**\n * Throws a detailed error for unfillable holes.\n *\n * @param graph Graph containing holes.\n * @param holes Hole rectangles.\n * @throws Error when holes are found.\n */\n private throwHoleError(graph: AreasGraph, holes: Rect[]): never {\n const detail = {\n holes: holes.map((hole) => this.formatRect(hole)),\n areas: Object.values(graph.areas).map((area) => ({\n id: area.id,\n rect: this.formatRect(this.getAreaRect(graph, area)),\n })),\n }\n throw new Error(`Unfillable hole(s) detected in layout: ${JSON.stringify(detail)}`)\n }\n\n /**\n * Formats a rectangle to fixed precision for diagnostics.\n *\n * @param rect Rectangle to format.\n * @returns Formatted rectangle.\n */\n private formatRect(rect: Rect): { left: number; right: number; top: number; bottom: number } {\n return {\n left: Number(rect.left.toFixed(6)),\n right: Number(rect.right.toFixed(6)),\n top: Number(rect.top.toFixed(6)),\n bottom: Number(rect.bottom.toFixed(6)),\n }\n }\n\n /**\n * Collects vertices connected along a straight edge segment.\n *\n * @param graph Graph to inspect.\n * @param axis Axis of the edge.\n * @param coord Edge coordinate.\n * @param rangeStart Segment start.\n * @param rangeEnd Segment end.\n * @returns Set of connected vertex ids.\n */\n private collectConnectedVerts(\n graph: AreasGraph,\n axis: SplitAxis,\n coord: number,\n rangeStart: number,\n rangeEnd: number,\n ): Set<VertId> {\n const min = Math.min(rangeStart, rangeEnd) - EPS\n const max = Math.max(rangeStart, rangeEnd) + EPS\n const isOnAxis = (vert: GraphVert) =>\n axis === 'vertical' ? Math.abs(vert.x - coord) <= EPS : Math.abs(vert.y - coord) <= EPS\n const isInRange = (vert: GraphVert) =>\n axis === 'vertical' ? vert.y >= min && vert.y <= max : vert.x >= min && vert.x <= max\n\n const queue: VertId[] = []\n const visited = new Set<VertId>()\n\n for (const vert of Object.values(graph.verts)) {\n if (isOnAxis(vert) && isInRange(vert)) {\n queue.push(vert.id)\n visited.add(vert.id)\n }\n }\n\n if (queue.length === 0) return visited\n\n const edges = Object.values(graph.edges)\n while (queue.length > 0) {\n const current = queue.shift()\n if (!current) continue\n\n for (const edge of edges) {\n if (edge.v1 !== current && edge.v2 !== current) continue\n const v1 = graph.verts[edge.v1]\n const v2 = graph.verts[edge.v2]\n if (!v1 || !v2) continue\n\n if (!isOnAxis(v1) || !isOnAxis(v2)) continue\n\n const nextVert = edge.v1 === current ? edge.v2 : edge.v1\n if (visited.has(nextVert)) continue\n visited.add(nextVert)\n queue.push(nextVert)\n }\n }\n\n return visited\n }\n}\n\n/**\n * Registers the custom element when not already defined.\n */\nexport const registerSlicedAreasElement = () => {\n if (!customElements.get('sliced-areas')) {\n customElements.define('sliced-areas', SlicedAreasElement)\n }\n}\n\nregisterSlicedAreasElement()\n\n/**\n * Global tag name mapping for the custom element.\n */\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sliced-areas': SlicedAreasElement\n }\n}\n"],"mappings":"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"}
|