UNPKG

@atlaskit/modal-dialog

Version:

A modal dialog displays content that requires user interaction, in a layer above the page.

86 lines (84 loc) 3.33 kB
/* scroll-container.tsx generated by @compiled/babel-plugin v0.39.1 */ import "./scroll-container.compiled.css"; import { ax, ix } from "@compiled/react/runtime"; import React, { forwardRef, useEffect, useRef, useState } from 'react'; import { bind } from 'bind-event-listener'; import rafSchedule from 'raf-schd'; import { cx } from '@atlaskit/css'; 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 { Focusable } from '@atlaskit/primitives/compiled'; const keylineColor = "var(--ds-border, #0B120E24)"; const styles = { base: "_kkes1kw7 _1e0c1kw7 _2lx21kw7 _16jlkb7n _6rthze3t _1pfhze3t _12l2ze3t _ahbqze3t _1reo15vq _18m91wug _1jykn7od _wzg61wug", topKeyline: "_mqm21uh4", bottomKeyline: "_179r1uh4" }; const keylineHeight = 2; /** * A container that shows top and bottom keylines when the * content overflows into the scrollable element. */ const ScrollContainer = /*#__PURE__*/forwardRef(({ testId, children }, ref) => { const scrollableRef = useRef(null); const [showTopKeyline, setTopKeyline] = useState(false); const [showBottomKeyline, setBottomKeyline] = useState(false); const [showContentFocus, setContentFocus] = useState(false); // Schedule a content focus on the target element // WARNING: In theory, `target` may not be available when `rafSchedule` hits in concurrent rendering useEffect(() => { const schedule = rafSchedule(() => { const target = scrollableRef.current; target && setContentFocus(target.scrollHeight > target.clientHeight); }); schedule(); }, [scrollableRef]); const setLazyKeylines = useLazyCallback(rafSchedule(() => { const target = scrollableRef.current; if (target) { const scrollableDistance = target.scrollHeight - target.clientHeight; if (target.previousElementSibling) { setTopKeyline(target.scrollTop > keylineHeight); } if (target.nextElementSibling) { setBottomKeyline(target.scrollTop <= scrollableDistance - keylineHeight); } } })); // On load (and scroll/resize events), we set "keylines" // these border the content to indicate scrollability when content underflows the header or footer useEffect(() => { const target = scrollableRef.current; setLazyKeylines(); const unbindWindowEvent = bind(window, { type: 'resize', listener: setLazyKeylines }); const unbindTargetEvent = target ? bind(target, { type: 'scroll', listener: setLazyKeylines }) : noop; return () => { unbindWindowEvent(); unbindTargetEvent(); }; }, [setLazyKeylines]); return /*#__PURE__*/React.createElement(Focusable, { as: "div", isInset: true // tabindex is allowed here so that keyboard users can scroll content , tabIndex: showContentFocus ? 0 : undefined, role: showContentFocus ? 'region' : undefined, "aria-label": showContentFocus ? 'Scrollable content' : undefined, testId: testId && `${testId}--scrollable`, ref: mergeRefs([ref, scrollableRef]), xcss: cx(styles.base, showTopKeyline && styles.topKeyline, showBottomKeyline && styles.bottomKeyline) }, children); }); ScrollContainer.displayName = 'ScrollContainer'; export default ScrollContainer;