Problem statement
When the picker is used in controlled mode the parent component may reject an out-of-range value (e.g. user scrolls to “12 AM” while min is 12 PM).
Typical pattern:
- In
onValueChange we set a temporary state so the wheel shows the rejected item.
- Immediately revert to the last valid value.
While inertia is still running the picker’s internal scrollRef.current is reset during that round-trip.
The next wheel delta is therefore measured against a new baseline and the picker emits the same rejected value again, causing AM ↔ PM flicker and repeated callbacks.
What would fix it
-
Expose scroll-lifecycle hooks
<WheelPicker
…
onScrollStart={() => {/* gesture started */}}
onScrollEnd={() => {/* safe to revert */}}
/>
We can then delay the “reject & revert” until onScrollEnd, eliminating the loop.
OR
Accept a boolean from onValueChange:
onValueChange?: (value: string) => boolean // return false → library animates snap-back
-
Quality-of-life API additions (zero breakage)
- Forward a
ref to the root <div data-rwp>
- Spread unknown props onto that root (data-attributes, test-ids, etc.)
These small changes let consumers cleanly reject values, observe gesture boundaries, and imperatively access the component—no DOM queries or debounce hacks required.
Problem statement
When the picker is used in controlled mode the parent component may reject an out-of-range value (e.g. user scrolls to “12 AM” while min is 12 PM).
Typical pattern:
onValueChangewe set a temporary state so the wheel shows the rejected item.While inertia is still running the picker’s internal
scrollRef.currentis reset during that round-trip.The next wheel delta is therefore measured against a new baseline and the picker emits the same rejected value again, causing AM ↔ PM flicker and repeated callbacks.
What would fix it
Expose scroll-lifecycle hooks
We can then delay the “reject & revert” until
onScrollEnd, eliminating the loop.OR
Accept a boolean from
onValueChange:Quality-of-life API additions (zero breakage)
refto the root<div data-rwp>These small changes let consumers cleanly reject values, observe gesture boundaries, and imperatively access the component—no DOM queries or debounce hacks required.