Skip to content

Drag-across-to-select is not expressible: no drag-over channel, and on-drag lifts the source #319

Description

@MohakBajaj

Gap

Drag-across-to-select — press on a row, move the pointer, select everything
passed over — is not expressible in either core language.

on-drag is the only signal that a button is held while the pointer moves,
but it reports the drag SOURCE (sourceId) plus raw view-local x/y. An
app cannot turn that y into a row: layout lives in the runtime, and rows
vary in height (wrapping, inline images). There is also no press-down /
press-up pair, so there is no other way to know a button is down.

on-drag also lifts the source out of flow and draws it under the pointer.
That is right for reordering and wrong for selection: every drag looks like
the row is being dragged away.

on-hover-enter is not an answer either — containment advances on
hover-phase motion, which a button-down drag is not.

Why the obvious fix doesn't help

Reporting the widget id under the pointer is useless to an app: it has no
map from ObjectId back to its own data.

Proposed shape

Report the global key of the widget under the pointer.

Apps already set global-key="{row.id}" to their own item id, so the value
is meaningful with no new mapping. WidgetOptions.global_key is already
stored per widget (integer or string), and the runtime already hit-tests
during a drag — so the value exists at dispatch time.

Two candidate spellings, and I'd rather have direction than guess:

  1. A 7th field (overKey) on the existing drag record, behind a new
    reflect predicate so the current 6-field shape keeps working. Cheapest,
    but widens a record the docs describe as closed.
  2. A separate on-drag-over naming an arm of
    { sourceKey, overKey, phase }. More surface, but it leaves the reorder
    record alone and reads as its own gesture.

(2) looks like the better citizen from outside, but you own that call.

Selection drag must also not lift the source — either a
drag-mode="select" attribute, or infer it (an element with on-drag-over
and no on-drag does not lift).

Touch list

Mirrors #318: ui_markup_reflect.zig, ui.zig,
canvas_widget_events.zig (resolve the global key under the pointer during
a drag), both engines, ui_markup_contract.zig (payload class + artifact
version), automation (widget-drag routing the over-key), tests, docs,
skill-data.

Context

Came out of building a capture inbox where multi-select is core. #318
(press modifiers) covers cmd-click and shift-click; this is the remaining
gesture. Happy to implement it once you've said which spelling you want —
and it probably wants to land after #318, since it touches adjacent code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions