import _extends from "@babel/runtime/helpers/esm/extends";
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
var _excluded = ["open", "onExitTransitionEnd"];
import * as React from 'react';
import cx from 'classnames';
import { useBodyNoScroll } from './useBodyNoScroll';
import { useFocusTrap } from './useFocusTrap';
import DialogOverlay, { SLOTS } from './DialogOverlay'; // https://github.com/jsdom/jsdom/issues/1781

var supportsTransitions = function supportsTransitions() {
  return typeof window !== 'undefined' && typeof window.TransitionEvent !== 'undefined';
};

/**
 * The react-docgen has a problem with default values
 * of nested components (see BaseDialog inside the
 * Dialog) and this is for documentation purposes.
 */
Dialog.defaultProps = {
  size: 'm',
  scroll: 'outside',
  position: 'center',
  overlay: 'light',
  appearance: 'dialog'
};
/**
 * The Dialog component controls mounting
 * when BaseDialog controls its own states.
 */

function BaseDialog(_ref) {
  var open = _ref.open,
      children = _ref.children,
      _ref$size = _ref.size,
      size = _ref$size === void 0 ? 'm' : _ref$size,
      _ref$motionPreset = _ref.motionPreset,
      motionPreset = _ref$motionPreset === void 0 ? 'default' : _ref$motionPreset,
      _ref$scroll = _ref.scroll,
      scroll = _ref$scroll === void 0 ? 'outside' : _ref$scroll,
      ariaLabelledBy = _ref['aria-labelledby'],
      ariaLabel = _ref['aria-label'],
      ariaDescribedBy = _ref['aria-describedby'],
      ariaDescription = _ref['aria-description'],
      _ref$ariaModal = _ref['aria-modal'],
      ariaModal = _ref$ariaModal === void 0 ? true : _ref$ariaModal,
      _ref$zIndex = _ref.zIndex,
      zIndex = _ref$zIndex === void 0 ? 'auto' : _ref$zIndex,
      onDismiss = _ref.onDismiss,
      onEntryTransitionEnd = _ref.onEntryTransitionEnd,
      onExitTransitionEnd = _ref.onExitTransitionEnd,
      dataTestId = _ref['data-testid'],
      _ref$position = _ref.position,
      position = _ref$position === void 0 ? 'center' : _ref$position,
      _ref$overlay = _ref.overlay,
      overlay = _ref$overlay === void 0 ? 'light' : _ref$overlay,
      _ref$appearance = _ref.appearance,
      appearance = _ref$appearance === void 0 ? 'dialog' : _ref$appearance;
  var overlayRef = React.useRef(null);
  var containerRef = React.useRef(null);

  var _React$useState = React.useState(false),
      _React$useState2 = _slicedToArray(_React$useState, 2),
      exiting = _React$useState2[0],
      setExiting = _React$useState2[1];

  if (exiting === open) {
    setExiting(!open);
  }
  /**
   * The name of transition with the longest duration, because
   * a component can have an animation of many properties.
   */


  var lastTransitionName = exiting ? 'opacity' : 'transform';
  /**
   * CSS3 transition requires a deferredOpen value to be one
   * paint behind the actual open prop to trigger a transition.
   */

  var _React$useState3 = React.useState(false),
      _React$useState4 = _slicedToArray(_React$useState3, 2),
      deferredOpen = _React$useState4[0],
      setDeferredOpen = _React$useState4[1];

  var _React$useState5 = React.useState(false),
      _React$useState6 = _slicedToArray(_React$useState5, 2),
      hasFinishedTransition = _React$useState6[0],
      setHasFinishedTransition = _React$useState6[1];

  var _React$useState7 = React.useState(false),
      _React$useState8 = _slicedToArray(_React$useState7, 2),
      isDialogHigherThanOverlay = _React$useState8[0],
      setIsDialogHigherThanOverlay = _React$useState8[1];

  var hasAnimations = supportsTransitions() && motionPreset !== 'none';
  var cleanupBodyNoScroll = useBodyNoScroll(overlayRef);
  var fireTransitionEndCallbacks = React.useCallback(function () {
    setHasFinishedTransition(true);

    if (open) {
      if (onEntryTransitionEnd) {
        onEntryTransitionEnd();
      }
    } else if (onExitTransitionEnd) {
      cleanupBodyNoScroll();
      onExitTransitionEnd();
    }
  }, [open, onExitTransitionEnd, onEntryTransitionEnd, cleanupBodyNoScroll]);
  React.useEffect(function () {
    setDeferredOpen(open);

    if (!hasAnimations) {
      fireTransitionEndCallbacks();
    }
  }, [open, hasAnimations, fireTransitionEndCallbacks]);
  React.useEffect(function () {
    /**
     * Check if Dialog itself is higher than the overlay.
     * We need to check this, so we can determine if we should show scrollbars on the Dialog.
     */
    if (open) {
      // Didn't use optional chaining
      // as it causes ArgsTable and controls to not display correctly
      var dialogHeight = containerRef.current && containerRef.current.getBoundingClientRect().height;
      var overlayHeight = overlayRef.current && overlayRef.current.getBoundingClientRect().height;
      if (!dialogHeight || !overlayHeight) return;
      if (dialogHeight > overlayHeight) setIsDialogHigherThanOverlay(true);
    }
  }, [open, containerRef, overlayRef]);
  useFocusTrap({
    dialogRef: containerRef,
    overlayRef: overlayRef
  });
  var handleTransitionEnd = React.useCallback(function (event) {
    if (event.target === event.currentTarget && event.propertyName === lastTransitionName) {
      fireTransitionEndCallbacks();
    }
  }, [fireTransitionEndCallbacks, lastTransitionName]);
  var handleOverlayClick = React.useCallback(function (event) {
    if (onDismiss && event.target instanceof HTMLElement && event.target.closest('[data-dialog-container="true"]') !== containerRef.current) {
      onDismiss();
    }

    event.stopPropagation();
  }, [onDismiss]);
  var handleKeyUp = React.useCallback(function (event) {
    if (onDismiss && event.key === 'Escape') {
      onDismiss();
      event.stopPropagation();
    }
  }, [onDismiss]);
  var overlayClass = cx('js-dialog', 'sg-dialog__overlay', "sg-dialog__overlay--size-".concat(size), "sg-dialog__overlay--open--".concat(overlay), "sg-dialog__overlay--motion-".concat(motionPreset), {
    'sg-dialog__overlay--scroll': (isDialogHigherThanOverlay || hasFinishedTransition) && scroll === 'outside',
    'sg-dialog__overlay--open': deferredOpen,
    'sg-dialog__overlay--fullscreen': size === 'fullscreen',
    'sg-dialog__overlay--space-top': position === 'top'
  });
  var containerClass = cx('sg-dialog__container', "sg-dialog__container--motion-".concat(motionPreset), {
    'sg-dialog__container--fullscreen': size === 'fullscreen',
    'sg-dialog__container--scroll': scroll === 'inside',
    'sg-dialog__container--open': deferredOpen,
    'sg-dialog__container--exiting': exiting,
    'sg-dialog__container--top': position === 'top',
    'sg-dialog__container--appearance-dialog': appearance === 'dialog',
    'sg-dialog__container--fullscreen--motion-none': size === 'fullscreen' && motionPreset === 'none',
    'sg-dialog__container--fullscreen--motion-default': size === 'fullscreen' && motionPreset === 'default'
  });
  var childrenWithoutSlots = React.useMemo(function () {
    return React.Children.toArray(children).filter(function (reactNode) {
      return /*#__PURE__*/React.isValidElement(reactNode) && reactNode.type !== DialogOverlay || ! /*#__PURE__*/React.isValidElement(reactNode);
    });
  }, [children]);
  var childrenWithSlots = React.useMemo(function () {
    return React.Children.toArray(children).filter(function (reactNode) {
      return /*#__PURE__*/React.isValidElement(reactNode) && reactNode.type === DialogOverlay;
    });
  }, [children]);
  var childrenBySlot = React.useMemo(function () {
    return SLOTS.reduce(function (acc, next) {
      childrenWithSlots.filter(function (child) {
        return /*#__PURE__*/React.isValidElement(child) && child.props.slot === next;
      }).forEach(function (child) {
        if (!acc[next]) {
          acc[next] = [];
        }

        acc[next].push(child);
      });
      return acc;
    }, {});
  }, [childrenWithSlots]);
  return /*#__PURE__*/React.createElement("div", {
    className: overlayClass,
    style: {
      zIndex: zIndex
    },
    onClick: onDismiss ? handleOverlayClick : undefined,
    onKeyUp: handleKeyUp,
    ref: overlayRef
  }, childrenBySlot.backdrop ? /*#__PURE__*/React.createElement("span", {
    className: "sg-dialog-overlay-slot--backdrop"
  }, childrenBySlot.backdrop) : null, SLOTS.filter(function (slot) {
    return slot !== 'backdrop';
  }).map(function (slot) {
    return /*#__PURE__*/React.createElement("div", {
      className: cx('sg-dialog-overlay-slot', "sg-dialog-overlay-slot--".concat(slot), {
        'sg-dialog-overlay-slot--hidden': !childrenBySlot[slot] || size === 'fullscreen'
      }),
      key: slot
    }, childrenBySlot[slot] ? childrenBySlot[slot] : null);
  }), /*#__PURE__*/React.createElement("div", {
    tabIndex: 0
  }), /*#__PURE__*/React.createElement("div", {
    role: "dialog",
    ref: containerRef,
    "data-dialog-container": true,
    className: containerClass,
    onTransitionEnd: hasAnimations ? handleTransitionEnd : undefined,
    "aria-modal": ariaModal,
    "aria-labelledby": ariaLabelledBy,
    "aria-label": ariaLabel,
    "aria-describedby": ariaDescribedBy,
    "aria-description": ariaDescription,
    tabIndex: -1,
    "data-testid": dataTestId,
    "data-animating": !hasFinishedTransition
  }, childrenWithoutSlots), /*#__PURE__*/React.createElement("div", {
    tabIndex: 0
  }));
}

function Dialog(_ref2) {
  var open = _ref2.open,
      onExitTransitionEnd = _ref2.onExitTransitionEnd,
      otherProps = _objectWithoutProperties(_ref2, _excluded);

  var _React$useState9 = React.useState(open),
      _React$useState10 = _slicedToArray(_React$useState9, 2),
      mounted = _React$useState10[0],
      setMounted = _React$useState10[1];

  if (open && !mounted) {
    setMounted(true);
  }

  var handleExitTransitionEnd = React.useCallback(function () {
    setMounted(false); // proxy an actual event

    if (onExitTransitionEnd) {
      onExitTransitionEnd();
    }
  }, [onExitTransitionEnd]);
  return mounted ? /*#__PURE__*/React.createElement(BaseDialog, _extends({}, otherProps, {
    onExitTransitionEnd: handleExitTransitionEnd,
    open: open
  })) : null;
}

Dialog.Overlay = DialogOverlay;
export default Dialog;