function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) { ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } } return n; }, _extends.apply(null, arguments); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0) { ; } } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) { o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } } return i; }
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) { if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } } return t; }
/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * The OpenSearch Contributors require contributions made to
 * this file be licensed under the Apache-2.0 license or a
 * compatible open source license.
 *
 * Modifications Copyright OpenSearch Contributors. See
 * GitHub history for details.
 */

/*
 * Licensed to Elasticsearch B.V. under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch B.V. licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import React, { useEffect, useState, forwardRef, Fragment } from 'react';
import classnames from 'classnames';
import { keys, OuiWindowEvent, useCombinedRefs, isWithinMinBreakpoint, throttle } from '../../services';
import { keysOf } from '../common';
import { OuiFocusTrap } from '../focus_trap';
import { OuiOverlayMask } from '../overlay_mask';
import { OuiButtonIcon } from '../button';
import { OuiI18n } from '../i18n';
import { useResizeObserver } from '../observer/resize_observer';
import { OuiOutsideClickDetector } from '../outside_click_detector';
import { OuiPortal } from '../portal';
var typeToClassNameMap = {
  push: 'ouiFlyout--push',
  overlay: null
};
export var TYPES = keysOf(typeToClassNameMap);
var sideToClassNameMap = {
  left: 'ouiFlyout--left',
  right: null
};
export var SIDES = keysOf(sideToClassNameMap);
var sizeToClassNameMap = {
  s: 'ouiFlyout--small',
  m: 'ouiFlyout--medium',
  l: 'ouiFlyout--large'
};
export var SIZES = keysOf(sizeToClassNameMap);
/**
 * Custom type checker for named flyout sizes since the prop
 * `size` can also be CSSProperties['width'] (string | number)
 */
function isOuiFlyoutSizeNamed(value) {
  return SIZES.includes(value);
}
var paddingSizeToClassNameMap = {
  none: 'ouiFlyout--paddingNone',
  s: 'ouiFlyout--paddingSmall',
  m: 'ouiFlyout--paddingMedium',
  l: 'ouiFlyout--paddingLarge'
};
export var PADDING_SIZES = keysOf(paddingSizeToClassNameMap);

// Using ReactHTML rather than JSX.IntrinsicElements here because it does not include
// SVG element types which cause errors because they do not have all the attributes needed.

var OuiFlyout = /*#__PURE__*/forwardRef(function (_ref, ref) {
  var className = _ref.className,
    children = _ref.children,
    _ref$as = _ref.as,
    Element = _ref$as === void 0 ? 'div' : _ref$as,
    _ref$hideCloseButton = _ref.hideCloseButton,
    hideCloseButton = _ref$hideCloseButton === void 0 ? false : _ref$hideCloseButton,
    closeButtonProps = _ref.closeButtonProps,
    closeButtonAriaLabel = _ref.closeButtonAriaLabel,
    _ref$closeButtonPosit = _ref.closeButtonPosition,
    closeButtonPosition = _ref$closeButtonPosit === void 0 ? 'inside' : _ref$closeButtonPosit,
    onClose = _ref.onClose,
    _ref$ownFocus = _ref.ownFocus,
    ownFocus = _ref$ownFocus === void 0 ? true : _ref$ownFocus,
    _ref$side = _ref.side,
    side = _ref$side === void 0 ? 'right' : _ref$side,
    _ref$size = _ref.size,
    size = _ref$size === void 0 ? 'm' : _ref$size,
    _ref$paddingSize = _ref.paddingSize,
    paddingSize = _ref$paddingSize === void 0 ? 'l' : _ref$paddingSize,
    _ref$maxWidth = _ref.maxWidth,
    maxWidth = _ref$maxWidth === void 0 ? false : _ref$maxWidth,
    style = _ref.style,
    maskProps = _ref.maskProps,
    _ref$type = _ref.type,
    type = _ref$type === void 0 ? 'overlay' : _ref$type,
    _ref$outsideClickClos = _ref.outsideClickCloses,
    outsideClickCloses = _ref$outsideClickClos === void 0 ? false : _ref$outsideClickClos,
    _ref$role = _ref.role,
    role = _ref$role === void 0 ? 'dialog' : _ref$role,
    _ref$pushMinBreakpoin = _ref.pushMinBreakpoint,
    pushMinBreakpoint = _ref$pushMinBreakpoin === void 0 ? 'l' : _ref$pushMinBreakpoin,
    rest = _objectWithoutProperties(_ref, ["className", "children", "as", "hideCloseButton", "closeButtonProps", "closeButtonAriaLabel", "closeButtonPosition", "onClose", "ownFocus", "side", "size", "paddingSize", "maxWidth", "style", "maskProps", "type", "outsideClickCloses", "role", "pushMinBreakpoint"]);
  /**
   * Setting the initial state of pushed based on the `type` prop
   * and if the current window size is large enough (larger than `pushMinBreakpoint`)
   */
  var _useState = useState(isWithinMinBreakpoint(typeof window === 'undefined' ? 0 : window.innerWidth, pushMinBreakpoint)),
    _useState2 = _slicedToArray(_useState, 2),
    windowIsLargeEnoughToPush = _useState2[0],
    setWindowIsLargeEnoughToPush = _useState2[1];
  var isPushed = type === 'push' && windowIsLargeEnoughToPush;

  /**
   * Watcher added to the window to maintain `isPushed` state depending on
   * the window size compared to the `pushBreakpoint`
   */
  var functionToCallOnWindowResize = throttle(function () {
    if (isWithinMinBreakpoint(window.innerWidth, pushMinBreakpoint)) {
      setWindowIsLargeEnoughToPush(true);
    } else {
      setWindowIsLargeEnoughToPush(false);
    }
    // reacts every 50ms to resize changes and always gets the final update
  }, 50);

  /**
   * Setting up the refs on the actual flyout element in order to
   * accommodate for the `isPushed` state by adding padding to the body equal to the width of the element
   */
  var _useState3 = useState(null),
    _useState4 = _slicedToArray(_useState3, 2),
    resizeRef = _useState4[0],
    setResizeRef = _useState4[1];
  var setRef = useCombinedRefs([setResizeRef, ref]);
  // TODO: Allow this hooke to be conditional
  var dimensions = useResizeObserver(resizeRef);
  useEffect(function () {
    // This class doesn't actually do anything by OUI, but is nice to add for consumers (JIC)
    document.body.classList.add('ouiBody--hasFlyout');

    /**
     * Accomodate for the `isPushed` state by adding padding to the body equal to the width of the element
     */
    if (type === 'push') {
      // Only add the event listener if we'll need to accommodate with padding
      window.addEventListener('resize', functionToCallOnWindowResize);
      if (isPushed) {
        if (side === 'right') {
          document.body.style.paddingRight = "".concat(dimensions.width, "px");
        } else if (side === 'left') {
          document.body.style.paddingLeft = "".concat(dimensions.width, "px");
        }
      }
    }
    return function () {
      document.body.classList.remove('ouiBody--hasFlyout');
      if (type === 'push') {
        window.removeEventListener('resize', functionToCallOnWindowResize);
        if (side === 'right') {
          document.body.style.paddingRight = '';
        } else if (side === 'left') {
          document.body.style.paddingLeft = '';
        }
      }
    };
  }, [type, side, dimensions, isPushed, functionToCallOnWindowResize]);

  /**
   * ESC key closes flyout (always?)
   */
  var onKeyDown = function onKeyDown(event) {
    if (!isPushed && event.key === keys.ESCAPE) {
      event.preventDefault();
      onClose();
    }
  };
  var newStyle;
  var widthClassName;
  var sizeClassName;

  // Setting max-width
  if (maxWidth === true) {
    widthClassName = 'ouiFlyout--maxWidth-default';
  } else if (maxWidth !== false) {
    var value = typeof maxWidth === 'number' ? "".concat(maxWidth, "px") : maxWidth;
    newStyle = _objectSpread(_objectSpread({}, style), {}, {
      maxWidth: value
    });
  }

  // Setting size
  if (isOuiFlyoutSizeNamed(size)) {
    sizeClassName = sizeToClassNameMap[size];
  } else if (newStyle) {
    newStyle.width = size;
  } else {
    newStyle = _objectSpread(_objectSpread({}, style), {}, {
      width: size
    });
  }
  var classes = classnames('ouiFlyout', typeToClassNameMap[type], sideToClassNameMap[side], sizeClassName, paddingSizeToClassNameMap[paddingSize], widthClassName, className);
  var closeButton;
  if (onClose && !hideCloseButton) {
    var closeButtonClasses = classnames('ouiFlyout__closeButton', "ouiFlyout__closeButton--".concat(closeButtonPosition), closeButtonProps === null || closeButtonProps === void 0 ? void 0 : closeButtonProps.className);
    closeButton = /*#__PURE__*/React.createElement(OuiI18n, {
      token: "ouiFlyout.closeAriaLabel",
      default: "Close this dialog"
    }, function (closeAriaLabel) {
      return /*#__PURE__*/React.createElement(OuiButtonIcon, _extends({
        display: closeButtonPosition === 'outside' ? 'fill' : 'empty',
        iconType: "cross",
        color: "text",
        "aria-label": closeButtonAriaLabel || closeAriaLabel,
        "data-test-subj": "ouiFlyoutCloseButton"
      }, closeButtonProps, {
        className: closeButtonClasses,
        onClick: function onClick(e) {
          onClose();
          (closeButtonProps === null || closeButtonProps === void 0 ? void 0 : closeButtonProps.onClick) && closeButtonProps.onClick(e);
        }
      }));
    });
  }
  var flyoutContent =
  /*#__PURE__*/
  // @ts-expect-error JSX element without construct
  React.createElement(Element, _extends({}, rest, {
    role: role,
    className: classes,
    tabIndex: -1,
    style: newStyle || style,
    ref: setRef
  }), closeButton, children);

  /*
   * Trap focus even when `ownFocus={false}`, otherwise closing
   * the flyout won't return focus to the originating button.
   *
   * Set `clickOutsideDisables={true}` when `ownFocus={false}`
   * to allow non-keyboard users the ability to interact with
   * elements outside the flyout.
   */
  var flyout = /*#__PURE__*/React.createElement(OuiFocusTrap, {
    disabled: isPushed,
    clickOutsideDisables: !ownFocus
  }, /*#__PURE__*/React.createElement(OuiOutsideClickDetector, {
    isDisabled: isPushed || !outsideClickCloses,
    onOutsideClick: function onOutsideClick() {
      return onClose();
    }
  }, flyoutContent));

  // If ownFocus is set, wrap with an overlay and allow the user to click it to close it.
  if (ownFocus && !isPushed) {
    flyout = /*#__PURE__*/React.createElement(OuiOverlayMask, _extends({
      onClick: onClose,
      headerZindexLocation: "below"
    }, maskProps), flyout);
  } else if (!isPushed) {
    // Otherwise still wrap within an OuiPortal so it appends (unless it is the push style)
    flyout = /*#__PURE__*/React.createElement(OuiPortal, null, flyout);
  }
  return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(OuiWindowEvent, {
    event: "keydown",
    handler: onKeyDown
  }), flyout);
});
OuiFlyout.displayName = 'OuiFlyout';
export { OuiFlyout };

/* OUI -> EUI Aliases: Build-Time */