@helpscout/hsds-react
Version:
React component library for Help Scout's Design System
125 lines (106 loc) • 4.61 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.default = useScrollShadow;
exports.getScrollableSectionsState = getScrollableSectionsState;
var _react = require("react");
var _lodash = _interopRequireDefault(require("lodash.throttle"));
// very difficult to test with JSDom, some basic interaction is tested in ScrollableContainer
/* istanbul ignore file */
var BOX_SHADOW_INITIAL = '0 0 0 1px rgba(0, 0, 0, 0.1)';
var BOX_SHADOW_SCROLLED = '0 0 0 1px rgba(0, 0, 0, 0.1), 0 0 0 5px rgba(0, 0, 0, 0.05)';
function useScrollShadow(_ref) {
var bottomRef = _ref.bottomRef,
_ref$drawInitialShado = _ref.drawInitialShadowsDelay,
drawInitialShadowsDelay = _ref$drawInitialShado === void 0 ? 0 : _ref$drawInitialShado,
scrollableRef = _ref.scrollableRef,
_ref$shadows = _ref.shadows,
shadows = _ref$shadows === void 0 ? {} : _ref$shadows,
topRef = _ref.topRef;
var initialShadow = shadows.initial || BOX_SHADOW_INITIAL;
var scrolledShadow = shadows.scrolled || BOX_SHADOW_SCROLLED;
var _useState = (0, _react.useState)(null),
isTopScrolled = _useState[0],
setIsTopScrolled = _useState[1];
var _useState2 = (0, _react.useState)(null),
isBottomScrolled = _useState2[0],
setIsBottomScrolled = _useState2[1];
var topElement = getElement(topRef);
var bottomElement = getElement(bottomRef);
var scrollableElement = getElement(scrollableRef);
var scrollableHeight = scrollableElement && scrollableElement.getBoundingClientRect().height;
(0, _react.useEffect)(function () {
var timeoutID = setTimeout(function () {
if (scrollableElement) {
var _getScrollableSection = getScrollableSectionsState(scrollableElement),
_isBottomScrolled = _getScrollableSection.isBottomScrolled,
_isTopScrolled = _getScrollableSection.isTopScrolled;
applyShadows(topElement, _isTopScrolled, {
initialShadow: initialShadow,
scrolledShadow: scrolledShadow
});
applyShadows(bottomElement, _isBottomScrolled, {
initialShadow: initialShadow,
scrolledShadow: scrolledShadow
});
setIsTopScrolled(_isTopScrolled);
setIsBottomScrolled(_isBottomScrolled);
}
}, drawInitialShadowsDelay);
return function () {
clearTimeout(timeoutID);
};
}, [drawInitialShadowsDelay, initialShadow, scrolledShadow, topElement, bottomElement, scrollableElement, scrollableHeight]);
var handleOnScroll = (0, _lodash.default)(function () {
var scrollableElement = getElement(scrollableRef);
var _getScrollableSection2 = getScrollableSectionsState(scrollableElement),
isTopScrolled = _getScrollableSection2.isTopScrolled,
isBottomScrolled = _getScrollableSection2.isBottomScrolled;
applyShadows(topElement, isTopScrolled, {
initialShadow: initialShadow,
scrolledShadow: scrolledShadow
});
applyShadows(bottomElement, isBottomScrolled, {
initialShadow: initialShadow,
scrolledShadow: scrolledShadow
});
setIsTopScrolled(isTopScrolled);
setIsBottomScrolled(isBottomScrolled);
}, 100);
return [handleOnScroll, isTopScrolled, isBottomScrolled];
}
function getElement(someRef) {
if (someRef instanceof HTMLElement) return someRef;
return someRef && someRef.current;
}
function applyShadows(element, isScrolled, _ref2) {
var initialShadow = _ref2.initialShadow,
scrolledShadow = _ref2.scrolledShadow;
if (element) {
element.style.boxShadow = 'var(--scroll-shadow)';
if (isScrolled) {
element.style.setProperty('--scroll-shadow', scrolledShadow);
} else {
element.style.setProperty('--scroll-shadow', initialShadow);
}
}
}
function getScrollableSectionsState(scrollable) {
if (!scrollable) {
return {
isTopScrolled: false,
isBottomScrolled: false
};
}
var style = window.getComputedStyle(scrollable);
var paddingTop = Number.parseInt(style.paddingTop, 10);
var paddingBottom = Number.parseInt(style.paddingBottom, 10);
var scrollableScrollHeight = scrollable.scrollHeight;
var scrollableHeight = scrollable.offsetHeight;
var scrollablePaddingTop = paddingTop > 0 ? paddingTop - paddingTop / 2 : 0;
var scrollablePaddingBottom = paddingBottom > 0 ? paddingBottom + paddingBottom / 2 : 0;
return {
isTopScrolled: scrollable.scrollTop - scrollablePaddingTop > 0,
isBottomScrolled: scrollable.scrollTop + scrollableHeight + scrollablePaddingBottom < scrollableScrollHeight
};
}
;