Skip to content

Commit f677c44

Browse files
chore(site): add custom popover component (#10319)
1 parent b8c7b56 commit f677c44

File tree

22 files changed

+791
-1017
lines changed

22 files changed

+791
-1017
lines changed

site/.eslintrc.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ rules:
135135
message:
136136
"You should use the Alert component provided on
137137
components/Alert/Alert"
138+
- name: "@mui/material/Popover"
139+
message:
140+
"You should use the Popover component provided on
141+
components/Popover/Popover"
138142
no-unused-vars: "off"
139143
"object-curly-spacing": "off"
140144
react-hooks/exhaustive-deps: warn

site/src/components/Dashboard/Navbar/UserDropdown/BorderedMenu.tsx

Lines changed: 0 additions & 30 deletions
This file was deleted.

site/src/components/Dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MockUser } from "testHelpers/entities";
1+
import { MockBuildInfo, MockUser } from "testHelpers/entities";
22
import { UserDropdown } from "./UserDropdown";
33
import type { Meta, StoryObj } from "@storybook/react";
44

@@ -7,6 +7,13 @@ const meta: Meta<typeof UserDropdown> = {
77
component: UserDropdown,
88
args: {
99
user: MockUser,
10+
isDefaultOpen: true,
11+
buildInfo: MockBuildInfo,
12+
supportLinks: [
13+
{ icon: "docs", name: "Documentation", target: "" },
14+
{ icon: "bug", name: "Report a bug", target: "" },
15+
{ icon: "chat", name: "Join the Coder Discord", target: "" },
16+
],
1017
},
1118
};
1219

Lines changed: 67 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,95 @@
11
import Badge from "@mui/material/Badge";
2-
import MenuItem from "@mui/material/MenuItem";
3-
import { useState, FC, PropsWithChildren, MouseEvent } from "react";
2+
import { FC, PropsWithChildren } from "react";
43
import { colors } from "theme/colors";
54
import * as TypesGen from "api/typesGenerated";
65
import { navHeight } from "theme/constants";
7-
import { BorderedMenu } from "./BorderedMenu";
86
import { DropdownArrow } from "components/DropdownArrow/DropdownArrow";
97
import { UserAvatar } from "components/UserAvatar/UserAvatar";
108
import { UserDropdownContent } from "./UserDropdownContent";
119
import { BUTTON_SM_HEIGHT } from "theme/theme";
1210
import { css } from "@emotion/react";
11+
import {
12+
Popover,
13+
PopoverContent,
14+
PopoverTrigger,
15+
} from "components/Popover/Popover";
1316

1417
export interface UserDropdownProps {
1518
user: TypesGen.User;
1619
buildInfo?: TypesGen.BuildInfoResponse;
1720
supportLinks?: TypesGen.LinkConfig[];
1821
onSignOut: () => void;
22+
isDefaultOpen?: boolean;
1923
}
2024

2125
export const UserDropdown: FC<PropsWithChildren<UserDropdownProps>> = ({
2226
buildInfo,
2327
user,
2428
supportLinks,
2529
onSignOut,
30+
isDefaultOpen,
2631
}: UserDropdownProps) => {
27-
const [anchorEl, setAnchorEl] = useState<HTMLElement | undefined>();
28-
29-
const handleDropdownClick = (ev: MouseEvent<HTMLLIElement>): void => {
30-
setAnchorEl(ev.currentTarget);
31-
};
32-
const onPopoverClose = () => {
33-
setAnchorEl(undefined);
34-
};
35-
3632
return (
37-
<>
38-
<MenuItem
39-
css={(theme) => css`
40-
height: ${navHeight}px;
41-
padding: ${theme.spacing(1.5, 0)};
33+
<Popover isDefaultOpen={isDefaultOpen}>
34+
{(popover) => (
35+
<>
36+
<PopoverTrigger>
37+
<button
38+
css={(theme) => css`
39+
background: none;
40+
border: 0;
41+
cursor: pointer;
42+
height: ${navHeight}px;
43+
padding: ${theme.spacing(1.5, 0)};
4244
43-
&:hover {
44-
background-color: transparent;
45-
}
46-
`}
47-
onClick={handleDropdownClick}
48-
data-testid="user-dropdown-trigger"
49-
>
50-
<div
51-
css={{
52-
display: "flex",
53-
alignItems: "center",
54-
minWidth: 0,
55-
maxWidth: 300,
56-
}}
57-
>
58-
<Badge overlap="circular">
59-
<UserAvatar
60-
sx={{
61-
width: BUTTON_SM_HEIGHT,
62-
height: BUTTON_SM_HEIGHT,
63-
fontSize: 16,
64-
}}
65-
username={user.username}
66-
avatarURL={user.avatar_url}
67-
/>
68-
</Badge>
69-
<DropdownArrow color={colors.gray[6]} close={Boolean(anchorEl)} />
70-
</div>
71-
</MenuItem>
45+
&:hover {
46+
background-color: transparent;
47+
}
48+
`}
49+
data-testid="user-dropdown-trigger"
50+
>
51+
<div
52+
css={{
53+
display: "flex",
54+
alignItems: "center",
55+
minWidth: 0,
56+
maxWidth: 300,
57+
}}
58+
>
59+
<Badge overlap="circular">
60+
<UserAvatar
61+
sx={{
62+
width: BUTTON_SM_HEIGHT,
63+
height: BUTTON_SM_HEIGHT,
64+
fontSize: 16,
65+
}}
66+
username={user.username}
67+
avatarURL={user.avatar_url}
68+
/>
69+
</Badge>
70+
<DropdownArrow color={colors.gray[6]} close={popover.isOpen} />
71+
</div>
72+
</button>
73+
</PopoverTrigger>
7274

73-
<BorderedMenu
74-
anchorEl={anchorEl}
75-
open={Boolean(anchorEl)}
76-
anchorOrigin={{
77-
vertical: "bottom",
78-
horizontal: "right",
79-
}}
80-
transformOrigin={{
81-
vertical: "top",
82-
horizontal: "right",
83-
}}
84-
marginThreshold={0}
85-
variant="user-dropdown"
86-
onClose={onPopoverClose}
87-
>
88-
<UserDropdownContent
89-
user={user}
90-
buildInfo={buildInfo}
91-
supportLinks={supportLinks}
92-
onPopoverClose={onPopoverClose}
93-
onSignOut={onSignOut}
94-
/>
95-
</BorderedMenu>
96-
</>
75+
<PopoverContent
76+
horizontal="right"
77+
css={(theme) => ({
78+
".MuiPaper-root": {
79+
width: 260,
80+
boxShadow: theme.shadows[6],
81+
},
82+
})}
83+
>
84+
<UserDropdownContent
85+
user={user}
86+
buildInfo={buildInfo}
87+
supportLinks={supportLinks}
88+
onSignOut={onSignOut}
89+
/>
90+
</PopoverContent>
91+
</>
92+
)}
93+
</Popover>
9794
);
9895
};

site/src/components/Dashboard/Navbar/UserDropdown/UserDropdownContent.stories.tsx

Lines changed: 0 additions & 42 deletions
This file was deleted.

site/src/components/Dashboard/Navbar/UserDropdown/UserDropdownContent.test.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ import { screen } from "@testing-library/react";
22
import { MockUser } from "testHelpers/entities";
33
import { render, waitForLoaderToBeRemoved } from "testHelpers/renderHelpers";
44
import { Language, UserDropdownContent } from "./UserDropdownContent";
5+
import { Popover } from "components/Popover/Popover";
56

67
describe("UserDropdownContent", () => {
78
it("has the correct link for the account item", async () => {
89
render(
9-
<UserDropdownContent
10-
user={MockUser}
11-
onSignOut={jest.fn()}
12-
onPopoverClose={jest.fn()}
13-
/>,
10+
<Popover>
11+
<UserDropdownContent user={MockUser} onSignOut={jest.fn()} />
12+
</Popover>,
1413
);
1514
await waitForLoaderToBeRemoved();
1615

@@ -25,11 +24,9 @@ describe("UserDropdownContent", () => {
2524
it("calls the onSignOut function", async () => {
2625
const onSignOut = jest.fn();
2726
render(
28-
<UserDropdownContent
29-
user={MockUser}
30-
onSignOut={onSignOut}
31-
onPopoverClose={jest.fn()}
32-
/>,
27+
<Popover>
28+
<UserDropdownContent user={MockUser} onSignOut={onSignOut} />
29+
</Popover>,
3330
);
3431
await waitForLoaderToBeRemoved();
3532
screen.getByText(Language.signOutLabel).click();

site/src/components/Dashboard/Navbar/UserDropdown/UserDropdownContent.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
type Interpolation,
1717
type Theme,
1818
} from "@emotion/react";
19+
import { usePopover } from "components/Popover/Popover";
1920

2021
export const Language = {
2122
accountLabel: "Account",
@@ -82,17 +83,21 @@ export interface UserDropdownContentProps {
8283
user: TypesGen.User;
8384
buildInfo?: TypesGen.BuildInfoResponse;
8485
supportLinks?: TypesGen.LinkConfig[];
85-
onPopoverClose: () => void;
8686
onSignOut: () => void;
8787
}
8888

8989
export const UserDropdownContent: FC<UserDropdownContentProps> = ({
9090
buildInfo,
9191
user,
9292
supportLinks,
93-
onPopoverClose,
9493
onSignOut,
9594
}) => {
95+
const popover = usePopover();
96+
97+
const onPopoverClose = () => {
98+
popover.setIsOpen(false);
99+
};
100+
96101
return (
97102
<div>
98103
<Stack css={styles.info} spacing={0}>

site/src/components/HelpTooltip/HelpTooltip.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import Link from "@mui/material/Link";
2+
// This is used as base for the main HelpTooltip component
3+
// eslint-disable-next-line no-restricted-imports -- Read above
24
import Popover, { PopoverProps } from "@mui/material/Popover";
35
import HelpIcon from "@mui/icons-material/HelpOutline";
46
import OpenInNewIcon from "@mui/icons-material/OpenInNew";

0 commit comments

Comments
 (0)