diff --git a/docs/plans/2026-06-02-001-refactor-ssr-rendering-modernization-plan.md b/docs/plans/2026-06-02-001-refactor-ssr-rendering-modernization-plan.md index 400b289e..2e0648a5 100644 --- a/docs/plans/2026-06-02-001-refactor-ssr-rendering-modernization-plan.md +++ b/docs/plans/2026-06-02-001-refactor-ssr-rendering-modernization-plan.md @@ -187,6 +187,38 @@ state: (assoc attrs :key (str id "--" current-value)) ``` +**Selector strategy for targeted swaps (a consideration, not a mandate).** +Rules 2 and 4 above need a stable `hx-target`/`hx-select`. The obvious approach +— a unique `id` on every swappable element — gets noisy in repeated structures +(e.g. a table of financial accounts where choosing an account must swap *that +row's* dropdown). When you reach those advanced cases, consider a more +consistent scheme instead of hand-minting ids everywhere: + +- **Semantic markup + data-attributes** to craft a fine-grained selector without + per-element ids. For example, mark rows/cells with their identity and target + by attribute: + ```html + + + + + … + + ``` +- **A `form-path -> id` (or `-> selector`) function**, derived the same way a + cursor path is, so the server and the markup agree on the target by + construction rather than by convention. A render fn at form-path + `[:accounts 0 :location]` would compute its own stable selector (id or + data-attribute query) from that path, mirroring §3.2's top-rooted cursor. + +The aim is *consistency and predictability* of swap targets in repeated/nested +structures — pick whichever keeps targets unambiguous and easy to generate. Note +this in `reference/swap-doctrine.md` and let the first modal that hits nested +repeated swaps (Phase 5 / the wizards) settle on a convention for the cookbook. + ### 3.2 Render functions: explicit data, or a top-rooted cursor One function, data in, markup out. The data can arrive as a plain map or via a @@ -367,7 +399,8 @@ convention, e.g. `.claude/skills/testing-conventions/SKILL.md`). .claude/skills/ssr-form-migration/ SKILL.md # the playbook (§8): classify → migrate → verify → record reference/ - swap-doctrine.md # §3.1 rules, focus invariant, OOB-vs-hoist, Alpine hardening + swap-doctrine.md # §3.1 rules, focus invariant, OOB-vs-hoist, Alpine hardening, + # target-selector strategy (semantic/data-attr/form-path->id) render-functions.md # §3.2 explicit-data or top-rooted cursor; no faked positions form-vs-wizard.md # §3.3 classification + the data-driven engine selmer-conventions.md # §3.4 attr style, interop bridge, include/block patterns @@ -585,6 +618,10 @@ apply it cold." Single-step form currently wearing a wizard costume. cookbook entries from Phase 2. - [ ] Add-row: a `POST` that appends a fresh row; totals re-render via the sibling-`` swap, **not** OOB. +- [ ] **Settle a target-selector convention** for repeated/nested rows (§3.1 + "Selector strategy"): semantic data-attributes and/or a `form-path -> selector` + helper, rather than hand-minted ids per element. Record the chosen convention + in `reference/swap-doctrine.md` + `component-cookbook.md` so later wizards reuse it. - [ ] Collapse 4 wizard routes → 3 (open, submit, add-row). - [ ] Verify add/remove rows + totals + apply (assert DB) + full suite green. - [ ] Feed the skill; append scorecard row.