Skip to content

Commit d1b89c7

Browse files
committed
Integrated tooltip popover directly into Tab component
1 parent 15437be commit d1b89c7

File tree

3 files changed

+86
-50
lines changed

3 files changed

+86
-50
lines changed

src/scripts/Popover.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,26 @@ import React, {
44
FC,
55
ReactNode,
66
forwardRef,
7+
useEffect,
78
} from 'react';
89
import classnames from 'classnames';
910
import {
1011
AutoAlign,
1112
AutoAlignInjectedProps,
1213
RectangleAlignment,
1314
} from './AutoAlign';
15+
import { registerStyle } from './util';
16+
17+
/**
18+
*
19+
*/
20+
function useInitComponentStyle() {
21+
useEffect(() => {
22+
registerStyle('popover', [
23+
['.slds-popover_tooltip a', '{ color: white; }'],
24+
]);
25+
}, []);
26+
}
1427

1528
/**
1629
*
@@ -119,6 +132,8 @@ export const PopoverInner = forwardRef<
119132
*/
120133
export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
121134
({ position, ...props }, ref) => {
135+
useInitComponentStyle();
136+
122137
const alignment: RectangleAlignment | undefined = position?.split('-') as
123138
| RectangleAlignment
124139
| undefined;

src/scripts/Tabs.tsx

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, {
22
FC,
3+
FocusEvent,
34
ComponentType,
45
HTMLAttributes,
56
ReactElement,
@@ -11,12 +12,15 @@ import React, {
1112
useRef,
1213
useState,
1314
useEffect,
15+
useCallback,
1416
} from 'react';
1517
import classnames from 'classnames';
1618
import { registerStyle } from './util';
1719
import { DropdownButton, DropdownButtonProps } from './DropdownButton';
1820
import { useControlledValue, useEventCallback } from './hooks';
1921
import { Bivariant } from './typeUtils';
22+
import { Button } from './Button';
23+
import { Popover } from './Popover';
2024

2125
/**
2226
*
@@ -95,6 +99,37 @@ const TabMenu: FC<TabMenuProps> = (props) => {
9599
);
96100
};
97101

102+
/**
103+
*
104+
*/
105+
const TooltipContent = (props: { children: ReactNode; icon: string }) => {
106+
const { children, icon } = props;
107+
const [isHideTooltip, setIsHideTooltip] = useState(true);
108+
const popoverRef = useRef<HTMLDivElement>(null);
109+
const tooltipToggle = useCallback(() => {
110+
setIsHideTooltip((hidden) => !hidden);
111+
}, []);
112+
const onBlur = useCallback((e: FocusEvent<HTMLElement>) => {
113+
if (!popoverRef.current?.contains(e.relatedTarget)) {
114+
setIsHideTooltip(true);
115+
}
116+
}, []);
117+
return (
118+
<span className='slds-dropdown-trigger react-slds-tooltip-content'>
119+
<Button type='icon' icon={icon} onClick={tooltipToggle} onBlur={onBlur} />
120+
<Popover
121+
ref={popoverRef}
122+
hidden={isHideTooltip}
123+
tabIndex={-1}
124+
onBlur={onBlur}
125+
tooltip
126+
>
127+
{children}
128+
</Popover>
129+
</span>
130+
);
131+
};
132+
98133
/**
99134
*
100135
*/
@@ -113,6 +148,7 @@ export type TabItemRendererProps = {
113148
(eventKey: TabKey, e: React.KeyboardEvent<HTMLAnchorElement>) => void
114149
>;
115150
tooltip?: ReactNode;
151+
tooltipIcon?: string;
116152
};
117153

118154
const DefaultTabItemRenderer: FC<{ children?: ReactNode }> = (props) => {
@@ -137,7 +173,14 @@ export type TabItemProps<RendererProps extends TabItemRendererProps> = {
137173
const TabItem = <RendererProps extends TabItemRendererProps>(
138174
props: TabItemProps<RendererProps>
139175
) => {
140-
const { title, eventKey, menu, menuIcon, tooltip } = props;
176+
const {
177+
title,
178+
eventKey,
179+
menu,
180+
menuIcon,
181+
tooltip,
182+
tooltipIcon = 'info',
183+
} = props;
141184
const { type, activeTabRef } = useContext(TabsContext);
142185
const activeKey = useContext(TabsActiveKeyContext);
143186
const { onTabClick, onTabKeyDown } = useContext(TabsHandlersContext);
@@ -194,9 +237,7 @@ const TabItem = <RendererProps extends TabItemRendererProps>(
194237
{title}
195238
</a>
196239
{tooltip ? (
197-
<span className='slds-dropdown-trigger react-slds-tooltip-content'>
198-
{tooltip}
199-
</span>
240+
<TooltipContent icon={tooltipIcon}>{tooltip}</TooltipContent>
200241
) : null}
201242
{menuItems ? (
202243
<TabMenu icon={menuIcon} {...menuProps}>
@@ -293,7 +334,6 @@ function useInitComponentStyle() {
293334
'.react-slds-tooltip-content',
294335
'{ position: absolute; top: 0.6rem; right: 2.25rem; }',
295336
],
296-
['.slds-popover_tooltip', '{ left: -1rem !important; }'],
297337
[
298338
'.react-slds-tab-menu button',
299339
'{ height: 2.5rem; line-height: 2rem; width: 2rem; visibility: hidden; justify-content: center }',

stories/Tabs.stories.tsx

Lines changed: 26 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import React, { FocusEvent, useCallback, useRef, useState } from 'react';
1+
import React from 'react';
22
import {
33
Tabs,
44
Tab,
55
Icon,
66
MenuItem,
77
TabItemRendererProps,
8-
Button,
9-
Popover,
108
} from '../src/scripts';
119
import { ComponentMeta, ComponentStoryObj } from '@storybook/react';
1210

@@ -52,43 +50,6 @@ function CustomTabItemContent(props: TabItemRendererProps & { icon: string }) {
5250
);
5351
}
5452

55-
function TooltipContent(props: { text: string }) {
56-
const { text } = props;
57-
const [isHideTooltip, setIsHideTooltip] = useState(true);
58-
const popoverRef = useRef<HTMLDivElement>(null);
59-
const tooltipToggle = useCallback(() => {
60-
setIsHideTooltip((hidden) => !hidden);
61-
}, []);
62-
const onIconBlur = useCallback((e: FocusEvent<HTMLElement>) => {
63-
if (popoverRef.current !== e.relatedTarget) {
64-
setIsHideTooltip(true);
65-
}
66-
}, []);
67-
const onPopoverBlur = useCallback(() => {
68-
setIsHideTooltip(true);
69-
}, []);
70-
return (
71-
<>
72-
<Button
73-
type='icon'
74-
icon='info'
75-
onClick={tooltipToggle}
76-
onBlur={onIconBlur}
77-
title={text}
78-
/>
79-
<Popover
80-
ref={popoverRef}
81-
hidden={isHideTooltip}
82-
tabIndex={-1}
83-
onBlur={onPopoverBlur}
84-
tooltip
85-
>
86-
{text}
87-
</Popover>
88-
</>
89-
);
90-
}
91-
9253
/**
9354
*
9455
*/
@@ -240,17 +201,37 @@ export const WithTooltipScoped: ComponentStoryObj<typeof Tabs> = {
240201
title='Tab 1'
241202
menuItems={createMenu()}
242203
tooltip={
243-
<TooltipContent
244-
text={'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'}
245-
/>
204+
<div>
205+
This is a tooltip for tab #1
206+
<br />
207+
<a
208+
href='https://www.example.com/helllo?name=world'
209+
target='_blank'
210+
rel='noreferrer'
211+
>
212+
https://www.example.com/helllo?name=world
213+
</a>
214+
</div>
246215
}
247216
>
248217
This is in tab #1
249218
</Tab>
250-
<Tab eventKey='2' title='Tab 2' menuItems={createMenu()}>
219+
<Tab
220+
eventKey='2'
221+
title='Tab 2'
222+
menuItems={createMenu()}
223+
tooltip={<div>Warning!</div>}
224+
tooltipIcon='warning'
225+
>
251226
This is in tab #2
252227
</Tab>
253-
<Tab eventKey='3' title='Tab 3' menuItems={createMenu()}>
228+
<Tab
229+
eventKey='3'
230+
title='Tab 3'
231+
menuItems={createMenu()}
232+
tooltip={<div>Error!</div>}
233+
tooltipIcon='error'
234+
>
254235
This is in tab #3
255236
</Tab>
256237
</Tabs>

0 commit comments

Comments
 (0)