Source

Utils/DataDisplay/CustomTooltip.js

import React from 'react';
import PropTypes from 'prop-types';
import clsx from "clsx";
import { makeStyles } from "@material-ui/core/styles";
import { mergeClasses } from "../utilFunctions";
import Tooltip from "@material-ui/core/Tooltip";

// To get unblurred tooltip text in Google Chrome
const disableGpuProps = {
    popperOptions: {
        modifiers: {
            computeStyle: {
                enabled: true,
                gpuAcceleration: false
            }
        }
    }
};

const useStyles = makeStyles(theme => ({
    arrow: {
        color: theme.palette.background.sub
    },
    disableMaxWidth: {
        maxWidth: "none"
    },
    tooltip: {
        backgroundColor: theme.palette.background.sub,
        boxShadow: theme.shadows[6],
        color: theme.palette.text.main2,
        fontSize: "smaller"
    },
    wrapper: {}
}), {name: "CustomTooltip"});

function DefaultWrapper(props, ref) {
    const { children, component, ...other } = props;
    return React.createElement(component, {ref, ...other}, children)
}

const WrapperForwardRef = React.forwardRef(DefaultWrapper);

/**
 * <h3>Overview</h3>
 * The Tooltip component from Material-UI library with custom styling.
 * For full documentation check out Material-UI docs on
 * <a href="https://material-ui.com/api/tooltip/" target="_blank">Tooltip</a>.
 *
 * <h3>Usage</h3>
 * There is a custom <code>Wrapper</code> element that can hold reference.
 * This composition enables you to forward children without the ability to hold ref to the Tooltip component.
 *
 * @constructor
 * @category Utils
 * @subcategory Data Display
 * @param {Object} props - Any other props will be forwarded to the Tooltip component.
 * @param {Object} [props.classes] - Override or extend the styles applied to the component.
 * @param {string} [props.className] - The class name of the Wrapper element.
 * @param {boolean} [props.disableGpu=true] - If <code>true</code> GPU acceleration will be disabled. <br>
 *     Disable GPU acceleration to get unblurred tooltip text in Google Chrome.
 * @param {boolean} [props.disableMaxWidth=false] - If <code>true</code> <code>maxWidth</code> property will be set to "none".
 * @param {React.ElementType} [props.WrapperComponent=div] - The component used for the wrapper element.
 * @param {Object} [props.WrapperProps] - Props applied to the <code>Wrapper</code> element.
 * @returns {React.ReactElement}
 */
function CustomTooltip(props) {
    const {
        children,
        classes: propsClasses,
        className,
        disableGpu,
        disableMaxWidth,
        PopperProps,
        WrapperComponent,
        WrapperProps,
        ...other } = props;

    let classes = useStyles();
    if (propsClasses) classes = mergeClasses(classes, propsClasses);

    if (disableMaxWidth) {
        classes = mergeClasses(classes, {tooltip: classes.disableMaxWidth})
    }

    let newPopperProps = { ...PopperProps };
    if (disableGpu) {
        newPopperProps = { ...PopperProps, ...disableGpuProps };
    }

    return (
        <Tooltip
            classes={{tooltip: classes.tooltip, arrow: classes.arrow}}
            PopperProps={{...newPopperProps}}
            {...other}
        >
            <WrapperForwardRef
                className={clsx(classes.wrapper, className)}
                component={WrapperComponent}
                {...WrapperProps}
            >
                {children}
            </WrapperForwardRef>
        </Tooltip>
    )
}

CustomTooltip.propTypes = {
    arrow: PropTypes.bool,
    children: PropTypes.node,
    classes: PropTypes.shape({
        arrow: PropTypes.string,
        disableMaxWidth: PropTypes.string,
        tooltip: PropTypes.string,
        wrapper: PropTypes.string
    }),
    className: PropTypes.string,
    disableFocusListener: PropTypes.bool,
    disableGpu: PropTypes.bool,
    disableHoverListener: PropTypes.bool,
    disableTouchListener: PropTypes.bool,
    disableMaxWidth: PropTypes.bool,
    enterDelay: PropTypes.number,
    enterNextDelay: PropTypes.number,
    enterTouchDelay: PropTypes.number,
    id: PropTypes.string,
    interactive: PropTypes.bool,
    leaveDelay: PropTypes.number,
    leaveTouchDelay: PropTypes.number,
    onClose: PropTypes.func,
    onOpen: PropTypes.func,
    open: PropTypes.bool,
    placement: PropTypes.oneOf([
        "bottom-end",
        "bottom-start",
        "bottom",
        "left-start",
        "left-end",
        "left",
        "right-start",
        "right-end",
        "right",
        "top-start",
        "top-end",
        "top"
    ]),
    PopperProps: PropTypes.object,
    title: PropTypes.node.isRequired,
    TransitionComponent: PropTypes.elementType,
    TransitionProps: PropTypes.object,
    WrapperComponent: PropTypes.elementType,
    WrapperProps: PropTypes.object
};

CustomTooltip.defaultProps = {
    disableGpu: true,
    WrapperComponent: 'div'
};

export default CustomTooltip;