UNPKG

@commercetools-uikit/collapsible-motion

Version:

A component which allows building collapsible elements with an arbitrary height.

158 lines (152 loc) • 7.99 kB
import _Object$keys from '@babel/runtime-corejs3/core-js-stable/object/keys'; import _Object$getOwnPropertySymbols from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols'; import _filterInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/filter'; import _Object$getOwnPropertyDescriptor from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor'; import _forEachInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/for-each'; import _Object$getOwnPropertyDescriptors from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors'; import _Object$defineProperties from '@babel/runtime-corejs3/core-js-stable/object/define-properties'; import _Object$defineProperty from '@babel/runtime-corejs3/core-js-stable/object/define-property'; import _objectDestructuringEmpty from '@babel/runtime-corejs3/helpers/esm/objectDestructuringEmpty'; import _extends from '@babel/runtime-corejs3/helpers/esm/extends'; import _objectWithoutProperties from '@babel/runtime-corejs3/helpers/esm/objectWithoutProperties'; import _defineProperty from '@babel/runtime-corejs3/helpers/esm/defineProperty'; import _slicedToArray from '@babel/runtime-corejs3/helpers/esm/slicedToArray'; import { useRef, useEffect, useCallback } from 'react'; import { warning } from '@commercetools-uikit/utils'; import { ClassNames, keyframes } from '@emotion/react'; import isNil from 'lodash/isNil'; import { useToggleState, usePrevious } from '@commercetools-uikit/hooks'; import { jsx } from '@emotion/react/jsx-runtime'; const _excluded = ["minHeight"]; function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = _filterInstanceProperty(o).call(o, function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty(_context = ownKeys(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : _forEachInstanceProperty(_context2 = ownKeys(Object(t))).call(_context2, function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; } const getMinHeight = minHeight => minHeight !== 0 ? `${minHeight}px` : minHeight; const getVisibility = height => height === 0 ? 'hidden' : 'visible'; const createOpeningAnimation = function (height) { let minHeight = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return keyframes` 0% { height: ${getMinHeight(minHeight)}; overflow: hidden; visibility: ${getVisibility(minHeight)}; } 99% { height: ${height}px; overflow: hidden; } 100% { height: auto; overflow: visible; } `; }; const createClosingAnimation = function (height) { let minHeight = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return keyframes` from { height: ${height}px; } to { height: ${getMinHeight(minHeight)}; overflow: hidden; visibility: ${getVisibility(minHeight)}; } `; }; const useToggleAnimation = function (isOpen, toggle) { let minHeight = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; const nodeRef = useRef(null); const animationRef = useRef(null); const prevIsOpen = usePrevious(isOpen); useEffect(() => { process.env.NODE_ENV !== "production" ? warning(nodeRef.current, 'You need to call `registerContentNode` in order to use this component') : void 0; }, // to match the componentDidMount behaviour [nodeRef]); const handleToggle = useCallback(() => { process.env.NODE_ENV !== "production" ? warning(nodeRef.current, 'You need to call `registerContentNode` in order to use this component') : void 0; // set panel height to the height of the content, // so we can animate between the height and 0 toggle && toggle(); }, [nodeRef, toggle]); const containerStyles = isOpen ? { height: 'auto' } : { height: getMinHeight(minHeight), overflow: 'hidden', visibility: getVisibility(minHeight) }; // if state has changed if (typeof prevIsOpen !== 'undefined' && prevIsOpen !== isOpen && nodeRef.current) { animationRef.current = isOpen ? createOpeningAnimation(nodeRef.current.clientHeight, minHeight) : createClosingAnimation(nodeRef.current.clientHeight, minHeight); } return [animationRef.current, containerStyles, handleToggle, nodeRef]; }; const ControlledCollapsibleMotion = props => { const _useToggleAnimation = useToggleAnimation(!props.isClosed, props.onToggle, props.minHeight), _useToggleAnimation2 = _slicedToArray(_useToggleAnimation, 4), animation = _useToggleAnimation2[0], containerStyles = _useToggleAnimation2[1], animationToggle = _useToggleAnimation2[2], registerContentNode = _useToggleAnimation2[3]; return jsx(ClassNames, { children: _ref => { let css = _ref.css; let animationStyle = {}; if (animation) { // By calling `css`, emotion injects the required CSS into the document head. // eslint-disable-next-line no-unused-expressions css` animation: ${animation} 200ms forwards; `; animationStyle = { animation: `${animation.name} 200ms forwards` }; } return props.children({ isOpen: !props.isClosed, containerStyles: _objectSpread(_objectSpread({}, containerStyles), animationStyle), toggle: animationToggle, registerContentNode: registerContentNode }); } }); }; ControlledCollapsibleMotion.displayName = 'ControlledCollapsibleMotion'; const UncontrolledCollapsibleMotion = _ref2 => { let _ref2$minHeight = _ref2.minHeight, minHeight = _ref2$minHeight === void 0 ? 0 : _ref2$minHeight, props = _objectWithoutProperties(_ref2, _excluded); const _useToggleState = useToggleState(!props.isDefaultClosed), _useToggleState2 = _slicedToArray(_useToggleState, 2), isOpen = _useToggleState2[0], toggle = _useToggleState2[1]; const _useToggleAnimation3 = useToggleAnimation(isOpen, toggle, minHeight), _useToggleAnimation4 = _slicedToArray(_useToggleAnimation3, 4), animation = _useToggleAnimation4[0], containerStyles = _useToggleAnimation4[1], animationToggle = _useToggleAnimation4[2], registerContentNode = _useToggleAnimation4[3]; return jsx(ClassNames, { children: _ref3 => { let css = _ref3.css; let animationStyle = {}; if (animation) { // By calling `css`, emotion injects the required CSS into the document head. // eslint-disable-next-line no-unused-expressions css` animation: ${animation} 200ms forwards; `; animationStyle = { animation: `${animation.name} 200ms forwards` }; } return props.children({ isOpen, containerStyles: _objectSpread(_objectSpread({}, containerStyles), animationStyle), toggle: animationToggle, registerContentNode: registerContentNode }); } }); }; UncontrolledCollapsibleMotion.displayName = 'UncontrolledCollapsibleMotion'; const CollapsibleMotion = _ref4 => { let props = _extends({}, (_objectDestructuringEmpty(_ref4), _ref4)); const isControlledComponent = !isNil(props.isClosed); if (isControlledComponent) { return jsx(ControlledCollapsibleMotion, _objectSpread({}, props)); } return jsx(UncontrolledCollapsibleMotion, _objectSpread({}, props)); }; CollapsibleMotion.displayName = 'CollapsibleMotion'; var CollapsibleMotion$1 = CollapsibleMotion; // NOTE: This string will be replaced on build time with the package version. var version = "20.6.5"; export { CollapsibleMotion$1 as default, version };