define(["require", "exports", "tslib", "react", "../../Utilities", "../../utilities/positioning", "../../Popup", "./Callout.scss", "../../Styling"], function (require, exports, tslib_1, React, Utilities_1, positioning_1, Popup_1, stylesImport, Styling_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var styles = stylesImport;
    var BEAK_ORIGIN_POSITION = { top: 0, left: 0 };
    // Microsoft Edge will overwrite inline styles if there is an animation pertaining to that style.
    // To help ensure that edge will respect the offscreen style opacity
    // filter needs to be added as an additional way to set opacity.
    var OFF_SCREEN_STYLE = { opacity: 0, filter: 'opacity(0)' };
    var BORDER_WIDTH = 1;
    var SLIDE_ANIMATIONS = (_a = {},
        _a[positioning_1.RectangleEdge.top] = 'slideUpIn20',
        _a[positioning_1.RectangleEdge.bottom] = 'slideDownIn20',
        _a[positioning_1.RectangleEdge.left] = 'slideLeftIn20',
        _a[positioning_1.RectangleEdge.right] = 'slideRightIn20',
        _a);
    var CalloutContent = /** @class */ (function (_super) {
        tslib_1.__extends(CalloutContent, _super);
        function CalloutContent(props) {
            var _this = _super.call(this, props) || this;
            _this._warnDeprecations({ 'beakStyle': 'beakWidth' });
            _this._didSetInitialFocus = false;
            _this.state = {
                positions: undefined,
                slideDirectionalClassName: undefined,
                // @TODO it looks like this is not even being used anymore.
                calloutElementRect: undefined,
                heightOffset: 0
            };
            _this._positionAttempts = 0;
            return _this;
        }
        CalloutContent.prototype.componentDidUpdate = function () {
            this._setInitialFocus();
            this._updateAsyncPosition();
        };
        CalloutContent.prototype.componentWillMount = function () {
            this._setTargetWindowAndElement(this._getTarget());
        };
        CalloutContent.prototype.componentWillUpdate = function (newProps) {
            // If the target element changed, find the new one. If we are tracking target with class name, always find element because we do not know if fabric has rendered a new element and disposed the old element.
            var newTarget = this._getTarget(newProps);
            var oldTarget = this._getTarget();
            if (newTarget !== oldTarget || typeof (newTarget) === 'string' || newTarget instanceof String) {
                this._maxHeight = undefined;
                this._setTargetWindowAndElement(newTarget);
            }
            if (newProps.gapSpace !== this.props.gapSpace || this.props.beakWidth !== newProps.beakWidth) {
                this._maxHeight = undefined;
            }
            if (newProps.finalHeight !== this.props.finalHeight) {
                this._setHeightOffsetEveryFrame();
            }
        };
        CalloutContent.prototype.componentDidMount = function () {
            this._onComponentDidMount();
        };
        CalloutContent.prototype.render = function () {
            // If there is no target window then we are likely in server side rendering and we should not render anything.
            if (!this._targetWindow) {
                return null;
            }
            var _a = this.props, role = _a.role, ariaLabel = _a.ariaLabel, ariaDescribedBy = _a.ariaDescribedBy, ariaLabelledBy = _a.ariaLabelledBy, className = _a.className, target = _a.target, isBeakVisible = _a.isBeakVisible, beakStyle = _a.beakStyle, children = _a.children, beakWidth = _a.beakWidth, calloutWidth = _a.calloutWidth, finalHeight = _a.finalHeight, backgroundColor = _a.backgroundColor, calloutMaxHeight = _a.calloutMaxHeight, onScroll = _a.onScroll;
            target = this._getTarget();
            var positions = this.state.positions;
            var directionalClassName = (positions && positions.targetEdge)
                ? Styling_1.AnimationClassNames[SLIDE_ANIMATIONS[positions.targetEdge]]
                : '';
            var getContentMaxHeight = this._getMaxHeight() + this.state.heightOffset;
            var contentMaxHeight = calloutMaxHeight && (calloutMaxHeight < getContentMaxHeight) ? calloutMaxHeight : getContentMaxHeight;
            var beakReactStyle = this._getBeakPosition(positions, beakWidth, backgroundColor, beakStyle);
            var beakVisible = isBeakVisible && (!!target);
            var content = (React.createElement("div", { ref: this._resolveRef('_hostElement'), className: Utilities_1.css('ms-Callout-container', styles.container) },
                React.createElement("div", { className: Styling_1.mergeStyles('ms-Callout', styles.root, className, directionalClassName, !!calloutWidth && { width: calloutWidth }), style: positions ? positions.elementPosition : OFF_SCREEN_STYLE, tabIndex: -1, 
                    // See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus
                    ref: this._resolveRef('_calloutElement') },
                    beakVisible && (React.createElement("div", { className: Utilities_1.css('ms-Callout-beak', styles.beak), style: beakReactStyle })),
                    beakVisible &&
                        (React.createElement("div", { className: Utilities_1.css('ms-Callout-beakCurtain', styles.beakCurtain) })),
                    React.createElement(Popup_1.Popup, { role: role, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, ariaLabelledBy: ariaLabelledBy, className: Utilities_1.css('ms-Callout-main', styles.main, (_b = {},
                            _b[styles.overFlowYHidden] = !!finalHeight,
                            _b)), onDismiss: this.dismiss, onScroll: onScroll, shouldRestoreFocus: true, style: { maxHeight: contentMaxHeight, backgroundColor: backgroundColor } }, children))));
            return content;
            var _b;
        };
        CalloutContent.prototype.dismiss = function (ev) {
            var onDismiss = this.props.onDismiss;
            if (onDismiss) {
                onDismiss(ev);
            }
        };
        CalloutContent.prototype._dismissOnScroll = function (ev) {
            var preventDismissOnScroll = this.props.preventDismissOnScroll;
            if (this.state.positions && !preventDismissOnScroll) {
                this._dismissOnLostFocus(ev);
            }
        };
        CalloutContent.prototype._dismissOnLostFocus = function (ev) {
            var target = ev.target;
            var clickedOutsideCallout = this._hostElement && !Utilities_1.elementContains(this._hostElement, target);
            if ((!this._target && clickedOutsideCallout) ||
                ev.target !== this._targetWindow &&
                    clickedOutsideCallout &&
                    (this._target.stopPropagation ||
                        (!this._target || (target !== this._target && !Utilities_1.elementContains(this._target, target))))) {
                this.dismiss(ev);
            }
        };
        CalloutContent.prototype._setInitialFocus = function () {
            if (this.props.setInitialFocus && !this._didSetInitialFocus && this.state.positions) {
                this._didSetInitialFocus = true;
                Utilities_1.focusFirstChild(this._calloutElement);
            }
        };
        CalloutContent.prototype._onComponentDidMount = function () {
            var _this = this;
            // This is added so the callout will dismiss when the window is scrolled
            // but not when something inside the callout is scrolled. The delay seems
            // to be required to avoid React firing an async focus event in IE from
            // the target changing focus quickly prior to rendering the callout.
            this._async.setTimeout(function () {
                _this._events.on(_this._targetWindow, 'scroll', _this._dismissOnScroll, true);
                _this._events.on(_this._targetWindow, 'resize', _this.dismiss, true);
                _this._events.on(_this._targetWindow.document.body, 'focus', _this._dismissOnLostFocus, true);
                _this._events.on(_this._targetWindow.document.body, 'click', _this._dismissOnLostFocus, true);
            }, 0);
            if (this.props.onLayerMounted) {
                this.props.onLayerMounted();
            }
            this._updateAsyncPosition();
            this._setHeightOffsetEveryFrame();
        };
        CalloutContent.prototype._updateAsyncPosition = function () {
            var _this = this;
            this._async.requestAnimationFrame(function () { return _this._updatePosition(); });
        };
        CalloutContent.prototype._updatePosition = function () {
            var positions = this.state.positions;
            var hostElement = this._hostElement;
            var calloutElement = this._calloutElement;
            if (hostElement && calloutElement) {
                var currentProps = void 0;
                currentProps = Utilities_1.assign(currentProps, this.props);
                currentProps.bounds = this._getBounds();
                currentProps.target = this._target;
                var newPositions = positioning_1.positionCallout(currentProps, hostElement, calloutElement);
                // Set the new position only when the positions are not exists or one of the new callout positions are different.
                // The position should not change if the position is within 2 decimal places.
                if ((!positions && newPositions) ||
                    (positions && newPositions && !this._arePositionsEqual(positions, newPositions)
                        && this._positionAttempts < 5)) {
                    // We should not reposition the callout more than a few times, if it is then the content is likely resizing
                    // and we should stop trying to reposition to prevent a stack overflow.
                    this._positionAttempts++;
                    this.setState({
                        positions: newPositions
                    });
                }
                else {
                    this._positionAttempts = 0;
                    if (this.props.onPositioned) {
                        this.props.onPositioned(this.state.positions);
                    }
                }
            }
        };
        CalloutContent.prototype._getBeakPosition = function (positions, beakWidth, backgroundColor, beakStyle) {
            var beakStyleWidth = beakWidth;
            // This is here to support the old way of setting the beak size until version 1.0.0.
            // beakStyle is now deprecated and will be be removed at version 1.0.0
            if (beakStyle === 'ms-Callout-smallbeak') {
                beakStyleWidth = 16;
            }
            var beakReactStyle = tslib_1.__assign({}, (positions && positions.beakPosition ? positions.beakPosition.elementPosition : null));
            beakReactStyle.height = beakStyleWidth;
            beakReactStyle.width = beakStyleWidth;
            beakReactStyle.backgroundColor = backgroundColor;
            if (!beakReactStyle.top && !beakReactStyle.bottom && !beakReactStyle.left && !beakReactStyle.right) {
                beakReactStyle.left = BEAK_ORIGIN_POSITION.left;
                beakReactStyle.top = BEAK_ORIGIN_POSITION.top;
            }
            return beakReactStyle;
        };
        CalloutContent.prototype._getBounds = function () {
            if (!this._bounds) {
                var currentBounds = this.props.bounds;
                if (!currentBounds) {
                    currentBounds = {
                        top: 0 + this.props.minPagePadding,
                        left: 0 + this.props.minPagePadding,
                        right: this._targetWindow.innerWidth - this.props.minPagePadding,
                        bottom: this._targetWindow.innerHeight - this.props.minPagePadding,
                        width: this._targetWindow.innerWidth - this.props.minPagePadding * 2,
                        height: this._targetWindow.innerHeight - this.props.minPagePadding * 2
                    };
                }
                this._bounds = currentBounds;
            }
            return this._bounds;
        };
        CalloutContent.prototype._getMaxHeight = function () {
            if (!this._maxHeight) {
                if (this.props.directionalHintFixed && this._target) {
                    var beakWidth = this.props.isBeakVisible ? this.props.beakWidth : 0;
                    var gapSpace = this.props.gapSpace ? this.props.gapSpace : 0;
                    // Since the callout cannot measure it's border size it must be taken into account here. Otherwise it will
                    // overlap with the target.
                    var totalGap = gapSpace + beakWidth + BORDER_WIDTH * 2;
                    this._maxHeight = positioning_1.getMaxHeight(this._target, this.props.directionalHint, totalGap, this._getBounds());
                }
                else {
                    this._maxHeight = this._getBounds().height - BORDER_WIDTH * 2;
                }
            }
            return this._maxHeight;
        };
        CalloutContent.prototype._arePositionsEqual = function (positions, newPosition) {
            return this._comparePositions(positions.elementPosition, newPosition.elementPosition) &&
                this._comparePositions(positions.beakPosition.elementPosition, newPosition.beakPosition.elementPosition);
        };
        CalloutContent.prototype._comparePositions = function (oldPositions, newPositions) {
            for (var key in newPositions) {
                // This needs to be checked here and below because there is a linting error if for in does not immediately have an if statement
                if (newPositions.hasOwnProperty(key)) {
                    var oldPositionEdge = oldPositions[key];
                    var newPositionEdge = newPositions[key];
                    if (oldPositionEdge !== undefined && newPositionEdge !== undefined) {
                        if (oldPositionEdge.toFixed(2) !== newPositionEdge.toFixed(2)) {
                            return false;
                        }
                    }
                    else {
                        return false;
                    }
                }
            }
            return true;
        };
        CalloutContent.prototype._setTargetWindowAndElement = function (target) {
            if (target) {
                if (typeof target === 'string') {
                    var currentDoc = Utilities_1.getDocument();
                    this._target = currentDoc ? currentDoc.querySelector(target) : null;
                    this._targetWindow = Utilities_1.getWindow();
                }
                else if (target.stopPropagation) {
                    this._targetWindow = Utilities_1.getWindow(target.toElement);
                    this._target = target;
                }
                else if (target.getBoundingClientRect) {
                    var targetElement = target;
                    this._targetWindow = Utilities_1.getWindow(targetElement);
                    this._target = target;
                    // HTMLImgElements can have x and y values. The check for it being a point must go last.
                }
                else {
                    this._targetWindow = Utilities_1.getWindow();
                    this._target = target;
                }
            }
            else {
                this._targetWindow = Utilities_1.getWindow();
            }
        };
        CalloutContent.prototype._setHeightOffsetEveryFrame = function () {
            var _this = this;
            if (this._calloutElement && this.props.finalHeight) {
                this._setHeightOffsetTimer = this._async.requestAnimationFrame(function () {
                    var calloutMainElem = _this._calloutElement.lastChild;
                    var cardScrollHeight = calloutMainElem.scrollHeight;
                    var cardCurrHeight = calloutMainElem.offsetHeight;
                    var scrollDiff = cardScrollHeight - cardCurrHeight;
                    _this.setState({
                        heightOffset: _this.state.heightOffset + scrollDiff
                    });
                    if (calloutMainElem.offsetHeight < _this.props.finalHeight) {
                        _this._setHeightOffsetEveryFrame();
                    }
                    else {
                        _this._async.cancelAnimationFrame(_this._setHeightOffsetTimer);
                    }
                });
            }
        };
        CalloutContent.prototype._getTarget = function (props) {
            if (props === void 0) { props = this.props; }
            var useTargetPoint = props.useTargetPoint, targetPoint = props.targetPoint, target = props.target;
            return useTargetPoint ? targetPoint : target;
        };
        CalloutContent.defaultProps = {
            preventDismissOnScroll: false,
            isBeakVisible: true,
            beakWidth: 16,
            gapSpace: 0,
            minPagePadding: 8,
            directionalHint: 7 /* bottomAutoEdge */
        };
        tslib_1.__decorate([
            Utilities_1.autobind
        ], CalloutContent.prototype, "dismiss", null);
        tslib_1.__decorate([
            Utilities_1.autobind
        ], CalloutContent.prototype, "_setInitialFocus", null);
        tslib_1.__decorate([
            Utilities_1.autobind
        ], CalloutContent.prototype, "_onComponentDidMount", null);
        return CalloutContent;
    }(Utilities_1.BaseComponent));
    exports.CalloutContent = CalloutContent;
    var _a;
});
//# sourceMappingURL=CalloutContent.js.map