Editor: interactive composition wireframe — drag to reorder and restructure

Drag a view's box (or Alt+up/down) to reorder it within its container; drag onto another view's edge to pair the two in a new row/column, move across containers, or insert. Each leaf shows a glyph of its mark type.

Core: spec-restructure.wrapViews (wrap, with flatten-to-insert, collapse, and data-pin invariants) and spec-insert.moveViewTo; the editor applies every drag as one undoable edit via AppStore.composeRequest, keeping the editor the single text source.
This commit is contained in:
2026-06-29 14:25:31 +03:00
parent 57604a80a6
commit 216797ff9b
16 changed files with 1160 additions and 56 deletions
@@ -43,10 +43,46 @@
.leaf {
min-height: 48px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
/* The mark glyph is a quiet identity hint, not chrome — muted, inherits theme. */
.markIcon {
color: var(--text-secondary);
}
.node:hover {
border-color: var(--text-secondary);
}
/* Draggable boxes (draft only) advertise the drag with a grab cursor; the body
cursor flips to grabbing for the duration of an active drag (set in JS). */
.node[data-draggable] {
cursor: grab;
}
.node[data-dragging] {
opacity: 0.4;
}
/* Drop indicator (arch 10 §5): a 3px accent line on the edge the dragged box would
land. `wrap` mode additionally rings + tints the target box, signalling the two
pair into a new split rather than just reordering. */
.node[data-drop-edge='left'] {
box-shadow: inset 3px 0 0 var(--accent);
}
.node[data-drop-edge='right'] {
box-shadow: inset -3px 0 0 var(--accent);
}
.node[data-drop-edge='top'] {
box-shadow: inset 0 3px 0 var(--accent);
}
.node[data-drop-edge='bottom'] {
box-shadow: inset 0 -3px 0 var(--accent);
}
.node[data-drop-mode='wrap'] {
background: var(--accent-soft);
outline: 2px solid var(--accent);
outline-offset: -2px;
}
/* Selection mirrors the library's active-row language (arch 09 §4). */
.node.selected {
border-color: var(--accent);