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

Commit

Permalink
Improve tooltip positioning
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Weimann <mail@michael-weimann.eu>
  • Loading branch information
weeman1337 committed Apr 3, 2022
1 parent 1f64835 commit 5aa74cf
Show file tree
Hide file tree
Showing 15 changed files with 44 additions and 65 deletions.
7 changes: 5 additions & 2 deletions res/css/views/elements/_Tooltip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ limitations under the License.
font-weight: 500;
max-width: 300px;
word-break: break-word;
margin-left: 6px;
margin-right: 6px;

background-color: #21262C; // Same on both themes
color: $accent-fg-color;
Expand All @@ -81,6 +79,11 @@ limitations under the License.
}
}

.mx_Tooltip_Natural, .mx_Tooltip_Left, .mx_Tooltip_Right {
margin-left: 6px;
margin-right: 6px;
}

// These tooltips use an older style with a chevron
.mx_Field_tooltip {
background-color: $menu-bg-color;
Expand Down
3 changes: 2 additions & 1 deletion src/components/structures/SpaceHierarchy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
import { JoinRoomReadyPayload } from "../../dispatcher/payloads/JoinRoomReadyPayload";
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
import { getKeyBindingsManager } from "../../KeyBindingsManager";
import { Alignment } from "../views/elements/Tooltip";

interface IProps {
space: Room;
Expand Down Expand Up @@ -584,7 +585,7 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu
Button = AccessibleTooltipButton;
props = {
tooltip: _t("Select a room below first"),
yOffset: -40,
alignment: Alignment.Top,
};
}

Expand Down
1 change: 0 additions & 1 deletion src/components/views/beta/BetaCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export const BetaPill = ({ onClick }: { onClick?: () => void }) => {
</div>
</div>}
onClick={onClick}
yOffset={-10}
>
{ _t("Beta") }
</AccessibleTooltipButton>;
Expand Down
2 changes: 0 additions & 2 deletions src/components/views/dialogs/ForwardDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
className="mx_ForwardList_roomButton"
onClick={jumpToRoom}
title={_t("Open link")}
yOffset={-20}
alignment={Alignment.Top}
>
<DecoratedRoomAvatar room={room} avatarSize={32} />
Expand All @@ -147,7 +146,6 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
onClick={send}
disabled={disabled}
title={title}
yOffset={-20}
alignment={Alignment.Top}
>
<div className="mx_ForwardList_sendLabel">{ _t("Send") }</div>
Expand Down
4 changes: 1 addition & 3 deletions src/components/views/elements/AccessibleTooltipButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ interface IProps extends React.ComponentProps<typeof AccessibleButton> {
label?: React.ReactNode;
tooltipClassName?: string;
forceHide?: boolean;
yOffset?: number;
alignment?: Alignment;
onHideTooltip?(ev: SyntheticEvent): void;
}
Expand Down Expand Up @@ -69,13 +68,12 @@ export default class AccessibleTooltipButton extends React.PureComponent<IProps,

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

const tip = this.state.hover && <Tooltip
tooltipClassName={tooltipClassName}
label={tooltip || title}
yOffset={yOffset}
alignment={alignment}
/>;
return (
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/elements/FacePile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const FacePile: FC<IProps> = ({ room, onlyKnownUsers = true, numShown = DEFAULT_
}

return <div {...props} className="mx_FacePile">
<TextWithTooltip class="mx_FacePile_faces" tooltip={tooltip} tooltipProps={{ yOffset: 32 }}>
<TextWithTooltip class="mx_FacePile_faces" tooltip={tooltip}>
{ members.length > numShown ? <span className="mx_FacePile_face mx_FacePile_more" /> : null }
{ shownMembers.map(m =>
<MemberAvatar key={m.userId} member={m} width={28} height={28} className="mx_FacePile_face" />) }
Expand Down
4 changes: 1 addition & 3 deletions src/components/views/elements/Pill.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,9 @@ class Pill extends React.Component {
});

if (this.state.pillType) {
const { yOffset } = this.props;

let tip;
if (this.state.hover && resource) {
tip = <Tooltip label={resource} yOffset={yOffset} />;
tip = <Tooltip label={resource} />;
}

return <MatrixClientContext.Provider value={this._matrixClient}>
Expand Down
64 changes: 31 additions & 33 deletions src/components/views/elements/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,13 @@ import classNames from 'classnames';
import { replaceableComponent } from "../../../utils/replaceableComponent";
import UIStore from "../../../stores/UIStore";

const MIN_TOOLTIP_HEIGHT = 25;

export enum Alignment {
Natural, // Pick left or right
Left,
Right,
Top, // Centered
Bottom, // Centered
InnerBottom, // Inside the target, at the bottom
Natural = 'Natural', // Pick left or right
Left = 'Left',
Right = 'Right',
Top = 'Top', // Centered
Bottom = 'Bottom', // Centered
InnerBottom = 'InnerBottom', // Inside the target, at the bottom
}

export interface ITooltipProps {
Expand All @@ -47,7 +45,6 @@ export interface ITooltipProps {
// the react element to put into the tooltip
label: React.ReactNode;
alignment?: Alignment; // defaults to Natural
yOffset?: number;
// id describing tooltip
// used to associate tooltip with target for a11y
id?: string;
Expand All @@ -66,7 +63,6 @@ export default class Tooltip extends React.Component<ITooltipProps> {

public static readonly defaultProps = {
visible: true,
yOffset: 0,
alignment: Alignment.Natural,
};

Expand Down Expand Up @@ -102,55 +98,52 @@ export default class Tooltip extends React.Component<ITooltipProps> {
// positioned, also taking into account any window zoom
private updatePosition(style: CSSProperties) {
const parentBox = this.parent.getBoundingClientRect();
let offset = 0;
if (parentBox.height > MIN_TOOLTIP_HEIGHT) {
offset = Math.floor((parentBox.height - MIN_TOOLTIP_HEIGHT) / 2);
} else {
// The tooltip is larger than the parent height: figure out what offset
// we need so that we're still centered.
offset = Math.floor(parentBox.height - MIN_TOOLTIP_HEIGHT);
}
const height = UIStore.instance.windowHeight;
const width = UIStore.instance.windowWidth;
const parentWidth = (
this.props.maxParentWidth
? Math.min(parentBox.width, this.props.maxParentWidth)
: parentBox.width
);
const baseTop = (parentBox.top - 2 + this.props.yOffset) + window.pageYOffset;
const top = baseTop + offset;
const right = width - parentBox.left - window.pageXOffset;
const left = parentBox.right + window.pageXOffset;
const horizontalCenter = (
parentBox.left - window.pageXOffset + (parentWidth / 2)
);
const leftRightTop = parentBox.top + (parentBox.height / 2);

switch (this.props.alignment) {
case Alignment.Natural:
if (parentBox.right > width / 2) {
style.right = right;
style.top = top;
style.top = leftRightTop;
style.transform = "translateY(-50%)";
break;
}
// fall through to Right
case Alignment.Right:
style.left = left;
style.top = top;
style.left = parentBox.right + window.pageXOffset;
style.top = leftRightTop;
style.transform = "translateY(-50%)";
break;
case Alignment.Left:
style.right = right;
style.top = top;
style.top = leftRightTop;
style.transform = "translateY(-50%)";
break;
case Alignment.Top:
style.top = baseTop - 16;
style.bottom = height - parentBox.top + 2;
style.left = horizontalCenter;
style.transform = "translateX(-50%)";
break;
case Alignment.Bottom:
style.top = baseTop + parentBox.height;
style.top = parentBox.top + parentBox.height + 2;
style.left = horizontalCenter;
style.transform = "translateX(-50%)";
break;
case Alignment.InnerBottom:
style.top = baseTop + parentBox.height - 50;
style.top = parentBox.top + parentBox.height - 50;
style.left = horizontalCenter;
style.transform = "translate(-50%)";
style.transform = "translateX(-50%)";
}

return style;
Expand All @@ -167,10 +160,15 @@ export default class Tooltip extends React.Component<ITooltipProps> {
// if it is not meant to be visible on first mount.
style.display = this.props.visible ? "block" : "none";

const tooltipClasses = classNames("mx_Tooltip", this.props.tooltipClassName, {
"mx_Tooltip_visible": this.props.visible,
"mx_Tooltip_invisible": !this.props.visible,
});
const tooltipClasses = classNames(
"mx_Tooltip",
`mx_Tooltip_${this.props.alignment}`,
this.props.tooltipClassName,
{
"mx_Tooltip_visible": this.props.visible,
"mx_Tooltip_invisible": !this.props.visible,
},
);

const tooltip = (
<div className={tooltipClasses} style={style}>
Expand Down
2 changes: 0 additions & 2 deletions src/components/views/elements/TooltipTarget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ const TooltipTarget: React.FC<IProps> = ({
id,
label,
alignment,
yOffset,
tooltipClassName,
maxParentWidth,
...rest
Expand All @@ -51,7 +50,6 @@ const TooltipTarget: React.FC<IProps> = ({
className={className}
tooltipClassName={tooltipClassName}
label={label}
yOffset={yOffset}
alignment={alignment}
visible={isVisible}
maxParentWidth={maxParentWidth}
Expand Down
4 changes: 0 additions & 4 deletions src/components/views/right_panel/RoomSummaryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ const AppRow: React.FC<IAppRowProps> = ({ app, room }) => {
title={openTitle}
forceHide={!(isPinned || isMaximised)}
disabled={isPinned || isMaximised}
yOffset={-48}
>
<WidgetAvatar app={app} />
<span>{ name }</span>
Expand All @@ -178,21 +177,18 @@ const AppRow: React.FC<IAppRowProps> = ({ app, room }) => {
isExpanded={menuDisplayed}
onClick={openMenu}
title={_t("Options")}
yOffset={-24}
/> }

<AccessibleTooltipButton
className="mx_RoomSummaryCard_app_pinToggle"
onClick={togglePin}
title={pinTitle}
disabled={cannotPin}
yOffset={-24}
/>
<AccessibleTooltipButton
className="mx_RoomSummaryCard_app_maximiseToggle"
onClick={toggleMaximised}
title={maximiseTitle}
yOffset={-24}
/>

{ contextMenu }
Expand Down
4 changes: 1 addition & 3 deletions src/components/views/rooms/EventTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1736,9 +1736,7 @@ class SentReceipt extends React.PureComponent<ISentReceiptProps, ISentReceiptSta
} else if (isFailed) {
label = _t("Failed to send");
}
// The yOffset is somewhat arbitrary - it just brings the tooltip down to be more associated
// with the read receipt.
tooltip = <Tooltip className="mx_EventTile_readAvatars_receiptTooltip" label={label} yOffset={3} />;
tooltip = <Tooltip className="mx_EventTile_readAvatars_receiptTooltip" label={label} />;
}

return (
Expand Down
1 change: 0 additions & 1 deletion src/components/views/rooms/MessageComposer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
recordingTooltip = <Tooltip
label={_t("%(seconds)ss left", { seconds: secondsLeft })}
alignment={Alignment.Top}
yOffset={-50}
/>;
}

Expand Down
6 changes: 0 additions & 6 deletions src/components/views/voip/CallView/CallViewButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ import { _t } from "../../../../languageHandler";
// height to get the max height of the video
const CONTEXT_MENU_VPADDING = 8; // How far the context menu sits above the button (px)

const TOOLTIP_Y_OFFSET = -24;

const CONTROLS_HIDE_DELAY = 2000;

interface IButtonProps {
Expand All @@ -59,7 +57,6 @@ const CallViewToggleButton: React.FC<IButtonProps> = ({ state: isOn, className,
onClick={onClick}
title={isOn ? onLabel : offLabel}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/>
);
};
Expand Down Expand Up @@ -219,7 +216,6 @@ export default class CallViewButtons extends React.Component<IProps, IState> {
isExpanded={this.state.showDialpad}
title={_t("Dialpad")}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/> }
<CallViewToggleButton
state={!this.props.buttonsState.micMuted}
Expand Down Expand Up @@ -256,14 +252,12 @@ export default class CallViewButtons extends React.Component<IProps, IState> {
isExpanded={this.state.showMoreMenu}
title={_t("More")}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/> }
<AccessibleTooltipButton
className="mx_CallViewButtons_button mx_CallViewButtons_button_hangup"
onClick={this.props.handlers.onHangupClick}
title={_t("Hangup")}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/>
</div>
);
Expand Down
1 change: 0 additions & 1 deletion test/components/views/elements/TooltipTarget-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ describe('<TooltipTarget />', () => {
"className": 'test className',
"tooltipClassName": 'test tooltipClassName',
"label": 'test label',
"yOffset": 1,
"alignment": Alignment.Left,
"id": 'test id',
'data-test-id': 'test',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

exports[`<TooltipTarget /> displays tooltip on mouseover 1`] = `
<div
class="mx_Tooltip test tooltipClassName mx_Tooltip_visible"
style="right: 1024px; top: -26px; display: block;"
class="mx_Tooltip mx_Tooltip_Left test tooltipClassName mx_Tooltip_visible"
style="right: 1024px; top: 0px; transform: translateY(-50%); display: block;"
>
<div
class="mx_Tooltip_chevron"
Expand Down

0 comments on commit 5aa74cf

Please sign in to comment.