MacPullToRefresh

0.4.0

Native-feeling pull-to-refresh for macOS SwiftUI, backed by the real NSScrollView rubber-band. Works with List, uses Liquid Glass, and forwards to .refreshable on iOS.
adamtheturtle/MacPullToRefresh

What's New

0.4.0

2026-07-18T17:51:26Z

Gesture state-machine fixes. Each carries a regression test verified to fail without it.

Fixed

  • A cancelled pull no longer fires a refresh (#2). gapOpen latched the moment the pull crossed the threshold and was never cleared mid-drag, so pulling past the threshold, dragging back to the top, and releasing still triggered a full refresh — contradicting the documented "release beyond a threshold" contract, and diverging from the iOS gesture, which cancels. The release decision now reads the actual over-scroll.
  • The baseline inset can no longer be corrupted by a scroll during the gap close (#3). closeGap cleared gapOpen immediately but left the enlarged inset in place for the full 300ms animation, so a scroll starting in that window captured the gap inset as the new baseline. The threshold then doubled (44pt → 88pt), the spoke reveal halved, and repeating the race compounded it. The baseline is now captured into the completion handler, and re-capture is suppressed while a close is in flight.
  • The spinner no longer blinks out at the hand-off (#4). Zeroing the pull before the refresh state round-tripped through SwiftUI dropped the indicator to zero opacity for a frame — the exact "waiting a beat" the design set out to avoid. The pull is now held at full reveal until the refresh state lands, with a fallback so a hand-off that never arrives can't strand the indicator.

Upgrading

The cancel fix changes gesture behaviour: releasing at zero over-scroll after crossing the threshold now cancels instead of refreshing. While the gap is open, the arming bar sits at refreshGap rather than zero, so an ordinary release still reads as a refresh rather than a cancel.

Full changelog: 0.3.1...0.4.0

MacPullToRefresh

Native-feeling pull-to-refresh for macOS SwiftUI, backed by NSScrollView over-scroll and forwarded to .refreshable on iOS.

Documentation | Swift Package Index

Demo

Pull past the top of a List or ScrollView: the indicator fills as you drag, arms once you pass the threshold, and spins while the refresh runs.

If the player above doesn't load, watch the clip directly.

Installation

.package(url: "https://github.com/adamtheturtle/MacPullToRefresh.git", from: "0.3.1")

Add the MacPullToRefresh product to your target dependencies.

Product

  • MacPullToRefresh: A SwiftUI modifier for pull-to-refresh on macOS and iOS.

Requirements

  • Swift 6.2+
  • macOS 13+ or iOS 16+

License

MIT. See LICENSE.

Description

  • Swift Tools 6.2.0
View More Packages from this Author

Dependencies

  • None
Last updated: Sun Jul 26 2026 09:01:07 GMT-0900 (Hawaii-Aleutian Daylight Time)