Build the sole-selection attachment carousel
The card face's in-place expansion (03-board-ui.md § Card face): a card with attachments, as the sole selection, grows a paged media band below its title; every other state stays compact behind the quiet paperclip. - CardCarousel owns the pure rules: the sole-selection predicate decides by identity (a sole-selected lane matches no face, no snapshot walk), and expansion is suppressed outside the animation key while a rubber band is active — a band names a set in progress, so carousels neither flicker nor animate under it. - QuickLook thumbnails generate off-main into a per-window cache keyed to survive reselection, with the Finder-icon fallback while loading and for non-previewable types; pages ride the platform paging behavior, dots (glass underlay, solid under Reduce Transparency) click to page, and a local wheel monitor turns a discrete tick into one clamped page — precise trackpad pans fall through untouched. - The expansion animates under Motion's new carouselExpansion transaction keyed narrowly on the sole-selected card; Reduce Motion goes instant. Drop-slot math and the marquee read the expanded height for free — both re-register on every size change. 928 unit tests (24 new). m5-interactions complete. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -94,6 +94,14 @@ struct BoardView: View {
|
||||
/// the cards and trash rows only *register* into it (`MarqueeTargetRegistry`).
|
||||
@State private var marqueeTargets = MarqueeTargetRegistry()
|
||||
|
||||
/// This window's attachment thumbnails, for the sole-selected card's carousel (03-board-ui.md
|
||||
/// § Card face). `@State` for the sessions' reason — one per window, living exactly as long as
|
||||
/// the window, so a board that closes forgets the files it was showing (see
|
||||
/// `AttachmentThumbnailCache` on why the window and not the app). Handed down through the
|
||||
/// environment rather than threaded, since nothing between here and a card face has any use for
|
||||
/// it.
|
||||
@State private var thumbnails = AttachmentThumbnailCache()
|
||||
|
||||
/// The name of the strip's coordinate space, which is what a drop out of the trash is resolved
|
||||
/// in: `LaneLayoutMath.laneIndex` reads an x measured from the strip's leading edge, outer margin
|
||||
/// included, and no global or lane-local space is that.
|
||||
@@ -149,6 +157,7 @@ struct BoardView: View {
|
||||
.onDrop(of: boardDropTypes, delegate: StripDropDelegate(context: dropContext))
|
||||
}
|
||||
.background(boardBackground)
|
||||
.environment(thumbnails)
|
||||
// The window-level fallback, *behind* the specific targets: a release over any in-window
|
||||
// region they don't cover commits the current proposal instead of leaking the session into a
|
||||
// cancel-snapback — the drop lands where the shadows show, which is what the shadows promise.
|
||||
|
||||
Reference in New Issue
Block a user