{"version":3,"file":"DraggablePanel.mjs","names":["useControlledState","defaultSize: Size","Center","Icon"],"sources":["../../src/DraggablePanel/DraggablePanel.tsx"],"sourcesContent":["'use client';\n\nimport { useHover } from 'ahooks';\nimport { ConfigProvider } from 'antd';\nimport { cx } from 'antd-style';\nimport isEqual from 'fast-deep-equal';\nimport { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from 'lucide-react';\nimport type { Enable, NumberSize, Size } from 're-resizable';\nimport { Resizable } from 're-resizable';\nimport {\n  memo,\n  use,\n  useCallback,\n  useEffect,\n  useMemo,\n  useReducer,\n  useRef,\n  useTransition,\n} from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { Center } from '@/Flex';\nimport Icon from '@/Icon';\n\nimport { handleVariants, panelVariants, styles, toggleVariants } from './style';\nimport type { DraggablePanelProps } from './type';\nimport { reversePlacement } from './utils';\n\n// Constants\nconst DEFAULT_HEIGHT = 180;\nconst DEFAULT_WIDTH = 280;\nconst DEFAULT_HEADER_HEIGHT = 0;\nconst DEFAULT_PIN = true;\nconst DEFAULT_MODE = 'fixed';\nconst DEFAULT_EXPANDABLE = true;\nconst DEFAULT_EXPAND = true;\nconst DEFAULT_SHOW_HANDLE_WIDE_AREA = true;\n\n// State reducer for better state management\ninterface DraggablePanelState {\n  isResizing: boolean;\n  showExpand: boolean;\n}\n\ntype DraggablePanelAction =\n  | { type: 'START_RESIZE' }\n  | { type: 'STOP_RESIZE' }\n  | { payload: boolean; type: 'SET_SHOW_EXPAND' };\n\nfunction draggablePanelReducer(\n  state: DraggablePanelState,\n  action: DraggablePanelAction,\n): DraggablePanelState {\n  switch (action.type) {\n    case 'START_RESIZE': {\n      return { ...state, isResizing: true, showExpand: false };\n    }\n    case 'STOP_RESIZE': {\n      return { ...state, isResizing: false, showExpand: true };\n    }\n    case 'SET_SHOW_EXPAND': {\n      return { ...state, showExpand: action.payload };\n    }\n    default: {\n      return state;\n    }\n  }\n}\n\nconst DraggablePanel = memo<DraggablePanelProps>(\n  ({\n    headerHeight = DEFAULT_HEADER_HEIGHT,\n    fullscreen,\n    maxHeight,\n    pin = DEFAULT_PIN,\n    mode = DEFAULT_MODE,\n    children,\n    placement = 'right',\n    resize,\n    style,\n    showBorder = true,\n    showHandleHighlight = false,\n    showHandleWideArea = DEFAULT_SHOW_HANDLE_WIDE_AREA,\n    backgroundColor,\n    size,\n    defaultSize: customizeDefaultSize,\n    minWidth,\n    minHeight,\n    maxWidth,\n    onSizeChange,\n    onSizeDragging,\n    expandable = DEFAULT_EXPANDABLE,\n    expand,\n    defaultExpand = DEFAULT_EXPAND,\n    onExpandChange,\n    className,\n    showHandleWhenCollapsed,\n    destroyOnClose,\n    styles: customStyles,\n    classNames,\n    dir,\n  }) => {\n    const ref = useRef<HTMLDivElement>(null);\n    const isHovering = useHover(ref);\n    const isVertical = placement === 'top' || placement === 'bottom';\n    const [isPending, startTransition] = useTransition();\n\n    // Use ref for hover timeout to avoid memory leaks\n    const hoverTimeoutRef = useRef<any>(undefined);\n\n    // inherit direction from Ant Design ConfigProvider\n    const { direction: antdDirection } = use(ConfigProvider.ConfigContext);\n    const direction = dir ?? antdDirection;\n\n    // Handle RTL direction\n    const internalPlacement = useMemo(() => {\n      return direction === 'rtl' && ['left', 'right'].includes(placement)\n        ? placement === 'left'\n          ? 'right'\n          : 'left'\n        : placement;\n    }, [direction, placement]);\n\n    const cssVariables = useMemo<Record<string, string>>(\n      () => ({\n        '--draggable-panel-bg': backgroundColor || '',\n        '--draggable-panel-header-height': `${headerHeight}px`,\n      }),\n      [backgroundColor, headerHeight],\n    );\n\n    const [isExpand, setIsExpand] = useControlledState(defaultExpand, {\n      onChange: onExpandChange,\n      value: expand,\n    });\n\n    // Initialize state with useReducer for better performance\n    const initialState: DraggablePanelState = {\n      isResizing: false,\n      showExpand: true,\n    };\n\n    const [state, dispatch] = useReducer(draggablePanelReducer, initialState);\n\n    // Auto-expand on hover if not pinned with optimized transition\n    useEffect(() => {\n      if (pin) return;\n\n      // Clear previous timeout\n      if (hoverTimeoutRef.current) {\n        clearTimeout(hoverTimeoutRef.current);\n      }\n\n      if (isHovering && !isExpand) {\n        startTransition(() => {\n          setIsExpand(true);\n        });\n      } else if (!isHovering && isExpand) {\n        // Add a small delay before collapsing to prevent flickering\n        hoverTimeoutRef.current = setTimeout(() => {\n          startTransition(() => {\n            setIsExpand(false);\n          });\n        }, 150);\n      }\n    }, [pin, isHovering, isExpand, setIsExpand]);\n\n    // Cleanup timeout on unmount\n    useEffect(() => {\n      return () => {\n        if (hoverTimeoutRef.current) {\n          clearTimeout(hoverTimeoutRef.current);\n        }\n      };\n    }, []);\n\n    const canResizing = resize !== false && isExpand;\n\n    // Configure resizing handles\n    const resizing = useMemo(\n      () => ({\n        bottom: false,\n        bottomLeft: false,\n        bottomRight: false,\n        left: false,\n        right: false,\n        top: false,\n        topLeft: false,\n        topRight: false,\n        [reversePlacement(internalPlacement)]: true,\n        ...(resize as Enable),\n      }),\n      [internalPlacement, resize],\n    );\n\n    // Calculate default size based on orientation\n    const defaultSize: Size = useMemo(() => {\n      if (isVertical)\n        return {\n          height: DEFAULT_HEIGHT,\n          width: '100%',\n          ...customizeDefaultSize,\n        };\n\n      return {\n        height: '100%',\n        width: DEFAULT_WIDTH,\n        ...customizeDefaultSize,\n      };\n    }, [isVertical, customizeDefaultSize]);\n\n    // Determine appropriate size props based on expand state\n    const sizeProps = useMemo(() => {\n      if (!isExpand) {\n        return isVertical\n          ? { minHeight: 0, size: { height: 0 } }\n          : { minWidth: 0, size: { width: 0 } };\n      }\n\n      return {\n        defaultSize,\n        maxHeight: typeof maxHeight === 'number' ? Math.max(maxHeight, 0) : maxHeight,\n        maxWidth: typeof maxWidth === 'number' ? Math.max(maxWidth, 0) : maxWidth,\n        minHeight: typeof minHeight === 'number' ? Math.max(minHeight, 0) : minHeight,\n        minWidth: typeof minWidth === 'number' ? Math.max(minWidth, 0) : minWidth,\n        size: size as Size,\n      };\n    }, [isExpand, isVertical, defaultSize, maxHeight, maxWidth, minHeight, minWidth, size]);\n\n    // Determine the appropriate arrow icon based on placement\n    const Arrow = useMemo(() => {\n      switch (internalPlacement) {\n        case 'top': {\n          return ChevronDown;\n        }\n        case 'bottom': {\n          return ChevronUp;\n        }\n        case 'right': {\n          return ChevronLeft;\n        }\n        case 'left': {\n          return ChevronRight;\n        }\n        default: {\n          return ChevronLeft;\n        }\n      }\n    }, [internalPlacement]);\n\n    // Toggle expand state with transition for better performance\n    const toggleExpand = useCallback(() => {\n      if (!expandable) return;\n\n      startTransition(() => {\n        setIsExpand(!isExpand);\n      });\n    }, [expandable, isExpand, setIsExpand]);\n\n    // Toggle handle component\n    const handle = useMemo(\n      () => (\n        <Center\n          className={toggleVariants({ placement: internalPlacement, showHandleWideArea })}\n          style={{ opacity: isExpand ? (pin ? undefined : 0) : showHandleWhenCollapsed ? 1 : 0 }}\n        >\n          <Center\n            className={classNames?.handle}\n            style={customStyles?.handle}\n            onClick={toggleExpand}\n          >\n            <Icon\n              className={styles.handlerIcon}\n              icon={Arrow}\n              size={16}\n              style={{\n                marginBottom: internalPlacement === 'top' ? 4 : 0,\n                marginLeft: internalPlacement === 'right' ? 4 : 0,\n                marginRight: internalPlacement === 'left' ? 4 : 0,\n                marginTop: internalPlacement === 'bottom' ? 4 : 0,\n                transform: `rotate(${isExpand ? 180 : 0}deg)`,\n                transition: 'transform 0.3s ease',\n              }}\n            />\n          </Center>\n        </Center>\n      ),\n      [\n        toggleVariants,\n        internalPlacement,\n        isExpand,\n        pin,\n        showHandleWhenCollapsed,\n        classNames?.handle,\n        toggleExpand,\n        customStyles?.handle,\n        styles.handlerIcon,\n        Arrow,\n      ],\n    );\n\n    // Handle resize events with memoization\n    const handleResize = useCallback(\n      (_: unknown, _direction: unknown, reference_: HTMLElement, delta: NumberSize) => {\n        onSizeDragging?.(delta, {\n          height: reference_.style.height,\n          width: reference_.style.width,\n        });\n      },\n      [onSizeDragging],\n    );\n\n    const handleResizeStart = useCallback(() => {\n      dispatch({ type: 'START_RESIZE' });\n    }, []);\n\n    const handleResizeStop = useCallback(\n      (e: unknown, direction: unknown, reference_: HTMLElement, delta: NumberSize) => {\n        dispatch({ type: 'STOP_RESIZE' });\n        onSizeChange?.(delta, {\n          height: reference_.style.height,\n          width: reference_.style.width,\n        });\n      },\n      [onSizeChange],\n    );\n\n    // Main panel content\n    const inner = useMemo(\n      () => (\n        <Resizable\n          {...sizeProps}\n          className={cx(styles.panel, classNames?.content)}\n          enable={canResizing ? (resizing as Enable) : undefined}\n          handleClasses={\n            canResizing\n              ? {\n                  [reversePlacement(internalPlacement)]: cx(\n                    handleVariants({\n                      placement: reversePlacement(internalPlacement),\n                    }),\n                    showHandleHighlight && styles.handleHighlight,\n                  ),\n                }\n              : {}\n          }\n          style={{\n            ...cssVariables,\n            opacity: isPending ? 0.95 : 1,\n            transition: state.isResizing ? 'unset' : undefined,\n            ...style,\n          }}\n          onResize={handleResize}\n          onResizeStart={handleResizeStart}\n          onResizeStop={handleResizeStop}\n        >\n          {children}\n        </Resizable>\n      ),\n      [\n        sizeProps,\n        styles.panel,\n        classNames?.content,\n        canResizing,\n        resizing,\n        internalPlacement,\n        handleVariants,\n        showHandleHighlight,\n        styles.handleHighlight,\n        handleResize,\n        handleResizeStart,\n        handleResizeStop,\n        state.isResizing,\n        isPending,\n        style,\n        children,\n        cx,\n      ],\n    );\n\n    // For fullscreen mode, return a simpler layout\n    if (fullscreen) {\n      return (\n        <div className={cx(styles.fullscreen, className)} style={cssVariables}>\n          {children}\n        </div>\n      );\n    }\n\n    return (\n      <aside\n        dir={dir}\n        ref={ref}\n        style={cssVariables}\n        className={cx(\n          panelVariants({\n            isExpand,\n            mode,\n            placement: internalPlacement,\n            showBorder,\n          }),\n          className,\n        )}\n      >\n        {expandable && state.showExpand && handle}\n        {destroyOnClose ? isExpand && inner : inner}\n      </aside>\n    );\n  },\n  isEqual,\n);\n\nDraggablePanel.displayName = 'DraggablePanel';\n\nexport default DraggablePanel;\n"],"mappings":"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"}