import React from 'react';
import PropTypes from 'prop-types';
import FocusLock from 'react-focus-lock';
import { SoftOutsideClickDetector } from '../OutsideClickDetector';
const OutsideEventDetector = ({ children, handleEvent, ...rest }) => {
    const eventHanders = ['onMouseDown', 'onTouchStart'].reduce((obj, eventName) => {
        obj[eventName] = handleEvent;
        return obj;
    }, {});
    return (React.createElement("div", Object.assign({}, eventHanders, rest), children));
};
export class SoftFocusTrap extends React.Component {
    constructor() {
        super(...arguments);
        this.state = {
            hasBeenDisabledByClick: false
        };
        this.lastInterceptedEvent = null;
        this.preventFocusExit = false;
        // Programmatically sets focus on a nested DOM node; optional
        this.setInitalFocus = (initialFocus) => {
            let node = initialFocus;
            if (typeof node === 'string') {
                node = document.querySelector(initialFocus);
            }
            if (typeof node === 'function') {
                node = initialFocus();
            }
            if (!node)
                return;
            // `data-autofocus` is part of the 'react-focus-lock' API
            node.setAttribute('data-autofocus', true);
        };
        // Sets whether the focus trap has been disabled by clicks outside its component tree
        // Only applicable for `clickOutsideDisables`
        this.toggleDisabled = (shouldDisable = !this.state.hasBeenDisabledByClick) => {
            this.setState({
                hasBeenDisabledByClick: shouldDisable
            });
        };
        // Sets whether an event has been prevented from disabling the focus trap
        // Only applicable for `clickOutsideDisables`
        this.toggleExitPrevented = (shouldPrevent = !this.preventFocusExit) => {
            this.preventFocusExit = shouldPrevent;
        };
        // Event handler to determine whether a mouse or key event should disable the focus trap
        // Only applicable for `clickOutsideDisables`
        this.handleOutsideClick = (event) => {
            this.toggleExitPrevented(false);
            if (this.preventFocusExit && event.target === this.lastInterceptedEvent.target)
                return;
            this.toggleDisabled(true);
        };
        // Event handler to capture events from within the focus trap subtree and prevent them from disabling the trap (mostly for portals)
        // Only applicable for `clickOutsideDisables`
        this.handleBubbledEvent = (e) => {
            this.lastInterceptedEvent = e.nativeEvent;
            this.toggleExitPrevented(true);
        };
    }
    componentDidMount() {
        this.setInitalFocus(this.props.initialFocus);
    }
    render() {
        const { children, clickOutsideDisables, disabled, ...rest } = this.props;
        const isDisabled = disabled || this.state.hasBeenDisabledByClick;
        const lockProps = {
            disabled: isDisabled,
            ...rest
        };
        return (clickOutsideDisables ? (React.createElement(SoftOutsideClickDetector, { isDisabled: isDisabled, onOutsideClick: this.handleOutsideClick },
            React.createElement(OutsideEventDetector, { handleEvent: this.handleBubbledEvent },
                React.createElement(FocusLock, Object.assign({}, lockProps), children)))) : (React.createElement(FocusLock, Object.assign({}, lockProps), children)));
    }
}
SoftFocusTrap.propTypes = {
    children: PropTypes.node.isRequired,
    /**
     * Disables the focus trap when clicks occur outside of the trapped area
     */
    clickOutsideDisables: PropTypes.bool,
    /**
     * From `react-focus-lock`.
     * Focus will not be trapped if false
     */
    disabled: PropTypes.bool,
    /**
     * A DOM node, a selector string (which will be passed to
     * `document.querySelector()` to find the DOM node), or a function that
     * returns a DOM node.
     */
    initialFocus: PropTypes.oneOfType([
        PropTypes.instanceOf(HTMLElement),
        PropTypes.func,
        PropTypes.string,
    ]),
    /**
     * From `react-focus-lock`.
     * When exiting/disabling, focus will return to the element that previously help focus
     */
    returnFocus: PropTypes.bool
};
SoftFocusTrap.defaultProps = {
    clickOutsideDisables: false,
    disabled: false,
    returnFocus: true
};
//# sourceMappingURL=SoftFocusTrap.js.map