docs: add swap-target selector strategy consideration
Note in 3.1 that targeted hx-select/hx-target swaps in repeated/nested structures may want a consistent scheme -- semantic markup + data-attributes, or a form-path->selector helper (mirroring cursors) -- instead of hand-minting a unique id per element. Framed as a consideration for advanced cases, with a Phase 5 task to settle the convention into the skill cookbook. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -187,6 +187,38 @@ state:
|
|||||||
(assoc attrs :key (str id "--" current-value))
|
(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
|
||||||
|
<tr data-row="account" data-index="0">
|
||||||
|
<td data-cell="account">
|
||||||
|
<select hx-post="/transaction/edit-form-changed"
|
||||||
|
hx-target="[data-row='account'][data-index='0'] [data-cell='location']"
|
||||||
|
hx-select="[data-row='account'][data-index='0'] [data-cell='location']"
|
||||||
|
hx-swap="outerHTML" hx-trigger="changed">…</select>
|
||||||
|
</td>
|
||||||
|
<td data-cell="location">…</td>
|
||||||
|
</tr>
|
||||||
|
```
|
||||||
|
- **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
|
### 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
|
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/
|
.claude/skills/ssr-form-migration/
|
||||||
SKILL.md # the playbook (§8): classify → migrate → verify → record
|
SKILL.md # the playbook (§8): classify → migrate → verify → record
|
||||||
reference/
|
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
|
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
|
form-vs-wizard.md # §3.3 classification + the data-driven engine
|
||||||
selmer-conventions.md # §3.4 attr style, interop bridge, include/block patterns
|
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.
|
cookbook entries from Phase 2.
|
||||||
- [ ] Add-row: a `POST` that appends a fresh row; totals re-render via the
|
- [ ] Add-row: a `POST` that appends a fresh row; totals re-render via the
|
||||||
sibling-`<tbody>` swap, **not** OOB.
|
sibling-`<tbody>` 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).
|
- [ ] Collapse 4 wizard routes → 3 (open, submit, add-row).
|
||||||
- [ ] Verify add/remove rows + totals + apply (assert DB) + full suite green.
|
- [ ] Verify add/remove rows + totals + apply (assert DB) + full suite green.
|
||||||
- [ ] Feed the skill; append scorecard row.
|
- [ ] Feed the skill; append scorecard row.
|
||||||
|
|||||||
Reference in New Issue
Block a user