@@ -13,7 +13,7 @@ import {
1313} from '@floating-ui/react'
1414import { AnimatePresence , motion } from 'framer-motion'
1515import { transparentize } from 'polished'
16- import React , { ReactNode , useRef , useState } from 'react'
16+ import React , { CSSProperties , ReactNode , useRef , useState } from 'react'
1717import { SolvedTheme , solvedThemes } from '../styles'
1818import { Card , CardProps } from './Card'
1919
@@ -53,10 +53,20 @@ const renderSide = {
5353 left : 'right' ,
5454} as const
5555
56+ type TooltipPlacementBasic = 'top' | 'right' | 'bottom' | 'left'
57+ type TooltipPlacementRelative = 'start' | 'end'
58+
59+ export type TooltipPlacement =
60+ | `${TooltipPlacementBasic } -${TooltipPlacementRelative } `
61+ | TooltipPlacementBasic
62+
5663export type TooltipProps = {
5764 title ?: ReactNode
5865 theme ?: SolvedTheme
5966 children ?: ReactNode
67+ arrow ?: boolean
68+ keepOpen ?: boolean
69+ place ?: TooltipPlacement
6070} & (
6171 | {
6272 noDefaultStyles : false
@@ -66,15 +76,56 @@ export type TooltipProps = {
6676 } )
6777)
6878
79+ const resolveArrowStyles = (
80+ arrowX : number | undefined | null ,
81+ arrowY : number | undefined | null ,
82+ arrowPosition : 'top' | 'bottom' | 'left' | 'right' ,
83+ padding = 16
84+ ) : CSSProperties => {
85+ if ( arrowPosition === 'bottom' ) {
86+ return {
87+ left : arrowX ?? undefined ,
88+ bottom : - padding ,
89+ transform : `scaleY(-1)` ,
90+ }
91+ }
92+ if ( arrowPosition === 'top' ) {
93+ return {
94+ left : arrowX ?? undefined ,
95+ top : - padding ,
96+ }
97+ }
98+ if ( arrowPosition === 'left' ) {
99+ return {
100+ top : arrowY ?? undefined ,
101+ left : - 16 ,
102+ transform : `rotate(-90deg)` ,
103+ }
104+ }
105+ if ( arrowPosition === 'right' ) {
106+ return {
107+ top : arrowY ?? undefined ,
108+ right : - 16 ,
109+ transform : `rotate(90deg)` ,
110+ }
111+ }
112+ return { }
113+ }
114+
69115export const Tooltip : React . FC < TooltipProps > = ( props ) => {
70116 const {
71117 title,
72118 theme,
73119 noDefaultStyles : noBackground ,
74120 children,
121+ arrow : drawArrow = true ,
122+ keepOpen = false ,
123+ place,
75124 ...cardProps
76125 } = props
77126 const [ isOpen , setIsOpen ] = useState ( false )
127+ const renderTooltip = keepOpen || isOpen
128+
78129 const arrowRef = useRef ( null )
79130
80131 const {
@@ -86,13 +137,14 @@ export const Tooltip: React.FC<TooltipProps> = (props) => {
86137 placement,
87138 middlewareData : { arrow : { x : arrowX , y : arrowY } = { } } ,
88139 } = useFloating ( {
140+ placement : place ,
89141 strategy : 'fixed' ,
90142 open : isOpen ,
91143 onOpenChange : setIsOpen ,
92144 middleware : [
93- offset ( 8 ) ,
145+ offset ( 16 ) ,
146+ shift ( { padding : 16 } ) ,
94147 flip ( ) ,
95- shift ( { padding : 8 } ) ,
96148 arrow ( { element : arrowRef } ) ,
97149 ] ,
98150 whileElementsMounted : ( reference , floating , update ) =>
@@ -112,6 +164,8 @@ export const Tooltip: React.FC<TooltipProps> = (props) => {
112164 const arrowPosition =
113165 renderSide [ placement . split ( '-' ) [ 0 ] as keyof typeof renderSide ]
114166
167+ console . log ( arrowPosition )
168+
115169 return (
116170 < React . Fragment >
117171 < TooltipWrapper ref = { refs . setReference } { ...getReferenceProps ( ) } >
@@ -120,7 +174,7 @@ export const Tooltip: React.FC<TooltipProps> = (props) => {
120174 < FloatingPortal >
121175 < ThemeProvider theme = { theme || solvedThemes . dark } >
122176 < AnimatePresence >
123- { isOpen && (
177+ { renderTooltip && (
124178 < React . Fragment >
125179 < RenderComponent
126180 ref = { refs . setFloating }
@@ -133,27 +187,17 @@ export const Tooltip: React.FC<TooltipProps> = (props) => {
133187 } ) }
134188 { ...cardProps }
135189 transition = { { duration : 0.2 , ease : 'easeInOut' } }
136- initial = { { opacity : 0 , y : 0 , scale : 0.9 } }
137- animate = { { opacity : 1 , y : 8 , scale : 1 } }
138- exit = { { opacity : 0 , y : 0 , scale : 0.9 } }
190+ initial = { { opacity : 0 , scale : 0.9 } }
191+ animate = { { opacity : 1 , scale : 1 } }
192+ exit = { { opacity : 0 , scale : 0.9 } }
139193 >
140194 { title }
141- < Arrow
142- ref = { arrowRef }
143- style = {
144- arrowPosition === 'bottom'
145- ? {
146- left : arrowX ?? undefined ,
147- [ arrowPosition ] : - 16 ,
148- transform : `scaleY(-1)` ,
149- }
150- : {
151- top :
152- arrowY !== null ? ( arrowY || 0 ) - 16 : undefined ,
153- left : arrowX ?? undefined ,
154- }
155- }
156- />
195+ { drawArrow && (
196+ < Arrow
197+ ref = { arrowRef }
198+ style = { resolveArrowStyles ( arrowX , arrowY , arrowPosition ) }
199+ />
200+ ) }
157201 </ RenderComponent >
158202 </ React . Fragment >
159203 ) }
0 commit comments