Skip to content

Commit 61b174f

Browse files
authored
fix(tooltips): fix arrow position when using end-bottom placement (#1902)
1 parent e009570 commit 61b174f

File tree

2 files changed

+26
-13
lines changed

2 files changed

+26
-13
lines changed

packages/theming/src/utils/arrowStyles.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { ArrowPosition } from '../types';
1212
type ArrowOptions = {
1313
size?: string;
1414
inset?: string;
15+
shift?: string;
1516
animationModifier?: string;
1617
};
1718

@@ -34,7 +35,7 @@ const animationStyles = (position: ArrowPosition, modifier: string) => {
3435
`;
3536
};
3637

37-
const positionStyles = (position: ArrowPosition, size: number, inset: number) => {
38+
const positionStyles = (position: ArrowPosition, size: number, inset: number, shift: number) => {
3839
/** Overlap the arrow with the base element's border.
3940
* This value + rounding have been found to work well regardless of monitor pixel density and browser.
4041
*/
@@ -44,7 +45,7 @@ const positionStyles = (position: ArrowPosition, size: number, inset: number) =>
4445

4546
const marginPx = `${margin}px`;
4647
const placementPx = `${placement}px`;
47-
const sizePx = `${size}px`;
48+
const offsetPx = `${size + shift}px`;
4849

4950
let positionCss;
5051
let transform;
@@ -53,31 +54,31 @@ const positionStyles = (position: ArrowPosition, size: number, inset: number) =>
5354
transform = 'rotate(-135deg)';
5455
positionCss = css`
5556
top: ${placementPx};
56-
right: ${position === 'top-right' && sizePx};
57-
left: ${position === 'top' ? '50%' : position === 'top-left' && sizePx};
57+
right: ${position === 'top-right' && offsetPx};
58+
left: ${position === 'top' ? '50%' : position === 'top-left' && offsetPx};
5859
margin-left: ${position === 'top' && marginPx};
5960
`;
6061
} else if (position.startsWith('right')) {
6162
transform = 'rotate(-45deg)';
6263
positionCss = css`
63-
top: ${position === 'right' ? '50%' : position === 'right-top' && sizePx};
64+
top: ${position === 'right' ? '50%' : position === 'right-top' && offsetPx};
6465
right: ${placementPx};
65-
bottom: ${position === 'right-bottom' && sizePx};
66+
bottom: ${position === 'right-bottom' && offsetPx};
6667
margin-top: ${position === 'right' && marginPx};
6768
`;
6869
} else if (position.startsWith('bottom')) {
6970
transform = 'rotate(45deg)';
7071
positionCss = css`
71-
right: ${position === 'bottom-right' && sizePx};
72+
right: ${position === 'bottom-right' && offsetPx};
7273
bottom: ${placementPx};
73-
left: ${position === 'bottom' ? '50%' : position === 'bottom-left' && sizePx};
74+
left: ${position === 'bottom' ? '50%' : position === 'bottom-left' && offsetPx};
7475
margin-left: ${position === 'bottom' && marginPx};
7576
`;
7677
} else if (position.startsWith('left')) {
7778
transform = 'rotate(135deg)';
7879
positionCss = css`
79-
top: ${position === 'left' ? '50%' : position === 'left-top' && sizePx};
80-
bottom: ${size};
80+
top: ${position === 'left' ? '50%' : position === 'left-top' && offsetPx};
81+
bottom: ${offsetPx};
8182
left: ${placementPx};
8283
margin-top: ${position === 'left' && marginPx};
8384
`;
@@ -123,6 +124,8 @@ const positionStyles = (position: ArrowPosition, size: number, inset: number) =>
123124
* (right angle) of the arrow expressed as a CSS dimension.
124125
* @param {string} [options.inset='0'] Tweak arrow positioning by adjusting with
125126
* either a positive (push the arrow in) or negative (pull the arrow out) value.
127+
* @param {string} [options.shift='0'] Shifts arrow positioning along
128+
* the edge of the parent container.
126129
* @param {string} [options.animationModifier] A CSS class or attribute selector
127130
* which, when applied, animates the arrow's appearance.
128131
*
@@ -131,6 +134,7 @@ const positionStyles = (position: ArrowPosition, size: number, inset: number) =>
131134
export default function arrowStyles(position: ArrowPosition, options: ArrowOptions = {}) {
132135
const inset = stripUnit(options.inset || '0') as number;
133136
const size = stripUnit(options.size || '6') as number;
137+
const shift = stripUnit(options.shift || '0') as number;
134138

135139
/**
136140
* Adjusts the size to account for the overlap between the arrow and the base element.
@@ -181,7 +185,7 @@ export default function arrowStyles(position: ArrowPosition, options: ArrowOptio
181185
clip-path: polygon(100% ${afterOffset}px, ${afterOffset}px 100%, 100% 100%); /* [5] */
182186
}
183187
184-
${positionStyles(position, squareSizeRounded, inset)};
188+
${positionStyles(position, squareSizeRounded, inset, shift)};
185189
${options.animationModifier && animationStyles(position, options.animationModifier)};
186190
`;
187191
}

packages/tooltips/src/styled/StyledTooltip.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,17 @@ const sizeStyles = ({
7373
}
7474

7575
let arrowSize;
76+
let arrowShift;
7677

7778
if (hasArrow) {
78-
if (size === 'small' || size === 'medium') {
79+
if (size === 'small') {
80+
arrowSize = margin;
81+
if (['left-start', 'left-end', 'right-start', 'right-end'].includes(placement)) {
82+
arrowShift = `-${theme.borderRadii.md}px`;
83+
} else {
84+
arrowShift = '0';
85+
}
86+
} else if (size === 'medium') {
7987
arrowSize = margin;
8088
} else if (size === 'large') {
8189
margin = `${theme.space.base * 2}px`;
@@ -97,7 +105,8 @@ const sizeStyles = ({
97105
font-size: ${fontSize};
98106
overflow-wrap: ${overflowWrap};
99107
100-
${hasArrow && arrowStyles(getArrowPosition(theme, placement), { size: arrowSize })};
108+
${hasArrow &&
109+
arrowStyles(getArrowPosition(theme, placement), { size: arrowSize, shift: arrowShift })};
101110
102111
${StyledParagraph} {
103112
margin-top: ${paragraphMarginTop};

0 commit comments

Comments
 (0)