Two forms. Interactive resizing passes the dragged edge and a pixel delta; the opposite edge stays anchored.
import { resizeItem, type GridLayout, type GridResizeEdge } from 'gridla'export function dragEdge( layout: GridLayout, itemId: string, edge: GridResizeEdge, dx: number, dy: number,): GridLayout { const result = resizeItem({ layout, itemId, edge, delta: { x: dx, y: dy }, options: { gap: 12 } }) return result.accepted ? result.layout : layout}
Programmatic resizing passes a rect; missing fields keep their current values. edge is optional here and only informs snapping.
import { resizeItem, type GridLayout } from 'gridla'export function setSize(layout: GridLayout, itemId: string, w: number, h: number): GridLayout { const result = resizeItem({ layout, itemId, rect: { w, h }, options: { gap: 12, snap: false } }) return result.accepted ? result.layout : layout}
What happens: the requested rectangle is clamped to bounds and constraints, the moving edge snaps to nearby sibling and canvas edges, and neighbors that the new rectangle newly collides with are trimmed on the facing side down to their minimums (resize-shrink-neighbors). A collision with a locked item, a ghost, or a neighbor that cannot shrink enough rejects the resize.
resizeRect(item, edge, delta, bounds) gives the constrained rectangle without considering siblings; useful for a cursor-tracked outline while the solver decides where things land.
The handles are 10px divs inside the item along each edge or corner, with the matching resize cursor; size them with --gridla-handle-size and paint them as shown in the styling guide. Custom handles: use the render prop and spread getResizeHandleProps(edge) on your own element.
Programmatic resize uses actions.resize(itemId, { edge, delta } | { rect }, options). Alt + arrow keys resize the south-east corner by keyboardStep pixels out of the box.