Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Material-UI - Tooltip on Select/MenuItem component stays displayed after selection

I'm using Material-UI's Select component with a Tooltip surrounding it, like so:

<Tooltip title="Tooltip Test">
  <Select value={this.state.age} onChange={this.handleChange}
    inputProps={{ name: "age", id: "age-simple" }}
  >
    <MenuItem value="">
      <em>None</em>
    </MenuItem>
    <MenuItem value={10}>Ten</MenuItem>
    <MenuItem value={20}>...</MenuItem>
  </Select>
</Tooltip>

My problem is that when I click the Select component, the Tooltip stays displayed, during the use of the Select, and even after an item was selected.

I want it to disappear as soon as the Select is clicked so that it doesn't stay over the MenuItems (Changing the zIndex is not the solution I want) and also still is not displayed even after selecting an item in the menu.

I made a codesandbox with the simple issue I have: https://codesandbox.io/s/yvloqr5qoj

But I am using typescript and this is the actual code I'm working with:

ControlledTooltip

import * as React from 'react';
import PropTypes from 'prop-types';

import withStyles, { WithStyles } from 'material-ui/styles/withStyles';
import { Tooltip } from 'material-ui';

const styles = {

}

type State = {
    open: boolean,
};

type Props = {
    id: string,
    msg: string,
    children: PropTypes.node,
};


class ControlledTooltip extends React.PureComponent<Props & WithStyles<keyof typeof styles>, State> {

    constructor(props) {
        super(props);

        this.state = {
            open: false,
        };
    }

    private handleTooltipClose(): void {
        this.setState({ open: false });
    }

    private handleTooltipOpen(): void {
        this.setState({ open: true });
    }

    render() {
        const { id, msg, children } = this.props;
        const { open } = this.state;

        return(
            <div>
                <Tooltip id={id}
                    title={msg}
                    open={open}
                    onClose={this.handleTooltipClose}
                    onOpen={this.handleTooltipOpen}
                >
                    {children ? children : null}
                </Tooltip>
            </div>
        );
    }
}

export default withStyles(styles)(ControlledTooltip);

Component using the Tooltip

<ControlledTooltip msg={'Filter'}>
    <Select value={this.state.type} onChange={this.handleChange.bind(this, Filter.Type)}>
        {this.docTypeFilters.map(item => {
            return (<MenuItem key={item} value={item}>{item}</MenuItem>);
        })}
    </Select>
</ControlledTooltip>
like image 612
Antoine Avatar asked Dec 14 '22 16:12

Antoine


1 Answers

TL;DR: You have to make your tooltip controlled.

UPDATE: Based on your actual code, replace the return of your render() with this:

            <Tooltip id={id}
                title={msg}
                open={open}
            >
                <div onMouseEnter={this.handleTooltipOpen}
                     onMouseLeave={this.handleTooltipClose}
                     onClick={this.handleTooltipClose}
                >
                   {children ? children : null}
                </div>
            </Tooltip>

The problem was that you were using onClose/onOpen from the tooltip, which works as is uncontrolled. Now the div containing the select(or any children) has the control over the tooltip.

ANSWER FOR THE PASTEBINS

You will need to handle the open prop of the Tooltip:

class SimpleSelect ... 
    constructor(...
        state = {..., open: false}; // the variable to control the tooltip

Alter your change handling:

handleChange = event => {
    this.setState({ [event.target.name]: event.target.value, open: false });// keeps the tooltip hidding on the select changes
};

handleOpen = (open) => {
    this.setState({ open }); // will show/hide tooltip when called
}

And reflect it in your render():

 const { open } = this.state; // obtains the current value for the tooltip prop
 ...
 <Tooltip title="Tooltip Test" open={open}>
 ...
   <Select ... onMouseEnter={() => this.handleOpen(true)}
               onMouseLeave={() => this.handleOpen(false)}
               onClick={() => this.handleOpen(false)} >

The event handlers(onMouseEnter, onMouseLeave, onClick) in Select now control the tooltip show/hide behavior.

like image 70
David I. Samudio Avatar answered Dec 17 '22 23:12

David I. Samudio