Proposal changes stop rebuilding the whole board — lanes and card faces gate on their values
LaneView and CardFaceView become Equatable and are instantiated through .equatable(): the strip's body re-runs on every drop-proposal change, and without the gates that rebuilt every lane and every card face on every cursor move of a drag. The == compares value inputs and window-lived collaborator identities; the closures BoardView rebuilds each pass are deliberately excluded (BoardDropContext.isEquivalent / MarqueeControl. isEquivalent / CardFaceRole.isEquivalent own that judgment). Observation reads inside the bodies still self-invalidate — the lane under the drag keeps re-running; the other lanes stop. Ports the pathfinder's CardView/ColumnView gating pattern (drag-perf suspect #2, card cbb6e476). Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
@@ -110,6 +110,23 @@ struct BoardDropContext {
|
||||
/// The strip's 1× lane width for the current drag context (`LaneLayoutMath.standardWidth`).
|
||||
let standard: @MainActor () -> CGFloat
|
||||
|
||||
/// Whether two of these would send a drop to the same place — **the whole of what this value
|
||||
/// contributes to `LaneView.==` and `CardFaceView.==`.**
|
||||
///
|
||||
/// `BoardView.dropContext` rebuilds this struct on every body pass, closures and all, so a naive
|
||||
/// value comparison is impossible and a reference comparison is meaningless: the three closures
|
||||
/// are freshly allocated each time and would make every lane and every card face unequal on every
|
||||
/// pass, which is exactly the rebuild the gates exist to stop. They are also the members it is
|
||||
/// safe to ignore — each one *reads* window and strip geometry at event time rather than carrying
|
||||
/// any (see this type's own note), so two contexts with the same store, session and registry
|
||||
/// resolve every hover identically whatever closure objects they happen to hold.
|
||||
nonisolated func isEquivalent(to other: BoardDropContext) -> Bool {
|
||||
store === other.store
|
||||
&& session === other.session
|
||||
&& registry === other.registry
|
||||
&& gap == other.gap
|
||||
}
|
||||
|
||||
// MARK: The cursor
|
||||
|
||||
/// The physical cursor in the window's SwiftUI global space.
|
||||
|
||||
Reference in New Issue
Block a user