Skip to content

Commit

Permalink
Bring back the tooltip warm-up period
Browse files Browse the repository at this point in the history
To make it easier to browse through tooltips on neighboring elements, a common UX optimization is to allow the hover delay to be "warmed up", so that it goes to zero after the first hover. We used to have this before the tooltip component was rewritten.

This is a breaking change because consumers are now required to wrap their application in a <TooltipProvider> component once again.
  • Loading branch information
robintown committed Aug 2, 2024
1 parent 4767b77 commit f550d26
Show file tree
Hide file tree
Showing 15 changed files with 200 additions and 164 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tooltip": "^1.0.6",
"classnames": "^2.3.2",
"ts-xor": "^1.3.0",
"vaul": "^0.7.0"
Expand Down
11 changes: 7 additions & 4 deletions src/components/Button/ActionButton.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ import { fn } from "@storybook/test";
import * as icons from "@vector-im/compound-design-tokens/assets/web/icons";

import { Button as ButtonComponent } from "./Button";
import { Tooltip } from "../..";
import { Tooltip } from "../Tooltip/Tooltip";
import { TooltipProvider } from "../Tooltip/TooltipProvider";

const Template: React.FC<
{ label: string } & React.ComponentProps<typeof ButtonComponent>
> = ({ label, ...args }) => (
<Tooltip label={label}>
<ButtonComponent iconOnly {...args} />
</Tooltip>
<TooltipProvider>
<Tooltip label={label}>
<ButtonComponent iconOnly {...args} />
</Tooltip>
</TooltipProvider>
);

export default {
Expand Down
5 changes: 4 additions & 1 deletion src/components/Form/Controls/Action/Action.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Meta, StoryObj } from "@storybook/react";
import * as icons from "@vector-im/compound-design-tokens/assets/web/icons";

import { ActionInput } from "./";
import { TooltipProvider } from "../../../Tooltip/TooltipProvider";

type Props = { invalid?: boolean } & React.ComponentProps<typeof ActionInput>;

Expand Down Expand Up @@ -79,7 +80,9 @@ export default {
},
},
render: ({ invalid, ...restArgs }) => (
<ActionInput data-invalid={invalid || undefined} {...restArgs} />
<TooltipProvider>
<ActionInput data-invalid={invalid || undefined} {...restArgs} />
</TooltipProvider>
),
args: {
placeholder: "",
Expand Down
29 changes: 17 additions & 12 deletions src/components/Form/Controls/Action/Action.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,21 @@ import React from "react";
import ChatIcon from "@vector-im/compound-design-tokens/assets/web/icons/chat";

import { ActionInput } from "./Action";
import { TooltipProvider } from "../../../Tooltip/TooltipProvider";
import userEvent from "@testing-library/user-event";

describe("ActionInput", () => {
it("renders", () => {
const { asFragment } = render(
<ActionInput
Icon={ChatIcon}
actionLabel="Click me!"
onActionClick={() => {
console.log("clicked!");
}}
/>,
<TooltipProvider>
<ActionInput
Icon={ChatIcon}
actionLabel="Click me!"
onActionClick={() => {
console.log("clicked!");
}}
/>
</TooltipProvider>,
);
expect(asFragment()).toMatchSnapshot();
});
Expand All @@ -41,11 +44,13 @@ describe("ActionInput", () => {
const spy = vi.fn();

render(
<ActionInput
Icon={ChatIcon}
actionLabel="Click me!"
onActionClick={spy}
/>,
<TooltipProvider>
<ActionInput
Icon={ChatIcon}
actionLabel="Click me!"
onActionClick={spy}
/>
</TooltipProvider>,
);

await user.click(screen.getByRole("button", { name: "Click me!" }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { EditInPlace } from "./";
import { Meta, StoryObj } from "@storybook/react";
import { expect, userEvent, within } from "@storybook/test";
import { ErrorMessage } from "../../Message";
import { TooltipProvider } from "../../../Tooltip/TooltipProvider";

type Props = { invalid?: boolean } & React.ComponentProps<typeof EditInPlace>;

Expand Down Expand Up @@ -87,7 +88,11 @@ export default {
type: "boolean",
},
},
render: ({ ...restArgs }) => <EditInPlace {...restArgs} />,
render: ({ ...restArgs }) => (
<TooltipProvider>
<EditInPlace {...restArgs} />
</TooltipProvider>
),
args: {
label: "Label",
onSave: () => new Promise((resolve) => setTimeout(resolve, 1000)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import {
waitForElementToBeRemoved,
} from "@testing-library/react";

import { TooltipProvider } from "@radix-ui/react-tooltip";
import { EditInPlace } from "./EditInPlace";
import { ErrorMessage } from "../../Message";
import { TooltipProvider } from "../../../Tooltip/TooltipProvider";
import userEvent from "@testing-library/user-event";

type EditInPlaceTestProps = Omit<
Expand Down
5 changes: 4 additions & 1 deletion src/components/Form/Controls/Password/Password.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import React from "react";
import { Meta, StoryObj } from "@storybook/react";

import { PasswordInput } from "./";
import { TooltipProvider } from "../../../Tooltip/TooltipProvider";
import { screen } from "@storybook/test";
import { userEvent } from "@storybook/test";

Expand Down Expand Up @@ -62,7 +63,9 @@ export default {
},
},
render: ({ invalid, ...restArgs }) => (
<PasswordInput data-invalid={invalid || undefined} {...restArgs} />
<TooltipProvider>
<PasswordInput data-invalid={invalid || undefined} {...restArgs} />
</TooltipProvider>
),
args: {
placeholder: "",
Expand Down
7 changes: 6 additions & 1 deletion src/components/Form/Controls/Password/Password.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import { PasswordInput } from "./Password";
import { TooltipProvider } from "../../../Tooltip/TooltipProvider";

describe("PasswordControl", () => {
it("switches the input type", async () => {
const user = userEvent.setup();
const { container } = render(<PasswordInput defaultValue="p4ssw0rd!" />);
const { container } = render(
<TooltipProvider>
<PasswordInput defaultValue="p4ssw0rd!" />
</TooltipProvider>,
);

expect(container.querySelector("[type=password]")).toBeInTheDocument();
expect(container).toMatchSnapshot("invisible");
Expand Down
Loading

0 comments on commit f550d26

Please sign in to comment.