Description
@siepra is working User Event scroll
API design, the code is quite advanced, so it's high time that we have a solid API with nice DX for that feature. There is no RTL's User Event API for scrolling, so we need to come up with our own. As a base for discussion, I have prepare an initial proposal.
User Event scroll API
Base case
// vertical scroll
user.scrollTo(element, { y: targetPos })
// horizontal scroll:
user.scrollTo(element, { x: targetPos })
Note: the function is named scrollTo
instead of scroll
to remove ambiguity whether this is target value or relative value. Coincidently this is also the name of imperative handle for scrolling in RN.
This will emit a sequence of onScrollBeginDrag
, onScroll
(x N), onScrollEndDrag
.
By default, the first scroll will start from (0, 0) and will emit default of 5 onScroll
intermediate steps between initial position and target position. Subsequent scrolls will start from where the last scroll (using User Event) ended.
Intermediate steps
Explicit steps
Alternatively, you can pass exact steps that will be called as an array. First element is the initial position, and all other elements indicate subsequent steps. The number of steps will be equal to the length of the array.
user.scrollTo(element, { y: [0, 10, 20, 30] })
Number of steps (alternative approach)
You can customize the intermediate steps by passing number of steps and/or ininitial position:
user.scrollTo(element, { y: targetPos, steps: 10 })
user.scrollTo(element, { y: targetPos, fromY: initialPos })
user.scrollTo(element, { y: targetPos, fromY: initialPos, steps: 10 })
We probably should pick only one of the above. Based on my surveys with CK devs, the first one seems to be preferred.
Momentum scroll
Momentum scroll happens after initial sequence of onScrollBeginDrag
, onScroll
(x N), onScrollEndDrag
when scroll view has some velocity (momentum) after user lifts the finger up. This will result in calling onMomentumScrollBegin
, onScroll
(x N), onMomentumScrollEnd
.
By default scrollBy
will only invoke drag scroll without momentum part. User can activate momentum scroll passing momentumY
or momentumX
variables:
// vertical
user.scrollTo({ momentumY: targetPos })
// horizontal
user.scrollTo({ momentumX: targetPos })
This can be linked with previous options:
// Drag scroll from initial position to targetPos1, then momentum scroll to targetPos2
user.scrollTo({ y: targetPos1, momentumY: targetPos2 })
// Pass explicit steps and/or momentum steps
user.scrollTo({ y: [0, 10, 20], momentumY: [30, 40] })
// Control the number of drag steps using `steps`, and momentum steps using `momentumSteps` (alternative intermediate steps approach)
user.scrollTo({ y: targetPos1, momentumY: targetPos2, steps: 5, momentumSteps: 4 })
If the user did not pass drag scroll position, then distance from last position, or default (0, 0), to target position will be divided equally between drag scroll and momentum scroll.
Please share your comments on all things involved, naming of function and options, ways of conveying ideas like intermediate steps, etc, etc. Feel free to challenge this design, propose alternatives, etc. The API is very flexible at this stage, changing it later will probably require breaking changes, etc.
Links
- Our wiki page about experiment Scroll View events
- Current implementation PR
- RN ScrollView docs
- Cypress
scrollTo
docs - MDN's
scrollTo
docs - Detox
scroll
/scrollTo
docs
Specific questions:
- Should the API be named
scrollTo
orscroll
? - What should be default number of scroll steps, if not specified by user. Similar for momentum steps?
- Should we support indicating number of steps using
steps
param,y: [0, 10, 20]
array or both? Or other perhaps? - How should we expose momentum scroll concept:
momentumY
params,momentum: boolean
param,user.momentumScrollTo()
function, or other perhaps? - Should RNTL remember the last scroll position and start next scroll from there? Or should we always start from explicit position or (0,0) if not provided?
CC: @pierrezimmermannbam @AugustinLF @MattAgn @thymikee @siepra