azure-devops-ui
Version:
React components for building web UI in Azure DevOps
122 lines (121 loc) • 4.71 kB
JavaScript
import "../../CommonImports";
import "../../Core/core.css";
import * as React from "react";
import { isFunctionalChildren } from '../../Util';
export class MouseWithin extends React.Component {
constructor() {
super(...arguments);
this.enterTimeout = 0;
this.delayTimeout = 0;
this.mouse = false;
/**
* onMouseEnter method that should be attached to the onMouseEnter handler of the
* continer's root element.
*/
this.onMouseEnter = (event) => {
// If the mouse is just entering one of the child components and not just moving
// from one child to another we will call the onMouseEnter delegate if supplied.
if (!this.mouse) {
this.mouse = true;
// Clear any pending leave if we have left and re-entered the component during
// the leaveTimeout.
if (this.delayTimeout) {
window.clearTimeout(this.delayTimeout);
this.delayTimeout = 0;
}
if (this.props.enterDelay) {
event.persist();
// persist does not preserve the currentTarget so we do that manually
const currentTarget = event.currentTarget;
this.enterTimeout = window.setTimeout(() => {
this.enterTimeout = 0;
const newCurrentTarget = event.currentTarget;
event.currentTarget = currentTarget;
this.mouseEntered(event);
event.currentTarget = newCurrentTarget;
}, this.props.enterDelay);
}
else {
this.mouseEntered(event);
}
}
};
/**
* onMouseLeave method that should be attached to the onMouseLeave handler of the
* container's root element.
*/
this.onMouseLeave = (event) => {
if (this.mouse) {
this.mouse = false;
// Clear any pending enterTimeout if we didnt stay over the element long enough.
if (this.enterTimeout) {
window.clearTimeout(this.enterTimeout);
this.enterTimeout = 0;
}
if (this.props.leaveDelay) {
event.persist();
this.delayTimeout = window.setTimeout(() => {
this.delayTimeout = 0;
this.mouseLeft(event);
}, this.props.leaveDelay);
}
else {
this.mouseLeft(event);
}
}
};
}
render() {
const newProps = {
onMouseEnter: this.onMouseEnter,
onMouseLeave: this.onMouseLeave
};
if (isFunctionalChildren(this.props.children)) {
const child = this.props.children;
// For functional components we pass the hasMouse attribute as well.
newProps.hasMouse = this.mouse;
return child(newProps);
}
else {
const child = React.Children.only(this.props.children);
return React.cloneElement(child, Object.assign(Object.assign({}, child.props), newProps), child.props.children);
}
}
componentWillUnmount() {
if (this.enterTimeout) {
window.clearTimeout(this.enterTimeout);
}
if (this.delayTimeout) {
window.clearTimeout(this.delayTimeout);
}
}
/**
* hasMouse returns true if the mouse is contained within the component
* hierarchy. This includes portals, the element may or may not
* be a direct descendant of the component in the DOM structure.
*/
hasMouse() {
return this.mouse;
}
mouseEntered(event) {
// If we are tracking the mouse state we will force a component update.
if (this.props.updateStateOnMouseChange) {
this.forceUpdate();
}
if (this.props.onMouseEnter) {
this.props.onMouseEnter(event);
}
}
mouseLeft(event) {
// If we are tracking the mouse state we will force a component update.
if (this.props.updateStateOnMouseChange) {
this.forceUpdate();
}
if (this.props.onMouseLeave) {
this.props.onMouseLeave(event);
}
}
}
MouseWithin.defaultProps = {
updateStateOnMouseChange: true
};