Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 7ed3089

Browse files
committed
Improve tooltip positioning
Signed-off-by: Michael Weimann <[email protected]>
1 parent 1e73184 commit 7ed3089

File tree

16 files changed

+112
-68
lines changed

16 files changed

+112
-68
lines changed

res/css/views/elements/_MiniAvatarUploader.scss

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ limitations under the License.
2525
z-index: unset;
2626
width: max-content;
2727
left: 72px;
28-
top: 0;
28+
// top edge starting at 50 % of parent - 50 % of itself -> centered vertically
29+
top: 50%;
30+
transform: translateY(-50%);
2931
}
3032

3133
.mx_MiniAvatarUploader_indicator {

res/css/views/elements/_Tooltip.scss

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ limitations under the License.
7070
font-weight: 500;
7171
max-width: 300px;
7272
word-break: break-word;
73-
margin-left: 6px;
74-
margin-right: 6px;
7573

7674
background-color: #21262C; // Same on both themes
7775
color: $accent-fg-color;

res/css/views/rooms/_RoomSublist.scss

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -406,10 +406,6 @@ limitations under the License.
406406
}
407407
}
408408

409-
.mx_RoomSublist_addRoomTooltip {
410-
margin-top: -3px;
411-
}
412-
413409
.mx_RoomSublist_skeletonUI {
414410
position: relative;
415411
margin-left: 4px;

src/components/structures/SpaceHierarchy.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
6464
import { JoinRoomReadyPayload } from "../../dispatcher/payloads/JoinRoomReadyPayload";
6565
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
6666
import { getKeyBindingsManager } from "../../KeyBindingsManager";
67+
import { Alignment } from "../views/elements/Tooltip";
6768

6869
interface IProps {
6970
space: Room;
@@ -583,7 +584,7 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu
583584
Button = AccessibleTooltipButton;
584585
props = {
585586
tooltip: _t("Select a room below first"),
586-
yOffset: -40,
587+
alignment: Alignment.Top,
587588
};
588589
}
589590

src/components/views/beta/BetaCard.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ export const BetaPill = ({
6060
</div>
6161
</div>}
6262
onClick={onClick}
63-
yOffset={-10}
6463
>
6564
{ _t("Beta") }
6665
</AccessibleTooltipButton>;

src/components/views/dialogs/ForwardDialog.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
136136
className="mx_ForwardList_roomButton"
137137
onClick={jumpToRoom}
138138
title={_t("Open room")}
139-
yOffset={-20}
140139
alignment={Alignment.Top}
141140
>
142141
<DecoratedRoomAvatar room={room} avatarSize={32} />
@@ -151,7 +150,6 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
151150
onClick={send}
152151
disabled={disabled}
153152
title={title}
154-
yOffset={-20}
155153
alignment={Alignment.Top}
156154
>
157155
<div className="mx_ForwardList_sendLabel">{ _t("Send") }</div>

src/components/views/elements/AccessibleTooltipButton.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ interface IProps extends React.ComponentProps<typeof AccessibleButton> {
2626
label?: string;
2727
tooltipClassName?: string;
2828
forceHide?: boolean;
29-
yOffset?: number;
3029
alignment?: Alignment;
3130
onHover?: (hovering: boolean) => void;
3231
onHideTooltip?(ev: SyntheticEvent): void;
@@ -76,13 +75,12 @@ export default class AccessibleTooltipButton extends React.PureComponent<IProps,
7675

7776
render() {
7877
// eslint-disable-next-line @typescript-eslint/no-unused-vars
79-
const { title, tooltip, children, tooltipClassName, forceHide, yOffset, alignment, onHideTooltip,
78+
const { title, tooltip, children, tooltipClassName, forceHide, alignment, onHideTooltip,
8079
...props } = this.props;
8180

8281
const tip = this.state.hover && <Tooltip
8382
tooltipClassName={tooltipClassName}
8483
label={tooltip || title}
85-
yOffset={yOffset}
8684
alignment={alignment}
8785
/>;
8886
return (

src/components/views/elements/FacePile.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const FacePile: FC<IProps> = ({ members, faceSize, overflow, tooltip, children,
5151

5252
return <div {...props} className="mx_FacePile">
5353
{ tooltip ? (
54-
<TextWithTooltip class="mx_FacePile_faces" tooltip={tooltip} tooltipProps={{ yOffset: 32 }}>
54+
<TextWithTooltip class="mx_FacePile_faces" tooltip={tooltip}>
5555
{ pileContents }
5656
</TextWithTooltip>
5757
) : (

src/components/views/elements/Tooltip.tsx

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ import classNames from 'classnames';
2323

2424
import UIStore from "../../../stores/UIStore";
2525

26-
const MIN_TOOLTIP_HEIGHT = 25;
27-
2826
export enum Alignment {
2927
Natural, // Pick left or right
3028
Left,
@@ -33,7 +31,6 @@ export enum Alignment {
3331
Bottom, // Centered
3432
InnerBottom, // Inside the target, at the bottom
3533
TopRight, // On top of the target, right aligned
36-
TopCenter, // On top of the target, center aligned
3734
}
3835

3936
export interface ITooltipProps {
@@ -48,7 +45,6 @@ export interface ITooltipProps {
4845
// the react element to put into the tooltip
4946
label: React.ReactNode;
5047
alignment?: Alignment; // defaults to Natural
51-
yOffset?: number;
5248
// id describing tooltip
5349
// used to associate tooltip with target for a11y
5450
id?: string;
@@ -66,7 +62,6 @@ export default class Tooltip extends React.Component<ITooltipProps> {
6662

6763
public static readonly defaultProps = {
6864
visible: true,
69-
yOffset: 0,
7065
alignment: Alignment.Natural,
7166
};
7267

@@ -102,65 +97,60 @@ export default class Tooltip extends React.Component<ITooltipProps> {
10297
// positioned, also taking into account any window zoom
10398
private updatePosition(style: CSSProperties) {
10499
const parentBox = this.parent.getBoundingClientRect();
105-
let offset = 0;
106-
if (parentBox.height > MIN_TOOLTIP_HEIGHT) {
107-
offset = Math.floor((parentBox.height - MIN_TOOLTIP_HEIGHT) / 2);
108-
} else {
109-
// The tooltip is larger than the parent height: figure out what offset
110-
// we need so that we're still centered.
111-
offset = Math.floor(parentBox.height - MIN_TOOLTIP_HEIGHT);
112-
}
113100
const width = UIStore.instance.windowWidth;
101+
const spacing = 6;
114102
const parentWidth = (
115103
this.props.maxParentWidth
116104
? Math.min(parentBox.width, this.props.maxParentWidth)
117105
: parentBox.width
118106
);
119-
const baseTop = (parentBox.top - 2 + this.props.yOffset) + window.scrollY;
120-
const top = baseTop + offset;
107+
const baseTop = parentBox.top + window.scrollY;
108+
const centerTop = parentBox.top + window.scrollY + (parentBox.height / 2);
121109
const right = width - parentBox.left - window.scrollX;
122110
const left = parentBox.right + window.scrollX;
123111
const horizontalCenter = (
124112
parentBox.left - window.scrollX + (parentWidth / 2)
125113
);
114+
126115
switch (this.props.alignment) {
127116
case Alignment.Natural:
128117
if (parentBox.right > width / 2) {
129-
style.right = right;
130-
style.top = top;
118+
style.right = right + spacing;
119+
style.top = centerTop;
120+
style.transform = "translateY(-50%)";
131121
break;
132122
}
133123
// fall through to Right
134124
case Alignment.Right:
135-
style.left = left;
136-
style.top = top;
125+
style.left = left + spacing;
126+
style.top = centerTop;
127+
style.transform = "translateY(-50%)";
137128
break;
138129
case Alignment.Left:
139-
style.right = right;
140-
style.top = top;
130+
style.right = right + spacing;
131+
style.top = centerTop;
132+
style.transform = "translateY(-50%)";
141133
break;
142134
case Alignment.Top:
143-
style.top = baseTop - 16;
135+
style.top = baseTop - spacing;
144136
style.left = horizontalCenter;
137+
style.transform = "translate(-50%, -100%)";
145138
break;
146139
case Alignment.Bottom:
147-
style.top = baseTop + parentBox.height;
140+
style.top = baseTop + parentBox.height + spacing;
148141
style.left = horizontalCenter;
142+
style.transform = "translate(-50%)";
149143
break;
150144
case Alignment.InnerBottom:
151145
style.top = baseTop + parentBox.height - 50;
152146
style.left = horizontalCenter;
153147
style.transform = "translate(-50%)";
154148
break;
155149
case Alignment.TopRight:
156-
style.top = baseTop - 5;
150+
style.top = baseTop - spacing;
157151
style.right = width - parentBox.right - window.scrollX;
158-
style.transform = "translate(5px, -100%)";
152+
style.transform = "translateY(-100%)";
159153
break;
160-
case Alignment.TopCenter:
161-
style.top = baseTop - 5;
162-
style.left = horizontalCenter;
163-
style.transform = "translate(-50%, -100%)";
164154
}
165155

166156
return style;

src/components/views/elements/TooltipTarget.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ const TooltipTarget: React.FC<IProps> = ({
3434
id,
3535
label,
3636
alignment,
37-
yOffset,
3837
tooltipClassName,
3938
maxParentWidth,
4039
...rest
@@ -51,7 +50,6 @@ const TooltipTarget: React.FC<IProps> = ({
5150
className={className}
5251
tooltipClassName={tooltipClassName}
5352
label={label}
54-
yOffset={yOffset}
5553
alignment={alignment}
5654
visible={isVisible}
5755
maxParentWidth={maxParentWidth}

src/components/views/right_panel/RoomSummaryCard.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@ const AppRow: React.FC<IAppRowProps> = ({ app, room }) => {
166166
title={openTitle}
167167
forceHide={!(isPinned || isMaximised)}
168168
disabled={isPinned || isMaximised}
169-
yOffset={-48}
170169
>
171170
<WidgetAvatar app={app} />
172171
<span>{ name }</span>
@@ -178,21 +177,18 @@ const AppRow: React.FC<IAppRowProps> = ({ app, room }) => {
178177
isExpanded={menuDisplayed}
179178
onClick={openMenu}
180179
title={_t("Options")}
181-
yOffset={-24}
182180
/> }
183181

184182
<AccessibleTooltipButton
185183
className="mx_RoomSummaryCard_app_pinToggle"
186184
onClick={togglePin}
187185
title={pinTitle}
188186
disabled={cannotPin}
189-
yOffset={-24}
190187
/>
191188
<AccessibleTooltipButton
192189
className="mx_RoomSummaryCard_app_maximiseToggle"
193190
onClick={toggleMaximised}
194191
title={maximiseTitle}
195-
yOffset={-24}
196192
/>
197193

198194
{ contextMenu }

src/components/views/rooms/MessageComposer.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
421421
recordingTooltip = <Tooltip
422422
label={_t("%(seconds)ss left", { seconds: secondsLeft })}
423423
alignment={Alignment.Top}
424-
yOffset={-50}
425424
/>;
426425
}
427426

src/components/views/rooms/ReadReceiptGroup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ interface ReadReceiptPersonProps extends IReadReceiptProps {
233233

234234
function ReadReceiptPerson({ userId, roomMember, ts, isTwelveHour, onAfterClick }: ReadReceiptPersonProps) {
235235
const [{ showTooltip, hideTooltip }, tooltip] = useTooltip({
236-
alignment: Alignment.TopCenter,
236+
alignment: Alignment.Top,
237237
tooltipClassName: "mx_ReadReceiptGroup_person--tooltip",
238238
label: (
239239
<>

src/components/views/voip/CallView/CallViewButtons.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ import { MediaDeviceKindEnum } from "../../../../MediaDeviceHandler";
3939
// height to get the max height of the video
4040
const CONTEXT_MENU_VPADDING = 8; // How far the context menu sits above the button (px)
4141

42-
const TOOLTIP_Y_OFFSET = -24;
43-
4442
const CONTROLS_HIDE_DELAY = 2000;
4543

4644
interface IButtonProps extends Omit<React.ComponentProps<typeof AccessibleTooltipButton>, "title"> {
@@ -69,7 +67,6 @@ const CallViewToggleButton: React.FC<IButtonProps> = ({
6967
className={classes}
7068
title={isOn ? onLabel : offLabel}
7169
alignment={Alignment.Top}
72-
yOffset={TOOLTIP_Y_OFFSET}
7370
{...props}
7471
>
7572
{ children }
@@ -267,7 +264,6 @@ export default class CallViewButtons extends React.Component<IProps, IState> {
267264
isExpanded={this.state.showDialpad}
268265
title={_t("Dialpad")}
269266
alignment={Alignment.Top}
270-
yOffset={TOOLTIP_Y_OFFSET}
271267
/> }
272268
<CallViewDropdownButton
273269
state={!this.props.buttonsState.micMuted}
@@ -306,14 +302,12 @@ export default class CallViewButtons extends React.Component<IProps, IState> {
306302
isExpanded={this.state.showMoreMenu}
307303
title={_t("More")}
308304
alignment={Alignment.Top}
309-
yOffset={TOOLTIP_Y_OFFSET}
310305
/> }
311306
<AccessibleTooltipButton
312307
className="mx_CallViewButtons_button mx_CallViewButtons_button_hangup"
313308
onClick={this.props.handlers.onHangupClick}
314309
title={_t("Hangup")}
315310
alignment={Alignment.Top}
316-
yOffset={TOOLTIP_Y_OFFSET}
317311
/>
318312
</div>
319313
);

test/components/views/elements/TooltipTarget-test.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ describe('<TooltipTarget />', () => {
3030
"className": 'test className',
3131
"tooltipClassName": 'test tooltipClassName',
3232
"label": 'test label',
33-
"yOffset": 1,
3433
"alignment": Alignment.Left,
3534
"id": 'test id',
3635
'data-test-id': 'test',
@@ -64,13 +63,17 @@ describe('<TooltipTarget />', () => {
6463
expect(getVisibleTooltip()).toBeFalsy();
6564
});
6665

67-
it('displays tooltip on mouseover', () => {
68-
const wrapper = getComponent();
69-
act(() => {
70-
Simulate.mouseOver(wrapper);
71-
});
72-
expect(getVisibleTooltip()).toMatchSnapshot();
73-
});
66+
for (const alignment in Alignment) {
67+
if (isNaN(Number(alignment))) {
68+
it(`displays ${alignment} aligned tooltip on mouseover`, () => {
69+
const wrapper = getComponent({ alignment: Alignment[alignment] });
70+
act(() => {
71+
Simulate.mouseOver(wrapper);
72+
});
73+
expect(getVisibleTooltip()).toMatchSnapshot();
74+
});
75+
}
76+
}
7477

7578
it('hides tooltip on mouseleave', () => {
7679
const wrapper = getComponent();

0 commit comments

Comments
 (0)