Tooltip: migrate remaining tooltips from `AccessibleTooltipButton` to `AccessibleButton` (#12522)

* Use `AccessibleButton` in `RovingAccessibleTooltipButton`

* Update snapshots

* Update @vector-im/compound-web

* Update composer

* Update formating buttons

* Update snapshots

* Update `ContextMenuTooltipButton.tsx`

* Fix placement

* Update tests

* Remove placement

* Update space panel snapshot

* Remove default placement

* Update snapshots

* Update snapshots

* Use kbd

* Update ``@vector-im/compound-web`

* Migrate remaining files

* Remove `AccessibleTooltipButton.tsx`

* Add test to `InteractiveAuthEntryComponents`

* Add test to `InteractiveAuthEntryComponents`

* Back to old RoomList-test.tsx

* Improve `InteractiveAuthEntryComponent` tests

* Review changes
pull/28217/head
Florian Duros 2024-05-17 16:11:07 +02:00 committed by GitHub
parent 8f3c8b3515
commit 75562b1d1b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 114 additions and 139 deletions

View File

@ -26,10 +26,8 @@ import SettingsStore from "../../../settings/SettingsStore";
import { LocalisedPolicy, Policies } from "../../../Terms";
import { AuthHeaderModifier } from "../../structures/auth/header/AuthHeaderModifier";
import AccessibleButton, { AccessibleButtonKind, ButtonEvent } from "../elements/AccessibleButton";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import Field from "../elements/Field";
import Spinner from "../elements/Spinner";
import { Alignment } from "../elements/Tooltip";
import CaptchaForm from "./CaptchaForm";
/* This file contains a collection of components which are used by the
@ -501,15 +499,16 @@ export class EmailIdentityAuthEntry extends React.Component<
{},
{
a: (text: string) => (
<AccessibleTooltipButton
<AccessibleButton
kind="link_inline"
title={
this.state.requested ? _t("auth|uia|email_resent") : _t("action|resend")
}
alignment={Alignment.Right}
onHideTooltip={
onTooltipOpenChange={
this.state.requested
? () => this.setState({ requested: false })
? (open) => {
if (!open) this.setState({ requested: false });
}
: undefined
}
onClick={async (): Promise<void> => {
@ -524,7 +523,7 @@ export class EmailIdentityAuthEntry extends React.Component<
}}
>
{text}
</AccessibleTooltipButton>
</AccessibleButton>
),
},
)}

View File

@ -27,7 +27,6 @@ import SdkConfig from "../../../SdkConfig";
import SettingsFlag from "../elements/SettingsFlag";
import { useFeatureEnabled } from "../../../hooks/useSettings";
import InlineSpinner from "../elements/InlineSpinner";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { shouldShowFeedback } from "../../../utils/Feedback";
// XXX: Keep this around for re-use in future Betas
@ -50,19 +49,15 @@ export const BetaPill: React.FC<IBetaPillProps> = ({
}) => {
if (onClick) {
return (
<AccessibleTooltipButton
<AccessibleButton
className="mx_BetaCard_betaPill"
title={`${tooltipTitle} ${tooltipCaption}`}
tooltip={
<div>
<div className="mx_Tooltip_title">{tooltipTitle}</div>
<div className="mx_Tooltip_sub">{tooltipCaption}</div>
</div>
}
aria-label={`${tooltipTitle} ${tooltipCaption}`}
title={tooltipTitle}
caption={tooltipCaption}
onClick={onClick}
>
{_t("common|beta")}
</AccessibleTooltipButton>
</AccessibleButton>
);
}

View File

@ -1,118 +0,0 @@
/*
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { SyntheticEvent, FocusEvent, forwardRef, useEffect, Ref, useState, ComponentProps } from "react";
import AccessibleButton from "./AccessibleButton";
import Tooltip, { Alignment } from "./Tooltip";
/**
* Type of props accepted by {@link AccessibleTooltipButton}.
*
* Extends that of {@link AccessibleButton}.
*/
type Props<T extends keyof JSX.IntrinsicElements> = ComponentProps<typeof AccessibleButton<T>> & {
/**
* Title to show in the tooltip and use as aria-label
*/
title?: string;
/**
* Tooltip node to show in the tooltip, takes precedence over `title`
*/
tooltip?: React.ReactNode;
/**
* Trigger label to render
*/
label?: string;
/**
* Classname to apply to the tooltip
*/
tooltipClassName?: string;
/**
* Force the tooltip to be hidden
*/
forceHide?: boolean;
/**
* Alignment to render the tooltip with
*/
alignment?: Alignment;
/**
* Function to call when the children are hovered over
*/
onHover?: (hovering: boolean) => void;
/**
* Function to call when the tooltip goes from shown to hidden.
*/
onHideTooltip?(ev: SyntheticEvent): void;
};
/**
* @deprecated use AccessibleButton with `title` and `caption` instead.
*/
const AccessibleTooltipButton = forwardRef(function <T extends keyof JSX.IntrinsicElements>(
{ title, tooltip, children, forceHide, alignment, onHideTooltip, tooltipClassName, element, ...props }: Props<T>,
ref: Ref<HTMLElement>,
) {
const [hover, setHover] = useState(false);
useEffect(() => {
// If forceHide is set then force hover to off to hide the tooltip
if (forceHide && hover) {
setHover(false);
}
}, [forceHide, hover]);
const showTooltip = (): void => {
props.onHover?.(true);
if (forceHide) return;
setHover(true);
};
const hideTooltip = (ev: SyntheticEvent): void => {
props.onHover?.(false);
setHover(false);
onHideTooltip?.(ev);
};
const onFocus = (ev: FocusEvent): void => {
// We only show the tooltip if focus arrived here from some other
// element, to avoid leaving tooltips hanging around when a modal closes
if (ev.relatedTarget) showTooltip();
};
const tip = hover && (title || tooltip) && (
<Tooltip tooltipClassName={tooltipClassName} label={tooltip || title} alignment={alignment} />
);
return (
<AccessibleButton
{...props}
element={element as keyof JSX.IntrinsicElements}
onMouseOver={showTooltip}
onMouseLeave={hideTooltip}
onFocus={onFocus}
onBlur={hideTooltip}
aria-label={title || props["aria-label"]}
ref={ref}
>
{children}
{props.label}
{(tooltip || title) && tip}
</AccessibleButton>
);
});
export default AccessibleTooltipButton;

View File

@ -19,10 +19,10 @@ import React, { ComponentProps } from "react";
import { Icon as CaretIcon } from "../../../../../res/img/feather-customised/dropdown-arrow.svg";
import { _t } from "../../../../languageHandler";
import AccessibleTooltipButton from "../../elements/AccessibleTooltipButton";
import AccessibleButton from "../../elements/AccessibleButton";
type Props<T extends keyof JSX.IntrinsicElements> = Omit<
ComponentProps<typeof AccessibleTooltipButton<T>>,
ComponentProps<typeof AccessibleButton<T>>,
"aria-label" | "title" | "kind" | "className" | "onClick" | "element"
> & {
isExpanded: boolean;
@ -36,7 +36,7 @@ export const DeviceExpandDetailsButton = <T extends keyof JSX.IntrinsicElements>
}: Props<T>): JSX.Element => {
const label = isExpanded ? _t("settings|sessions|hide_details") : _t("settings|sessions|show_details");
return (
<AccessibleTooltipButton
<AccessibleButton
{...rest}
aria-label={label}
title={label}
@ -47,6 +47,6 @@ export const DeviceExpandDetailsButton = <T extends keyof JSX.IntrinsicElements>
onClick={onClick}
>
<CaretIcon className="mx_DeviceExpandDetailsButton_icon" />
</AccessibleTooltipButton>
</AccessibleButton>
);
};

View File

@ -0,0 +1,65 @@
/*
* Copyright 2024 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from "react";
import { render, screen, waitFor, act } from "@testing-library/react";
import { AuthType } from "matrix-js-sdk/src/interactive-auth";
import userEvent from "@testing-library/user-event";
import { EmailIdentityAuthEntry } from "../../../../src/components/views/auth/InteractiveAuthEntryComponents";
import { createTestClient } from "../../../test-utils";
describe("<EmailIdentityAuthEntry/>", () => {
const renderIdentityAuth = () => {
const matrixClient = createTestClient();
return render(
<EmailIdentityAuthEntry
matrixClient={matrixClient}
loginType={AuthType.Email}
onPhaseChange={jest.fn()}
submitAuthDict={jest.fn()}
fail={jest.fn()}
clientSecret="my secret"
showContinue={true}
inputs={{ emailAddress: "alice@example.xyz" }}
/>,
);
};
test("should render", () => {
const { container } = renderIdentityAuth();
expect(container).toMatchSnapshot();
});
test("should clear the requested state when the button tooltip is hidden", async () => {
renderIdentityAuth();
// After a click on the resend button, the button should display the resent label
screen.getByRole("button", { name: "Resend" }).click();
await waitFor(() => expect(screen.queryByRole("button", { name: "Resent!" })).toBeInTheDocument());
expect(screen.queryByRole("button", { name: "Resend" })).toBeNull();
const resentButton = screen.getByRole("button", { name: "Resent!" });
// Hover briefly the button and wait for the tooltip to be displayed
await userEvent.hover(resentButton);
await waitFor(() => expect(screen.getByRole("tooltip", { name: "Resent!" })).toBeInTheDocument());
// On unhover, it should display again the resend button
await act(() => userEvent.unhover(resentButton));
await waitFor(() => expect(screen.queryByRole("button", { name: "Resend" })).toBeInTheDocument());
});
});

View File

@ -0,0 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<EmailIdentityAuthEntry/> should render 1`] = `
<div>
<div
class="mx_InteractiveAuthEntryComponents_emailWrapper"
>
<p>
<span>
To create your account, open the link in the email we just sent to
<b>
alice@example.xyz
</b>
.
</span>
</p>
<p
class="secondary"
>
<span>
Did not receive it?
<div
aria-label="Resend"
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button"
tabindex="0"
>
Resend it
</div>
</span>
</p>
</div>
</div>
`;