Skip to content

layout-DSL: port the example app-shell demos (learning material) #110

Description

@blendsdk

Part of the layout-DSL adoption epic #108.

Port the app-shell demos in @jsvision/examples from the imperative new Group().layout.add() idiom to col/row/grow/fixed. Extra weight here: examples are the first thing people read to learn the framework, so these should model the recommended composition idiom, not the raw one. Behavior-preserving — the demos must render identically.

Portable composition + sizing sites concentrate in these files (line refs are exact):

Clean wins (do these)

  • editor-demo/main.ts (S, zero risk) — the cleanest: root = col(grow(ed), fixed(ind, 1)) (sites 67/68/69).
  • event-demo/main.ts (M) — app-shell header/body/dialog/status. row({ fixed:1, gap:2 }, btnOk, btnOpen) (107/109), col({ fixed:2, background:'dialog' }, dialogLabel, btnClose) (114/116/119), col({ padding:1, background:'desktop' }, header, body, dialog, status) (103/124/128). Layout is incidental scaffolding for the event-loop demo → low-risk.
  • controls-demo/main.ts (S–M) — keep the data-driven loop: const form = col({ padding:1, gap:0, background:'window' }); for (const [v, rows] of …) form.add(fixed(v, rows)); (sites 95/107).
  • router-demo/main.ts (M) — the list route build() closure → col({ padding:1, background:'window' }, fixed(title,1), grow(listView)) (101/104/111). The DetailScreen extends Group stays self-config (site 59), but its children become this.add(fixed(title,1)) / fixed(hint,1) / fixed(back,2) (63/65/67).
  • kitchen-sink/stories/drill-down.story.ts (S–M) — mirror of router-demo: col({ background:'window' }, grow(list)) (69/77) + the same DetailScreen child sizings (32/34/36). Story at() infra around it stays absolute.
  • chrome-bars-demo/main.ts (S, trivial) — one-line consistency fix win.add(grow(body)) (site 99); the file already imports spacer/fixed.

Judgment calls (flag on the PR, decide with the reviewer)

  • view-demo/main.ts (M) — a textbook col-over-row app-shell (sites 50/53/57/59/61/67/77) that ports beautifully, but its stated job is to teach the raw View/Group spine. Porting arguably teaches the recommended idiom better — but confirm that's the intent before changing the lesson.
  • layout.story.ts (S) — site 31 is a clean row(...), but (a) the local variable is literally named row (collides with the builder — needs a rename) and (b) the story exists to teach the raw cell-native flex engine. Port only if the intent shifts to "here's the DSL over the engine."

Out of scope (surveyed, not portable — leave as-is)

Every deliberate absolute-coordinate demo using the shared at()/place() idiom (dropdowns, containers, date, color, tabs, tree, surface, feedback, table, files, playground, themes, controls-live, wizard-demo, amiga-clock, tvedit-demo, kitchen-sink shell.ts/story.ts), and the already-ported exemplars (recipes/form-dialog.ts, layout-dsl.story.ts, forms-showcase.story.ts, layout-dsl-playground/*, status-bar.story.ts). The *.layout.rect = window-placement mutations are also out of scope.

Note: wizard-demo and themes-demo define local place()/row() helpers that look like the DSL but aren't — see the cleanup issue.

Acceptance

  • Each ported demo renders identically (headless smoke + a manual run).
  • yarn verify green; yarn lint:fix run before the PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationeffort: MMedium — one focused planenhancementNew feature or requestgood first issueGood for newcomerspriority: mediumValuable; schedule after the high tier

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions