Skip to content

Commit c7aee48

Browse files
gabrieljablonskidanielbarion
authored andcommitted
add tooltip wrapper
1 parent 3816d14 commit c7aee48

File tree

6 files changed

+123
-48
lines changed

6 files changed

+123
-48
lines changed

src/App.tsx

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,32 @@
11
import { TooltipController as Tooltip } from 'components/TooltipController'
2-
import { TooltipProvider, useTooltip } from 'components/TooltipProvider'
2+
import { TooltipProvider, TooltipWrapper, useTooltip } from 'components/TooltipProvider'
33
import { useEffect, useRef, useState } from 'react'
44
import styles from './styles.module.css'
55

6-
function WithProvider() {
6+
function WithProviderMinimal() {
7+
const ref = useRef<HTMLButtonElement>(null)
8+
9+
return (
10+
<section style={{ marginTop: '100px' }}>
11+
<p>
12+
<TooltipWrapper forwardRef={ref} place="bottom" content="Shared Global Tooltip">
13+
<button
14+
// this will not work, must use wrapper `forwardRef`
15+
ref={ref}
16+
>
17+
Minimal 1
18+
</button>
19+
</TooltipWrapper>
20+
<TooltipWrapper place="right" content="Shared Global Tooltip">
21+
<button>Minimal 2</button>
22+
</TooltipWrapper>
23+
</p>
24+
<Tooltip />
25+
</section>
26+
)
27+
}
28+
29+
function WithProviderFullControl() {
730
const { attach, detach } = useTooltip()
831
const { attach: attach1, detach: detach1 } = useTooltip()('tooltip-1')
932
const { attach: attach2, detach: detach2 } = useTooltip()('tooltip-2')
@@ -51,39 +74,13 @@ function WithProvider() {
5174
Provider 6
5275
</button>
5376
</p>
77+
<Tooltip />
5478
<Tooltip id="tooltip-1" />
5579
<Tooltip id="tooltip-2" />
5680
</section>
5781
)
5882
}
5983

60-
function WithProviderMinimal() {
61-
const { attach, detach } = useTooltip()
62-
const buttonRef1 = useRef<HTMLButtonElement>(null)
63-
const buttonRef2 = useRef<HTMLButtonElement>(null)
64-
65-
useEffect(() => {
66-
attach(buttonRef1, buttonRef2)
67-
return () => {
68-
detach(buttonRef1, buttonRef2)
69-
}
70-
}, [])
71-
72-
return (
73-
<section style={{ marginTop: '100px' }}>
74-
<p>
75-
<button ref={buttonRef1} data-tooltip-content="Shared Global Tooltip">
76-
Minimal 1
77-
</button>
78-
<button ref={buttonRef2} data-tooltip-content="Shared Global Tooltip">
79-
Minimal 2
80-
</button>
81-
</p>
82-
<Tooltip />
83-
</section>
84-
)
85-
}
86-
8784
function App() {
8885
const [anchorId, setAnchorId] = useState('button')
8986
const [isDarkOpen, setIsDarkOpen] = useState(false)
@@ -155,10 +152,10 @@ function App() {
155152
</p>
156153
</section>
157154
<TooltipProvider>
158-
<WithProvider />
155+
<WithProviderMinimal />
159156
</TooltipProvider>
160157
<TooltipProvider>
161-
<WithProviderMinimal />
158+
<WithProviderFullControl />
162159
</TooltipProvider>
163160
</main>
164161
)

src/components/TooltipProvider/TooltipProvider.tsx

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,11 @@ import React, {
88
useState,
99
} from 'react'
1010

11-
type AnchorRef = React.RefObject<HTMLElement>
12-
13-
interface TooltipContextData {
14-
anchorRefs: Set<AnchorRef>
15-
activeAnchor: AnchorRef
16-
attach: (...refs: AnchorRef[]) => void
17-
detach: (...refs: AnchorRef[]) => void
18-
setActiveAnchor: (ref: AnchorRef) => void
19-
}
20-
21-
type TooltipContextDataWrapper = TooltipContextData & {
22-
// This means the context is a callable object
23-
(tooltipId?: string): TooltipContextData
24-
}
11+
import type {
12+
AnchorRef,
13+
TooltipContextData,
14+
TooltipContextDataWrapper,
15+
} from './TooltipProviderTypes'
2516

2617
const defaultContextData: TooltipContextData = {
2718
anchorRefs: new Set(),
@@ -54,7 +45,7 @@ const TooltipProvider: React.FC<PropsWithChildren> = ({ children }) => {
5445
const tooltipRefs = oldMap[tooltipId] ?? new Set()
5546
refs.forEach((ref) => tooltipRefs.add(ref))
5647
// create new object to trigger re-render
57-
return { ...oldMap, [tooltipId]: tooltipRefs }
48+
return { ...oldMap, [tooltipId]: new Set(tooltipRefs) }
5849
})
5950
}
6051

@@ -113,4 +104,4 @@ export function useTooltip() {
113104
return useContext(TooltipContext)
114105
}
115106

116-
export { TooltipProvider }
107+
export default TooltipProvider
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { MutableRefObject, ReactElement, RefObject } from 'react'
2+
import type { ITooltipController } from '../TooltipController/TooltipControllerTypes'
3+
4+
export type AnchorRef = RefObject<HTMLElement>
5+
6+
export interface TooltipContextData {
7+
anchorRefs: Set<AnchorRef>
8+
activeAnchor: AnchorRef
9+
attach: (...refs: AnchorRef[]) => void
10+
detach: (...refs: AnchorRef[]) => void
11+
setActiveAnchor: (ref: AnchorRef) => void
12+
}
13+
14+
export type TooltipContextDataWrapper = TooltipContextData & {
15+
// This means the context is a callable object
16+
(tooltipId?: string): TooltipContextData
17+
}
18+
19+
export interface ITooltipWrapper {
20+
tooltipId?: string
21+
forwardRef?: MutableRefObject<HTMLElement | null>
22+
children: ReactElement
23+
24+
place?: ITooltipController['place']
25+
content?: ITooltipController['content']
26+
html?: ITooltipController['html']
27+
variant?: ITooltipController['variant']
28+
offset?: ITooltipController['offset']
29+
wrapper?: ITooltipController['wrapper']
30+
events?: ITooltipController['events']
31+
positionStrategy?: ITooltipController['positionStrategy']
32+
delayShow?: ITooltipController['delayShow']
33+
delayHide?: ITooltipController['delayHide']
34+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React, { useEffect, useRef } from 'react'
2+
import { useTooltip } from './TooltipProvider'
3+
import type { ITooltipWrapper } from './TooltipProviderTypes'
4+
5+
const TooltipWrapper = ({
6+
tooltipId,
7+
forwardRef,
8+
children,
9+
place,
10+
content,
11+
html,
12+
variant,
13+
offset,
14+
wrapper,
15+
events,
16+
positionStrategy,
17+
delayShow,
18+
delayHide,
19+
}: ITooltipWrapper) => {
20+
const { attach, detach } = useTooltip()(tooltipId)
21+
const anchorRef = useRef<HTMLElement | null>(null)
22+
23+
useEffect(() => {
24+
attach(anchorRef)
25+
return () => {
26+
detach(anchorRef)
27+
}
28+
}, [])
29+
30+
return React.cloneElement(children, {
31+
ref: (ref: HTMLElement) => {
32+
anchorRef.current = ref
33+
if (forwardRef) {
34+
// eslint-disable-next-line no-param-reassign
35+
forwardRef.current = ref
36+
}
37+
},
38+
'data-tooltip-place': place,
39+
'data-tooltip-content': content,
40+
'data-tooltip-html': html,
41+
'data-tooltip-variant': variant,
42+
'data-tooltip-offset': offset,
43+
'data-tooltip-wrapper': wrapper,
44+
'data-tooltip-events': events,
45+
'data-tooltip-position-strategy': positionStrategy,
46+
'data-tooltip-delay-show': delayShow,
47+
'data-tooltip-delay-hide': delayHide,
48+
})
49+
}
50+
51+
export default TooltipWrapper
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
export { TooltipProvider, useTooltip } from './TooltipProvider'
1+
export { default as TooltipProvider, useTooltip } from './TooltipProvider'
2+
export { default as TooltipWrapper } from './TooltipWrapper'

src/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import './tokens.css'
22

33
export { TooltipController as Tooltip } from './components/TooltipController'
4+
export { TooltipProvider, TooltipWrapper } from './components/TooltipProvider'

0 commit comments

Comments
 (0)