Skip to content

Instantly share code, notes, and snippets.

@SebastianHGonzalez
Created December 2, 2019 18:06
Show Gist options
  • Save SebastianHGonzalez/629e4113a4e88974423f58b5dc1fe571 to your computer and use it in GitHub Desktop.
Save SebastianHGonzalez/629e4113a4e88974423f58b5dc1fe571 to your computer and use it in GitHub Desktop.
import React, {
useCallback, useState, useEffect, cloneElement,
} from 'react';
import { findDOMNode } from 'react-dom';
import { node, bool, number } from 'prop-types';
import styled from 'styled-components';
import usePrevious from 'hooks/usePrevious';
const Collapsible = styled.div.attrs(
({
collapsed, height, transitionDuration, overflow,
}) => ({
style: {
maxHeight: collapsed ? 0 : height,
transitionDuration: `${transitionDuration}ms`,
overflow,
},
}),
)`
transition-property: max-height;
`;
function measureElement(element) {
if (!element) {
return {};
}
// eslint-disable-next-line react/no-find-dom-node
const DOMNode = findDOMNode(element);
return {
width: DOMNode.offsetWidth,
height: DOMNode.offsetHeight,
};
}
export default function Collapse({ children, collapsed, transitionDuration }) {
const [height, setHeight] = useState(0);
const ref = useCallback((r) => {
setHeight(measureElement(r).height);
});
const [overflow, setOverflow] = useState(collapsed ? 'hidden' : 'unset');
const prevCollapsed = usePrevious(collapsed);
useEffect(() => {
if (!prevCollapsed && collapsed) {
setOverflow('hidden');
return () => {};
}
if (prevCollapsed && !collapsed) {
const timeout = setTimeout(() => {
setOverflow('unset');
}, transitionDuration);
return () => {
clearTimeout(timeout);
};
}
return () => {};
}, [prevCollapsed, collapsed]);
return (
<Collapsible
collapsed={collapsed}
height={height}
transitionDuration={transitionDuration}
overflow={overflow}
>
{cloneElement(children, { ref })}
</Collapsible>
);
}
Collapse.propTypes = {
collapsed: bool,
children: node.isRequired,
transitionDuration: number,
};
Collapse.defaultProps = {
collapsed: false,
transitionDuration: 500,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment