UNPKG

react-scroll-to-bottom-updated

Version:
631 lines (558 loc) 85.2 kB
import _defineProperty from "@babel/runtime-corejs3/helpers/defineProperty"; import _toConsumableArray from "@babel/runtime-corejs3/helpers/toConsumableArray"; import _slicedToArray from "@babel/runtime-corejs3/helpers/slicedToArray"; function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); if (enumerableOnly) { symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context21; _forEachInstanceProperty(_context21 = ownKeys(Object(source), true)).call(_context21, function (key) { _defineProperty(target, key, source[key]); }); } else if (_Object$getOwnPropertyDescriptors) { _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)); } else { var _context22; _forEachInstanceProperty(_context22 = ownKeys(Object(source))).call(_context22, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } } return target; } import "core-js/modules/es.regexp.exec.js"; import "core-js/modules/es.string.replace.js"; import _setInterval from "@babel/runtime-corejs3/core-js-stable/set-interval"; import _indexOfInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/index-of"; import _spliceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/splice"; import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat"; import _Date$now from "@babel/runtime-corejs3/core-js-stable/date/now"; import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each"; import _Object$keys from "@babel/runtime-corejs3/core-js-stable/object/keys"; import _Object$getOwnPropertySymbols from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols"; import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter"; import _Object$getOwnPropertyDescriptor from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor"; import _Object$getOwnPropertyDescriptors from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors"; import _Object$defineProperties from "@babel/runtime-corejs3/core-js-stable/object/define-properties"; import _Object$defineProperty from "@babel/runtime-corejs3/core-js-stable/object/define-property"; import createEmotion from '@emotion/css/create-instance'; import PropTypes from 'prop-types'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import createCSSKey from '../createCSSKey'; import createDebug from '../utils/debug'; import EventSpy from '../EventSpy'; import FunctionContext from './FunctionContext'; import InternalContext from './InternalContext'; import SpineTo from '../SpineTo'; import State1Context from './State1Context'; import State2Context from './State2Context'; import StateContext from './StateContext'; import styleConsole from '../utils/styleConsole'; import useStateRef from '../hooks/internal/useStateRef'; var DEFAULT_SCROLLER = function DEFAULT_SCROLLER() { return Infinity; }; var MIN_CHECK_INTERVAL = 17; // 1 frame var MODE_BOTTOM = 'bottom'; var MODE_TOP = 'top'; var NEAR_END_THRESHOLD = 1; var SCROLL_DECISION_DURATION = 34; // 2 frames // We pool the emotion object by nonce. // This is to make sure we don't generate too many unneeded <style> tags. var emotionPool = {}; function setImmediateInterval(fn, ms) { fn(); return _setInterval(fn, ms); } function computeViewState(_ref) { var mode = _ref.mode, _ref$target = _ref.target, offsetHeight = _ref$target.offsetHeight, scrollHeight = _ref$target.scrollHeight, scrollTop = _ref$target.scrollTop; var atBottom = scrollHeight - scrollTop - offsetHeight < NEAR_END_THRESHOLD; var atTop = scrollTop < NEAR_END_THRESHOLD; var atEnd = mode === MODE_TOP ? atTop : atBottom; var atStart = mode !== MODE_TOP ? atTop : atBottom; return { atBottom: atBottom, atEnd: atEnd, atStart: atStart, atTop: atTop }; } function isEnd(animateTo, mode) { return animateTo === (mode === MODE_TOP ? 0 : '100%'); } var Composer = function Composer(_ref2) { var _ref2$checkInterval = _ref2.checkInterval, checkInterval = _ref2$checkInterval === void 0 ? 100 : _ref2$checkInterval, children = _ref2.children, _ref2$debounce = _ref2.debounce, debounce = _ref2$debounce === void 0 ? 17 : _ref2$debounce, debugFromProp = _ref2.debug, _ref2$initialScrollBe = _ref2.initialScrollBehavior, initialScrollBehavior = _ref2$initialScrollBe === void 0 ? 'smooth' : _ref2$initialScrollBe, mode = _ref2.mode, nonce = _ref2.nonce, _ref2$scroller = _ref2.scroller, scroller = _ref2$scroller === void 0 ? DEFAULT_SCROLLER : _ref2$scroller; var debug = useMemo(function () { return createDebug("<ScrollToBottom>", { force: debugFromProp }); }, [debugFromProp]); mode = mode === MODE_TOP ? MODE_TOP : MODE_BOTTOM; var ignoreScrollEventBeforeRef = useRef(0); var initialScrollBehaviorRef = useRef(initialScrollBehavior); var _useStateRef = useStateRef(mode === MODE_TOP ? 0 : '100%'), _useStateRef2 = _slicedToArray(_useStateRef, 3), animateTo = _useStateRef2[0], setAnimateTo = _useStateRef2[1], animateToRef = _useStateRef2[2]; var _useStateRef3 = useStateRef(null), _useStateRef4 = _slicedToArray(_useStateRef3, 3), target = _useStateRef4[0], setTarget = _useStateRef4[1], targetRef = _useStateRef4[2]; // Internal context var animateFromRef = useRef(0); var offsetHeightRef = useRef(0); var scrollHeightRef = useRef(0); // State context var _useState = useState(true), _useState2 = _slicedToArray(_useState, 2), atBottom = _useState2[0], setAtBottom = _useState2[1]; var _useState3 = useState(true), _useState4 = _slicedToArray(_useState3, 2), atEnd = _useState4[0], setAtEnd = _useState4[1]; var _useState5 = useState(true), _useState6 = _slicedToArray(_useState5, 2), atTop = _useState6[0], setAtTop = _useState6[1]; var _useState7 = useState(false), _useState8 = _slicedToArray(_useState7, 2), atStart = _useState8[0], setAtStart = _useState8[1]; var _useStateRef5 = useStateRef(true), _useStateRef6 = _slicedToArray(_useStateRef5, 3), sticky = _useStateRef6[0], setSticky = _useStateRef6[1], stickyRef = _useStateRef6[2]; // High-rate state context var scrollPositionObserversRef = useRef([]); var observeScrollPosition = useCallback(function (fn) { var target = targetRef.current; scrollPositionObserversRef.current.push(fn); target && fn({ scrollTop: target.scrollTop }); return function () { var scrollPositionObservers = scrollPositionObserversRef.current; var index = _indexOfInstanceProperty(scrollPositionObservers).call(scrollPositionObservers, fn); ~index && _spliceInstanceProperty(scrollPositionObservers).call(scrollPositionObservers, index, 1); }; }, [scrollPositionObserversRef, targetRef]); var handleSpineToEnd = useCallback(function () { var animateTo = animateToRef.current; debug(function () { var _context; return _concatInstanceProperty(_context = ['%cSpineTo%c: %conEnd%c is fired.']).call(_context, _toConsumableArray(styleConsole('magenta')), _toConsumableArray(styleConsole('orange')), [{ animateTo: animateTo }]); }); ignoreScrollEventBeforeRef.current = _Date$now(); // handleScrollEnd may end at a position which should lose stickiness. // In that case, we will need to set sticky to false to stop the interval check. // Test case: // 1. Add a scroller that always return 0 // 2. Show a panel with mode === MODE_BOTTOM // 3. Programmatically scroll to 0 (set element.scrollTop = 0) // Expected: it should not repetitively call scrollTo(0) // it should set stickiness to false isEnd(animateTo, mode) || setSticky(false); setAnimateTo(null); }, [animateToRef, debug, ignoreScrollEventBeforeRef, mode, setAnimateTo, setSticky]); // Function context var scrollTo = useCallback(function (nextAnimateTo) { var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, behavior = _ref3.behavior; var target = targetRef.current; if (typeof nextAnimateTo !== 'number' && nextAnimateTo !== '100%') { return console.warn('react-scroll-to-bottom: Arguments passed to scrollTo() must be either number or "100%".'); } // If it is trying to scroll to a position which is not "atEnd", it should set sticky to false after scroll ended. debug(function () { var _context2; return [_concatInstanceProperty(_context2 = ["%cscrollTo%c: Will scroll to %c".concat(typeof nextAnimateTo === 'number' ? nextAnimateTo + 'px' : nextAnimateTo.replace(/%/g, '%%'), "%c")]).call(_context2, _toConsumableArray(styleConsole('lime', '')), _toConsumableArray(styleConsole('purple'))), { behavior: behavior, nextAnimateTo: nextAnimateTo, target: target }]; }); if (behavior === 'auto') { // Stop any existing animation handleSpineToEnd(); if (target) { // Jump to the scroll position target.scrollTop = nextAnimateTo === '100%' ? target.scrollHeight - target.offsetHeight : nextAnimateTo; } } else { behavior !== 'smooth' && console.warn('react-scroll-to-bottom: Please set "behavior" when calling "scrollTo". In future versions, the default behavior will be changed from smooth scrolling to discrete scrolling to align with HTML Standard.'); setAnimateTo(nextAnimateTo); } // This is for handling a case. When calling scrollTo('100%', { behavior: 'auto' }) multiple times, it would lose stickiness. if (isEnd(nextAnimateTo, mode)) { debug(function () { var _context3; return [_concatInstanceProperty(_context3 = ["%cscrollTo%c: Scrolling to end, will set sticky to %ctrue%c."]).call(_context3, _toConsumableArray(styleConsole('lime', '')), _toConsumableArray(styleConsole('purple'))), [{ mode: mode, nextAnimateTo: nextAnimateTo }]]; }); setSticky(true); } }, [debug, handleSpineToEnd, mode, setAnimateTo, setSticky, targetRef]); var scrollToBottom = useCallback(function () { var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, behavior = _ref4.behavior; debug(function () { var _context4; return _concatInstanceProperty(_context4 = ['%cscrollToBottom%c: Called']).call(_context4, _toConsumableArray(styleConsole('yellow', ''))); }); behavior !== 'smooth' && console.warn('react-scroll-to-bottom: Please set "behavior" when calling "scrollToBottom". In future versions, the default behavior will be changed from smooth scrolling to discrete scrolling to align with HTML Standard.'); scrollTo('100%', { behavior: behavior || 'smooth' }); }, [debug, scrollTo]); var scrollToTop = useCallback(function () { var _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, behavior = _ref5.behavior; debug(function () { var _context5; return _concatInstanceProperty(_context5 = ['%cscrollToTop%c: Called']).call(_context5, _toConsumableArray(styleConsole('yellow', ''))); }); behavior !== 'smooth' && console.warn('react-scroll-to-bottom: Please set "behavior" when calling "scrollToTop". In future versions, the default behavior will be changed from smooth scrolling to discrete scrolling to align with HTML Standard.'); scrollTo(0, { behavior: behavior || 'smooth' }); }, [debug, scrollTo]); var scrollToEnd = useCallback(function () { var _ref6 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, behavior = _ref6.behavior; debug(function () { var _context6; return _concatInstanceProperty(_context6 = ['%cscrollToEnd%c: Called']).call(_context6, _toConsumableArray(styleConsole('yellow', ''))); }); behavior !== 'smooth' && console.warn('react-scroll-to-bottom: Please set "behavior" when calling "scrollToEnd". In future versions, the default behavior will be changed from smooth scrolling to discrete scrolling to align with HTML Standard.'); var options = { behavior: behavior || 'smooth' }; mode === MODE_TOP ? scrollToTop(options) : scrollToBottom(options); }, [debug, mode, scrollToBottom, scrollToTop]); var scrollToStart = useCallback(function () { var _ref7 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, behavior = _ref7.behavior; debug(function () { var _context7; return _concatInstanceProperty(_context7 = ['%cscrollToStart%c: Called']).call(_context7, _toConsumableArray(styleConsole('yellow', ''))); }); behavior !== 'smooth' && console.warn('react-scroll-to-bottom: Please set "behavior" when calling "scrollToStart". In future versions, the default behavior will be changed from smooth scrolling to discrete scrolling to align with HTML Standard.'); var options = { behavior: behavior || 'smooth' }; mode === MODE_TOP ? scrollToBottom(options) : scrollToTop(options); }, [debug, mode, scrollToBottom, scrollToTop]); var scrollToSticky = useCallback(function () { var target = targetRef.current; if (target) { if (initialScrollBehaviorRef.current === 'auto') { debug(function () { var _context8; return _concatInstanceProperty(_context8 = ["%ctarget changed%c: Initial scroll"]).call(_context8, _toConsumableArray(styleConsole('blue'))); }); target.scrollTop = mode === MODE_TOP ? 0 : target.scrollHeight - target.offsetHeight; initialScrollBehaviorRef.current = false; return; } // This is very similar to scrollToEnd(). // Instead of scrolling to end, it will call props.scroller() to determines how far it should scroll. // This function could be called while it is auto-scrolling. var animateFrom = animateFromRef.current; var offsetHeight = target.offsetHeight, scrollHeight = target.scrollHeight, scrollTop = target.scrollTop; var maxValue = mode === MODE_TOP ? 0 : Math.max(0, scrollHeight - offsetHeight - scrollTop); var minValue = Math.max(0, animateFrom - scrollTop); var rawNextValue = scroller({ maxValue: maxValue, minValue: minValue, offsetHeight: offsetHeight, scrollHeight: scrollHeight, scrollTop: scrollTop }); var nextValue = Math.max(0, Math.min(maxValue, rawNextValue)); var nextAnimateTo; if (mode === MODE_TOP || nextValue !== maxValue) { nextAnimateTo = scrollTop + nextValue; } else { // When scrolling to bottom, we should scroll to "100%". // Otherwise, if we scroll to any number, it will lose stickiness when elements are adding too fast. // "100%" is a special argument intended to make sure stickiness is not lost while new elements are being added. nextAnimateTo = '100%'; } debug(function () { var _context9, _context10, _context11; return [_concatInstanceProperty(_context9 = [_concatInstanceProperty(_context10 = _concatInstanceProperty(_context11 = "%cscrollToSticky%c: Will animate from %c".concat(animateFrom, "px%c to %c")).call(_context11, typeof nextAnimateTo === 'number' ? nextAnimateTo + 'px' : nextAnimateTo.replace(/%/g, '%%'), "%c (%c")).call(_context10, (nextAnimateTo === '100%' ? maxValue : nextAnimateTo) + animateFrom, "px%c)")]).call(_context9, _toConsumableArray(styleConsole('orange')), _toConsumableArray(styleConsole('purple')), _toConsumableArray(styleConsole('purple')), _toConsumableArray(styleConsole('purple'))), { animateFrom: animateFrom, maxValue: maxValue, minValue: minValue, nextAnimateTo: nextAnimateTo, nextValue: nextValue, offsetHeight: offsetHeight, rawNextValue: rawNextValue, scrollHeight: scrollHeight, scrollTop: scrollTop }]; }); scrollTo(nextAnimateTo, { behavior: 'smooth' }); } }, [animateFromRef, debug, mode, scroller, scrollTo, targetRef]); var handleScroll = useCallback(function (_ref8) { var _context17; var timeStampLow = _ref8.timeStampLow; var animateTo = animateToRef.current; var target = targetRef.current; var animating = animateTo !== null; // Currently, there are no reliable way to check if the "scroll" event is trigger due to // user gesture, programmatic scrolling, or Chrome-synthesized "scroll" event to compensate size change. // Thus, we use our best-effort to guess if it is triggered by user gesture, and disable sticky if it is heading towards the start direction. if (timeStampLow <= ignoreScrollEventBeforeRef.current || !target) { // Since we debounce "scroll" event, this handler might be called after spineTo.onEnd (a.k.a. artificial scrolling). // We should ignore debounced event fired after scrollEnd, because without skipping them, the userInitiatedScroll calculated below will not be accurate. // Thus, on a fast machine, adding elements super fast will lose the "stickiness". return; } var _computeViewState = computeViewState({ mode: mode, target: target }), atBottom = _computeViewState.atBottom, atEnd = _computeViewState.atEnd, atStart = _computeViewState.atStart, atTop = _computeViewState.atTop; setAtBottom(atBottom); setAtEnd(atEnd); setAtStart(atStart); setAtTop(atTop); // Chrome will emit "synthetic" scroll event if the container is resized or an element is added // We need to ignore these "synthetic" events // Repro: In playground, press 4-1-5-1-1 (small, add one, normal, add one, add one) // Nomatter how fast or slow the sequence is being pressed, it should still stick to the bottom var nextOffsetHeight = target.offsetHeight, nextScrollHeight = target.scrollHeight; var offsetHeight = offsetHeightRef.current; var scrollHeight = scrollHeightRef.current; var offsetHeightChanged = nextOffsetHeight !== offsetHeight; var scrollHeightChanged = nextScrollHeight !== scrollHeight; if (offsetHeightChanged) { offsetHeightRef.current = nextOffsetHeight; } if (scrollHeightChanged) { scrollHeightRef.current = nextScrollHeight; } // Sticky means: // - If it is scrolled programatically, we are still in sticky mode // - If it is scrolled by the user, then sticky means if we are at the end // Only update stickiness if the scroll event is not due to synthetic scroll done by Chrome if (!offsetHeightChanged && !scrollHeightChanged) { // We are sticky if we are animating to the end, or we are already at the end. // We can be "animating but not sticky" by calling "scrollTo(100)" where the container scrollHeight is 200px. var nextSticky = animating && isEnd(animateTo, mode) || atEnd; if (stickyRef.current !== nextSticky) { debug(function () { var _context12, _context13, _context14, _context15; return [_concatInstanceProperty(_context12 = ["%conScroll%c: %csetSticky%c(%c".concat(nextSticky, "%c)")]).call(_context12, _toConsumableArray(styleConsole('red')), _toConsumableArray(styleConsole('red')), _toConsumableArray(styleConsole('purple'))), _concatInstanceProperty(_context13 = [_concatInstanceProperty(_context14 = _concatInstanceProperty(_context15 = "(animating = %c".concat(animating, "%c && isEnd = %c")).call(_context15, isEnd(animateTo, mode), "%c) || atEnd = %c")).call(_context14, atEnd, "%c")]).call(_context13, _toConsumableArray(styleConsole('purple')), _toConsumableArray(styleConsole('purple')), _toConsumableArray(styleConsole('purple')), [{ animating: animating, animateTo: animateTo, atEnd: atEnd, mode: mode, offsetHeight: target.offsetHeight, scrollHeight: target.scrollHeight, sticky: stickyRef.current, nextSticky: nextSticky }])]; }); setSticky(nextSticky); } } else if (stickyRef.current) { debug(function () { var _context16; return [_concatInstanceProperty(_context16 = ["%conScroll%c: Size changed while sticky, calling %cscrollToSticky()%c"]).call(_context16, _toConsumableArray(styleConsole('red')), _toConsumableArray(styleConsole('orange')), [{ offsetHeightChanged: offsetHeightChanged, scrollHeightChanged: scrollHeightChanged }]), { nextOffsetHeight: nextOffsetHeight, prevOffsetHeight: offsetHeight, nextScrollHeight: nextScrollHeight, prevScrollHeight: scrollHeight }]; }); scrollToSticky(); } var actualScrollTop = target.scrollTop; _forEachInstanceProperty(_context17 = scrollPositionObserversRef.current).call(_context17, function (observer) { return observer({ scrollTop: actualScrollTop }); }); }, [animateToRef, debug, ignoreScrollEventBeforeRef, mode, offsetHeightRef, scrollHeightRef, scrollPositionObserversRef, scrollToSticky, setAtBottom, setAtEnd, setAtStart, setAtTop, setSticky, stickyRef, targetRef]); useEffect(function () { if (target) { var stickyButNotAtEndSince = false; var timeout = setImmediateInterval(function () { var target = targetRef.current; var animating = animateToRef.current !== null; if (stickyRef.current) { if (!computeViewState({ mode: mode, target: target }).atEnd) { if (!stickyButNotAtEndSince) { stickyButNotAtEndSince = _Date$now(); } else if (_Date$now() - stickyButNotAtEndSince > SCROLL_DECISION_DURATION) { // Quirks: In Firefox, after user scroll down, Firefox do two things: // 1. Set to a new "scrollTop" // 2. Fire "scroll" event // For what we observed, #1 is fired about 20ms before #2. There is a chance that this stickyCheckTimeout is being scheduled between 1 and 2. // That means, if we just look at #1 to decide if we should scroll, we will always scroll, in oppose to the user's intention. // Repro: Open Firefox, set checkInterval to a lower number, and try to scroll by dragging the scroll handler. It will jump back. // The "animating" check will make sure stickiness is not lost when elements are adding at a very fast pace. if (!animating) { animateFromRef.current = target.scrollTop; debug(function () { var _context18; return _concatInstanceProperty(_context18 = ["%cInterval check%c: Should sticky but not at end, calling %cscrollToSticky()%c to scroll"]).call(_context18, _toConsumableArray(styleConsole('navy')), _toConsumableArray(styleConsole('orange'))); }); scrollToSticky(); } stickyButNotAtEndSince = false; } } else { stickyButNotAtEndSince = false; } } else if (target.scrollHeight <= target.offsetHeight && !stickyRef.current) { // When the container is emptied, we will set sticky back to true. debug(function () { var _context19; return [_concatInstanceProperty(_context19 = ["%cInterval check%c: Container is emptied, setting sticky back to %ctrue%c"]).call(_context19, _toConsumableArray(styleConsole('navy')), _toConsumableArray(styleConsole('purple'))), [{ offsetHeight: target.offsetHeight, scrollHeight: target.scrollHeight, sticky: stickyRef.current }]]; }); setSticky(true); } }, Math.max(MIN_CHECK_INTERVAL, checkInterval) || MIN_CHECK_INTERVAL); return function () { return clearInterval(timeout); }; } }, [animateToRef, checkInterval, debug, mode, scrollToSticky, setSticky, stickyRef, target, targetRef]); var styleToClassName = useMemo(function () { var emotion = emotionPool[nonce] || (emotionPool[nonce] = createEmotion({ key: 'react-scroll-to-bottom--css-' + createCSSKey(), nonce: nonce })); return function (style) { return emotion.css(style) + ''; }; }, [nonce]); var internalContext = useMemo(function () { return { observeScrollPosition: observeScrollPosition, setTarget: setTarget, styleToClassName: styleToClassName }; }, [observeScrollPosition, setTarget, styleToClassName]); var state1Context = useMemo(function () { return { atBottom: atBottom, atEnd: atEnd, atStart: atStart, atTop: atTop, mode: mode }; }, [atBottom, atEnd, atStart, atTop, mode]); var state2Context = useMemo(function () { var animating = animateTo !== null; return { animating: animating, animatingToEnd: animating && isEnd(animateTo, mode), sticky: sticky }; }, [animateTo, mode, sticky]); var combinedStateContext = useMemo(function () { return _objectSpread(_objectSpread({}, state1Context), state2Context); }, [state1Context, state2Context]); var functionContext = useMemo(function () { return { scrollTo: scrollTo, scrollToBottom: scrollToBottom, scrollToEnd: scrollToEnd, scrollToStart: scrollToStart, scrollToTop: scrollToTop }; }, [scrollTo, scrollToBottom, scrollToEnd, scrollToStart, scrollToTop]); useEffect(function () { // We need to update the "scrollHeight" value to latest when the user do a focus inside the box. // // This is because: // - In our code that mitigate Chrome synthetic scrolling, that code will look at whether "scrollHeight" value is latest or not. // - That code only run on "scroll" event. // - That means, on every "scroll" event, if the "scrollHeight" value is not latest, we will skip modifying the stickiness. // - That means, if the user "focus" to an element that cause the scroll view to scroll to the bottom, the user agent will fire "scroll" event. // Since the "scrollHeight" is not latest value, this "scroll" event will be ignored and stickiness will not be modified. // - That means, if the user "focus" to a newly added element that is at the end of the scroll view, the "scroll to bottom" button will continue to show. // // Repro in Chrome: // 1. Fill up a scroll view // 2. Scroll up, the "scroll to bottom" button should show up // 3. Click "Add a button" // 4. Click on the scroll view (to pseudo-focus on it) // 5. Press TAB, the scroll view will be at the bottom // // Expect: // - The "scroll to bottom" button should be gone. if (target) { var handleFocus = function handleFocus() { scrollHeightRef.current = target.scrollHeight; }; target.addEventListener('focus', handleFocus, { capture: true, passive: true }); return function () { return target.removeEventListener('focus', handleFocus); }; } }, [target]); debug(function () { var _context20; return [_concatInstanceProperty(_context20 = ["%cRender%c: Render"]).call(_context20, _toConsumableArray(styleConsole('cyan', ''))), { animateTo: animateTo, animating: animateTo !== null, sticky: sticky, target: target }]; }); return /*#__PURE__*/React.createElement(InternalContext.Provider, { value: internalContext }, /*#__PURE__*/React.createElement(FunctionContext.Provider, { value: functionContext }, /*#__PURE__*/React.createElement(StateContext.Provider, { value: combinedStateContext }, /*#__PURE__*/React.createElement(State1Context.Provider, { value: state1Context }, /*#__PURE__*/React.createElement(State2Context.Provider, { value: state2Context }, children, target && /*#__PURE__*/React.createElement(EventSpy, { debounce: debounce, name: "scroll", onEvent: handleScroll, target: target }), target && animateTo !== null && /*#__PURE__*/React.createElement(SpineTo, { name: "scrollTop", onEnd: handleSpineToEnd, target: target, value: animateTo })))))); }; Composer.propTypes = { checkInterval: PropTypes.number, children: PropTypes.any, debounce: PropTypes.number, debug: PropTypes.bool, initialScrollBehavior: PropTypes.oneOf(['auto', 'smooth']), mode: PropTypes.oneOf(['bottom', 'top']), nonce: PropTypes.string, scroller: PropTypes.func }; export default Composer; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9TY3JvbGxUb0JvdHRvbS9Db21wb3Nlci5qcyJdLCJuYW1lcyI6WyJjcmVhdGVFbW90aW9uIiwiUHJvcFR5cGVzIiwiUmVhY3QiLCJ1c2VDYWxsYmFjayIsInVzZUVmZmVjdCIsInVzZU1lbW8iLCJ1c2VSZWYiLCJ1c2VTdGF0ZSIsImNyZWF0ZUNTU0tleSIsImNyZWF0ZURlYnVnIiwiRXZlbnRTcHkiLCJGdW5jdGlvbkNvbnRleHQiLCJJbnRlcm5hbENvbnRleHQiLCJTcGluZVRvIiwiU3RhdGUxQ29udGV4dCIsIlN0YXRlMkNvbnRleHQiLCJTdGF0ZUNvbnRleHQiLCJzdHlsZUNvbnNvbGUiLCJ1c2VTdGF0ZVJlZiIsIkRFRkFVTFRfU0NST0xMRVIiLCJJbmZpbml0eSIsIk1JTl9DSEVDS19JTlRFUlZBTCIsIk1PREVfQk9UVE9NIiwiTU9ERV9UT1AiLCJORUFSX0VORF9USFJFU0hPTEQiLCJTQ1JPTExfREVDSVNJT05fRFVSQVRJT04iLCJlbW90aW9uUG9vbCIsInNldEltbWVkaWF0ZUludGVydmFsIiwiZm4iLCJtcyIsImNvbXB1dGVWaWV3U3RhdGUiLCJtb2RlIiwidGFyZ2V0Iiwib2Zmc2V0SGVpZ2h0Iiwic2Nyb2xsSGVpZ2h0Iiwic2Nyb2xsVG9wIiwiYXRCb3R0b20iLCJhdFRvcCIsImF0RW5kIiwiYXRTdGFydCIsImlzRW5kIiwiYW5pbWF0ZVRvIiwiQ29tcG9zZXIiLCJjaGVja0ludGVydmFsIiwiY2hpbGRyZW4iLCJkZWJvdW5jZSIsImRlYnVnRnJvbVByb3AiLCJkZWJ1ZyIsImluaXRpYWxTY3JvbGxCZWhhdmlvciIsIm5vbmNlIiwic2Nyb2xsZXIiLCJmb3JjZSIsImlnbm9yZVNjcm9sbEV2ZW50QmVmb3JlUmVmIiwiaW5pdGlhbFNjcm9sbEJlaGF2aW9yUmVmIiwic2V0QW5pbWF0ZVRvIiwiYW5pbWF0ZVRvUmVmIiwic2V0VGFyZ2V0IiwidGFyZ2V0UmVmIiwiYW5pbWF0ZUZyb21SZWYiLCJvZmZzZXRIZWlnaHRSZWYiLCJzY3JvbGxIZWlnaHRSZWYiLCJzZXRBdEJvdHRvbSIsInNldEF0RW5kIiwic2V0QXRUb3AiLCJzZXRBdFN0YXJ0Iiwic3RpY2t5Iiwic2V0U3RpY2t5Iiwic3RpY2t5UmVmIiwic2Nyb2xsUG9zaXRpb25PYnNlcnZlcnNSZWYiLCJvYnNlcnZlU2Nyb2xsUG9zaXRpb24iLCJjdXJyZW50IiwicHVzaCIsInNjcm9sbFBvc2l0aW9uT2JzZXJ2ZXJzIiwiaW5kZXgiLCJoYW5kbGVTcGluZVRvRW5kIiwic2Nyb2xsVG8iLCJuZXh0QW5pbWF0ZVRvIiwiYmVoYXZpb3IiLCJjb25zb2xlIiwid2FybiIsInJlcGxhY2UiLCJzY3JvbGxUb0JvdHRvbSIsInNjcm9sbFRvVG9wIiwic2Nyb2xsVG9FbmQiLCJvcHRpb25zIiwic2Nyb2xsVG9TdGFydCIsInNjcm9sbFRvU3RpY2t5IiwiYW5pbWF0ZUZyb20iLCJtYXhWYWx1ZSIsIk1hdGgiLCJtYXgiLCJtaW5WYWx1ZSIsInJhd05leHRWYWx1ZSIsIm5leHRWYWx1ZSIsIm1pbiIsImhhbmRsZVNjcm9sbCIsInRpbWVTdGFtcExvdyIsImFuaW1hdGluZyIsIm5leHRPZmZzZXRIZWlnaHQiLCJuZXh0U2Nyb2xsSGVpZ2h0Iiwib2Zmc2V0SGVpZ2h0Q2hhbmdlZCIsInNjcm9sbEhlaWdodENoYW5nZWQiLCJuZXh0U3RpY2t5IiwicHJldk9mZnNldEhlaWdodCIsInByZXZTY3JvbGxIZWlnaHQiLCJhY3R1YWxTY3JvbGxUb3AiLCJvYnNlcnZlciIsInN0aWNreUJ1dE5vdEF0RW5kU2luY2UiLCJ0aW1lb3V0IiwiY2xlYXJJbnRlcnZhbCIsInN0eWxlVG9DbGFzc05hbWUiLCJlbW90aW9uIiwia2V5Iiwic3R5bGUiLCJjc3MiLCJpbnRlcm5hbENvbnRleHQiLCJzdGF0ZTFDb250ZXh0Iiwic3RhdGUyQ29udGV4dCIsImFuaW1hdGluZ1RvRW5kIiwiY29tYmluZWRTdGF0ZUNvbnRleHQiLCJmdW5jdGlvbkNvbnRleHQiLCJoYW5kbGVGb2N1cyIsImFkZEV2ZW50TGlzdGVuZXIiLCJjYXB0dXJlIiwicGFzc2l2ZSIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJwcm9wVHlwZXMiLCJudW1iZXIiLCJhbnkiLCJib29sIiwib25lT2YiLCJzdHJpbmciLCJmdW5jIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLE9BQU9BLGFBQVAsTUFBMEIsOEJBQTFCO0FBQ0EsT0FBT0MsU0FBUCxNQUFzQixZQUF0QjtBQUNBLE9BQU9DLEtBQVAsSUFBZ0JDLFdBQWhCLEVBQTZCQyxTQUE3QixFQUF3Q0MsT0FBeEMsRUFBaURDLE1BQWpELEVBQXlEQyxRQUF6RCxRQUF5RSxPQUF6RTtBQUVBLE9BQU9DLFlBQVAsTUFBeUIsaUJBQXpCO0FBQ0EsT0FBT0MsV0FBUCxNQUF3QixnQkFBeEI7QUFDQSxPQUFPQyxRQUFQLE1BQXFCLGFBQXJCO0FBQ0EsT0FBT0MsZUFBUCxNQUE0QixtQkFBNUI7QUFDQSxPQUFPQyxlQUFQLE1BQTRCLG1CQUE1QjtBQUNBLE9BQU9DLE9BQVAsTUFBb0IsWUFBcEI7QUFDQSxPQUFPQyxhQUFQLE1BQTBCLGlCQUExQjtBQUNBLE9BQU9DLGFBQVAsTUFBMEIsaUJBQTFCO0FBQ0EsT0FBT0MsWUFBUCxNQUF5QixnQkFBekI7QUFDQSxPQUFPQyxZQUFQLE1BQXlCLHVCQUF6QjtBQUNBLE9BQU9DLFdBQVAsTUFBd0IsK0JBQXhCOztBQUVBLElBQU1DLGdCQUFnQixHQUFHLFNBQW5CQSxnQkFBbUI7QUFBQSxTQUFNQyxRQUFOO0FBQUEsQ0FBekI7O0FBQ0EsSUFBTUMsa0JBQWtCLEdBQUcsRUFBM0IsQyxDQUErQjs7QUFDL0IsSUFBTUMsV0FBVyxHQUFHLFFBQXBCO0FBQ0EsSUFBTUMsUUFBUSxHQUFHLEtBQWpCO0FBQ0EsSUFBTUMsa0JBQWtCLEdBQUcsQ0FBM0I7QUFDQSxJQUFNQyx3QkFBd0IsR0FBRyxFQUFqQyxDLENBQXFDO0FBRXJDO0FBQ0E7O0FBQ0EsSUFBTUMsV0FBVyxHQUFHLEVBQXBCOztBQUVBLFNBQVNDLG9CQUFULENBQThCQyxF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