@atlaskit/modal-dialog
Version:
A modal dialog displays content that requires user interaction, in a layer above the page.
109 lines (108 loc) • 3.95 kB
JavaScript
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
/** @jsx jsx */
import React, { forwardRef, useEffect, useRef, useState } from 'react';
import { css, jsx } from '@emotion/react';
import { bind } from 'bind-event-listener';
import rafSchedule from 'raf-schd';
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
import noop from '@atlaskit/ds-lib/noop';
import useLazyCallback from '@atlaskit/ds-lib/use-lazy-callback';
import useStateRef from '@atlaskit/ds-lib/use-state-ref';
import FocusRing from '@atlaskit/focus-ring';
import { keylineColor, keylineHeight } from '../constants';
var baseStyles = css({
display: 'inherit',
margin: "var(--ds-space-0, 0px)",
flex: 'inherit',
flexDirection: 'inherit',
flexGrow: 1,
overflowX: 'hidden',
overflowY: 'auto',
'@media (min-width: 480px)': {
height: 'unset',
overflowY: 'auto'
}
});
var topKeylineStyles = css({
borderTop: "".concat(keylineHeight, "px solid ").concat(keylineColor)
});
var bottomKeylineStyles = css({
borderBottom: "".concat(keylineHeight, "px solid ").concat(keylineColor)
});
/**
* A container that shows top and bottom keylines when the
* content overflows into the scrollable element.
*/
var ScrollContainer = /*#__PURE__*/forwardRef(function (props, ref) {
var testId = props.testId,
children = props.children;
var _useStateRef = useStateRef({
previous: false,
next: false
}),
_useStateRef2 = _slicedToArray(_useStateRef, 2),
hasSiblings = _useStateRef2[0],
setSiblings = _useStateRef2[1];
var _useState = useState(false),
_useState2 = _slicedToArray(_useState, 2),
showContentFocus = _useState2[0],
setContentFocus = _useState2[1];
var _useState3 = useState(false),
_useState4 = _slicedToArray(_useState3, 2),
showTopKeyline = _useState4[0],
setTopKeyline = _useState4[1];
var _useState5 = useState(false),
_useState6 = _slicedToArray(_useState5, 2),
showBottomKeyline = _useState6[0],
setBottomKeyline = _useState6[1];
var scrollableRef = useRef(null);
var setLazySiblings = useLazyCallback(setSiblings);
var setLazyContentFocus = useLazyCallback(rafSchedule(function () {
var target = scrollableRef.current;
target && setContentFocus(target.scrollHeight > target.clientHeight);
}));
var setLazyKeylines = useLazyCallback(rafSchedule(function () {
var target = scrollableRef.current;
if (target) {
var scrollableDistance = target.scrollHeight - target.clientHeight;
if (hasSiblings.current.previous) {
setTopKeyline(target.scrollTop > keylineHeight);
}
if (hasSiblings.current.next) {
setBottomKeyline(target.scrollTop <= scrollableDistance - keylineHeight);
}
}
}));
useEffect(function () {
var target = scrollableRef.current;
var unbindWindowEvent = bind(window, {
type: 'resize',
listener: setLazyKeylines
});
var unbindTargetEvent = target ? bind(target, {
type: 'scroll',
listener: setLazyKeylines
}) : noop;
setLazyContentFocus();
setLazyKeylines();
setLazySiblings({
previous: Boolean(target === null || target === void 0 ? void 0 : target.previousElementSibling),
next: Boolean(target === null || target === void 0 ? void 0 : target.nextElementSibling)
});
return function () {
unbindWindowEvent();
unbindTargetEvent();
};
}, [setLazyContentFocus, setLazyKeylines, setLazySiblings]);
return jsx(FocusRing, {
isInset: true
}, jsx("div", {
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
tabIndex: showContentFocus ? 0 : undefined,
"data-testid": testId && "".concat(testId, "--scrollable"),
ref: mergeRefs([ref, scrollableRef]),
css: [baseStyles, showTopKeyline && topKeylineStyles, showBottomKeyline && bottomKeylineStyles]
}, children));
});
ScrollContainer.displayName = 'ScrollContainer';
export default ScrollContainer;