GridProvider is controlled when you pass layout; it never stores the layout itself and reports every accepted change through onLayoutChange. If you do not adopt a change, nothing changes: the provider re-renders from the prop you gave it.
'move', 'resize', 'place', 'remove', 'update', 'transfer', or 'set'
itemId
The item the operation targeted, when there is one.
strategy
The solver strategy for move, resize, place, and transfer.
onCommit fires with the same detail but only for interactive gestures that committed (pointer release) and for incoming transfers; programmatic actions do not trigger it. Use it to debounce saves without reacting to every keyboard nudge.
Selection is controlled the same way with selectedId and onSelectedIdChange. Pointer down on an item selects it before any drag starts; actions.select(null) clears it. Uncontrolled selection works out of the box when you omit selectedId.
The layout passed to onLayoutChange is expressed in the canvas size it was rendered at (the measured element size when responsive is on). That is by design: it is a valid layout, and rendering it again at the same size is the identity. If you need it in an authoring size, project it: projectLayout(next, { width: 1200, height: 720 }).
Set the prop and the provider re-projects. To go through the same pipeline as an interactive change (so onLayoutChange fires with reason: 'set'), call actions.setLayout(next) instead. actions.update(itemId, patch) patches constraints, policy, or data on one item and re-clamps its geometry, emitting reason: 'update'.