Fix the collapsed-lanes render on initial board open
The strip's standard-width division read the drop registry's strip frame during body evaluation, but the registry is deliberately unobserved (it exists for event-time reads): the first body ran against a zero frame, every lane collapsed to the 1pt floor, and nothing invalidated the view when the real measurement landed — the board stayed corrupted until an unrelated re-render. The layout now reads the GeometryReader's live proposal (reactive by construction); the drop delegates keep reading the registry at event time. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -121,7 +121,7 @@ struct BoardView: View {
|
||||
private let spacing: CGFloat = 12
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { _ in
|
||||
GeometryReader { proxy in
|
||||
// The strip's slots: the lanes the strip should *show*, with the drag's N contiguous
|
||||
// shadows opened at the proposal. Recomputed on every render, so a foreign reload
|
||||
// mid-drag simply moves the zones (rule 1 of 04-interactions.md ▸ Drag and drop's
|
||||
@@ -129,7 +129,7 @@ struct BoardView: View {
|
||||
let slots = stripSlots
|
||||
ZStack(alignment: .topLeading) {
|
||||
backdrop
|
||||
laneStrip(slots)
|
||||
laneStrip(slots, standard: standardWidth(stripWidth: proxy.size.width))
|
||||
}
|
||||
.padding(spacing)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
|
||||
@@ -254,8 +254,7 @@ struct BoardView: View {
|
||||
|
||||
/// The lanes and the drag's shadows, plus the trash column when it is shown.
|
||||
@ViewBuilder
|
||||
private func laneStrip(_ slots: [StripSlot]) -> some View {
|
||||
let standard = standardWidth
|
||||
private func laneStrip(_ slots: [StripSlot], standard: CGFloat) -> some View {
|
||||
HStack(alignment: .top, spacing: spacing) {
|
||||
ForEach(slots) { slot in
|
||||
switch slot {
|
||||
@@ -480,11 +479,20 @@ struct BoardView: View {
|
||||
gap: spacing,
|
||||
window: window,
|
||||
stripFrame: { laneDrops.stripFrame },
|
||||
standard: { standardWidth }
|
||||
standard: { standardWidth(stripWidth: laneDrops.stripFrame.width) }
|
||||
)
|
||||
}
|
||||
|
||||
/// The strip's 1× lane width.
|
||||
/// The strip's 1× lane width, for a strip `stripWidth` points wide.
|
||||
///
|
||||
/// **The width is a parameter, and which width the caller passes matters.** Body evaluation
|
||||
/// passes the `GeometryReader`'s live proposal, because that is the one source that invalidates
|
||||
/// the view when it changes — the registry's `stripFrame` is deliberately unobserved (it exists
|
||||
/// for event-time reads), so a body computed from it renders the *previous* layout's width: on
|
||||
/// first open that is `.zero`, every lane collapses to `standardWidth`'s 1pt floor, and the
|
||||
/// board stays that way until an unrelated invalidation happens by. The drop delegates pass
|
||||
/// `laneDrops.stripFrame.width` instead, which is the same number read at event time — exactly
|
||||
/// the registry's purpose. The two agree because the padded container fills the reader.
|
||||
///
|
||||
/// During a resize session the standard is **frozen** at its drag-start value: the window is
|
||||
/// animating mid-resize, so deriving the standard from the live width would feed that animation
|
||||
@@ -504,12 +512,12 @@ struct BoardView: View {
|
||||
/// - a **cross-board lane arrival**'s units while its shadow hovers here, by the same rule read
|
||||
/// from the destination's side: the shadow occupies its units, and the strip has to make room
|
||||
/// for them or the shadow would be drawn at a width the lane will not have.
|
||||
private var standardWidth: CGFloat {
|
||||
private func standardWidth(stripWidth: CGFloat) -> CGFloat {
|
||||
if resize.isActive { return resize.standard }
|
||||
var units = LaneLayoutMath.totalUnits(of: liveLanes, trashUnits: isTrashVisible ? 1 : 0)
|
||||
units += arrivingLaneUnits
|
||||
return LaneLayoutMath.standardWidth(
|
||||
stripWidth: laneDrops.stripFrame.width,
|
||||
stripWidth: stripWidth,
|
||||
totalUnits: units,
|
||||
gap: spacing
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user