The resting layout is built once per snapshot — retargets stop rebuilding it per mouse sample
RestingLayoutCache (session-scoped, @ObservationIgnored on DragSession, cleared at begin and end) holds each lane's resting layout as ids + heights — never [Card] — keyed on the hovered board's applied snapshotGeneration, the registry's new heightsGeneration, the lane, and the operation-following hidden set. The grid stays event-time on purpose (autoscroll moves a lane's origin with the snapshot standing still), so re-grounding rule 1 holds exactly: nothing survives a reload, only the per-sample repetition goes. The steady-state cost of a hover is now the containment scan plus four stores and a divide. Drag-perf suspect #3, card b9f48fd1. Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
@@ -323,6 +323,20 @@ final class DragSession {
|
||||
/// whichever board's standard width it is being proposed into.
|
||||
@ObservationIgnored private(set) var laneUnits: [Int] = []
|
||||
|
||||
/// The per-lane resting layouts this drag's retargets propose against, built once per snapshot
|
||||
/// rather than once per mouse sample (`RestingLayoutCache`, which states why that leaves rule 1
|
||||
/// of the re-grounding trio exactly as it was).
|
||||
///
|
||||
/// `@ObservationIgnored` for the reason `LaneDropRegistry` is not `@Observable` at all: it is
|
||||
/// written from *event* handlers, and a cache fill that invalidated the strip would be the
|
||||
/// animation feedback loop this whole model exists to avoid (03-board-ui.md § Motion).
|
||||
///
|
||||
/// **Session-scoped**, so it cannot outlive the drag it was filled for — and so a layout can
|
||||
/// assume the one input that is neither in its key nor read live, `cardHeights`, is the frozen
|
||||
/// set this session picked up with. `begin` and `end` bracket every session this object has, and
|
||||
/// both clear it.
|
||||
@ObservationIgnored let restingLayouts = RestingLayoutCache()
|
||||
|
||||
// MARK: Where it would land
|
||||
|
||||
/// The current proposal, or `nil` when the drag has none — a fresh session before the first
|
||||
@@ -564,6 +578,7 @@ final class DragSession {
|
||||
mixesKinds: Bool
|
||||
) {
|
||||
endHold()
|
||||
restingLayouts.clear()
|
||||
self.kind = kind
|
||||
self.members = members
|
||||
self.memberSet = Set(members)
|
||||
@@ -627,6 +642,7 @@ final class DragSession {
|
||||
folders = []
|
||||
cardHeights = []
|
||||
laneUnits = []
|
||||
restingLayouts.clear()
|
||||
proposal = nil
|
||||
operation = .move
|
||||
sourceStore = nil
|
||||
|
||||
Reference in New Issue
Block a user