office-ui-fabric-react
Version:
Reusable React components for building experiences for Office 365.
177 lines (176 loc) • 9.84 kB
JavaScript
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 __());
};
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
define(["require", "exports", 'react', '../../common/DirectionalHint', '../../Utilities', '../../utilities/positioning', '../../utilities/focus', '../../Utilities', '../Popup/index', '../../common/BaseComponent', './Callout.scss'], function (require, exports, React, DirectionalHint_1, Utilities_1, positioning_1, focus_1, Utilities_2, index_1, BaseComponent_1) {
"use strict";
var BEAK_ORIGIN_POSITION = { top: 0, left: 0 };
var OFF_SCREEN_POSITION = { top: -9999, left: 0 };
var BORDER_WIDTH = 1;
var SPACE_FROM_EDGE = 8;
var CalloutContent = (function (_super) {
__extends(CalloutContent, _super);
function CalloutContent(props) {
_super.call(this, props);
this._didSetInitialFocus = false;
this.state = {
positions: null,
slideDirectionalClassName: null,
calloutElementRect: null
};
// This is used to allow the Callout to appear on a window other than the one the javascript is running in.
if (props.targetElement && props.targetElement.ownerDocument && props.targetElement.ownerDocument.defaultView) {
this._targetWindow = props.targetElement.ownerDocument.defaultView;
}
else {
this._targetWindow = window;
}
this._positionAttempts = 0;
}
CalloutContent.prototype.componentDidUpdate = function () {
this._setInitialFocus();
this._updatePosition();
};
CalloutContent.prototype.componentDidMount = function () {
this._onComponentDidMount();
};
CalloutContent.prototype.render = function () {
var _this = this;
var _a = this.props, className = _a.className, targetElement = _a.targetElement, isBeakVisible = _a.isBeakVisible, beakStyle = _a.beakStyle, children = _a.children, beakWidth = _a.beakWidth;
var _b = this.state, positions = _b.positions, slideDirectionalClassName = _b.slideDirectionalClassName;
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 = {
top: positions && positions.beak ? positions.beak.top : BEAK_ORIGIN_POSITION.top,
left: positions && positions.beak ? positions.beak.left : BEAK_ORIGIN_POSITION.left,
height: beakStyleWidth,
width: beakStyleWidth
};
var contentMaxHeight = this._getMaxHeight();
var beakVisible = isBeakVisible && !!targetElement;
var content = (React.createElement("div", {ref: this._resolveRef('_hostElement'), className: 'ms-Callout-container'},
React.createElement("div", {className: Utilities_1.css('ms-Callout', className, slideDirectionalClassName ? "ms-u-" + slideDirectionalClassName : ''), style: positions ? positions.callout : OFF_SCREEN_POSITION, ref: this._resolveRef('_calloutElement')},
beakVisible ? (React.createElement("div", {className: 'ms-Callout-beak', style: beakReactStyle})) : (null),
beakVisible ?
(React.createElement("div", {className: 'ms-Callout-beakCurtain'})) :
(null),
React.createElement(index_1.Popup, {className: 'ms-Callout-main', onDismiss: function (ev) { return _this.dismiss(); }, shouldRestoreFocus: true, style: { maxHeight: contentMaxHeight }}, children))
));
return content;
};
CalloutContent.prototype.dismiss = function () {
var onDismiss = this.props.onDismiss;
if (onDismiss) {
onDismiss();
}
};
CalloutContent.prototype._dismissOnLostFocus = function (ev) {
var targetElement = this.props.targetElement;
var target = ev.target;
if (ev.target !== this._targetWindow &&
this._hostElement &&
!Utilities_1.elementContains(this._hostElement, target) &&
(!targetElement || !Utilities_1.elementContains(targetElement, target))) {
this.dismiss();
}
};
CalloutContent.prototype._setInitialFocus = function () {
if (this.props.setInitialFocus && !this._didSetInitialFocus && this.state.positions) {
this._didSetInitialFocus = true;
focus_1.focusFirstChild(this._calloutElement);
}
};
CalloutContent.prototype._onComponentDidMount = function () {
// This is added so the callout will dismiss when the window is scrolled
// but not when something inside the callout is scrolled.
this._events.on(this._targetWindow, 'scroll', this._dismissOnLostFocus, true);
this._events.on(this._targetWindow, 'resize', this.dismiss, true);
this._events.on(this._targetWindow, 'focus', this._dismissOnLostFocus, true);
this._events.on(this._targetWindow, 'click', this._dismissOnLostFocus, true);
if (this.props.onLayerMounted) {
this.props.onLayerMounted();
}
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_2.assign(currentProps, this.props);
currentProps.bounds = this._getBounds();
var positionInfo = positioning_1.getRelativePositions(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 && positionInfo) ||
(positions && positionInfo &&
(positions.callout.top.toFixed(2) !== positionInfo.calloutPosition.top.toFixed(2) ||
positions.callout.left.toFixed(2) !== positionInfo.calloutPosition.left.toFixed(2))
&& 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: {
callout: positionInfo.calloutPosition,
beak: positionInfo.beakPosition,
},
slideDirectionalClassName: positionInfo.directionalClassName
});
}
}
else {
this._positionAttempts = 0;
}
};
CalloutContent.prototype._getBounds = function () {
if (!this._bounds) {
var currentBounds = this.props.bounds;
if (!currentBounds) {
currentBounds = {
top: 0 + SPACE_FROM_EDGE,
left: 0 + SPACE_FROM_EDGE,
right: this._targetWindow.innerWidth - SPACE_FROM_EDGE,
bottom: this._targetWindow.innerHeight - SPACE_FROM_EDGE,
width: this._targetWindow.innerWidth - SPACE_FROM_EDGE * 2,
height: this._targetWindow.innerHeight - SPACE_FROM_EDGE * 2
};
}
this._bounds = currentBounds;
}
return this._bounds;
};
CalloutContent.prototype._getMaxHeight = function () {
if (!this._maxHeight) {
this._maxHeight = this._getBounds().height - BORDER_WIDTH * 2;
}
return this._maxHeight;
};
CalloutContent.defaultProps = {
isBeakVisible: true,
beakWidth: 28,
gapSpace: 0,
directionalHint: DirectionalHint_1.DirectionalHint.bottomAutoEdge
};
__decorate([
Utilities_1.autobind
], CalloutContent.prototype, "_setInitialFocus", null);
__decorate([
Utilities_1.autobind
], CalloutContent.prototype, "_onComponentDidMount", null);
return CalloutContent;
}(BaseComponent_1.BaseComponent));
exports.CalloutContent = CalloutContent;
});