Use FloatingUI with Tooltip
This commit is contained in:
parent
6da45c3ef7
commit
8ec8d4a2ca
4 changed files with 70 additions and 69 deletions
Binary file not shown.
|
@ -1,67 +1,88 @@
|
||||||
import { TooltipPopup, useTooltip } from '@reach/tooltip';
|
import {
|
||||||
import React from 'react';
|
arrow,
|
||||||
|
FloatingArrow,
|
||||||
import Portal from '../portal/portal';
|
FloatingPortal,
|
||||||
|
offset,
|
||||||
import './tooltip.css';
|
useFloating,
|
||||||
|
useHover,
|
||||||
|
useInteractions,
|
||||||
|
useTransitionStyles,
|
||||||
|
} from '@floating-ui/react';
|
||||||
|
import React, { useRef, useState } from 'react';
|
||||||
|
|
||||||
interface ITooltip {
|
interface ITooltip {
|
||||||
|
/** Element to display the tooltip around. */
|
||||||
|
children: React.ReactElement<any, string | React.JSXElementConstructor<any>>
|
||||||
/** Text to display in the tooltip. */
|
/** Text to display in the tooltip. */
|
||||||
text: string
|
text: string
|
||||||
/** Element to display the tooltip around. */
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const centered = (triggerRect: any, tooltipRect: any) => {
|
/**
|
||||||
const triggerCenter = triggerRect.left + triggerRect.width / 2;
|
* Tooltip
|
||||||
const left = triggerCenter - tooltipRect.width / 2;
|
*/
|
||||||
const maxLeft = window.innerWidth - tooltipRect.width - 2;
|
const Tooltip: React.FC<ITooltip> = (props) => {
|
||||||
return {
|
const { children, text } = props;
|
||||||
left: Math.min(Math.max(2, left), maxLeft) + window.scrollX,
|
|
||||||
top: triggerRect.bottom + 8 + window.scrollY,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Hoverable tooltip element. */
|
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||||
const Tooltip: React.FC<ITooltip> = ({
|
|
||||||
children,
|
|
||||||
text,
|
|
||||||
}) => {
|
|
||||||
// get the props from useTooltip
|
|
||||||
const [trigger, tooltip] = useTooltip();
|
|
||||||
|
|
||||||
// destructure off what we need to position the triangle
|
const arrowRef = useRef<SVGSVGElement>(null);
|
||||||
const { isVisible, triggerRect } = tooltip;
|
|
||||||
|
const { x, y, strategy, refs, context } = useFloating({
|
||||||
|
open: isOpen,
|
||||||
|
onOpenChange: setIsOpen,
|
||||||
|
placement: 'top',
|
||||||
|
middleware: [
|
||||||
|
offset(6),
|
||||||
|
arrow({
|
||||||
|
element: arrowRef,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const hover = useHover(context);
|
||||||
|
const { isMounted, styles } = useTransitionStyles(context, {
|
||||||
|
initial: {
|
||||||
|
opacity: 0,
|
||||||
|
transform: 'scale(0.8)',
|
||||||
|
},
|
||||||
|
duration: {
|
||||||
|
open: 200,
|
||||||
|
close: 200,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { getReferenceProps, getFloatingProps } = useInteractions([
|
||||||
|
hover,
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<>
|
||||||
{React.cloneElement(children as any, trigger)}
|
{React.cloneElement(children, {
|
||||||
|
ref: refs.setReference,
|
||||||
|
...getReferenceProps(),
|
||||||
|
})}
|
||||||
|
|
||||||
{isVisible && (
|
{(isMounted) && (
|
||||||
// The Triangle. We position it relative to the trigger, not the popup
|
<FloatingPortal>
|
||||||
// so that collisions don't have a triangle pointing off to nowhere.
|
|
||||||
// Using a Portal may seem a little extreme, but we can keep the
|
|
||||||
// positioning logic simpler here instead of needing to consider
|
|
||||||
// the popup's position relative to the trigger and collisions
|
|
||||||
<Portal>
|
|
||||||
<div
|
<div
|
||||||
data-reach-tooltip-arrow='true'
|
ref={refs.setFloating}
|
||||||
style={{
|
style={{
|
||||||
left:
|
position: strategy,
|
||||||
triggerRect && triggerRect.left - 10 + triggerRect.width / 2 as any,
|
top: y ?? 0,
|
||||||
top: triggerRect && triggerRect.bottom + window.scrollY as any,
|
left: x ?? 0,
|
||||||
|
...styles,
|
||||||
}}
|
}}
|
||||||
/>
|
className='pointer-events-none z-[100] whitespace-nowrap rounded bg-gray-800 px-2.5 py-1.5 text-xs font-medium text-gray-100 shadow dark:bg-gray-100 dark:text-gray-900'
|
||||||
</Portal>
|
{...getFloatingProps()}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
|
||||||
|
<FloatingArrow ref={arrowRef} context={context} className='fill-gray-800 dark:fill-gray-100' />
|
||||||
|
</div>
|
||||||
|
</FloatingPortal>
|
||||||
)}
|
)}
|
||||||
<TooltipPopup
|
</>
|
||||||
{...tooltip}
|
|
||||||
label={text}
|
|
||||||
aria-label={text}
|
|
||||||
position={centered}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Tooltip;
|
export default Tooltip;
|
|
@ -61,7 +61,6 @@
|
||||||
"@reach/popover": "^0.18.0",
|
"@reach/popover": "^0.18.0",
|
||||||
"@reach/rect": "^0.18.0",
|
"@reach/rect": "^0.18.0",
|
||||||
"@reach/tabs": "^0.18.0",
|
"@reach/tabs": "^0.18.0",
|
||||||
"@reach/tooltip": "^0.18.0",
|
|
||||||
"@reduxjs/toolkit": "^1.8.1",
|
"@reduxjs/toolkit": "^1.8.1",
|
||||||
"@sentry/browser": "^7.37.2",
|
"@sentry/browser": "^7.37.2",
|
||||||
"@sentry/react": "^7.37.2",
|
"@sentry/react": "^7.37.2",
|
||||||
|
|
19
yarn.lock
19
yarn.lock
|
@ -2749,30 +2749,11 @@
|
||||||
"@reach/polymorphic" "0.18.0"
|
"@reach/polymorphic" "0.18.0"
|
||||||
"@reach/utils" "0.18.0"
|
"@reach/utils" "0.18.0"
|
||||||
|
|
||||||
"@reach/tooltip@^0.18.0":
|
|
||||||
version "0.18.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@reach/tooltip/-/tooltip-0.18.0.tgz#6d416e77a82543af9a57d122962f9c0294fc2a5f"
|
|
||||||
integrity sha512-yugoTmTjB3qoMk/nUvcnw99MqpyE2TQMOXE29qnQhSqHriRwQhfftjXlTAGTSzsUJmbyms3A/1gQW0X61kjFZw==
|
|
||||||
dependencies:
|
|
||||||
"@reach/auto-id" "0.18.0"
|
|
||||||
"@reach/polymorphic" "0.18.0"
|
|
||||||
"@reach/portal" "0.18.0"
|
|
||||||
"@reach/rect" "0.18.0"
|
|
||||||
"@reach/utils" "0.18.0"
|
|
||||||
"@reach/visually-hidden" "0.18.0"
|
|
||||||
|
|
||||||
"@reach/utils@0.18.0":
|
"@reach/utils@0.18.0":
|
||||||
version "0.18.0"
|
version "0.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.18.0.tgz#4f3cebe093dd436eeaff633809bf0f68f4f9d2ee"
|
resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.18.0.tgz#4f3cebe093dd436eeaff633809bf0f68f4f9d2ee"
|
||||||
integrity sha512-KdVMdpTgDyK8FzdKO9SCpiibuy/kbv3pwgfXshTI6tEcQT1OOwj7BAksnzGC0rPz0UholwC+AgkqEl3EJX3M1A==
|
integrity sha512-KdVMdpTgDyK8FzdKO9SCpiibuy/kbv3pwgfXshTI6tEcQT1OOwj7BAksnzGC0rPz0UholwC+AgkqEl3EJX3M1A==
|
||||||
|
|
||||||
"@reach/visually-hidden@0.18.0":
|
|
||||||
version "0.18.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@reach/visually-hidden/-/visually-hidden-0.18.0.tgz#17923c08acc5946624c2836b2b09d359b3aa8c27"
|
|
||||||
integrity sha512-NsJ3oeHJtPc6UOeV6MHMuzQ5sl1ouKhW85i3C0S7VM+klxVlYScBZ2J4UVnWB50A2c+evdVpCnld2YeuyYYwBw==
|
|
||||||
dependencies:
|
|
||||||
"@reach/polymorphic" "0.18.0"
|
|
||||||
|
|
||||||
"@reduxjs/toolkit@^1.8.1":
|
"@reduxjs/toolkit@^1.8.1":
|
||||||
version "1.8.1"
|
version "1.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.8.1.tgz#94ee1981b8cf9227cda40163a04704a9544c9a9f"
|
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.8.1.tgz#94ee1981b8cf9227cda40163a04704a9544c9a9f"
|
||||||
|
|
Loading…
Reference in a new issue