import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useCallback, forwardRef, useState, useRef } from 'react';
import styled, { css } from 'styled-components';
import { remToPx } from 'polished';
import { useOuterEvent, useConsolidatedRef, usePrevious, useDirection } from '../../hooks';
import { getChildOfRootNode, reflow } from '../../utils';
import { defaultThemeProp } from '../../theme';
import { resizeDrawerKeyboardStep, resizeDrawerMaxWidth, resizeDrawerMinWidth } from '../../styles/constants';
import ResizeHandle from './ResizeHandle';
const drawerMinWidth = remToPx(resizeDrawerMinWidth);
export const StyledDrawer = styled.div(props => {
    const { state, shadow, position, placement, transitionSpeed, size, resizeable, theme } = props;
    let dimension = 'horizontal';
    let axis = 'X';
    let anchor = 'top';
    if (placement === 'top' || placement === 'bottom') {
        dimension = 'vertical';
        axis = 'Y';
        anchor = 'left';
    }
    const translate = state === 'open' || state === 'opening' ? 0 : '100%';
    const speed = transitionSpeed || theme.base.animation.speed;
    return css `
    z-index: ${theme.base['z-index'].drawer};
    position: ${position};
    ${placement}: 0;
    ${anchor}: 0;
    height: ${dimension === 'vertical' ? size : '100%'};
    width: ${dimension === 'horizontal' ? size : '100%'};
    transition-property: transform, box-shadow, opacity;
    transition-duration: max(${speed}, 0.0001s);
    transition-timing-function: ${theme.base.animation.timing.ease};
    transform: ${state === 'open'
        ? 'none'
        : `translate${axis}(${placement === 'top' || placement === 'left' ? '-' : ''}${translate})`};

    ${shadow &&
        css `
      box-shadow: ${theme.base.shadow.high};
    `}

    ${resizeable &&
        css `
      width: ${dimension === 'horizontal' ? 'var(--resize-drawer-width)' : '100%'};
    `}
  `;
});
StyledDrawer.defaultProps = defaultThemeProp;
export const Drawer = forwardRef(function Drawer(props, ref) {
    const { open = false, shadow = false, position = 'absolute', children, placement = 'right', transitionSpeed, size = '100%', resizeable = false, onAfterOpen, onAfterClose, onBeforeOpen, onBeforeClose, onOuterClick, nullWhenClosed = false, ...restProps } = props;
    const drawerRef = useConsolidatedRef(ref);
    const { ltr, rtl } = useDirection();
    const [state, setState] = useState(open ? 'open' : 'closed');
    let prevState = usePrevious(state);
    if (!prevState)
        prevState = state;
    useOuterEvent('mousedown', [drawerRef], useCallback(() => {
        if (open)
            onOuterClick?.();
    }, [open, onOuterClick]));
    useEffect(() => {
        if (open && (state === 'closed' || state === 'closing')) {
            onBeforeOpen?.();
            reflow(drawerRef.current);
            setState('opening');
        }
        else if (!open && (state === 'open' || state === 'opening')) {
            onBeforeClose?.();
            setState('closing');
        }
        else if (open && state === 'open' && prevState !== 'open') {
            onAfterOpen?.();
        }
        else if (!open && state === 'closed' && prevState !== 'closed') {
            onAfterClose?.();
        }
    }, [open, state, prevState, onBeforeOpen, onBeforeClose, onAfterOpen, onAfterClose]);
    const onTransitionEnd = useCallback((e) => {
        if (e.target !== drawerRef.current || e.propertyName !== 'transform')
            return;
        setState(open ? 'open' : 'closed');
    }, [open]);
    const dragStartXRef = useRef();
    useEffect(() => {
        if (!resizeable || !drawerRef.current)
            return;
        const targetNode = getChildOfRootNode(drawerRef);
        if (!targetNode)
            return;
        if (!targetNode.style.getPropertyValue('--resize-drawer-width')) {
            targetNode.style.setProperty('--resize-drawer-width', size);
        }
    }, [drawerRef.current]);
    const handleResize = useCallback((e) => {
        const targetNode = getChildOfRootNode(drawerRef);
        const rect = drawerRef.current?.getBoundingClientRect();
        if (!rect || !targetNode)
            return;
        dragStartXRef.current = e.clientX;
        const ac = new AbortController();
        targetNode.addEventListener('mousemove', moveEvent => {
            if (!dragStartXRef.current || !rect.width)
                return;
            const initialX = dragStartXRef.current;
            const widthDiff = placement === 'right' ? initialX - moveEvent.clientX : moveEvent.clientX - initialX;
            const newWidth = Math.max(widthDiff + rect.width, parseInt(drawerMinWidth, 10));
            // Set root-level CSS variable to communicate width to AppShell
            targetNode.style.setProperty('--resize-drawer-width', `clamp(${drawerMinWidth}, ${newWidth}px, ${resizeDrawerMaxWidth})`);
        }, { passive: true, signal: ac.signal });
        targetNode.addEventListener('mouseup', () => {
            ac.abort();
        }, { once: true });
    }, [placement]);
    const keyboardResize = useCallback((e, grabbed) => {
        if (!grabbed)
            return;
        const targetNode = getChildOfRootNode(drawerRef);
        const resizeStep = document.documentElement.clientWidth * resizeDrawerKeyboardStep;
        const rect = drawerRef.current?.getBoundingClientRect();
        if (!rect || !targetNode)
            return;
        if (e.code !== 'ArrowLeft' && e.code !== 'ArrowRight')
            return;
        e.preventDefault();
        const resizeDirection = (e.code === 'ArrowLeft' ? 1 : -1) * (placement === 'right' ? 1 : -1);
        const newWidth = Math.max(rect.width + resizeDirection * resizeStep, parseInt(drawerMinWidth, 10));
        targetNode.style.setProperty('--resize-drawer-width', `clamp(${drawerMinWidth}, ${newWidth}px, ${resizeDrawerMaxWidth})`);
    }, [placement]);
    const renderResizeHandle = resizeable &&
        state === 'open' &&
        ((placement === 'left' && rtl) || (placement === 'right' && ltr));
    return state === 'closed' && !open && nullWhenClosed ? null : (_jsxs(StyledDrawer, { ref: drawerRef, position: position, shadow: shadow && open, transitionSpeed: transitionSpeed, placement: placement, size: size, resizeable: resizeable, open: open, state: state, onTransitionEnd: onTransitionEnd, ...restProps, children: [children, renderResizeHandle && _jsx(ResizeHandle, { onMouseDown: handleResize, onKeyDown: keyboardResize })] }));
});
export default Drawer;
//# sourceMappingURL=Drawer.js.map