office-ui-fabric-react
Version:
Reusable React components for building experiences for Office 365.
182 lines • 8.99 kB
JavaScript
import * as tslib_1 from "tslib";
// Utilities
import * as React from 'react';
import { BaseComponent, classNamesFunction, createRef } from '../../Utilities';
import { DefaultPalette } from '../../Styling';
// Component Dependencies
import { PositioningContainer } from './PositioningContainer/index';
import { Beak } from './Beak/Beak';
import { getStyles } from './Coachmark.styles';
import { FocusZone } from '../../FocusZone';
var getClassNames = classNamesFunction();
var Coachmark = /** @class */ (function (_super) {
tslib_1.__extends(Coachmark, _super);
function Coachmark(props) {
var _this = _super.call(this, props) || this;
/**
* The cached HTMLElement reference to the Entity Inner Host
* element.
*/
_this._entityInnerHostElement = createRef();
_this._translateAnimationContainer = createRef();
_this._positioningContainer = createRef();
_this._onFocusHandler = function () {
_this._openCoachmark();
};
_this._openCoachmark = function () {
_this.setState({
collapsed: false
});
_this._translateAnimationContainer.current && _this._translateAnimationContainer.current.addEventListener('animationstart', function () {
if (_this.props.onAnimationOpenStart) {
_this.props.onAnimationOpenStart();
}
});
_this._translateAnimationContainer.current && _this._translateAnimationContainer.current.addEventListener('animationend', function () {
if (_this.props.onAnimationOpenEnd) {
_this.props.onAnimationOpenEnd();
}
});
};
// Set defaults for state
_this.state = {
collapsed: props.collapsed,
isBeaconAnimating: true,
isMeasuring: true,
entityInnerHostRect: {
width: 0,
height: 0
},
isMouseInProximity: false
};
return _this;
}
Coachmark.prototype.render = function () {
var _a = this.props, children = _a.children, beakWidth = _a.beakWidth, beakHeight = _a.beakHeight, target = _a.target, width = _a.width, height = _a.height, color = _a.color;
var classNames = getClassNames(getStyles, {
collapsed: this.state.collapsed,
isBeaconAnimating: this.state.isBeaconAnimating,
isMeasuring: this.state.isMeasuring,
entityHostHeight: this.state.entityInnerHostRect.height + 'px',
entityHostWidth: this.state.entityInnerHostRect.width + 'px',
width: width + 'px',
height: height + 'px',
color: color
});
return (React.createElement(PositioningContainer, { target: target, offsetFromTarget: beakHeight, componentRef: this._positioningContainer },
React.createElement("div", { className: classNames.root },
React.createElement("div", { className: classNames.pulsingBeacon }),
React.createElement("div", { className: classNames.translateAnimationContainer, ref: this._translateAnimationContainer },
React.createElement("div", { className: classNames.scaleAnimationLayer },
React.createElement("div", { className: classNames.rotateAnimationLayer },
this._positioningContainer.current && React.createElement(Beak, { width: beakWidth, height: beakHeight, left: this.state.beakLeft, top: this.state.beakTop }),
React.createElement(FocusZone, null,
React.createElement("div", { className: classNames.entityHost, "data-is-focusable": true, onFocus: this._onFocusHandler },
React.createElement("div", { className: classNames.entityInnerHost, ref: this._entityInnerHostElement }, children)))))))));
};
Coachmark.prototype.componentWillReceiveProps = function (newProps) {
if (this.props.collapsed && !newProps.collapsed) {
// The coachmark is about to open
this._openCoachmark();
}
};
Coachmark.prototype.componentDidMount = function () {
var _this = this;
this._async.requestAnimationFrame((function () {
if (_this._entityInnerHostElement.current && (_this.state.entityInnerHostRect.width + _this.state.entityInnerHostRect.width) === 0) {
// @TODO Eventually we need to add the various directions
var beakLeft = (_this.props.width / 2) - (_this.props.beakWidth / 2);
var beakTop = 0;
_this.setState({
isMeasuring: false,
entityInnerHostRect: {
width: _this._entityInnerHostElement.current.offsetWidth,
height: _this._entityInnerHostElement.current.offsetHeight
},
beakLeft: beakLeft + 'px',
beakTop: beakTop + 'px'
});
_this.forceUpdate();
}
// We dont want to the user to immediatley trigger the coachmark when it's opened
_this._async.setTimeout(function () {
_this._addProximityHandler(100);
}, _this.props.delayBeforeMouseOpen);
}));
};
Coachmark.prototype._addProximityHandler = function (mouseProximityOffset) {
var _this = this;
if (mouseProximityOffset === void 0) { mouseProximityOffset = 0; }
/**
* An array of cached ids returned when setTimeout runs during
* the window resize event trigger.
*/
var timeoutIds = [];
/**
* The target element the mouse would be in
* proximity to
*/
var targetElementRect;
// Take the initial measure out of the initial render to prevent
// an unnecessary render.
this._async.setTimeout(function () {
if (_this._entityInnerHostElement.current) {
targetElementRect = _this._entityInnerHostElement.current.getBoundingClientRect();
}
// When the window resizes we want to async
// get the bounding client rectangle.
// Every time the event is triggered we want to
// setTimeout and then clear any previous instances
// of setTimeout.
_this._events.on(window, 'resize', function () {
timeoutIds.forEach(function (value) {
clearInterval(value);
});
timeoutIds.push(_this._async.setTimeout(function () {
if (_this._entityInnerHostElement.current) {
targetElementRect = _this._entityInnerHostElement.current.getBoundingClientRect();
}
}, 100));
});
}, 10);
// Every time the document's mouse move is triggered
// we want to check if inside of an element and
// set the state with the result.
this._events.on(document, 'mousemove', function (e) {
var mouseY = e.pageY;
var mouseX = e.pageX;
var isMouseInProximity = _this._isInsideElement(mouseX, mouseY, targetElementRect, mouseProximityOffset);
if (isMouseInProximity !== _this.state.isMouseInProximity) {
// We don't want to update the isMouseInProximtiy state because
// The coachmark only opens and does not collapse.
// Setting isMouseInProximity here will cause the coachmark to open and close
_this.setState({
collapsed: !isMouseInProximity
});
}
if (_this.props.onMouseMove) {
_this.props.onMouseMove(e);
}
});
};
Coachmark.prototype._isInsideElement = function (mouseX, mouseY, elementRect, mouseProximityOffset) {
if (mouseProximityOffset === void 0) { mouseProximityOffset = 0; }
return mouseX > (elementRect.left - mouseProximityOffset) &&
mouseX < ((elementRect.left + elementRect.width) + mouseProximityOffset) &&
mouseY > (elementRect.top - mouseProximityOffset) &&
mouseY < ((elementRect.top + elementRect.height) + mouseProximityOffset);
};
Coachmark.defaultProps = {
collapsed: true,
mouseProximityOffset: 100,
beakWidth: 26,
beakHeight: 12,
delayBeforeMouseOpen: 3600,
width: 36,
height: 36,
color: DefaultPalette.themePrimary
};
return Coachmark;
}(BaseComponent));
export { Coachmark };
//# sourceMappingURL=Coachmark.js.map