"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.DropdownDecorator = exports.DropdownBase = exports.Dropdown = exports["default"] = void 0;

var _jsxRuntime = require("react/jsx-runtime");

var _dispatcher = require("@enact/core/dispatcher");

var _handle = require("@enact/core/handle");

var _hoc = _interopRequireDefault(require("@enact/core/hoc"));

var _keymap = require("@enact/core/keymap");

var _kind = _interopRequireDefault(require("@enact/core/kind"));

var _util = require("@enact/core/util");

var _spotlight = _interopRequireDefault(require("@enact/spotlight"));

var _SpotlightContainerDecorator = _interopRequireDefault(require("@enact/spotlight/SpotlightContainerDecorator"));

var _Changeable = _interopRequireDefault(require("@enact/ui/Changeable"));

var _Group = _interopRequireDefault(require("@enact/ui/Group"));

var _IdProvider = _interopRequireDefault(require("@enact/ui/internal/IdProvider"));

var _resolution = _interopRequireDefault(require("@enact/ui/resolution"));

var _Toggleable = _interopRequireDefault(require("@enact/ui/Toggleable"));

var _Transition = _interopRequireDefault(require("@enact/ui/Transition"));

var _classnames3 = _interopRequireDefault(require("classnames"));

var _propTypes = _interopRequireDefault(require("prop-types"));

var _compose = _interopRequireDefault(require("ramda/src/compose"));

var _react = require("react");

var _reactDom = _interopRequireDefault(require("react-dom"));

var _Button = _interopRequireDefault(require("../Button"));

var _Icon = _interopRequireDefault(require("../Icon"));

var _Item = _interopRequireDefault(require("../Item"));

var _RadioItem = _interopRequireDefault(require("../RadioItem"));

var _Scroller = _interopRequireDefault(require("../Scroller"));

var _Skinnable = _interopRequireDefault(require("../Skinnable"));

var _DropdownModule = _interopRequireDefault(require("./Dropdown.module.css"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }

function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }

function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _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(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

var oppositeDirection = {
  left: 'right',
  right: 'left',
  up: 'down',
  down: 'up'
};
var ContainerDiv = (0, _SpotlightContainerDecorator["default"])({
  enterTo: 'last-focused'
}, 'div');

var isSelectedValid = function isSelectedValid(_ref) {
  var children = _ref.children,
      selected = _ref.selected;
  return Array.isArray(children) && children[selected] != null;
};

var handleTransitionHide = function handleTransitionHide(ev, _ref2) {
  var containerId = _ref2['data-spotlight-id'];
  var containerSelector = "[data-spotlight-id='".concat(containerId, "']");

  var current = _spotlight["default"].getCurrent();

  if (!_spotlight["default"].isPaused() && current && document.querySelector("".concat(containerSelector, " .").concat(_DropdownModule["default"].dropdownList)).contains(current)) {
    var focusResult = _spotlight["default"].focus("".concat(containerSelector, " .").concat(_DropdownModule["default"].dropdown));

    if (!focusResult && _spotlight["default"].getPointerMode()) {
      document.querySelector("".concat(containerSelector, " .").concat(_DropdownModule["default"].dropdown)).focus();
    }
  }
}; // Add keymap for escape key


(0, _keymap.add)('cancel', 27);
/**
 * A stateless Dropdown component.
 *
 * @class DropdownBase
 * @memberof agate/Dropdown
 * @ui
 * @public
 */

var DropdownBase = (0, _kind["default"])({
  name: 'Dropdown',
  propTypes:
  /** @lends agate/Dropdown.DropdownBase.prototype */
  {
    /**
     * The selections for Dropdown
     *
     * @type {String[]|Array.<{key: (Number|String), children: (String|Component)}>}
     * @public
     */
    children: _propTypes["default"].array,

    /**
     * Customizes the component by mapping the supplied collection of CSS class names to the
     * corresponding internal elements and states of this component.
     *
     * @type {Object}
     * @private
     */
    css: _propTypes["default"].object,

    /**
     * This is passed onto the wrapped component to allow
     * it to customize the spotlight container for its use case.
     *
     * @type {String}
     * @private
     */
    'data-spotlight-id': _propTypes["default"].string,

    /**
     * The direction where the dropdown list appears.
     *
     * @type {('left'|'right'|'down'|'up')}
     * @default 'down'
     * @public
     */
    direction: _propTypes["default"].oneOf(['down', 'left', 'right', 'up']),

    /**
     * Disables Dropdown and becomes non-interactive.
     *
     * @type {Boolean}
     * @public
     */
    disabled: _propTypes["default"].bool,

    /**
     * Called when the Dropdown is closing.
     *
     * @type {Function}
     * @public
     */
    onClose: _propTypes["default"].func,

    /**
     * Called when the Dropdown is opening.
     *
     * @type {Function}
     * @public
     */
    onOpen: _propTypes["default"].func,

    /**
     * Called when an item is selected.
     *
     * @type {Function}
     * @public
     */
    onSelect: _propTypes["default"].func,

    /**
     * Displays the items.
     *
     * @type {Boolean}
     * @default false
     * @public
     */
    open: _propTypes["default"].bool,

    /**
     * Index of the selected item.
     *
     * @type {Number}
     * @public
     */
    selected: _propTypes["default"].number,

    /**
     * The current skin for this component.
     *
     * @type {String}
     * @public
     */
    skin: _propTypes["default"].string,

    /**
     * The primary title text of Dropdown.
     *
     * The title will be replaced with the selected item, if set.
     *
     * @type {String}
     * @public
     */
    title: _propTypes["default"].string
  },
  defaultProps: {
    direction: 'down',
    open: false
  },
  handlers: {
    onSelect: (0, _handle.handle)((0, _handle.forward)('onSelect'), (0, _handle.forward)('onClose'), handleTransitionHide),
    onOpen: (0, _handle.handle)((0, _handle.forProp)('open', false), (0, _handle.forward)('onOpen')),
    onScrollerClick: (0, _handle.handle)(function (ev) {
      return ev.stopPropagation();
    })
  },
  styles: {
    css: _DropdownModule["default"],
    className: 'dropdown',
    publicClassNames: true
  },
  computed: {
    adjustedDirection: function adjustedDirection(_ref3) {
      var direction = _ref3.direction,
          containerId = _ref3['data-spotlight-id'];

      if (typeof window !== 'undefined') {
        var calcOverflow = function calcOverflow(container, client, wrapper) {
          var KEEPOUT = _resolution["default"].scale(24); // keep out distance on the edge of the screen


          var wrapperTop = wrapper && wrapper.top || 0;
          var wrapperBottom = wrapper && wrapper.bottom || window.innerHeight;
          var overflow = {
            isOverTop: client.top - container.height - KEEPOUT < wrapperTop,
            isOverBottom: client.bottom + container.height + KEEPOUT > wrapperBottom
          };
          return overflow;
        };

        var adjustDirection = function adjustDirection(overflow) {
          var adjustedDirection = direction;

          if (overflow.isOverTop && !overflow.isOverBottom && direction === 'up') {
            adjustedDirection = 'down';
          } else if (overflow.isOverBottom && !overflow.isOverTop && direction === 'down') {
            adjustedDirection = 'up';
          }

          return adjustedDirection;
        };

        var containerSelector = "[data-spotlight-id='".concat(containerId, "']");
        var containerNode = document.querySelector("".concat(containerSelector, " .").concat(_DropdownModule["default"].dropdownList));
        var clientNode = document.querySelector("".concat(containerSelector, " .").concat(_DropdownModule["default"].dropdown));
        var wrapperNode = clientNode && clientNode.closest('div[style*=overflow]');

        if (containerNode && clientNode) {
          var containerNodeRect = containerNode.getBoundingClientRect();
          var clientNodeRect = clientNode.getBoundingClientRect();
          var wrapperNodeRect = wrapperNode && wrapperNode.getBoundingClientRect();
          return adjustDirection(calcOverflow(containerNodeRect, clientNodeRect, wrapperNodeRect));
        }
      }

      return direction;
    },
    buttonClassName: function buttonClassName(_ref4) {
      var open = _ref4.open,
          styler = _ref4.styler;
      return styler.append({
        open: open
      });
    },
    children: function children(_ref5) {
      var _children = _ref5.children,
          selected = _ref5.selected;
      if (!Array.isArray(_children)) return [];
      return _children.map(function (child, i) {
        var aria = {
          role: 'checkbox',
          'aria-checked': selected === i
        };

        if (typeof child === 'string') {
          return _objectSpread(_objectSpread({}, aria), {}, {
            children: child,
            key: "item_".concat(child)
          });
        }

        return _objectSpread(_objectSpread({}, aria), child);
      });
    },
    dropdownListClassName: function dropdownListClassName(_ref6) {
      var children = _ref6.children,
          css = _ref6.css,
          styler = _ref6.styler;
      return styler.join(css.dropdownList, {
        dropdownListWithScroller: children.length > 4
      });
    },
    title: function title(_ref7) {
      var children = _ref7.children,
          selected = _ref7.selected,
          _title = _ref7.title;

      if (isSelectedValid({
        children: children,
        selected: selected
      })) {
        var child = children[selected];
        return typeof child === 'object' ? child.children : child;
      }

      return _title;
    },
    hasChildren: function hasChildren(_ref8) {
      var children = _ref8.children;
      return children.length > 0;
    }
  },
  render: function render(_ref9) {
    var _classnames2;

    var adjustedDirection = _ref9.adjustedDirection,
        buttonClassName = _ref9.buttonClassName,
        children = _ref9.children,
        css = _ref9.css,
        dropdownListClassName = _ref9.dropdownListClassName,
        disabled = _ref9.disabled,
        hasChildren = _ref9.hasChildren,
        onClose = _ref9.onClose,
        onOpen = _ref9.onOpen,
        onScrollerClick = _ref9.onScrollerClick,
        onSelect = _ref9.onSelect,
        open = _ref9.open,
        selected = _ref9.selected,
        skin = _ref9.skin,
        title = _ref9.title,
        rest = _objectWithoutProperties(_ref9, ["adjustedDirection", "buttonClassName", "children", "css", "dropdownListClassName", "disabled", "hasChildren", "onClose", "onOpen", "onScrollerClick", "onSelect", "open", "selected", "skin", "title"]);

    var ariaProps = (0, _util.extractAriaProps)(rest);
    var dropdownButtonClassName = (0, _classnames3["default"])(css.dropdownButton, _defineProperty({}, css.upDropdownButton, adjustedDirection === 'up'));
    var opened = !disabled && open;
    var transitionContainerClassName = (0, _classnames3["default"])(css.transitionContainer, (_classnames2 = {}, _defineProperty(_classnames2, css.openTransitionContainer, open), _defineProperty(_classnames2, css.upTransitionContainer, adjustedDirection === 'up'), _classnames2));

    var _ref10 = skin === 'silicon' ? [_Button["default"], {
      icon: open ? 'arrowlargeup' : 'arrowlargedown',
      iconPosition: 'after',
      minWidth: true
    }, {
      className: dropdownButtonClassName
    }, {
      'night': false
    }, {
      childComponent: _RadioItem["default"],
      itemProps: {
        size: 'small',
        className: css.dropDownListItem,
        css: css
      },
      selectedProp: 'selected'
    }, []] : [_Item["default"], {}, {}, {}, {
      childComponent: _Item["default"]
    }, [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon["default"], {
      slot: "slotAfter",
      className: css.icon,
      size: "small",
      children: open ? 'arrowlargeup' : 'arrowlargedown'
    }, "icon")]],
        _ref11 = _slicedToArray(_ref10, 6),
        DropDownButton = _ref11[0],
        dropDownButtonProps = _ref11[1],
        wrapperProps = _ref11[2],
        skinVariants = _ref11[3],
        groupProps = _ref11[4],
        iconComponent = _ref11[5];

    return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", _objectSpread(_objectSpread({}, rest), {}, {
      children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", _objectSpread(_objectSpread({}, wrapperProps), {}, {
        children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(DropDownButton, _objectSpread(_objectSpread(_objectSpread({
          role: "button",
          className: buttonClassName,
          css: css,
          disabled: hasChildren ? disabled : true,
          onClick: opened ? onClose : onOpen
        }, dropDownButtonProps), ariaProps), {}, {
          children: [iconComponent, title]
        })), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Transition["default"], {
          className: transitionContainerClassName,
          visible: opened,
          direction: oppositeDirection[adjustedDirection],
          children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ContainerDiv, {
            className: dropdownListClassName,
            spotlightDisabled: !open,
            spotlightRestrict: "self-only",
            children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Scroller["default"], {
              skinVariants: skinVariants,
              className: css.scroller,
              onClick: onScrollerClick,
              children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Group["default"], _objectSpread(_objectSpread({
                role: null,
                className: css.group,
                onSelect: onSelect,
                selected: selected
              }, groupProps), {}, {
                children: children || []
              }))
            })
          })
        })]
      }))
    }));
  }
});
exports.DropdownBase = DropdownBase;
var DropDownExtended = (0, _hoc["default"])(function (config, Wrapped) {
  var _class, _temp;

  return _temp = _class = /*#__PURE__*/function (_Component) {
    _inherits(_class, _Component);

    var _super = _createSuper(_class);

    function _class(props) {
      var _this;

      _classCallCheck(this, _class);

      _this = _super.call(this, props);

      _this.clickedOutsideDropdown = function (_ref12) {
        var target = _ref12.target;
        return !_this.node.contains(target);
      };

      _this.handleClick = (0, _handle.handle)(_this.clickedOutsideDropdown, (0, _handle.forward)('onClick')).bindAs(_assertThisInitialized(_this), 'handleClick');
      _this.handleKeyDown = (0, _handle.handle)((0, _handle.forKey)('cancel'), (0, _handle.forward)('onClick')).bindAs(_assertThisInitialized(_this), 'handleKeyDown');
      return _this;
    }

    _createClass(_class, [{
      key: "componentDidMount",
      value: function componentDidMount() {
        // eslint-disable-next-line react/no-find-dom-node
        this.node = _reactDom["default"].findDOMNode(this);

        if (this.props.open) {
          (0, _dispatcher.on)('click', this.handleClick);
          (0, _dispatcher.on)('keydown', this.handleKeyDown);
        }
      }
    }, {
      key: "componentDidUpdate",
      value: function componentDidUpdate(prevProps) {
        var open = this.props.open;

        if (!prevProps.open && open) {
          (0, _dispatcher.on)('click', this.handleClick);
          (0, _dispatcher.on)('keydown', this.handleKeyDown);
        } else if (prevProps.open && !open) {
          (0, _dispatcher.off)('click', this.handleClick);
          (0, _dispatcher.off)('keydown', this.handleKeyDown);
        }
      }
    }, {
      key: "componentWillUnmount",
      value: function componentWillUnmount() {
        (0, _dispatcher.off)('click', this.handleClick);
        (0, _dispatcher.off)('keydown', this.handleKeyDown);
      }
    }, {
      key: "render",
      value: function render() {
        return /*#__PURE__*/(0, _jsxRuntime.jsx)(Wrapped, _objectSpread({}, this.props));
      }
    }]);

    return _class;
  }(_react.Component), _class.displayName = 'DropDownExtended', _class.propTypes = {
    open: _propTypes["default"].bool
  }, _temp;
});
/**
 * Applies Agate specific behaviors to [DropdownBase]{@link agate/Dropdown.DropdownBase}.
 *
 * @hoc
 * @memberof agate/Dropdown
 * @mixes agate/Skinnable.Skinnable
 * @public
 */

var DropdownDecorator = (0, _compose["default"])((0, _SpotlightContainerDecorator["default"])({
  enterTo: 'default-element',
  preserveId: true
}), (0, _IdProvider["default"])({
  generateProp: null,
  prefix: 'd_'
}), (0, _Toggleable["default"])({
  toggle: null,
  prop: 'open',
  activate: 'onOpen',
  deactivate: 'onClose',
  toggleProp: 'onClick'
}), (0, _Changeable["default"])({
  change: 'onSelect',
  prop: 'selected'
}), DropDownExtended, (0, _Skinnable["default"])({
  prop: 'skin'
}));
/**
 * An Agate Dropdown component.
 *
 * By default, `Dropdown` maintains the state of its `selected` property. Supply the
 * `defaultSelected` property to control its initial value. If you wish to directly control updates
 * to the component, supply a value to `selected` at creation time and update it in response to
 * `onSelect` events.
 *
 * @class Dropdown
 * @memberof agate/Dropdown
 * @extends agate/Dropdown.DropdownBase
 * @mixes agate/Dropdown.DropdownDecorator
 * @ui
 * @public
 */

exports.DropdownDecorator = DropdownDecorator;
var Dropdown = DropdownDecorator(DropdownBase);
exports.Dropdown = Dropdown;
var _default = Dropdown;
exports["default"] = _default;