index.tsx 2.0 KB

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