/* @oracle/oraclejet-preact: undefined */
'use strict';

var jsxRuntime = require('preact/jsx-runtime');
var compat = require('preact/compat');
var WindowOverlay = require('./WindowOverlay-7ef8a86f.js');
var useTestId = require('./useTestId-32c35bff.js');
var useAnimation = require('./useAnimation-fb11e4cc.js');
var hooks = require('preact/hooks');
var refUtils = require('./refUtils-915b985d.js');
var UNSAFE_Dialog_themes_redwood_DialogTheme = require('./UNSAFE_Dialog/themes/redwood/DialogTheme.js');
var FocusTrap = require('./FocusTrap-3d81c5e3.js');
var Layer = require('./Layer-2352de5e.js');
require('./LayerHost-8ec73638.js');
var Modal = require('./Modal-64a0608b.js');
var classNames = require('./classNames-c14c6ef3.js');
var ImageVars_css = require('./ImageVars.css-3fbb1c0b.js');
var useComponentTheme = require('./useComponentTheme-082fc8e4.js');
var useId = require('./useId-6c0eeb27.js');
var dimensions = require('./dimensions-b4be9793.js');
var mergeInterpolations = require('./mergeInterpolations-6727b536.js');
var useResizeObserver = require('./useResizeObserver-1597395f.js');
var useDraggable = require('./useDraggable-aa4ac3a2.js');
var Floating = require('./Floating-dd6667de.js');
var IconButton = require('./IconButton-fad4e4b2.js');
var Close = require('./Close-e7ca2eed.js');
var Resizable = require('./Resizable-e5428244.js');
var useBreakpoints = require('./useBreakpoints-f5c06998.js');
var useTranslationBundle = require('./useTranslationBundle-38c0edae.js');
var animationUtils = require('./animationUtils-54852d03.js');
var tabbableUtils = require('./tabbableUtils-66ae6ba3.js');

const StyledDialogHeader = ({ children, id, cancelBehavior, onClose, draggableProps, headerDecoration = 'on' }) => {
    const { styles } = useComponentTheme.useComponentTheme(UNSAFE_Dialog_themes_redwood_DialogTheme.DialogRedwoodTheme);
    const classes = classNames.classNames([
        styles.dialogHeaderStyle,
        ...(headerDecoration === 'on' ? [styles.dialogHeaderDecorationStyle] : [])
    ]);
    const content = typeof children === 'string' ? (jsxRuntime.jsx("h1", { id: id, className: styles.dialogTitleStyle, children: children })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: children }));
    const translations = useTranslationBundle.useTranslationBundle('@oracle/oraclejet-preact');
    const handleIconClose = () => {
        onClose?.({ reason: 'icon' });
    };
    const closeIcon = cancelBehavior === 'icon' ? (jsxRuntime.jsx("div", { children: jsxRuntime.jsx("div", { className: styles.dialogHeaderCloseIconStyle, children: jsxRuntime.jsx(IconButton.IconButton, { "aria-label": translations.message_close(), size: "sm", variant: "ghost", onAction: handleIconClose, children: jsxRuntime.jsx(Close.SvgClose, {}) }) }) })) : null;
    return (jsxRuntime.jsxs("div", { className: classes, ...draggableProps, children: [content, closeIcon] }));
};
const StyledDialogFooter = compat.forwardRef(({ children, style }, ref) => {
    return (jsxRuntime.jsx("div", { ref: ref, className: style, children: children }));
});
const StyledDialog = compat.forwardRef(({ children, header, footer, visibility, labelId, role, ariaLabelledBy, ariaDescribedBy, cancelBehavior, draggableProps, isResizable, headerDecoration, containerRef, onClose, onResizeStart, onResize, onResizeEnd, onKeyDown, testId, style, footerRef }, ref) => {
    const elementRef = hooks.useRef(null);
    const mergedRef = refUtils.mergeRefs(ref, elementRef);
    const [isSmallHeight, setSmallHeight] = hooks.useState(false);
    const isSmallWidth = !useBreakpoints.useBreakpoints()['md'];
    const { classes: styleClasses, styles } = useComponentTheme.useComponentTheme(UNSAFE_Dialog_themes_redwood_DialogTheme.DialogRedwoodTheme);
    const resizeHandler = hooks.useCallback(() => {
        if (elementRef.current) {
            if (elementRef.current.clientHeight < 400) {
                setSmallHeight(true);
            }
            else {
                setSmallHeight(false);
            }
        }
    }, []);
    // set initial Height
    hooks.useEffect(() => {
        resizeHandler();
    }, [resizeHandler]);
    useResizeObserver.useResizeObserver(elementRef, resizeHandler);
    // for small widths (mobile), use the 'smallWidth' dialog style
    // otherwise, check for small height to apply 'smallWidth' or 'desktop' styles accordingly
    const baseStyle = isSmallWidth ? styles.baseStyleSmallWidth : styles.baseStyleDesktop;
    // content should scroll depending on the viewport height
    // on large screens, the header and footer should be "sticky",
    // at small viewport heights, the entire content should be scrollable
    const contentStyle = isSmallHeight
        ? styles.dialogContentStyleNoShrink
        : styles.dialogContentStyle;
    const visibilityStyle = visibility === 'visible' ? styles.visibilityVisible : styles.visibilityHidden;
    const testIdProps = useTestId.useTestId(testId);
    return (jsxRuntime.jsx(FocusTrap.FocusTrap, { restoreFocusRef: false, children: jsxRuntime.jsxs("div", { ref: mergedRef, tabIndex: -1, className: classNames.classNames([styleClasses, baseStyle, visibilityStyle, ImageVars_css.globalImages]), style: style, onKeyDown: onKeyDown, role: role, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, ...testIdProps, children: [jsxRuntime.jsxs("div", { className: styles.dialogContainerStyle, children: [jsxRuntime.jsx(StyledDialogHeader, { id: labelId, onClose: onClose, headerDecoration: headerDecoration, cancelBehavior: cancelBehavior, draggableProps: draggableProps, children: header }), jsxRuntime.jsx("div", { className: contentStyle, children: jsxRuntime.jsx("div", { className: styles.dialogBodyStyle, children: children }) }), jsxRuntime.jsx(StyledDialogFooter, { ref: footerRef, style: styles.dialogFooterStyle, children: footer })] }), isResizable && (jsxRuntime.jsx(Resizable.Resizable, { onResizeStart: onResizeStart, onResize: onResize, onResizeEnd: onResizeEnd, containerRef: containerRef }))] }) }));
});
// main Dialog component
/**
 * WAI-ARIA-compliant dialog component. A dialog is a floating window that typically contains
 * a title bar and a content area.
 * The dialog is generally placed on top of the rest of the page content. It can be either modal
 * (only the content in the dialog can be interacted with) or non-modal (it's still possible
 * to interact with content outside of the dialog).
 */
const Dialog = compat.forwardRef(({ children, isOpen, header = '', footer, modality = 'modal', launcherRef, anchorRef, placement, offset = 0, cancelBehavior = 'none', dragAffordance = 'none', resizeBehavior = 'none', headerDecoration = 'on', onDragStart, onDragMove, onDragEnd, onResizeStart, onResize, onResizeEnd, onFocusSet, onClose, onTransitionEnd, role = 'dialog', 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, testId, ...props }, ref) => {
    const [status, setStatus] = hooks.useState(isOpen ? 'initial' : 'unmounted');
    const [visibility, setVisibility] = hooks.useState('hidden');
    const prevStatusRef = hooks.useRef('unmounted');
    const floatingRef = hooks.useRef(null);
    const contentWrapperRef = hooks.useRef(null);
    const localLauncherRef = hooks.useRef(null);
    const footerRef = hooks.useRef(null);
    const isSmallWidth = !useBreakpoints.useBreakpoints()['md'];
    const derivedPlacement = isSmallWidth ? 'bottom' : placement ? placement : 'center';
    const animationType = isSmallWidth
        ? status === 'opening'
            ? 'slideUp'
            : 'slideDown'
        : status === 'opening'
            ? 'zoomIn'
            : 'zoomOut';
    const uniqueId = useId.useId();
    const labelId = ariaLabelledBy ? ariaLabelledBy : uniqueId;
    const interpolations = [...Object.values(dimensions.dimensionInterpolations)];
    const styleInterpolations = mergeInterpolations.mergeInterpolations(interpolations);
    const { ...styles } = styleInterpolations(props);
    const shouldReturnFocus = hooks.useRef(false);
    const setInitialFocus = hooks.useCallback(() => {
        // Focus on first tabbable in the Dialog container or container itself if there is none
        if (footerRef.current && tabbableUtils.allTabbableElements(footerRef.current).length > 0) {
            tabbableUtils.focusWithin(footerRef.current);
        }
        else {
            tabbableUtils.focusWithin(contentWrapperRef.current);
        }
        onFocusSet?.();
    }, [onFocusSet]);
    const returnFocus = hooks.useCallback(() => {
        const launcherEl = localLauncherRef.current;
        if (shouldReturnFocus.current && launcherEl) {
            tabbableUtils.focusOn(launcherEl);
            shouldReturnFocus.current = false;
        }
    }, []);
    // Animation
    const { nodeRef } = useAnimation.useAnimation(animationType, {
        animationStates,
        isAnimatedOnMount: true,
        onAnimationEnd: () => {
            if (isOpen) {
                onTransitionEnd?.(true);
            }
            else if (!isOpen) {
                // Should return focus?
                // Modeless: check whether Dialog contains focus before it unmounts
                // Modal: always return focus
                shouldReturnFocus.current =
                    contentWrapperRef.current?.contains(tabbableUtils.getActiveElement()) || false;
                nodeRef(null);
                setVisibility('hidden');
                setStatus('unmounted');
                onTransitionEnd?.(false);
            }
        }
    });
    const mergedRef = hooks.useMemo(() => refUtils.mergeRefs(contentWrapperRef, ref), [contentWrapperRef, ref]);
    const launcherKeyDownCallback = hooks.useCallback((event) => {
        if (localLauncherRef.current === tabbableUtils.getActiveElement() && event.code === 'F6') {
            // Prevent default F6 handlers.
            // F6 is a standard Chrome address bar shortcut on Windows.
            event.preventDefault();
            event.stopPropagation();
            tabbableUtils.focusWithin(contentWrapperRef.current);
            onFocusSet?.();
        }
    }, 
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [modality]);
    const { draggableProps } = useDraggable.useDraggable({
        isDisabled: dragAffordance === 'none',
        containerRef: floatingRef,
        onDragStart,
        onDragMove,
        onDragEnd
    });
    hooks.useEffect(() => {
        // 1. Ignore status update on initial render or return focus on component unmount
        if (status === 'unmounted' && !isOpen) {
            if (status !== prevStatusRef.current) {
                returnFocus();
            }
        }
        // 2. Mount visually hidden component
        // Component gets mounted, but will be visually hidden to avoid flickering
        // Flickering happens because it gets rendered before animation hook repositions
        // it in next render cycle
        else if (status === 'unmounted' && isOpen) {
            setStatus('initial');
        }
        // 3. Setup animation
        // Component has been mounted.
        // We will kick out animation as node is already present in DOM.
        // To avoid flickering, we still keep it visually hidden until the next render cycle.
        else if (status === 'initial' && isOpen) {
            nodeRef(contentWrapperRef.current);
            setStatus('opening');
        }
        // 3. Unhide component. It becomes visible.
        else if (status === 'opening' && isOpen) {
            setVisibility('visible');
        }
        // 4. Closing
        else if (!isOpen) {
            setStatus('closing');
        }
        return () => {
            // remember the previous status
            prevStatusRef.current = status;
        };
    }, [isOpen, status, nodeRef, returnFocus]);
    // Destroy case handler
    hooks.useEffect(() => {
        return () => {
            const launcherEl = localLauncherRef.current;
            if (
            // eslint-disable-next-line react-hooks/exhaustive-deps
            (contentWrapperRef.current?.contains(tabbableUtils.getActiveElement()) || false) &&
                launcherEl) {
                // In destroy case ModalManager is blocking returning of the focus.
                // We need to reschedule it to workaround that
                setTimeout(() => {
                    tabbableUtils.focusOn(launcherEl);
                }, 0);
            }
        };
    }, []);
    // Initialize launcher
    hooks.useEffect(() => {
        if (isOpen) {
            if (!launcherRef?.current) {
                // 1. If launcher is not defined, most frequent scenario is,
                // that element, that has focus before opening the dialog is considered launcher
                localLauncherRef.current = tabbableUtils.getActiveElement();
            }
            else if (launcherRef.current instanceof Element) {
                // 2. launcherRef element was provided.
                // Verify, if it exists in DOM, otherwise use the last active element
                localLauncherRef.current = document.body.contains(launcherRef.current)
                    ? launcherRef.current
                    : tabbableUtils.getActiveElement();
            }
            else {
                localLauncherRef.current = tabbableUtils.getActiveElement();
            }
            // Register F6 key handler to enter a modeless dialog
            if (modality === 'modeless') {
                localLauncherRef.current?.addEventListener('keydown', launcherKeyDownCallback);
            }
        }
        return () => {
            // Deregister F6 key handler
            if (modality === 'modeless') {
                localLauncherRef.current?.removeEventListener('keydown', launcherKeyDownCallback);
            }
        };
    }, [isOpen, launcherRef, launcherKeyDownCallback, modality]);
    // setInitialFocus when the dialog becomes visible
    hooks.useEffect(() => {
        if (visibility === 'visible') {
            setInitialFocus();
        }
    }, [visibility, setInitialFocus]);
    const handleKeyDown = (event) => {
        switch (event.code) {
            case 'Escape':
                onClose?.({ reason: 'escapeKey' });
                break;
            case 'F6':
                // Focus launcher
                if (localLauncherRef.current && modality === 'modeless') {
                    tabbableUtils.focusOn(localLauncherRef.current);
                }
                // Prevent default F6 handlers. F6 is a standard Chrome address bar shortcut on Windows.
                event.preventDefault();
                event.stopPropagation();
                break;
        }
    };
    const handleBackdropClick = () => {
        // in case of a backdrop click, move focus to dialog's root element
        contentWrapperRef.current?.focus();
    };
    const renderDialogContent = () => {
        return (jsxRuntime.jsx(StyledDialog, { ref: mergedRef, labelId: labelId, header: header, footer: footer, role: role, ariaLabelledBy: labelId, ariaDescribedBy: ariaDescribedBy, onKeyDown: handleKeyDown, testId: testId, style: styles, visibility: visibility, cancelBehavior: cancelBehavior, draggableProps: draggableProps, isResizable: resizeBehavior === 'resizable', headerDecoration: headerDecoration, containerRef: floatingRef, onClose: onClose, onResizeStart: onResizeStart, onResize: onResize, onResizeEnd: onResizeEnd, footerRef: footerRef, children: children }));
    };
    const renderDialog = () => {
        if (anchorRef && anchorRef.current) {
            return (jsxRuntime.jsx(Floating.Floating, { ref: floatingRef, anchorRef: anchorRef, placement: 'bottom-start', flipOptions: { mainAxis: false, crossAxis: false }, shiftOptions: { mainAxis: false, crossAxis: false }, children: renderDialogContent() }));
        }
        else {
            return (jsxRuntime.jsx(WindowOverlay.WindowOverlay, { placement: derivedPlacement, offset: offset, children: renderDialogContent() }));
        }
    };
    if (modality === 'modal') {
        return (jsxRuntime.jsx(Modal.Modal, { isOpen: status !== 'unmounted', onBackdropClick: handleBackdropClick, children: renderDialog() }));
    }
    else {
        return status !== 'unmounted' ? jsxRuntime.jsx(Layer.Layer, { children: renderDialog() }) : null;
    }
});
const animationStates = {
    zoomIn: {
        from: {
            scaleX: 0.9,
            scaleY: 0.9,
            transformOrigin: 'center',
            opacity: 0
        },
        to: {
            scaleX: 1,
            scaleY: 1,
            opacity: 1
        },
        options: {
            duration: 200
        }
    },
    zoomOut: {
        from: {
            scaleX: 1,
            scaleY: 1,
            transformOrigin: 'center',
            opacity: 1
        },
        to: {
            scaleX: 0.9,
            scaleY: 0.9,
            opacity: 0
        },
        options: {
            duration: 200
        }
    },
    slideUp: {
        ...animationUtils.SLIDE_UP_XLARGE,
        options: {
            duration: animationUtils.DURATION_LARGE
        }
    },
    slideDown: {
        ...animationUtils.SLIDE_DOWN_XLARGE,
        options: {
            duration: animationUtils.DURATION_LARGE
        }
    }
};

exports.Dialog = Dialog;
//# sourceMappingURL=Dialog-4a0ba834.js.map
