|
|
|
@ -1,23 +1,45 @@
|
|
|
|
|
import React, { memo, useState, isValidElement } from 'react';
|
|
|
|
|
import React, { memo, useState, isValidElement, useRef } from 'react';
|
|
|
|
|
import { joinClassNames } from '@vizality/util/dom';
|
|
|
|
|
import { isComponent } from '@vizality/util/react';
|
|
|
|
|
import { getModule } from '@vizality/webpack';
|
|
|
|
|
import { useMeasure, useToggle } from '@vizality/hooks';
|
|
|
|
|
import { motion } from 'framer-motion';
|
|
|
|
|
|
|
|
|
|
import { Icon } from '..';
|
|
|
|
|
|
|
|
|
|
export default memo(({ title, description, icon, children, opened, className }) => {
|
|
|
|
|
const [ isOpened, onChange ] = useState(opened === undefined ? opened : false);
|
|
|
|
|
/**
|
|
|
|
|
* @component
|
|
|
|
|
* Some parts sourced from @see {@link https://codesandbox.io/s/animate-height-framer-motion-yn59l?file=/src/AnimateHeight.js}
|
|
|
|
|
*/
|
|
|
|
|
export default memo(({ title, description, icon, children, opened, className, ...other }) => {
|
|
|
|
|
const [ collapsed, toggleCollapsed ] = useToggle(opened === undefined ? !opened : true);
|
|
|
|
|
const { container, icon: _icon, description: _description, label } = getModule('icon', 'container', 'description');
|
|
|
|
|
const { size12, size16 } = getModule('size10', 'size12', 'size16');
|
|
|
|
|
const ref = useRef(null);
|
|
|
|
|
const bounds = useMeasure(ref);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the duration of the animation depending upon the height provided.
|
|
|
|
|
* @param {number} height of container
|
|
|
|
|
*/
|
|
|
|
|
const getAutoHeightDuration = height => {
|
|
|
|
|
if (!height) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
const constant = height / 36;
|
|
|
|
|
return Math.round((4 + 15 * constant ** 0.25 + constant / 5) * 10);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className={joinClassNames('vz-settings-item', 'vz-settings-category', className, container)}
|
|
|
|
|
vz-opened={isOpened ? '' : null}
|
|
|
|
|
vz-expanded={!collapsed && ''}
|
|
|
|
|
vz-collapsed={collapsed && ''}
|
|
|
|
|
{...other}
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
className='vz-settings-category-title-wrapper'
|
|
|
|
|
onClick={() => onChange(!isOpened)}
|
|
|
|
|
onClick={toggleCollapsed}
|
|
|
|
|
tabindex='0'
|
|
|
|
|
>
|
|
|
|
|
{(isComponent(icon) || isValidElement(icon)) && icon}
|
|
|
|
@ -43,11 +65,33 @@ export default memo(({ title, description, icon, children, opened, className })
|
|
|
|
|
size='18'
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
{isOpened &&
|
|
|
|
|
<div className='vz-settings-category-inner'>
|
|
|
|
|
<motion.div
|
|
|
|
|
className='vz-settings-category-inner'
|
|
|
|
|
initial={!collapsed ? 'open' : 'collapsed'}
|
|
|
|
|
animate={!collapsed ? 'open' : 'collapsed'}
|
|
|
|
|
inherit={false}
|
|
|
|
|
variants={{
|
|
|
|
|
open: { height: 'auto' },
|
|
|
|
|
collapsed: { height: 0 }
|
|
|
|
|
}}
|
|
|
|
|
transition={{
|
|
|
|
|
duration: getAutoHeightDuration(bounds.height) / 2000
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div ref={ref} className='vz-settings-category-contents'>
|
|
|
|
|
{children}
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
{/* {typeof children === 'function'
|
|
|
|
|
? (
|
|
|
|
|
children(ref)
|
|
|
|
|
)
|
|
|
|
|
: (
|
|
|
|
|
<div ref={ref} className='vz-settings-category-contents'>
|
|
|
|
|
{children}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
} */}
|
|
|
|
|
</motion.div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|