UNPKG

@renderlesskit/react

Version:

Collection of headless components/hooks that are accessible, composable, customizable from low level to build your own UI & Design System powered by Reakit

193 lines (167 loc) 8.57 kB
var _excluded = ["direction", "contentSize", "easing"], _excluded2 = ["ref", "style", "onTransitionEnd"]; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(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 = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } // Core Logic for transition is based on https://github.com/roginfarrer/react-collapsed import * as React from "react"; import { flushSync } from "react-dom"; import { createComponent } from "reakit-system"; import { useBox } from "reakit"; import { useForkRef, useLiveRef, useUpdateEffect } from "reakit-utils"; import raf from "raf"; import { createComposableHook } from "../system"; import { DISCLOSURE_COLLAPSE_CONTENT_KEYS } from "./__keys"; import { getAutoSizeDuration, getElementHeight, getElementWidth } from "./helpers"; export var disclosureCollapseComposableContent = createComposableHook({ name: "DisclosureCollapseContent", compose: useBox, keys: DISCLOSURE_COLLAPSE_CONTENT_KEYS, useOptions(options, htmlProps) { var { direction = "vertical", contentSize = 0, easing = "cubic-bezier(0.4, 0, 0.2, 1)" } = options, restOptions = _objectWithoutProperties(options, _excluded); return _objectSpread({ direction, contentSize, easing }, restOptions); }, useProps(options, htmlProps) { var { contentSize, visible, direction, duration, easing, onCollapseEnd, onCollapseStart, onExpandEnd, onExpandStart } = options; var { ref: htmlRef, style: htmlStyle, onTransitionEnd: htmlOnTransitionEnd } = htmlProps, restHtmlProps = _objectWithoutProperties(htmlProps, _excluded2); var ref = React.useRef(null); var onTransitionEndRef = useLiveRef(htmlOnTransitionEnd); var isVertical = direction === "vertical"; var currentSize = isVertical ? "height" : "width"; var getCurrentSizeStyle = React.useCallback(size => ({ [currentSize]: "".concat(size, "px") }), [currentSize]); var collapsedStyles = React.useMemo(() => { return _objectSpread(_objectSpread({}, getCurrentSizeStyle(contentSize)), {}, { overflow: "hidden" }); }, [contentSize, getCurrentSizeStyle]); var [styles, setStylesRaw] = React.useState(visible ? {} : collapsedStyles); var setStyles = newStyles => { // We rely on reading information from layout // at arbitrary times, so ensure all style changes // happen before we might attempt to read them. flushSync(() => { setStylesRaw(newStyles); }); }; var mergeStyles = React.useCallback(newStyles => { setStyles(oldStyles => _objectSpread(_objectSpread({}, oldStyles), newStyles)); }, []); function getTransitionStyles(size) { var _duration = duration || getAutoSizeDuration(size); return { transition: "".concat(currentSize, " ").concat(_duration, "ms ").concat(easing) }; } useUpdateEffect(() => { if (visible) { raf(() => { onExpandStart === null || onExpandStart === void 0 ? void 0 : onExpandStart(); mergeStyles({ willChange: "".concat(currentSize), overflow: "hidden" }); raf(() => { var size = isVertical ? getElementHeight(ref) : getElementWidth(ref); mergeStyles(_objectSpread(_objectSpread({}, getTransitionStyles(size)), isVertical ? { height: size } : { width: size })); }); }); } else { raf(() => { onCollapseStart === null || onCollapseStart === void 0 ? void 0 : onCollapseStart(); var size = isVertical ? getElementHeight(ref) : getElementWidth(ref); mergeStyles(_objectSpread(_objectSpread({ willChange: "".concat(currentSize) }, isVertical ? { height: size } : { width: size }), getTransitionStyles(size))); raf(() => { mergeStyles(_objectSpread(_objectSpread({}, getCurrentSizeStyle(contentSize)), {}, { overflow: "hidden" })); }); }); } }, [visible]); var onTransitionEnd = React.useCallback(event => { var _onTransitionEndRef$c; (_onTransitionEndRef$c = onTransitionEndRef.current) === null || _onTransitionEndRef$c === void 0 ? void 0 : _onTransitionEndRef$c.call(onTransitionEndRef, event); if (event.defaultPrevented) return; // Sometimes onTransitionEnd is triggered by another transition, // such as a nested collapse panel transitioning. But we only // want to handle this if this component's element is transitioning if (event.target !== ref.current || event.propertyName !== currentSize) { return; } // The height comparisons below are a final check before // completing the transition // Sometimes this callback is run even though we've already begun // transitioning the other direction // The conditions give us the opportunity to bail out, // which will prevent the collapsed content from flashing on the screen var stylesSize = isVertical ? styles.height : styles.width; if (visible) { var size = isVertical ? getElementHeight(ref) : getElementWidth(ref); // If the height at the end of the transition // matches the height we're animating to, if (size === stylesSize) { setStyles({}); } else { // If the heights don't match, this could be due the height // of the content changing mid-transition mergeStyles(_objectSpread({}, getCurrentSizeStyle(contentSize))); } onExpandEnd === null || onExpandEnd === void 0 ? void 0 : onExpandEnd(); // If the height we should be animating to matches the collapsed height, // it's safe to apply the collapsed overrides } else if (stylesSize === "".concat(contentSize, "px")) { setStyles(collapsedStyles); onCollapseEnd === null || onCollapseEnd === void 0 ? void 0 : onCollapseEnd(); } }, [onTransitionEndRef, currentSize, isVertical, styles.height, styles.width, visible, contentSize, onExpandEnd, mergeStyles, getCurrentSizeStyle, collapsedStyles, onCollapseEnd]); var style = _objectSpread(_objectSpread({}, styles), htmlStyle); return _objectSpread({ ref: useForkRef(ref, htmlRef), id: options.baseId, "aria-hidden": !visible, style, onTransitionEnd }, restHtmlProps); } }); export var useDisclosureCollapseContent = disclosureCollapseComposableContent(); export var DisclosureCollapseContent = createComponent({ as: "div", memo: true, useHook: useDisclosureCollapseContent }); //# sourceMappingURL=DisclosureCollapseContent.js.map