From 95133860e1f299f82eb2fcfb8db3797804e5977a Mon Sep 17 00:00:00 2001 From: rzen Date: Fri, 31 Jul 2026 07:17:50 -0400 Subject: [PATCH] Drag pickup: evaluate a lane's slots once per body, not once per card The per-element .accessibilitySortPriority read slots.count from inside the ForEach closure, re-running the whole slots -> renderedCards chain (an O(n) card filter plus the session's hidden-member resolution) once per element -- O(n^2) per lane body. A drag pickup runs a synchronous whole-board layout inside the drag-start nested run loop, which multiplied this into a stack- sampled ~700ms-1s stall between mouse-down and the visible lift. Hoisting the evaluation into a local makes pickup effectively immediate. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY --- Kanban/UI/Board/LaneView.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Kanban/UI/Board/LaneView.swift b/Kanban/UI/Board/LaneView.swift index 47a754b..c32cae4 100644 --- a/Kanban/UI/Board/LaneView.swift +++ b/Kanban/UI/Board/LaneView.swift @@ -657,7 +657,13 @@ struct LaneView: View { } private var scrollableCards: some View { - ScrollView(.vertical) { + // Evaluated ONCE per body, deliberately: the per-element `.accessibilitySortPriority` + // below reads `slots.count`, and reading the computed property from inside the `ForEach` + // closure re-runs the whole chain (`slots` → `renderedCards` → the O(n) card filter and + // the session's hidden-member resolution) once per element — O(n²) per lane body, which + // a drag pickup's synchronous whole-board layout multiplied into a visible stall. + let slots = self.slots + return ScrollView(.vertical) { // Cards stay standard width whatever the lane spans: at a slot width of // `units × standard + (units - 1) × gap`, `MasonryLayout` divides back into exactly // `units` columns of `standard` (03-board-ui.md § Layout — full visibility).