// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useEffect, useImperativeHandle, useRef } from 'react';
import clsx from 'clsx';
import { useStableCallback, useUniqueId } from '@cloudscape-design/component-toolkit/internal';
import { useRuntimeDrawerContext } from '../app-layout/runtime-drawer/use-runtime-drawer-context';
import { useAppLayoutToolbarDesignEnabled } from '../app-layout/utils/feature-flags';
import InternalButton from '../button/internal';
import { BuiltInErrorBoundary } from '../error-boundary/internal';
import { useInternalI18n } from '../i18n/context';
import { getBaseProps } from '../internal/base-component';
import FocusLock from '../internal/components/focus-lock';
import { getAllFocusables, isFocusable } from '../internal/components/focus-lock/utils';
import { fireNonCancelableEvent } from '../internal/events';
import { useEffectOnUpdate } from '../internal/hooks/use-effect-on-update';
import { createWidgetizedComponent } from '../internal/widgets';
import InternalLiveRegion from '../live-region/internal';
import InternalStatusIndicator from '../status-indicator/internal';
import { useStickyFooter } from './use-sticky-footer';
import { getPositionStyles } from './utils';
import styles from './styles.css.js';
import testClasses from './test-classes/styles.css.js';
export function DrawerImplementation({ header, footer, children, loading, i18nStrings, disableContentPaddings, __internalRootRef, __ref, headerActions, position = 'static', placement = 'end', offset, stickyOffset, zIndex, closeAction, hideCloseAction = false, backdrop = false, open, onClose, ariaLabel, ariaLabelledby, focusBehavior, role, ...restProps }) {
    var _a, _b;
    const containerRef = useRef(null);
    const footerRef = useRef(null);
    const returnFocusTargetRef = useRef(null);
    const baseProps = getBaseProps(restProps);
    const isToolbar = useAppLayoutToolbarDesignEnabled();
    const i18n = useInternalI18n('drawer');
    const positionStyles = getPositionStyles({ position, placement, offset, stickyOffset, zIndex });
    const headerId = useUniqueId('drawer-header');
    const defaultRegionLabelledBy = header ? headerId : undefined;
    ariaLabelledby = ariaLabelledby !== null && ariaLabelledby !== void 0 ? ariaLabelledby : (ariaLabel ? undefined : defaultRegionLabelledBy);
    role = role !== null && role !== void 0 ? role : (position === 'static' ? 'presentation' : 'region');
    const roleProps = role === 'region'
        ? { role: 'region', tabIndex: -1, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby }
        : {};
    const containerProps = {
        ref: containerRef,
        ...roleProps,
        style: positionStyles.style,
        className: clsx(styles.drawer, loading && styles['content-with-paddings'], isToolbar && styles['with-toolbar'], !!footer && styles['with-footer'], closeAction && !hideCloseAction && styles['has-close-action'], positionStyles.className),
    };
    const focusIn = useStableCallback(() => {
        var _a;
        returnFocusTargetRef.current = document.activeElement;
        if (containerRef.current && isFocusable(containerRef.current)) {
            containerRef.current.focus();
        }
        else if (containerRef.current) {
            (_a = getAllFocusables(containerRef.current)[0]) === null || _a === void 0 ? void 0 : _a.focus();
        }
    });
    const focusOut = useStableCallback(() => {
        if (focusBehavior === null || focusBehavior === void 0 ? void 0 : focusBehavior.returnFocus) {
            focusBehavior.returnFocus();
        }
        else if (returnFocusTargetRef.current && returnFocusTargetRef.current.isConnected) {
            returnFocusTargetRef.current.focus();
        }
        returnFocusTargetRef.current = null;
    });
    const autoFocusRef = useRef(false);
    autoFocusRef.current = (_a = focusBehavior === null || focusBehavior === void 0 ? void 0 : focusBehavior.autoFocus) !== null && _a !== void 0 ? _a : true;
    // The use-effect-on-update ensures no focus transition on component's initial render.
    // If focus transition is needed - the drawerRef.current.focus() should be used instead.
    useEffectOnUpdate(() => {
        if (open === undefined) {
            return;
        }
        if (open && autoFocusRef.current) {
            focusIn();
        }
        if (!open) {
            focusOut();
        }
    }, [open, focusIn, focusOut]);
    const handleClose = useStableCallback((method) => fireNonCancelableEvent(onClose, { method }));
    useImperativeHandle(__ref, () => ({ focus: () => { var _a; return (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.focus(); } }), []);
    const runtimeDrawerContext = useRuntimeDrawerContext({ rootRef: __internalRootRef });
    const hasAdditionalDrawerAction = !!(runtimeDrawerContext === null || runtimeDrawerContext === void 0 ? void 0 : runtimeDrawerContext.isExpandable);
    const { isSticky: isFooterSticky } = useStickyFooter({
        rootRef: __internalRootRef,
        drawerRef: containerRef,
        footerRef,
    });
    const showBackdrop = backdrop && (position === 'fixed' || position === 'absolute');
    const trapFocus = (_b = focusBehavior === null || focusBehavior === void 0 ? void 0 : focusBehavior.trapFocus) !== null && _b !== void 0 ? _b : showBackdrop;
    useEffect(() => {
        if (!showBackdrop) {
            return;
        }
        const onKeyDown = (event) => {
            if (event.key === 'Escape') {
                handleClose('escape');
            }
        };
        document.addEventListener('keydown', onKeyDown);
        return () => document.removeEventListener('keydown', onKeyDown);
    }, [showBackdrop, handleClose]);
    return (React.createElement("div", { ...baseProps, className: clsx(baseProps.className, styles.root, testClasses.root, open === false && styles.hidden), ref: __internalRootRef },
        showBackdrop && (React.createElement("div", { className: clsx(styles.backdrop, testClasses.backdrop, styles[`backdrop-${position}`]), style: { zIndex }, onClick: () => handleClose('backdrop-click') })),
        React.createElement(FocusLock, { disabled: !trapFocus, className: styles['focus-trap'] },
            React.createElement("div", { ...containerProps }, loading ? (React.createElement(InternalStatusIndicator, { type: "loading" },
                React.createElement(InternalLiveRegion, { tagName: "span" }, i18n('i18nStrings.loadingText', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.loadingText)))) : (React.createElement(React.Fragment, null,
                header && (React.createElement("div", { className: clsx(styles.header, runtimeDrawerContext && styles['with-runtime-context'], hasAdditionalDrawerAction && styles['with-additional-action'], hideCloseAction && styles['hide-close-action']) },
                    React.createElement("span", { id: headerId }, header),
                    headerActions && React.createElement("div", { className: styles['header-actions'] }, headerActions))),
                closeAction && !hideCloseAction && (React.createElement("div", { className: styles['close-action'] },
                    React.createElement(InternalButton, { variant: "icon", iconName: "close", ...closeAction, className: testClasses['close-action'], onClick: () => handleClose('close-action') }))),
                React.createElement("div", { className: clsx(styles['test-utils-drawer-content'], styles.content, !disableContentPaddings && styles['content-with-paddings']) },
                    React.createElement(BuiltInErrorBoundary, null, children)),
                footer && (React.createElement("div", { ref: footerRef, className: clsx(styles.footer, {
                        [styles['is-sticky']]: isFooterSticky,
                    }) }, footer))))))));
}
export const createWidgetizedDrawer = createWidgetizedComponent(DrawerImplementation);
//# sourceMappingURL=implementation.js.map