UNPKG

@shopify/polaris

Version:

Shopify’s product component library

80 lines (79 loc) 3.16 kB
import React from 'react'; import { createUniqueIDFactory } from '@shopify/javascript-utilities/other'; import { findFirstFocusableNode } from '@shopify/javascript-utilities/focus'; import { Portal } from '../Portal'; import { TooltipOverlay } from './components'; import styles from './Tooltip.scss'; const getUniqueID = createUniqueIDFactory('TooltipContent'); export class Tooltip extends React.PureComponent { constructor() { super(...arguments); this.state = { active: Boolean(this.props.active), activatorNode: null, }; this.id = getUniqueID(); this.mouseEntered = false; this.setActivator = (node) => { if (node == null) { this.activatorContainer = null; this.setState({ activatorNode: null }); return; } this.setState({ activatorNode: node.firstElementChild }); this.activatorContainer = node; }; this.handleFocus = () => { this.setState({ active: true }); }; this.handleBlur = () => { this.setState({ active: false }); }; this.handleMouseEnter = () => { this.mouseEntered = true; this.setState({ active: true }); }; this.handleMouseLeave = () => { this.mouseEntered = false; this.setState({ active: false }); }; // https://github.com/facebook/react/issues/10109 // Mouseenter event not triggered when cursor moves from disabled button this.handleMouseEnterFix = () => { !this.mouseEntered && this.handleMouseEnter(); }; } componentDidMount() { this.setAccessibilityAttributes(); } componentDidUpdate() { this.setAccessibilityAttributes(); } render() { const { id } = this; const { children, content, light, preferredPosition = 'below', activatorWrapper: WrapperComponent = 'span', } = this.props; const { active, activatorNode } = this.state; const portal = activatorNode ? (<Portal idPrefix="tooltip"> <TooltipOverlay id={id} preferredPosition={preferredPosition} activator={activatorNode} active={active} onClose={noop} light={light}> <div className={styles.Label} testID="TooltipOverlayLabel"> {content} </div> </TooltipOverlay> </Portal>) : null; return (<WrapperComponent testID="WrapperComponent" onFocus={this.handleFocus} onBlur={this.handleBlur} onMouseLeave={this.handleMouseLeave} onMouseOver={this.handleMouseEnterFix} ref={this.setActivator}> {children} {portal} </WrapperComponent>); } setAccessibilityAttributes() { const { activatorContainer, id } = this; if (activatorContainer == null) { return; } const firstFocusable = findFirstFocusableNode(activatorContainer); const accessibilityNode = firstFocusable || activatorContainer; accessibilityNode.tabIndex = 0; accessibilityNode.setAttribute('aria-describedby', id); } } function noop() { }