vitess.io/vitess@v0.16.2/web/vtadmin/src/components/tooltip/Tooltip.tsx (about)

     1  /**
     2   * Copyright 2021 The Vitess Authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  import React from 'react';
    17  import { Popover } from 'react-tiny-popover';
    18  
    19  import style from './Tooltip.module.scss';
    20  
    21  export interface TooltipProps {
    22      children: React.ReactElement;
    23      text: string | JSX.Element;
    24  }
    25  
    26  /**
    27   * Tooltips display informative text when users hover over or focus on
    28   * the child element.
    29   *
    30   * Tooltips are used:
    31   *  - To show secondary information
    32   *  - To show keyboard shortcuts
    33   *  - To provide context for visual controls like icon buttons
    34   *
    35   * Tooltips are (generally) NOT used:
    36   *  - To show secondary information that's longer than a sentence or two
    37   *  - To render interactive elements, like links
    38   *  - To render imagery, like images or SVGs
    39   *
    40   * See the Material documentation for helpful usage guidelines:
    41   * https://material.io/components/tooltips
    42   *
    43   * Note that custom components (like <Icon> -- namely, any
    44   * component that is not a native component like <div> and <span>)
    45   * must support ref forwarding for the tooltip to position itself correctly.
    46   * See https://reactjs.org/docs/forwarding-refs.html
    47   */
    48  export const Tooltip = ({ children, text }: TooltipProps) => {
    49      const [isOpen, setIsOpen] = React.useState<boolean>(false);
    50  
    51      const hideTooltip = () => setIsOpen(false);
    52      const showTooltip = () => setIsOpen(true);
    53  
    54      const content = <div className={style.tooltip}>{text}</div>;
    55  
    56      // React.cloneElement is used to attach event listeners to the child component in order
    57      // to show/hide the tooltip on hover and focus, without resorting to wrapping
    58      // the child component in a surrounding element like a <span>. For another
    59      // example of this, see https://github.com/alexkatz/react-tiny-popover/pull/10.
    60      //
    61      // Note that cloneElement will (by default) preserve the ref forwarding between
    62      // the Popover component and the child element, so we happily don't need to do
    63      // anything special there.
    64      const cloneChildren = React.cloneElement(children, {
    65          onBlur: hideTooltip,
    66          onFocus: showTooltip,
    67          onMouseEnter: showTooltip,
    68          onMouseLeave: hideTooltip,
    69          // For accessibility, tooltips are shown on focus (as well as on hover),
    70          // which means the child element needs to have a tabIndex.
    71          tabIndex: 0,
    72      });
    73  
    74      return (
    75          <Popover content={content} isOpen={isOpen}>
    76              {cloneChildren}
    77          </Popover>
    78      );
    79  };