-
Notifications
You must be signed in to change notification settings - Fork 49.8k
Polyfill onScrollEnd Event in Safari #32427
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Comparing: 3607f48...399aa22 Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: Expand to show |
|
Note that at one point in the past the |
Enabled in native and test-renderer since they shouldn't affect them anyway. Makes it easier to see that it's safe to ship.
d255e40 to
dead6ae
Compare
|
There's some movement in Safari. It's part of the roadmap for 2025. https://webkit.org/blog/16458/announcing-interop-2025/#scrollend-event But we still need to polyfill for now and for older versions. |
|
|
||
| if (listeners.length > 0) { | ||
| // Intentionally create event lazily. | ||
| const event: ReactSyntheticEvent = new SyntheticUIEvent( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spec says it's a generic Event not a UIEvent. I also get a generic Event in Chrome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but so is 'scroll' and we already treat these as SyntheticUIEvent:
We added support for `onScrollEnd` in #26789 but it only works in Chrome and Firefox. Safari still doesn't support `scrollend` and there's no indication that they will anytime soon so this polyfills it. While I don't particularly love our synthetic event system this tries to stay within the realm of how our other polyfills work. This implements all `onScrollEnd` events as a plugin. The basic principle is to first feature detect the `onscrollend` DOM property to see if there's native support and otherwise just use the native event. Then we listen to `scroll` events and set a timeout. If we don't get any more scroll events before the timeout we fire `onScrollEnd`. Basically debouncing it. If we're currently pressing down on touch or a mouse then we wait until it is lifted such as if you're scrolling with a finger or using the scrollbars on desktop but isn't currently moving. If we do get any native events even though we're in polyfilling mode, we use that as an indication to fire the `onScrollEnd` early. Part of the motivation is that this becomes extra useful pair for #32422. We also probably need these events to coincide with other gesture related internals so you're better off using our polyfill so they're synced. DiffTrain build for [605a880](605a880)
We added support for `onScrollEnd` in #26789 but it only works in Chrome and Firefox. Safari still doesn't support `scrollend` and there's no indication that they will anytime soon so this polyfills it. While I don't particularly love our synthetic event system this tries to stay within the realm of how our other polyfills work. This implements all `onScrollEnd` events as a plugin. The basic principle is to first feature detect the `onscrollend` DOM property to see if there's native support and otherwise just use the native event. Then we listen to `scroll` events and set a timeout. If we don't get any more scroll events before the timeout we fire `onScrollEnd`. Basically debouncing it. If we're currently pressing down on touch or a mouse then we wait until it is lifted such as if you're scrolling with a finger or using the scrollbars on desktop but isn't currently moving. If we do get any native events even though we're in polyfilling mode, we use that as an indication to fire the `onScrollEnd` early. Part of the motivation is that this becomes extra useful pair for #32422. We also probably need these events to coincide with other gesture related internals so you're better off using our polyfill so they're synced. DiffTrain build for [605a880](605a880)
| case 'touchstart': { | ||
| isTouchStarted = true; | ||
| break; | ||
| } | ||
| case 'touchcancel': | ||
| case 'touchend': { | ||
| // Note we cannot use pointer events for this because they get | ||
| // cancelled when native scrolling takes control. | ||
| isTouchStarted = false; | ||
| break; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the post-merge drive-by, but not accounting for multi-touch is an old pet peeve of mine. 😜
| case 'touchstart': { | |
| isTouchStarted = true; | |
| break; | |
| } | |
| case 'touchcancel': | |
| case 'touchend': { | |
| // Note we cannot use pointer events for this because they get | |
| // cancelled when native scrolling takes control. | |
| isTouchStarted = false; | |
| break; | |
| } | |
| case 'touchstart': | |
| case 'touchcancel': | |
| case 'touchend': { | |
| // Note we cannot use pointer events for this because they get | |
| // cancelled when native scrolling takes control. | |
| isTouchStarted = ((nativeEvent: any): TouchEvent).touches.length > 0; | |
| break; | |
| } |
| case 'mousedown': { | ||
| isMouseDown = true; | ||
| break; | ||
| } | ||
| case 'mouseup': { | ||
| isMouseDown = false; | ||
| break; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also shouldn't assume all mouse events are for left clicks, and mouseup won't fire after a drag starts.
| case 'mousedown': { | |
| isMouseDown = true; | |
| break; | |
| } | |
| case 'mouseup': { | |
| isMouseDown = false; | |
| break; | |
| } | |
| case 'mousedown': { | |
| if (((nativeEvent: any): MouseEvent).button === 0) { | |
| isMouseDown = true; | |
| } | |
| break; | |
| } | |
| case 'mouseup': | |
| case 'dragend': { | |
| if (((nativeEvent: any): MouseEvent).button === 0) { | |
| isMouseDown = false; | |
| } | |
| break; | |
| } |
We added support for
onScrollEndin #26789 but it only works in Chrome and Firefox. Safari still doesn't supportscrollendand there's no indication that they will anytime soon so this polyfills it.While I don't particularly love our synthetic event system this tries to stay within the realm of how our other polyfills work. This implements all
onScrollEndevents as a plugin.The basic principle is to first feature detect the
onscrollendDOM property to see if there's native support and otherwise just use the native event.Then we listen to
scrollevents and set a timeout. If we don't get any more scroll events before the timeout we fireonScrollEnd. Basically debouncing it. If we're currently pressing down on touch or a mouse then we wait until it is lifted such as if you're scrolling with a finger or using the scrollbars on desktop but isn't currently moving.If we do get any native events even though we're in polyfilling mode, we use that as an indication to fire the
onScrollEndearly.Part of the motivation is that this becomes extra useful pair for #32422. We also probably need these events to coincide with other gesture related internals so you're better off using our polyfill so they're synced.