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 };