index.tsx 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React, { useEffect } from 'react'
  4. import cn from 'classnames'
  5. import { useBoolean } from 'ahooks'
  6. import { ChevronRightIcon } from '@heroicons/react/24/outline'
  7. export type IPanelProps = {
  8. className?: string
  9. headerIcon: React.ReactNode
  10. title: React.ReactNode
  11. headerRight?: React.ReactNode
  12. bodyClassName?: string
  13. children: React.ReactNode
  14. keepUnFold?: boolean
  15. foldDisabled?: boolean
  16. onFoldChange?: (fold: boolean) => void
  17. controlUnFold?: number
  18. controlFold?: number
  19. }
  20. const Panel: FC<IPanelProps> = ({
  21. className,
  22. headerIcon,
  23. title,
  24. headerRight,
  25. bodyClassName,
  26. children,
  27. keepUnFold,
  28. foldDisabled = false,
  29. onFoldChange,
  30. controlUnFold,
  31. controlFold,
  32. }) => {
  33. const [fold, { setTrue: setFold, setFalse: setUnFold, toggle: toggleFold }] = useBoolean(!keepUnFold)
  34. useEffect(() => {
  35. onFoldChange?.(fold)
  36. }, [fold])
  37. useEffect(() => {
  38. if (controlUnFold)
  39. setUnFold()
  40. }, [controlUnFold])
  41. useEffect(() => {
  42. if (controlFold)
  43. setFold()
  44. }, [controlFold])
  45. // overflow-hidden
  46. return (
  47. <div className={cn(className, 'w-full rounded-xl border border-gray-100 overflow-hidden select-none')}>
  48. {/* Header */}
  49. <div
  50. onClick={() => (!foldDisabled && !keepUnFold) && toggleFold()}
  51. className={cn(!fold && 'border-b border-gray-100', 'flex justify-between items-center h-12 bg-gray-50 pl-4 pr-2')}>
  52. <div className='flex items-center gap-2'>
  53. {headerIcon}
  54. <div className='text-gray-900 text-sm'>{title}</div>
  55. </div>
  56. {(fold && headerRight) ? headerRight : ''}
  57. {!headerRight && !keepUnFold && (
  58. <ChevronRightIcon className={cn(!fold && 'rotate-90', 'mr-2 cursor-pointer')} width="16" height="16">
  59. </ChevronRightIcon>
  60. )}
  61. </div>
  62. {/* Main Content */}
  63. {!fold && !foldDisabled && (
  64. <div className={cn(bodyClassName)}>
  65. {children}
  66. </div>
  67. )}
  68. </div>
  69. )
  70. }
  71. export default React.memo(Panel)