slideOverPanel.tsx 1.4 KB

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