slideOverPanel.tsx 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import {ForwardedRef, forwardRef, useEffect} from 'react';
  2. import isPropValid from '@emotion/is-prop-valid';
  3. import styled from '@emotion/styled';
  4. import {motion} from 'framer-motion';
  5. const PANEL_WIDTH = '50vw';
  6. type SlideOverPanelProps = {
  7. children: React.ReactNode;
  8. collapsed: boolean;
  9. onOpen?: () => void;
  10. };
  11. export default forwardRef(SlideOverPanel);
  12. function SlideOverPanel(
  13. {collapsed, children, onOpen}: SlideOverPanelProps,
  14. ref: ForwardedRef<HTMLDivElement>
  15. ) {
  16. useEffect(() => {
  17. if (!collapsed && onOpen) {
  18. onOpen();
  19. }
  20. }, [collapsed, onOpen]);
  21. return (
  22. <_SlideOverPanel
  23. ref={ref}
  24. collapsed={collapsed}
  25. initial={{opacity: 0, x: PANEL_WIDTH}}
  26. animate={!collapsed ? {opacity: 1, x: 0} : {opacity: 0, x: PANEL_WIDTH}}
  27. transition={{
  28. type: 'spring',
  29. stiffness: 500,
  30. damping: 50,
  31. }}
  32. >
  33. {children}
  34. </_SlideOverPanel>
  35. );
  36. }
  37. const _SlideOverPanel = styled(motion.div, {
  38. shouldForwardProp: prop =>
  39. ['animate', 'transition', 'initial'].includes(prop) ||
  40. (prop !== 'collapsed' && isPropValid(prop)),
  41. })<{
  42. collapsed: boolean;
  43. }>`
  44. width: ${PANEL_WIDTH};
  45. position: fixed;
  46. top: 0;
  47. bottom: 0;
  48. right: 0;
  49. background: ${p => p.theme.background};
  50. color: ${p => p.theme.textColor};
  51. border-left: 1px solid ${p => p.theme.border};
  52. text-align: left;
  53. z-index: ${p => p.theme.zIndex.sidebar - 1};
  54. ${p =>
  55. p.collapsed
  56. ? 'overflow: hidden;'
  57. : `overflow-x: hidden;
  58. overflow-y: scroll;`}
  59. `;