var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
define(["require", "exports", 'react', '../../common/DirectionalHint', '../../FocusZone', '../../utilities/KeyCodes', '../../utilities/eventGroup/EventGroup', '../../utilities/css', '../../utilities/rtl', '../../utilities/Async/Async', '../../Callout', './ContextualMenu.scss'], function (require, exports, React, DirectionalHint_1, FocusZone_1, KeyCodes_1, EventGroup_1, css_1, rtl_1, Async_1, Callout_1) {
    "use strict";
    var ContextualMenuType;
    (function (ContextualMenuType) {
        ContextualMenuType[ContextualMenuType["vertical"] = 0] = "vertical";
        ContextualMenuType[ContextualMenuType["horizontal"] = 1] = "horizontal";
    })(ContextualMenuType || (ContextualMenuType = {}));
    var HorizontalAlignmentHint;
    (function (HorizontalAlignmentHint) {
        HorizontalAlignmentHint[HorizontalAlignmentHint["auto"] = 0] = "auto";
        HorizontalAlignmentHint[HorizontalAlignmentHint["left"] = 1] = "left";
        HorizontalAlignmentHint[HorizontalAlignmentHint["center"] = 2] = "center";
        HorizontalAlignmentHint[HorizontalAlignmentHint["right"] = 3] = "right";
    })(HorizontalAlignmentHint || (HorizontalAlignmentHint = {}));
    var VerticalAlignmentHint;
    (function (VerticalAlignmentHint) {
        VerticalAlignmentHint[VerticalAlignmentHint["top"] = 0] = "top";
        VerticalAlignmentHint[VerticalAlignmentHint["center"] = 1] = "center";
        VerticalAlignmentHint[VerticalAlignmentHint["bottom"] = 2] = "bottom";
    })(VerticalAlignmentHint || (VerticalAlignmentHint = {}));
    var _instance = 0;
    var ContextualMenu = (function (_super) {
        __extends(ContextualMenu, _super);
        function ContextualMenu(props) {
            _super.call(this, props);
            this.state = {
                contextualMenuItems: null,
                subMenuId: 'ContextualMenu-SubMenu-' + _instance++
            };
            this._isFocusingPreviousElement = false;
            this._didSetInitialFocus = false;
            this._enterTimerId = 0;
            this._events = new EventGroup_1.EventGroup(this);
            this._async = new Async_1.Async(this);
            this.dismiss = this.dismiss.bind(this);
            this._onKeyDown = this._onKeyDown.bind(this);
            this._onMouseDownCapture = this._onMouseDownCapture.bind(this);
            this._onItemClick = this._onItemClick.bind(this);
            this._onSubMenuDismiss = this._onSubMenuDismiss.bind(this);
            this._onMouseEnter = this._onMouseEnter.bind(this);
            this._onMouseLeave = this._onMouseLeave.bind(this);
        }
        ContextualMenu.prototype.dismiss = function (ev) {
            var onDismiss = this.props.onDismiss;
            if (onDismiss) {
                onDismiss(ev);
            }
        };
        // Invoked once, both on the client and server, immediately before the initial rendering occurs.
        ContextualMenu.prototype.componentWillMount = function () {
            this._previousActiveElement = document.activeElement;
        };
        // Invoked once, only on the client (not on the server), immediately after the initial rendering occurs.
        ContextualMenu.prototype.componentDidMount = function () {
            this._events.on(window, 'scroll', this._onScroll, true);
            this._events.on(window, 'resize', this.dismiss);
            this._events.on(window, 'mousedown', this._onMouseDownCapture, true);
            this._events.on(window, 'touchstart', this._onMouseDownCapture, true);
        };
        // Invoked when a component is receiving new props.
        ContextualMenu.prototype.componentWillReceiveProps = function (newProps, newState) {
            if (newProps.targetElement !== this.props.targetElement) {
                this._didSetInitialFocus = false;
            }
        };
        // Invoked immediately before a component is unmounted from the DOM.
        ContextualMenu.prototype.componentWillUnmount = function () {
            if (this._isFocusingPreviousElement && this._previousActiveElement) {
                this._previousActiveElement.focus();
            }
            this._events.dispose();
            this._async.dispose();
        };
        ContextualMenu.prototype.render = function () {
            var _this = this;
            var _a = this.props, className = _a.className, items = _a.items, isBeakVisible = _a.isBeakVisible, labelElementId = _a.labelElementId, targetElement = _a.targetElement, id = _a.id, targetPoint = _a.targetPoint, useTargetPoint = _a.useTargetPoint, beakWidth = _a.beakWidth, directionalHint = _a.directionalHint, gapSpace = _a.gapSpace;
            var submenuProps = this.state.submenuProps;
            var hasIcons = !!(items && items.some(function (item) { return !!item.icon; }));
            var hasCheckmarks = !!(items && items.some(function (item) { return !!item.canCheck; }));
            return (React.createElement(Callout_1.Callout, {targetElement: targetElement, targetPoint: targetPoint, useTargetPoint: useTargetPoint, isBeakVisible: isBeakVisible, beakWidth: beakWidth, directionalHint: directionalHint, gapSpace: gapSpace, doNotLayer: this.props.isSubMenu, beakStyle: 'ms-Callout-smallbeak', className: 'ms-ContextualMenu-Callout'}, React.createElement("div", {ref: function (host) { return _this._host = host; }, id: id, className: css_1.css('ms-ContextualMenu-container', className)}, (items && items.length) ? (React.createElement(FocusZone_1.FocusZone, {className: 'ms-ContextualMenu is-open', isCircularNavigation: true, role: 'menu', ariaLabelledBy: labelElementId, ref: function (focusZone) { return _this._tryFocus(focusZone); }}, React.createElement("ul", {className: 'ms-ContextualMenu-list is-open ', onKeyDown: this._onKeyDown}, items.map(function (item, index) { return (
            // If the item name is equal to '-', a divider will be generated.
            item.name === '-' ? (React.createElement("li", {role: 'separator', key: item.key || index, className: css_1.css('ms-ContextualMenu-item ms-ContextualMenu-item--divider', item.className)})) : (React.createElement("li", {role: 'menuitem', key: item.key || index, className: css_1.css('ms-ContextualMenu-item', item.className)}, _this._renderMenuItem(item, index, hasCheckmarks, hasIcons)))); })))) : (null), submenuProps ? (React.createElement(ContextualMenu, React.__spread({}, submenuProps))) : (null))));
        };
        ContextualMenu.prototype._renderMenuItem = function (item, index, hasCheckmarks, hasIcons) {
            var _a = this.state, expandedMenuItemKey = _a.expandedMenuItemKey, subMenuId = _a.subMenuId;
            if (item.onRender) {
                return item.onRender(item);
            }
            return React.createElement('button', { className: css_1.css('ms-ContextualMenu-link', { 'is-expanded': (expandedMenuItemKey === item.key) }),
                onClick: item.onClick || (item.items && item.items.length) ? this._onItemClick.bind(this, item) : item.href ? function () { location.href = item.href; } : null,
                onKeyDown: item.items && item.items.length ? this._onItemKeyDown.bind(this, item) : null,
                onMouseEnter: this._onMouseEnter.bind(this, item),
                onMouseLeave: this._onMouseLeave,
                disabled: item.isDisabled,
                dataCommandKey: index,
                role: 'menuitem',
                href: item.href,
                'aria-haspopup': item.items && item.items.length ? true : null,
                'aria-owns': item.key === expandedMenuItemKey ? subMenuId : null }, this._renderMenuItemChildren(item, index, hasCheckmarks, hasIcons));
        };
        ContextualMenu.prototype._renderMenuItemChildren = function (item, index, hasCheckmarks, hasIcons) {
            return React.createElement("div", null, (hasCheckmarks) ? (React.createElement("span", {className: css_1.css('ms-ContextualMenu-checkmark', { 'ms-Icon ms-Icon--check': item.isChecked, 'not-selected': !item.isChecked }), onClick: this._onItemClick.bind(this, item)})) : (null), (hasIcons) ? (React.createElement("span", {className: 'ms-ContextualMenu-icon' + ((item.icon) ? " ms-Icon ms-Icon--" + item.icon : ' no-icon')})) : (null), React.createElement("span", {className: 'ms-ContextualMenu-itemText ms-font-m ms-font-weight-regular'}, item.name), (item.items && item.items.length) ? (React.createElement("i", {className: css_1.css('ms-ContextualMenu-chevronRight ms-Icon', rtl_1.getRTL() ? 'ms-Icon--chevronLeft' : 'ms-Icon--chevronRight')})) : (null));
        };
        ContextualMenu.prototype._tryFocus = function (focusZone) {
            if (focusZone && this.props.shouldFocusOnMount) {
                focusZone.focus();
            }
        };
        ContextualMenu.prototype._onKeyDown = function (ev) {
            var submenuCloseKey = rtl_1.getRTL() ? KeyCodes_1.KeyCodes.right : KeyCodes_1.KeyCodes.left;
            if (ev.which === KeyCodes_1.KeyCodes.escape
                || (ev.which === submenuCloseKey && this.props.isSubMenu)) {
                // When a user presses escape, we will try to refocus the previous focused element.
                this._isFocusingPreviousElement = true;
                this.dismiss(ev);
            }
        };
        ContextualMenu.prototype._onMouseEnter = function (item, ev) {
            var _this = this;
            var targetElement = ev.currentTarget;
            if (item.items && item.items.length) {
                this._enterTimerId = this._async.setTimeout(function () { return _this._onSubMenuExpand(item, targetElement); }, 500);
            }
            else {
                this._enterTimerId = this._async.setTimeout(function () { return _this._onSubMenuDismiss(ev); }, 500);
            }
        };
        ContextualMenu.prototype._onMouseLeave = function (ev) {
            this._async.clearTimeout(this._enterTimerId);
        };
        ContextualMenu.prototype._onMouseDownCapture = function (ev) {
            if (!this._host.contains(ev.target)) {
                this.dismiss(ev);
            }
        };
        ContextualMenu.prototype._onScroll = function (ev) {
            if (!this._host.contains(ev.target)) {
                this.dismiss(ev);
            }
        };
        ContextualMenu.prototype._onItemClick = function (item, ev) {
            if (!item.items || !item.items.length) {
                if (item.onClick) {
                    item.onClick(item, ev);
                }
                this.dismiss(ev);
            }
            else {
                if (item.key === this.state.dismissedMenuItemKey) {
                    this._onSubMenuDismiss(ev);
                }
                else {
                    this._onSubMenuExpand(item, ev.currentTarget);
                }
            }
            ev.stopPropagation();
            ev.preventDefault();
        };
        ContextualMenu.prototype._onItemKeyDown = function (item, ev) {
            var openKey = rtl_1.getRTL() ? KeyCodes_1.KeyCodes.left : KeyCodes_1.KeyCodes.right;
            if (ev.which === openKey) {
                this._onSubMenuExpand(item, ev.currentTarget);
            }
        };
        ContextualMenu.prototype._onSubMenuExpand = function (item, target) {
            if (this.state.submenuProps && this.state.expandedMenuItemKey !== item.key) {
                this._onSubMenuDismiss();
            }
            this.setState({
                expandedMenuItemKey: item.key,
                submenuProps: {
                    items: item.items,
                    targetElement: target,
                    onDismiss: this._onSubMenuDismiss,
                    isSubMenu: true,
                    id: this.state.subMenuId,
                    shouldFocusOnMount: true,
                    directionalHint: DirectionalHint_1.DirectionalHint.rightTopEdge,
                    className: item.className
                }
            });
        };
        ContextualMenu.prototype._onSubMenuDismiss = function (ev) {
            var itemKey = null;
            var list = this.refs[this.state.expandedMenuItemKey];
            if (list && list.contains(ev.target)) {
                itemKey = this.state.expandedMenuItemKey;
            }
            this.setState({
                dismissedMenuItemKey: itemKey,
                expandedMenuItemKey: null,
                submenuProps: null
            });
        };
        // The default ContextualMenu properities have no items and beak, the default submenu direction is right and top.
        ContextualMenu.defaultProps = {
            items: [],
            shouldFocusOnMount: true,
            isBeakVisible: false,
            gapSpace: 0,
            directionalHint: DirectionalHint_1.DirectionalHint.rightBottomEdge,
            beakWidth: 16
        };
        return ContextualMenu;
    }(React.Component));
    exports.ContextualMenu = ContextualMenu;
});
