Composition / foldkit-builder

Dragging

A pointer drag is four Messages, the facts foldkit-primitives' PointerDrag reports. What is dragged is its source: a node on the page, { _tag: 'Existing', id }, or a new node of a Block, { _tag: 'New', block }, dragged from the palette.

  • DragStarted({ source }) puts the drag in the Model's drag, an Option, with over and at both none, and selects a node it drags. Nothing changes on the page yet. A node not on the page, or a Block with no starting props, starts no drag.
  • DraggedOver({ id, zone }) says which node the pointer is over and in which zone of it, before, inside or after; DraggedOff() that it is over none. The Builder works out where a drop would land, drag.at: before or after that node among its siblings, or last in the first of its Regions that accepts the dragged Block. Inside a node that takes nothing is after it, and drag.over's zone says so. Where that node has no place for it, the nearest node holding it that does is used, before it or after it, so a Section dropped on a Section's last Heading lands after that Section, and drag.over names the holder. It climbs no higher than a node being dragged, and a drop onto a node's own place is no move, not its holder's. Each place is tried as the edit a drop would make (a move for a node, an insert of the Block's starting props for a new one), and where the page would refuse it, such as a node into itself, at is none, so a mark never promises a drop the page refuses.
  • DraggedOverRegion({ id, region }) says the pointer is over a node's empty Region, which the canvas draws as a box of its own (see Composition's edit mode): a drop goes last in that Region, not the first that accepts the Block, so a Columns' right column can be filled while its left is not. drag.over is { id, zone: 'inside', region }; region is none on every other place. A Region that refuses the Block, or has no room, is weighed as DraggedOver inside the node would be.
  • DraggedOverPage() says a palette tile is over the page's own space, over none of its nodes: an empty page, or the space below the last node. It lands where a press with nothing selected would put it (placeFor): last among the roots, or last in the last Region that takes it. A node already on the page is moved only onto another.
  • DragDropped() works the place out again, since the page may have changed, and moves a node there as one edit, undone and announced like a key's; a new node is asked for as a press on the palette asks, so it gets an id, is added there, and is selected. With no place, nothing changes and "Not moved", or "Not added", is announced. DragCancelled() ends the drag the same way.

A drawing marks drag.over only while drag.at is set, so the mark is where the node will go. The keyboard's way to move a node is keyCommand.