chain table round 6: the thread bracket law (owner refinement)

The tree threads no longer touch their arrows. Each thread is
BRACKETED by checkbox bottom edges (live-measured anchors):
- starts at its parent row's checkbox bottom edge — a visible gap
  below the arrow's stroke (the stroke ends ~2.4px above the anchor)
- terminates exactly at the LAST child row's checkbox bottom edge
  (cluster: top-[23px]/bottom-[8px] incl. the 1px group rule; chain:
  top-[22px]/bottom-[8px]). Verified live: 23=23 top anchor, bottom
  ends within 0.13px of the last checkbox at both levels.
This commit is contained in:
amosblomqvist
2026-09-30 00:37:55 +03:00
parent 40b0c33f93
commit edb10e3791
3 changed files with 20 additions and 11 deletions
+14 -10
View File
@@ -322,15 +322,17 @@ export function ChainTableBody({
// top (header) and bottom. Never on individual rows. // top (header) and bottom. Never on individual rows.
className="relative border-b border-border/60" className="relative border-b border-border/60"
> >
{/* The TREE THREAD (owner round 5, trial): a vertical guide {/* The TREE THREAD (owner rounds 5–6): a vertical guide at the
dropping from the cluster's expander arrow down through expander arrow's column (center 37px: pl-3 + checkbox 14 +
its chain rows — the arrow's column (center 37px: pl-3 + gap 4 + half the 14px expander), BRACKETED by checkbox
checkbox 14 + gap 4 + half the 14px expander), from the bottom edges — it starts at the cluster row's own checkbox
arrow's own height to the last row's middle. */} bottom (top-[23px], leaving the arrow's stroke a visible
gap, live-measured) and terminates exactly at the LAST
checkbox bottom (bottom-[8px] = 9px from the border box minus the 1px group rule, measured). */}
{open && group.chains.length > 0 && ( {open && group.chains.length > 0 && (
<div <div
data-testid={`cluster-thread-${group.key}`} data-testid={`cluster-thread-${group.key}`}
className="pointer-events-none absolute bottom-3.5 left-[37px] top-4 w-px bg-border/50" className="pointer-events-none absolute bottom-[8px] left-[37px] top-[23px] w-px bg-border/50"
/> />
)} )}
{/* The cluster row: birth-session group header. */} {/* The cluster row: birth-session group header. */}
@@ -368,13 +370,15 @@ export function ChainTableBody({
const selectedInChain = memberIds.filter((id) => selection.has(id)).length; const selectedInChain = memberIds.filter((id) => selection.has(id)).length;
return ( return (
<div key={chain.id} data-testid={`chain-block-${chain.id}`} className="relative"> <div key={chain.id} data-testid={`chain-block-${chain.id}`} className="relative">
{/* The chain's own thread: from its expander arrow down {/* The chain's own thread (owner rounds 5–6): the same
through the statement rows (center 73px: pl-12 + bracket law one level down — at the chain arrow's column
checkbox 14 + gap 4 + half the expander). */} (center 73px), from the chain row's checkbox bottom
(top-[22px]) to the LAST statement row's checkbox bottom
(bottom-[8px]) — live-measured anchors. */}
{chainOpen && memberIds.length > 0 && ( {chainOpen && memberIds.length > 0 && (
<div <div
data-testid={`chain-thread-${chain.id}`} data-testid={`chain-thread-${chain.id}`}
className="pointer-events-none absolute bottom-3.5 left-[73px] top-3.5 w-px bg-border/50" className="pointer-events-none absolute bottom-[8px] left-[73px] top-[22px] w-px bg-border/50"
/> />
)} )}
<div <div
+1 -1
View File
File diff suppressed because one or more lines are too long
+5
View File
@@ -154,6 +154,11 @@ describe("ChainTableBody — THE shared TopBar + the lines law (owner, round 2)"
// the columns: the cluster arrow sits at 37px, the chain arrow at 73px // the columns: the cluster arrow sits at 37px, the chain arrow at 73px
assert.ok(open.includes("left-[37px]"), "thread at the cluster arrow's column"); assert.ok(open.includes("left-[37px]"), "thread at the cluster arrow's column");
assert.ok(open.includes("left-[73px]"), "thread at the chain arrow's column"); assert.ok(open.includes("left-[73px]"), "thread at the chain arrow's column");
// the BRACKET LAW (owner round 6): each thread runs from its parent
// row's checkbox bottom edge (a visible gap below the arrow's stroke)
// to the LAST child row's checkbox bottom edge — live-measured anchors
assert.ok(open.includes("bottom-[8px] left-[37px] top-[23px]"), "cluster thread bracketed by checkbox bottoms");
assert.ok(open.includes("top-[22px]") && open.includes("bottom-[8px]"), "chain thread bracketed by checkbox bottoms");
}); });
}); });