feat(layout): reveal/collapse/disclosure — cycle action arm + group sugar (2de.4)#105
Merged
Merged
Conversation
…e.4 slice 1)
{ set, cycle: [v0, v1, ...] } writes the SUCCESSOR of the current value,
wrapping; a current value outside the domain counts as the first member.
Gate derives as an allow-list of the members through the existing merge —
two cycles sharing a key union, which IS the accordion's writable path set.
{{ action }} grows the variadic display form: one display per cycle member
(positionally matched, current member's display renders) or one static
display; non-cycle kinds keep (display, boundValue) with arity >2 loud.
// [LAW:one-type-per-behavior] the bounded stepper's sibling: range vs
// enumerated domain — toggles, N-state cyclers, accordion paths are values
// of one arm, not new modes.
…closure (2de.4 slice 2)
{ kind: "group", name, label, open?, direction?, key?, bg?, fg?, when?,
children } is an INPUT-only node: it lowers at the loader to canonical
container/segment nodes and synthesizes its state var + cycle action +
toggle segment under the reserved groups.* namespace — one declaration,
every derived artifact single-sourced from it.
Accordion is key-sharing, not a mode: sibling groups naming one key each
toggle cycle [closed, ownName]; one key holds one open name, so opening a
sibling auto-closes the rest and the gate is the union of the sibling
cycles via the existing same-key merge. Nested disclosure nests groups
with distinct keys (a closed parent's when hides the subtree; child state
persists invisibly). An ancestor/descendant sharing a key is a load error.
// [LAW:one-type-per-behavior] group is never a canonical LayoutNode kind
// [LAW:dataflow-not-control-flow] accordion = a shared key value, no mode
…t (2de.4 slice 3)
Documents the cycle value-source arm, the variadic {{ action }} display
form, and the group sugar (independent toggle / accordion-by-shared-key /
nested disclosure). Folds the pending doc-drift fix: the architecture
recap now states the by-name merge for variables/segments/actions/helpers
and root-only wholesale replacement, matching mergeWithDefault.
brandon-fryslie
commented
Jun 12, 2026
brandon-fryslie
left a comment
Contributor
Author
There was a problem hiding this comment.
Adversarial review
The two new features — the cycle action arm and group layout sugar — are well-structured and internally consistent. The type system correctly models both forms, the gate derivation is sound (allow-list union for accordion), the 'unknown current counts as first member' rule is applied uniformly in both display selection and write computation, and the synthesis pass enforces the documented invariants with loud errors. One concrete defect: escapeTemplateLiteral does not neutralise newline or carriage-return characters in group labels, so a label containing a literal \n (legal in JSON5 string values) produces a broken Go template string literal at synthesis time.
… boundary Go-template string literals forbid literal newlines; a label containing \n would survive escapeTemplateLiteral and produce an unparseable synthesized template. Reject at the validator so the broken state is unrepresentable before synthesis runs. [LAW:no-silent-failure]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the design+build for brandon-layout-substrate-2de.4 — the feature layer atop the container|segment + actions foundation. Two additions, zero render-engine work; everything desugars to the shipped grammar.
1.
cycleaction arm (the enumerated-domain stepper){ set: key, cycle: [v0, v1, …] }writes the successor of the current value, wrapping; a current value outside the domain counts as the first member (order members default-state-first). The gate derives as an allow-list of the members through the existing same-key merge — no validator plumbing, the vocabulary grows by arms.{{ action }}grows a variadic display form for cycle actions: one display per member, positionally matched —{{ action "toggle" "▸ details" "▾ details" }}— or one static display. The current member's display renders; the click writes the successor. Non-cycle kinds keepdisplay [boundValue]; wrong arity is a loud render error.Deliberate contrast with
set-bounded: a cycle emits the absolute successor computed at render (the glyph names the current state, so the click delivers exactly the transition the glyph promised —[LAW:one-source-of-truth], display and write derive from one read), where the bounded stepper emits a relative nudge (rapid clicks must accumulate).2.
grouplayout sugar (input-only node kind){ kind: "group", name, label, open?, direction?, key?, bg?, fg?, when?, children }lowers at the loader to canonical container/segment nodes and synthesizes its state var + cycle action + toggle segment under the reservedgroups.namespace — one declaration, every derived artifact single-sourced ([LAW:one-source-of-truth]; a user name under the prefix is a load error). Group is never a canonicalLayoutNodekind ([LAW:one-type-per-behavior]— arranging + gating are behaviors container already has).key.key— one key holds one open name, so opening a sibling auto-closes the rest. Not a mode, a shared value ([LAW:dataflow-not-control-flow]); the gate is the union of the sibling cycles via the existing merge. No path grammar, no new action arm needed — the accordion semantics fall out of cycle's "unknown current counts as the first member" rule.whenhides the subtree, child state persists invisibly. Ancestor/descendant sharing a key is a load error.Verification
url-handleclick → ▾ + body → clicking the sibling auto-closed the first. Real OSC-8 wire URLs through the real set-state gate.check:schemagreen);check:protocolgreen.Out of scope (by design review with the user): auto-indent for nested groups → brandon-layout-polish-atn; a
{{ toggle }}helper — subsumed by the variadic display form.