Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React, { Component } from 'react';
- import { faInfoCircle } from '@fortawesome/free-solid-svg-icons';
- import InfoIcon from '../../InfoIcon/InfoIcon';
- let counter = 0;
- class TooltipContainer extends Component {
- constructor(props) {
- super(props);
- this.state = {
- isFocused: false,
- isHovered: false,
- };
- this.identifier = `react-accessible-tooltip-${counter}`;
- counter += 1;
- this.onFocus = this.onFocus.bind(this);
- this.onBlur = this.onBlur.bind(this);
- this.onMouseEnter = this.onMouseEnter.bind(this);
- this.onMouseLeave = this.onMouseLeave.bind(this);
- this.handleTouch = this.handleTouch.bind(this);
- this.handleKeyDown = this.handleKeyDown.bind(this);
- this.container = React.createRef();
- }
- componentDidMount() {
- document.addEventListener('keydown', this.handleKeyDown);
- document.addEventListener('touchstart', this.handleTouch);
- }
- componentWillUnmount() {
- document.removeEventListener('keydown', this.handleKeyDown);
- document.removeEventListener('touchstart', this.handleTouch);
- }
- onFocus() {
- this.setState({ isFocused: true });
- };
- onBlur({
- relatedTarget,
- currentTarget,
- }){
- // relatedTarget is better for React testability etc, but activeElement works as an IE11 fallback:
- const newTarget = relatedTarget || document.activeElement;
- // The idea of this logic is that we should only close the tooltip if focus has shifted from the tooltip AND all of its descendents.
- if (!(newTarget)) {
- this.setState({ isFocused: false });
- } else if (!currentTarget.contains(newTarget)) {
- this.setState({ isFocused: false });
- }
- }
- onMouseEnter() {
- this.setState({ isHovered: true });
- }
- onMouseLeave() {
- this.setState({ isHovered: false });
- }
- // This handles the support for touch devices that do not trigger blur on 'touch-away'.
- handleTouch({ target }) {
- const { activeElement } = document;
- if (
- activeElement instanceof Element &&
- target instanceof Element &&
- this.container instanceof Element &&
- !this.container.contains(target) && // touch target not a tooltip descendent
- this.state.isFocused // prevent redundant state change
- ) {
- this.setState({ isFocused: false });
- activeElement.blur();
- } else if (
- activeElement instanceof Element &&
- target instanceof Element &&
- this.container instanceof Element &&
- this.container.contains(target) && // touch target is on tooltip descendant
- !this.state.isFocused // prevent redundant state change
- ) {
- this.setState({ isFocused: true });
- }
- }
- handleKeyDown({ key, keyCode, which }) {
- if (key === 'Escape' || keyCode === 27 || which === 27) {
- this.setState({ isFocused: false });
- }
- }
- render() {
- console.log('props', this.props)
- const { label: Label, overlay: Overlay, ...rest } = this.props;
- const { isFocused, isHovered } = this.state;
- const isHidden = !(isFocused || isHovered);
- const labelProps = {
- labelAttributes: {
- tabIndex: '0',
- 'aria-describedby': this.identifier,
- onFocus: this.onFocus,
- },
- isHidden,
- };
- const overlayProps = {
- overlayAttributes: {
- role: 'tooltip',
- tabIndex: '-1',
- id: this.identifier,
- 'aria-hidden': isHidden.toString(),
- },
- isHidden,
- };
- return (
- <div
- {...rest}
- onBlur={this.onBlur}
- ref={ref => {
- this.container = ref;
- }}
- onMouseEnter={this.onMouseEnter}
- onMouseLeave={this.onMouseLeave}
- >
- <a><InfoIcon icon={faInfoCircle} {...labelProps} /></a>
- <Overlay {...overlayProps} />
- </div>
- );
- }
- }
- export default TooltipContainer;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement