1
1
import Link from "@mui/material/Link" ;
2
- // This is used as base for the main HelpTooltip component
3
- // eslint-disable-next-line no-restricted-imports -- Read above
4
- import Popover , { type PopoverProps } from "@mui/material/Popover" ;
5
2
import HelpIcon from "@mui/icons-material/HelpOutline" ;
6
3
import OpenInNewIcon from "@mui/icons-material/OpenInNew" ;
7
4
import {
8
- createContext ,
9
- useContext ,
10
- useRef ,
11
- useState ,
12
5
type FC ,
13
6
type PropsWithChildren ,
14
7
type HTMLAttributes ,
15
8
type ReactNode ,
9
+ forwardRef ,
10
+ ComponentProps ,
16
11
} from "react" ;
17
12
import { Stack } from "components/Stack/Stack" ;
18
- import type { CSSObject } from "@emotion/css" ;
13
+ import { type CSSObject } from "@emotion/css" ;
19
14
import { css , type Interpolation , type Theme , useTheme } from "@emotion/react" ;
20
- import { type ClassName , useClassName } from "hooks/useClassName" ;
15
+ import {
16
+ Popover ,
17
+ PopoverContent ,
18
+ PopoverTrigger ,
19
+ usePopover ,
20
+ } from "components/Popover/Popover" ;
21
21
22
22
type Icon = typeof HelpIcon ;
23
23
24
24
type Size = "small" | "medium" ;
25
25
26
- export const HelpTooltipContext = createContext <
27
- { open : boolean ; onClose : ( ) => void } | undefined
28
- > ( undefined ) ;
29
-
30
- const useHelpTooltip = ( ) => {
31
- const helpTooltipContext = useContext ( HelpTooltipContext ) ;
26
+ export const HelpTooltipIcon = HelpIcon ;
32
27
33
- if ( ! helpTooltipContext ) {
34
- throw new Error (
35
- "This hook should be used in side of the HelpTooltipContext." ,
36
- ) ;
37
- }
38
-
39
- return helpTooltipContext ;
28
+ export const HelpTooltip : FC < ComponentProps < typeof Popover > > = ( props ) => {
29
+ return < Popover mode = "hover" { ...props } /> ;
40
30
} ;
41
31
42
- interface HelpPopoverProps extends PopoverProps {
43
- onOpen : ( ) => void ;
44
- onClose : ( ) => void ;
45
- }
46
-
47
- export const HelpPopover : FC < HelpPopoverProps > = ( {
48
- onOpen,
49
- onClose,
50
- children,
51
- ...props
52
- } ) => {
53
- const popover = useClassName ( classNames . popover , [ ] ) ;
54
- const paper = useClassName ( classNames . paper , [ ] ) ;
32
+ export const HelpTooltipContent = (
33
+ props : ComponentProps < typeof PopoverContent > ,
34
+ ) => {
35
+ const theme = useTheme ( ) ;
55
36
56
37
return (
57
- < Popover
58
- className = { popover }
59
- classes = { { paper } }
60
- onClose = { onClose }
61
- anchorOrigin = { {
62
- vertical : "bottom" ,
63
- horizontal : "left" ,
64
- } }
65
- transformOrigin = { {
66
- vertical : "top" ,
67
- horizontal : "left" ,
68
- } }
69
- PaperProps = { {
70
- onMouseEnter : onOpen ,
71
- onMouseLeave : onClose ,
72
- } }
38
+ < PopoverContent
73
39
{ ...props }
74
- >
75
- { children }
76
- </ Popover >
40
+ css = { {
41
+ "& .MuiPaper-root" : {
42
+ fontSize : 14 ,
43
+ width : 304 ,
44
+ padding : 20 ,
45
+ color : theme . palette . text . secondary ,
46
+ } ,
47
+ } }
48
+ />
77
49
) ;
78
50
} ;
79
51
80
- export interface HelpTooltipProps {
81
- // Useful to test on storybook
82
- open ?: boolean ;
52
+ type HelpTooltipTriggerProps = HTMLAttributes < HTMLButtonElement > & {
83
53
size ?: Size ;
84
- icon ?: Icon ;
85
- buttonStyles ?: Interpolation < Theme > ;
86
- iconStyles ?: Interpolation < Theme > ;
87
- children ?: ReactNode ;
88
- }
89
-
90
- export const HelpTooltip : FC < HelpTooltipProps > = ( {
91
- children,
92
- open = false ,
93
- size = "medium" ,
94
- icon : Icon = HelpIcon ,
95
- buttonStyles,
96
- iconStyles,
97
- } ) => {
98
- const theme = useTheme ( ) ;
99
- const anchorRef = useRef < HTMLButtonElement > ( null ) ;
100
- const [ isOpen , setIsOpen ] = useState ( open ) ;
101
- const id = isOpen ? "help-popover" : undefined ;
54
+ hoverEffect ?: boolean ;
55
+ } ;
102
56
103
- const onClose = ( ) => {
104
- setIsOpen ( false ) ;
105
- } ;
57
+ export const HelpTooltipTrigger = forwardRef <
58
+ HTMLButtonElement ,
59
+ HelpTooltipTriggerProps
60
+ > ( ( props , ref ) => {
61
+ const {
62
+ size = "medium" ,
63
+ children = < HelpTooltipIcon /> ,
64
+ hoverEffect = true ,
65
+ ...buttonProps
66
+ } = props ;
67
+
68
+ const hoverEffectStyles = css ( {
69
+ opacity : 0.5 ,
70
+ "&:hover" : {
71
+ opacity : 0.75 ,
72
+ } ,
73
+ } ) ;
106
74
107
75
return (
108
- < >
76
+ < PopoverTrigger >
109
77
< button
110
- ref = { anchorRef }
111
- aria-describedby = { id }
78
+ { ...buttonProps }
79
+ aria-label = "More info"
80
+ ref = { ref }
112
81
css = { [
113
82
css `
114
83
display : flex;
115
84
align-items : center;
116
85
justify-content : center;
117
- width : ${ theme . spacing ( getButtonSpacingFromSize ( size ) ) } ;
118
- height : ${ theme . spacing ( getButtonSpacingFromSize ( size ) ) } ;
119
- padding : 0 ;
86
+ padding : 4px 0 ;
120
87
border : 0 ;
121
88
background : transparent;
122
- color : ${ theme . palette . text . primary } ;
123
- opacity : 0.5 ;
124
89
cursor : pointer;
90
+ color : inherit;
125
91
126
- & : hover {
127
- opacity : 0.75 ;
92
+ & svg {
93
+ width : ${ getIconSpacingFromSize ( size ) } px;
94
+ height : ${ getIconSpacingFromSize ( size ) } px;
128
95
}
129
96
` ,
130
- buttonStyles ,
97
+ hoverEffect ? hoverEffectStyles : null ,
131
98
] }
132
- onClick = { ( event ) => {
133
- event . stopPropagation ( ) ;
134
- setIsOpen ( true ) ;
135
- } }
136
- onMouseEnter = { ( ) => {
137
- setIsOpen ( true ) ;
138
- } }
139
- onMouseLeave = { ( ) => {
140
- setIsOpen ( false ) ;
141
- } }
142
- aria-label = "More info"
143
99
>
144
- < Icon
145
- css = { [
146
- {
147
- width : theme . spacing ( getIconSpacingFromSize ( size ) ) ,
148
- height : theme . spacing ( getIconSpacingFromSize ( size ) ) ,
149
- } ,
150
- iconStyles ,
151
- ] }
152
- />
100
+ { children }
153
101
</ button >
154
- < HelpPopover
155
- id = { id }
156
- open = { isOpen }
157
- anchorEl = { anchorRef . current }
158
- onOpen = { ( ) => setIsOpen ( true ) }
159
- onClose = { ( ) => setIsOpen ( false ) }
160
- >
161
- < HelpTooltipContext . Provider value = { { open : isOpen , onClose } } >
162
- { children }
163
- </ HelpTooltipContext . Provider >
164
- </ HelpPopover >
165
- </ >
102
+ </ PopoverTrigger >
166
103
) ;
167
- } ;
104
+ } ) ;
168
105
169
106
export const HelpTooltipTitle : FC < HTMLAttributes < HTMLHeadingElement > > = ( {
170
107
children,
@@ -213,7 +150,7 @@ export const HelpTooltipAction: FC<HelpTooltipActionProps> = ({
213
150
onClick,
214
151
ariaLabel,
215
152
} ) => {
216
- const tooltip = useHelpTooltip ( ) ;
153
+ const popover = usePopover ( ) ;
217
154
218
155
return (
219
156
< button
@@ -222,7 +159,7 @@ export const HelpTooltipAction: FC<HelpTooltipActionProps> = ({
222
159
onClick = { ( event ) => {
223
160
event . stopPropagation ( ) ;
224
161
onClick ( ) ;
225
- tooltip . onClose ( ) ;
162
+ popover . setIsOpen ( false ) ;
226
163
} }
227
164
>
228
165
< Icon css = { styles . actionIcon } />
@@ -239,42 +176,16 @@ export const HelpTooltipLinksGroup: FC<PropsWithChildren> = ({ children }) => {
239
176
) ;
240
177
} ;
241
178
242
- const getButtonSpacingFromSize = ( size ?: Size ) : number => {
243
- switch ( size ) {
244
- case "small" :
245
- return 2.5 ;
246
- case "medium" :
247
- default :
248
- return 3 ;
249
- }
250
- } ;
251
-
252
179
const getIconSpacingFromSize = ( size ?: Size ) : number => {
253
180
switch ( size ) {
254
181
case "small" :
255
- return 1.5 ;
182
+ return 12 ;
256
183
case "medium" :
257
184
default :
258
- return 2 ;
185
+ return 16 ;
259
186
}
260
187
} ;
261
188
262
- const classNames = {
263
- popover : ( css ) => css `
264
- pointer-events : none;
265
- ` ,
266
-
267
- paper : ( css , theme ) => css `
268
- ${ theme . typography . body2 as CSSObject }
269
-
270
- margin-top : 4px ;
271
- width : 304px ;
272
- padding : 20px ;
273
- color : ${ theme . palette . text . secondary } ;
274
- pointer-events : auto;
275
- ` ,
276
- } satisfies Record < string , ClassName > ;
277
-
278
189
const styles = {
279
190
title : ( theme ) => ( {
280
191
marginTop : 0 ,
0 commit comments