mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Editor: composition wireframe — pull-out, stacking, and simplify
This commit is contained in:
@@ -314,7 +314,13 @@ thin app-layer services.
|
||||
as a plain _insert_, not redundant nesting), **collapse** the source's emptied container (unwrap a
|
||||
one-child, drop a zero-child, recursing up the chain), and **data-pin** a source's inherited
|
||||
`data` before it changes ancestor (`dataBindingAtPath`, so it never silently rebinds). Degenerate
|
||||
drops — onto itself, its own ancestor/descendant, or the root — return null.
|
||||
drops — onto itself, its own ancestor/descendant, or the root — return null. `wrapContainer` is the
|
||||
complement for a frame-margin drop: it stacks the source against the _whole_ container rather than
|
||||
beside one view — the root included, lifting spec-level metadata onto the wrapper via
|
||||
`spec-transforms.concatRootBeside` — pulling a view out into a new full-span row/column. The same
|
||||
flatten/collapse cleanup runs after. `simplifyStructure` collapses redundant single-child
|
||||
compositions recursively (a `{hconcat:[v]}` is just `v`; `facet`/`repeat` hold one child by design
|
||||
and are left alone) — the wireframe's Simplify, returning null when nothing is redundant.
|
||||
|
||||
**Services (app, store-aware via `getState`):** `spec-transform-actions` (the
|
||||
wrap/simplify/add-view operations and their surfaces), `spec-dataset-hints` (completion,
|
||||
@@ -336,13 +342,20 @@ Decision rules:
|
||||
- **One edit path.** The lightbulb returns a `WorkspaceEdit` (no editor handle); the toolbar
|
||||
and palette use `executeEdits`. Both build the replacement through the same
|
||||
serialize-and-reindent step, bracketed by `pushUndoStop`, so ⌘Z restores the prior text.
|
||||
- **Wireframe restructuring is one core op + the editor's undo.** Every drag resolves to either
|
||||
`moveViewTo` (reorder within one container) or `wrapViews` (everything else — wrap, cross-container
|
||||
move, insert); the wireframe only _requests_ it (`AppStore.requestComposeMove`/`requestComposeWrap`)
|
||||
and `SpecEditor` applies it through the same `executeEdits` + `pushUndoStop` path as the other
|
||||
transforms, so a drag is one ⌘Z and the editor stays the single text source. `wrapViews` covers
|
||||
wrap and insert with one operation because it flattens bare same-orientation nesting afterward; the
|
||||
drag's edge-zone interaction model lives in [arch 10](10-interaction-and-feedback.md).
|
||||
- **Transform actions share an applier, never re-inline the skeleton.** Every `run*` action is
|
||||
parse → `build(spec)` → `writeBack` (toast on null). That prologue lives in a shared applier per
|
||||
family — `resolveTarget` (scoped), `applyArrayEdit` (one array), `applyWholeSpecEdit` (whole-spec
|
||||
drag/simplify) — so a new action passes its core call and differs only in scope and feedback. A
|
||||
fresh `run*` reuses the matching applier rather than copying the model/parse/writeBack lines.
|
||||
- **Wireframe restructuring is a core op + the editor's undo.** Every drag resolves to `moveViewTo`
|
||||
(reorder within one container), `wrapViews` (pair, cross-container move, insert), or `wrapContainer`
|
||||
(pull a view out around a container); the Simplify prompt resolves to `simplifyStructure`. The
|
||||
wireframe only _requests_ each (`AppStore.requestComposeMove`/`requestComposeWrap`/
|
||||
`requestComposeWrapContainer`/`requestComposeSimplify`) and `SpecEditor` applies it through the same
|
||||
`executeEdits` + `pushUndoStop` path as the other transforms, so a drag is one ⌘Z and the editor
|
||||
stays the single text source. `wrapViews` covers wrap and insert with one operation because it
|
||||
flattens bare same-orientation nesting afterward; the drag's zone interaction model lives in
|
||||
[arch 10](10-interaction-and-feedback.md).
|
||||
- **Composition CodeLens is cursor-scoped.** It follows the view the cursor sits in —
|
||||
`+ Add view above/below` at the view's edges and `↑/↓ Move` to reorder among its siblings —
|
||||
rather than one fixed button per composition array; an empty composition shows a single `+ Add view`,
|
||||
|
||||
@@ -247,16 +247,22 @@ never by writing the draft text directly — so the wireframe and editor share o
|
||||
the moved box for consecutive moves (so a screen reader re-announces its new position), a
|
||||
**polite** live region states the result, and `aria-keyshortcuts` advertises the keys. _(Council:
|
||||
APG listbox-rearrangeable.)_
|
||||
- **Restructure by drag — edge-zone (dock) model.** The nearest edge of the box under the pointer
|
||||
picks the **axis** (left/right → a row `hconcat`, top/bottom → a column `vconcat`) and **side**.
|
||||
A drop **along** a sibling's own container reorders within it; a drop **across** it — or onto an
|
||||
opaque `layer`/`facet`/`repeat` box — pairs the two in a new concat. The hit-test descends only
|
||||
through `hconcat`/`vconcat` and treats `layer`/`facet`/`repeat`/grid as **opaque** targets (their
|
||||
children overlap or are data-generated, so the unit is the target, never inside it). A 3px accent
|
||||
line marks the landing edge; a `wrap` drop also rings + tints the partner box. The drag is a
|
||||
pointer accelerator over capabilities that stay keyboard-reachable (in-container reorder via
|
||||
`Alt+↑/↓`; cross-container wrap via the editor's wrap actions), so it adds **no keyboard-only
|
||||
gap**. Transform invariants in [arch 08](08-vega-editor-techniques.md).
|
||||
- **Restructure by drag — zone model against the children's box.** Intent is read from where the
|
||||
pointer falls relative to a row/column's children, not one nearest edge, so each gesture owns a
|
||||
generous target: the **interior central band reorders** (an insertion slot by main-axis position —
|
||||
a drag _along_ the block rearranges it anywhere, not only on a sibling's edge); the **cross-axis
|
||||
frame margin** (a row's top/bottom, a column's left/right — the gutter between frame and children,
|
||||
or past the block) **pulls the source out** into a new full-span row/column wrapping the whole
|
||||
container, the root included; a drop onto **a view's far cross edge** pairs the two in a
|
||||
perpendicular split (`Shift` forces a pair from the centre). The source is the **innermost** view
|
||||
under the pointer — `beginDrag` stops propagation so a nested ancestor frame, itself draggable,
|
||||
can't claim the drag (un-stopped, its handler runs last on bubble and wins). The hit-test descends
|
||||
only through `hconcat`/`vconcat` and treats `layer`/`facet`/`repeat`/grid as **opaque**. Feedback:
|
||||
a cursor **chip** names the pending action, the target previews it (reorder line, pair half-split,
|
||||
pull-out band), and every frame's pull-out margins glow faintly while dragging. The drag is a
|
||||
pointer accelerator over keyboard-reachable capabilities (in-container reorder via `Alt+↑/↓`;
|
||||
cross-container restructure via the editor's wrap actions), so it adds **no keyboard-only gap**.
|
||||
Transform invariants in [arch 08](08-vega-editor-techniques.md).
|
||||
|
||||
**Resolved — pane toggle strip.** The persistent show/hide strip (spec §01A) is a **WAI-ARIA
|
||||
APG `toolbar`** (`role="toolbar"`, `aria-orientation="vertical"`, an `aria-label` such as
|
||||
|
||||
@@ -24,6 +24,17 @@ record the resolution into the contract (`docs/architecture/09`+`10` and the rel
|
||||
`storageErrorNotification` and `entityStorageErrorNotification` in `services/storage-errors.ts`
|
||||
and the import-quota copy in `services/transfer.ts`.
|
||||
|
||||
- **"Row" vs "column" naming differs between the wireframe's pull-out and pair drags** — the
|
||||
frame-margin pull-out chip/announcement (`pullLabel`, `commitDrop`) name the new full-span band
|
||||
by its _spatial_ shape (a `vconcat` slot is "a new row above"; an `hconcat` slot "a new column
|
||||
left"), while the pair-into-split chip/announcement use the _container_ convention (`hconcat` =
|
||||
"row", `vconcat` = "column"). Both describe the same axis — pulling a view above a row and
|
||||
pairing two views vertically are both a `vconcat` — yet one calls it a row and the other a
|
||||
column. Each reading is locally sensible (a pulled-out band reads as a row; a 2-cell vertical
|
||||
split reads as a column) but the divergence can confuse. Decide: unify on one vocabulary, or keep
|
||||
the gesture-specific framing. In `components/CompositionWireframe.tsx` (`pullLabel`, the
|
||||
`'row'`/`'column'` ternaries in `resolveDrop`/`commitDrop`).
|
||||
|
||||
## Deferred (not design debts, revisit on demand)
|
||||
|
||||
- **Drag-and-drop field assignment** — chips are click/keyboard-first by design; drag would
|
||||
|
||||
Reference in New Issue
Block a user