A pull-down-to-refresh wrapper: a rubber-banded drag claimed only while the scroller is at the top, a threshold that arms the release, an async refresh held until it settles, and a keyboard-reachable refresh button.
npx shadcn@latest add @zyeon/pull-to-refreshZyeon UI limits how often it can be asked, and Pull To Refresh hasn't had its turn. Its source will show here once it has.