UNPKG

@hypothesis/frontend-shared

Version:

Shared components, styles and utilities for Hypothesis projects

93 lines (88 loc) 3.63 kB
var _jsxFileName = "/home/runner/work/frontend-shared/frontend-shared/src/components/transition/Slider.tsx"; import { useCallback, useEffect, useRef, useState } from 'preact/hooks'; import { jsxDEV as _jsxDEV } from "preact/jsx-dev-runtime"; const Slider = ({ children, direction = 'in', onTransitionEnd }) => { const visible = direction === 'in'; const containerRef = useRef(null); const [containerHeight, setContainerHeight] = useState(visible ? 'auto' : 0); // Whether the content is currently partially or wholly visible. This is // different from `visible` when collapsing as it is true until the collapse // animation completes. const [contentVisible, setContentVisible] = useState(visible); // Adjust the container height when the `visible` prop changes. useEffect(() => { const isVisible = containerHeight !== 0; if (visible === isVisible) { // Do nothing after the initial mount. return; } const el = containerRef.current; if (visible) { // Show the content synchronously so that we can measure it here. el.style.display = ''; // Make content visible in future renders. setContentVisible(true); // When expanding, transition the container to the current fixed height // of the content. After the transition completes, we'll reset to "auto" // height to adapt to future content changes. setContainerHeight(el.scrollHeight); } else { // When collapsing, immediately change the current height to a fixed height // (in case it is currently "auto"), force a synchronous layout, // then transition to 0. // // These steps are needed because browsers will not animate transitions // from "auto" => "0" and may not animate "auto" => fixed height => 0 // if the layout tree transitions directly from "auto" => 0. el.style.height = `${el.scrollHeight}px`; // Force a sync layout. el.getBoundingClientRect(); setContainerHeight(0); } }, [containerHeight, visible]); const handleTransitionEnd = useCallback(e => { // Only transitions on the actual component and for the "height" property // are relevant "in"/"out" transitions. if (e.target !== containerRef.current || e.propertyName !== 'height') { return; } if (visible) { setContainerHeight('auto'); } else { // When the collapse animation completes, stop rendering the content so // that the browser has fewer nodes to render and the content is removed // from keyboard navigation. setContentVisible(false); } onTransitionEnd === null || onTransitionEnd === void 0 || onTransitionEnd(direction); }, [setContainerHeight, visible, onTransitionEnd, direction]); const isFullyVisible = containerHeight === 'auto'; return _jsxDEV("div", { // nb. Preact uses "ontransitionend" rather than "onTransitionEnd". // See https://bugs.chromium.org/p/chromium/issues/detail?id=961193 // // @ts-ignore ontransitionend: handleTransitionEnd, ref: containerRef, style: { display: contentVisible ? '' : 'none', height: containerHeight, // When the Slider is fully open, overflow is made visible so that // focus rings, which may extend outside the bounds of the Slider content, // are visible. overflow: isFullyVisible ? 'visible' : 'hidden', transition: `height 0.15s ease-in` }, children: children }, void 0, false, { fileName: _jsxFileName, lineNumber: 80, columnNumber: 5 }, this); }; export default Slider; //# sourceMappingURL=Slider.js.map