UNPKG

azure-devops-ui

Version:

React components for building web UI in Azure DevOps

122 lines (121 loc) 4.71 kB
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 };