Skip to content

Commit 06e3191

Browse files
maradwan26Gururajj77heloiselui
authored
feat(tooltip): react|wc parity (#21018)
* feat(tooltip): react|wc parity * fix: content alignment and dropShadow * fix: rtl * Update packages/web-components/src/components/tooltip/tooltip.stories.ts Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com> * Update packages/web-components/src/components/tooltip/tooltip-story.scss Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com> * Update packages/web-components/src/components/tooltip/tooltip-story.scss Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com> --------- Co-authored-by: Gururaj J <89023023+Gururajj77@users.noreply.github.com> Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com>
1 parent 0f3c1c0 commit 06e3191

File tree

7 files changed

+266
-108
lines changed

7 files changed

+266
-108
lines changed

packages/react/src/components/Tooltip/Tooltip.featureflag.stories.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright IBM Corp. 2016, 2023
2+
* Copyright IBM Corp. 2016, 2025
33
*
44
* This source code is licensed under the Apache-2.0 license found in the
55
* LICENSE file in the root directory of this source tree.
@@ -71,4 +71,19 @@ FloatingStyles.argTypes = {
7171
type: 'select',
7272
},
7373
},
74+
label: {
75+
control: {
76+
type: 'text',
77+
},
78+
},
79+
description: {
80+
control: {
81+
type: 'text',
82+
},
83+
},
84+
highContrast: {
85+
table: {
86+
disable: true,
87+
},
88+
},
7489
};

packages/react/src/components/Tooltip/Tooltip.stories.js

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright IBM Corp. 2016, 2023
2+
* Copyright IBM Corp. 2016, 2025
33
*
44
* This source code is licensed under the Apache-2.0 license found in the
55
* LICENSE file in the root directory of this source tree.
@@ -25,6 +25,45 @@ export default {
2525
page: mdx,
2626
},
2727
},
28+
argTypes: {
29+
align: {
30+
options: [
31+
'top',
32+
'top-start',
33+
'top-end',
34+
35+
'bottom',
36+
'bottom-start',
37+
'bottom-end',
38+
39+
'left',
40+
'left-end',
41+
'left-start',
42+
43+
'right',
44+
'right-end',
45+
'right-start',
46+
],
47+
control: {
48+
type: 'select',
49+
},
50+
},
51+
highContrast: {
52+
table: {
53+
disable: true,
54+
},
55+
},
56+
label: {
57+
control: {
58+
type: 'text',
59+
},
60+
},
61+
description: {
62+
control: {
63+
type: 'text',
64+
},
65+
},
66+
},
2867
decorators: [
2968
(Story, context) => {
3069
if (context.name.toLowerCase().includes('auto align')) {
@@ -52,54 +91,15 @@ export const Default = (args) => {
5291
);
5392
};
5493

55-
Default.argTypes = {
56-
align: {
57-
// TODO:
58-
// 1. Should the deprecated options be deleted?
59-
// 2. The list doesn't include all of the options available in the
60-
// component. Is it supposed to?
61-
options: [
62-
'top',
63-
'top-left',
64-
'top-right',
65-
66-
'bottom',
67-
'bottom-left',
68-
'bottom-right',
69-
70-
'left',
71-
'left-bottom',
72-
'left-top',
73-
74-
'right',
75-
'right-bottom',
76-
'right-top',
77-
],
78-
control: {
79-
type: 'select',
80-
},
81-
},
82-
label: {
83-
control: {
84-
type: 'text',
85-
},
86-
},
87-
description: {
88-
control: {
89-
type: 'text',
90-
},
91-
},
92-
};
93-
94-
export const Alignment = () => {
94+
export const Alignment = (args) => {
9595
return (
96-
<Tooltip label="Tooltip alignment" align="bottom-left">
96+
<Tooltip label="Tooltip alignment" align="bottom-left" {...args}>
9797
<Button>This button has a tooltip</Button>
9898
</Tooltip>
9999
);
100100
};
101101

102-
export const ExperimentalAutoAlign = () => {
102+
export const ExperimentalAutoAlign = (args) => {
103103
const ref = useRef();
104104
const tooltipLabel =
105105
'Scroll the container up, down, left or right to observe how the tooltip will automatically change its position in attempt to stay within the viewport. This works on initial render in addition to on scroll.';
@@ -115,7 +115,7 @@ export const ExperimentalAutoAlign = () => {
115115
top: '2500px',
116116
left: '2500px',
117117
}}>
118-
<Tooltip label={tooltipLabel} align="top" autoAlign>
118+
<Tooltip label={tooltipLabel} align="top" autoAlign {...args}>
119119
<Button ref={ref}>This button has a tooltip</Button>
120120
</Tooltip>
121121
</div>
@@ -125,9 +125,14 @@ export const ExperimentalAutoAlign = () => {
125125

126126
// Note: autoAlign is used here only to make tooltips visible in StackBlitz,
127127
// autoAlign is in preview and not part of the actual implementation.
128-
export const Duration = () => {
128+
export const Duration = (args) => {
129129
return (
130-
<Tooltip autoAlign label="Label one" enterDelayMs={0} leaveDelayMs={300}>
130+
<Tooltip
131+
autoAlign
132+
label="Label one"
133+
enterDelayMs={0}
134+
leaveDelayMs={300}
135+
{...args}>
131136
<Button>This button has a tooltip</Button>
132137
</Tooltip>
133138
);

packages/react/src/components/Tooltip/Tooltip.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ interface TooltipBaseProps {
8484
/**
8585
* Render the component using the high-contrast theme
8686
*/
87-
highContrast?: boolean;
87+
highContrast?: boolean; // TODO: remove in v12, highContrast should not be configurable
8888

8989
/**
9090
* Provide the label to be rendered inside of the Tooltip. The label will use
@@ -126,7 +126,7 @@ const Tooltip: TooltipComponent = React.forwardRef(
126126
defaultOpen = false,
127127
closeOnActivation = false,
128128
dropShadow = false,
129-
highContrast = true,
129+
highContrast = true, // TODO: remove in v12, highContrast should not be configurable
130130
...rest
131131
}: TooltipProps<T>,
132132
ref?: PolymorphicRef<T>
@@ -289,7 +289,7 @@ const Tooltip: TooltipComponent = React.forwardRef(
289289
align={align}
290290
className={cx(`${prefix}--tooltip`, customClassName)}
291291
dropShadow={dropShadow}
292-
highContrast={highContrast}
292+
highContrast={highContrast} // TODO: v12 hard-set highContrast to true
293293
onKeyDown={onKeyDown}
294294
onMouseLeave={onMouseLeave}
295295
open={open}>
@@ -391,7 +391,7 @@ const Tooltip: TooltipComponent = React.forwardRef(
391391
/**
392392
* Render the component using the high-contrast theme
393393
*/
394-
highContrast: PropTypes.bool,
394+
highContrast: PropTypes.bool, // TODO: remove in v12, highContrast should not be configurable
395395

396396
/**
397397
* Provide the label to be rendered inside of the Tooltip. The label will use

packages/web-components/src/components/popover/popover.scss

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -283,13 +283,21 @@ $popover-border-color: custom-property.get-var(
283283
:host(#{$prefix}-slug[alignment='bottom-start']:not([autoalign])) {
284284
.#{$prefix}--popover-content {
285285
inset-block-end: 0;
286-
inset-inline-start: 0;
286+
inset-inline-start: calc(50% - $popover-offset);
287287
transform: translate(
288288
calc(-1 * $popover-offset),
289289
calc(100% + $popover-offset)
290290
);
291291
}
292292
}
293+
:host(#{$prefix}-popover-content[tabTip][align='bottom-left']:not([autoalign])),
294+
:host(
295+
#{$prefix}-popover-content[tabTip][align='bottom-start']:not([autoalign])
296+
) {
297+
.#{$prefix}--popover-content {
298+
inset-inline-start: 0;
299+
}
300+
}
293301

294302
// rtl
295303
:host(
@@ -311,11 +319,26 @@ $popover-border-color: custom-property.get-var(
311319
:host(#{$prefix}-ai-label:dir(rtl)[alignment='bottom-start']:not([autoalign])),
312320
:host(#{$prefix}-slug:dir(rtl)[alignment='bottom-start']:not([autoalign])) {
313321
.#{$prefix}--popover-content {
314-
inset-inline-end: 0;
322+
inset-inline-end: calc(50% - $popover-offset);
315323
inset-inline-start: initial;
316324
}
317325
}
318326

327+
:host(
328+
#{$prefix}-popover-content:dir(rtl)[tabTip][align='bottom-left']:not(
329+
[autoalign]
330+
)
331+
),
332+
:host(
333+
#{$prefix}-popover-content:dir(rtl)[tabTip][align='bottom-start']:not(
334+
[autoalign]
335+
)
336+
) {
337+
.#{$prefix}--popover-content {
338+
inset-inline-end: 0;
339+
}
340+
}
341+
319342
:host(#{$prefix}-tooltip-content[align='bottom-right']:not([autoalign])),
320343
:host(#{$prefix}-popover-content[align='bottom-right']:not([autoalign])),
321344
:host(#{$prefix}-toggletip[alignment='bottom-right']:not([autoalign])),
@@ -328,10 +351,18 @@ $popover-border-color: custom-property.get-var(
328351
:host(#{$prefix}-slug[alignment='bottom-end']:not([autoalign])) {
329352
.#{$prefix}--popover-content {
330353
inset-block-end: 0;
331-
inset-inline-end: 0;
354+
inset-inline-end: calc(50% - $popover-offset);
332355
transform: translate($popover-offset, calc(100% + $popover-offset));
333356
}
334357
}
358+
:host(
359+
#{$prefix}-popover-content[tabTip][align='bottom-right']:not([autoalign])
360+
),
361+
:host(#{$prefix}-popover-content[tabTip][align='bottom-end']:not([autoalign])) {
362+
.#{$prefix}--popover-content {
363+
inset-inline-end: 0;
364+
}
365+
}
335366

336367
// rtl
337368
:host(
@@ -348,6 +379,21 @@ $popover-border-color: custom-property.get-var(
348379
:host(#{$prefix}-toggletip:dir(rtl)[alignment='bottom-end']:not([autoalign])),
349380
:host(#{$prefix}-ai-label:dir(rtl)[alignment='bottom-end']:not([autoalign])),
350381
:host(#{$prefix}-slug:dir(rtl)[alignment='bottom-end']:not([autoalign])) {
382+
.#{$prefix}--popover-content {
383+
inset-inline-start: calc(50% - $popover-offset);
384+
}
385+
}
386+
387+
:host(
388+
#{$prefix}-popover-content:dir(rtl)[tabTip][align='bottom-right']:not(
389+
[autoalign]
390+
)
391+
),
392+
:host(
393+
#{$prefix}-popover-content:dir(rtl)[tabTip][align='bottom-end']:not(
394+
[autoalign]
395+
)
396+
) {
351397
.#{$prefix}--popover-content {
352398
inset-inline-start: 0;
353399
}
@@ -697,7 +743,7 @@ $popover-border-color: custom-property.get-var(
697743
:host(#{$prefix}-slug[alignment='top-start']:not([autoalign])) {
698744
.#{$prefix}--popover-content {
699745
inset-block-start: 0;
700-
inset-inline-start: 0;
746+
inset-inline-start: calc(50% - $popover-offset);
701747
transform: translate(
702748
calc(-1 * $popover-offset),
703749
calc(-100% - $popover-offset)
@@ -717,7 +763,7 @@ $popover-border-color: custom-property.get-var(
717763
:host(#{$prefix}-ai-label:dir(rtl)[alignment='top-start']:not([autoalign])),
718764
:host(#{$prefix}-slug[alignment='top-start']:not([autoalign])) {
719765
.#{$prefix}--popover-content {
720-
inset-inline-end: 0;
766+
inset-inline-end: calc(50% - $popover-offset);
721767
inset-inline-start: initial;
722768
}
723769
}
@@ -734,7 +780,7 @@ $popover-border-color: custom-property.get-var(
734780
:host(#{$prefix}-slug[alignment='top-end']:not([autoalign])) {
735781
.#{$prefix}--popover-content {
736782
inset-block-start: 0;
737-
inset-inline-end: 0;
783+
inset-inline-end: calc(50% - $popover-offset);
738784
transform: translate($popover-offset, calc(-100% - $popover-offset));
739785
}
740786
}
@@ -751,7 +797,7 @@ $popover-border-color: custom-property.get-var(
751797
:host(#{$prefix}-ai-label:dir(rtl)[alignment='top-end']:not([autoalign])),
752798
:host(#{$prefix}-slug[alignment='top-end']:not([autoalign])) {
753799
.#{$prefix}--popover-content {
754-
inset-inline-start: 0;
800+
inset-inline-start: calc(50% - $popover-offset);
755801
}
756802
}
757803

@@ -780,7 +826,8 @@ $popover-border-color: custom-property.get-var(
780826
//-----------------------------------------------------------------------------
781827

782828
// autoalign caret
783-
:host(#{$prefix}-popover-content[open][caret][autoalign]) {
829+
:host(#{$prefix}-popover-content[open][caret][autoalign]),
830+
:host(#{$prefix}-tooltip-content[open][caret][autoalign]) {
784831
.#{$prefix}--popover-caret {
785832
&::before {
786833
block-size: 8px;
@@ -809,8 +856,8 @@ $popover-border-color: custom-property.get-var(
809856

810857
.#{$prefix}--popover-content[align^='bottom'] > .#{$prefix}--popover-caret {
811858
&::after {
812-
inset-block-end: -1px;
813-
inset-inline-start: 0.5px;
859+
inset-block-start: 1px;
860+
inset-inline-start: 1px;
814861
}
815862
}
816863

@@ -823,7 +870,7 @@ $popover-border-color: custom-property.get-var(
823870
.#{$prefix}--popover-content[align^='right'] > .#{$prefix}--popover-caret {
824871
&::after {
825872
inset-block-start: -1px;
826-
inset-inline-end: 0.5px;
873+
inset-inline-start: 1px;
827874
}
828875
}
829876
}

packages/web-components/src/components/tooltip/tooltip-story.scss

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright IBM Corp. 2019, 2024
2+
// Copyright IBM Corp. 2019, 2025
33
//
44
// This source code is licensed under the Apache-2.0 license found in the
55
// LICENSE file in the root directory of this source tree.
@@ -10,6 +10,7 @@
1010
@use '@carbon/styles/scss/spacing' as *;
1111
@use '@carbon/styles/scss/theme';
1212
@use '@carbon/styles/scss/type';
13+
@use '@carbon/styles/scss/utilities/focus-outline';
1314

1415
// This is a utility class to make sure that tooltip stories have a minimum
1516
// height when used in MDX docs
@@ -27,9 +28,12 @@
2728
display: flex;
2829
align-items: center;
2930
justify-content: center;
30-
border: 1px solid theme.$border-subtle;
31-
block-size: $spacing-07;
32-
inline-size: $spacing-07;
31+
block-size: $spacing-05;
32+
inline-size: $spacing-05;
33+
}
34+
35+
.sb-tooltip-trigger:focus {
36+
@include focus-outline.focus-outline;
3337
}
3438

3539
.sb-tooltip-trigger svg {

0 commit comments

Comments
 (0)