-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
39 changed files
with
1,247 additions
and
0 deletions.
There are no files selected for viewing
21 changes: 21 additions & 0 deletions
21
src/components/ApplicationLayout/AppAside/AppAside.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { screen } from "@testing-library/react"; | ||
import userEvent from "@testing-library/user-event"; | ||
|
||
import { renderComponent } from "testing/utils"; | ||
|
||
import AppAside from "./AppAside"; | ||
|
||
it("displays without a close", async () => { | ||
renderComponent(<AppAside>Content</AppAside>); | ||
expect( | ||
screen.queryByRole("button", { name: "Close" }), | ||
).not.toBeInTheDocument(); | ||
}); | ||
|
||
it("displays a close button", async () => { | ||
const onClose = jest.fn(); | ||
renderComponent(<AppAside onClose={onClose} />); | ||
expect(screen.getByText("Close")).toBeInTheDocument(); | ||
await userEvent.click(screen.getByRole("button", { name: "Close" })); | ||
expect(onClose).toHaveBeenCalled(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import Button from "@canonical/react-components/dist/components/Button"; | ||
import Icon from "@canonical/react-components/dist/components/Icon"; | ||
import type { PropsWithSpread } from "@canonical/react-components/dist/types"; | ||
import classNames from "classnames"; | ||
import { type HTMLProps, type PropsWithChildren } from "react"; | ||
|
||
import Panel, { type PanelProps } from "components/upstream/Panel"; | ||
|
||
export type Props = PropsWithSpread< | ||
{ | ||
forwardRef?: React.Ref<HTMLElement> | null; | ||
onClose?: () => void; | ||
panelProps?: PanelProps; | ||
pinned?: boolean; | ||
} & PropsWithChildren, | ||
HTMLProps<HTMLElement> | ||
>; | ||
|
||
const AppAside = ({ | ||
children, | ||
className, | ||
forwardRef, | ||
onClose, | ||
panelProps, | ||
pinned, | ||
...props | ||
}: Props) => { | ||
return ( | ||
<aside | ||
className={classNames("l-aside", className, { | ||
"is-pinned": pinned, | ||
})} | ||
{...props} | ||
ref={forwardRef} | ||
> | ||
<Panel | ||
{...(panelProps ?? {})} | ||
controls={ | ||
<> | ||
{panelProps?.controls} | ||
{onClose ? ( | ||
<Button | ||
appearance="base" | ||
className="u-no-margin--bottom" | ||
hasIcon | ||
onClick={() => onClose()} | ||
> | ||
<Icon name="close">Close</Icon> | ||
</Button> | ||
) : null} | ||
</> | ||
} | ||
> | ||
{children} | ||
</Panel> | ||
</aside> | ||
); | ||
}; | ||
export default AppAside; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { default } from "./AppAside"; | ||
export type { Props as AppAsideProps } from "./AppAside"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { screen } from "@testing-library/react"; | ||
|
||
import { renderComponent } from "testing/utils"; | ||
|
||
import AppMain from "./AppMain"; | ||
|
||
it("displays children", () => { | ||
const children = "Test content"; | ||
renderComponent(<AppMain>{children}</AppMain>); | ||
expect(screen.getByText(children)).toBeInTheDocument(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import classNames from "classnames"; | ||
import type { HTMLProps, PropsWithChildren } from "react"; | ||
|
||
type Props = PropsWithChildren & HTMLProps<HTMLDivElement>; | ||
|
||
const AppMain = ({ children, className, ...props }: Props) => { | ||
return ( | ||
<main className={classNames("l-main", className)} {...props}> | ||
{children} | ||
</main> | ||
); | ||
}; | ||
|
||
export default AppMain; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from "./AppMain"; |
21 changes: 21 additions & 0 deletions
21
src/components/ApplicationLayout/AppNavigation/AppNavigation.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { screen } from "@testing-library/react"; | ||
|
||
import { renderComponent } from "testing/utils"; | ||
|
||
import AppNavigation from "./AppNavigation"; | ||
|
||
it("displays children", () => { | ||
const children = "Test content"; | ||
renderComponent(<AppNavigation>{children}</AppNavigation>); | ||
expect(screen.getByText(children)).toBeInTheDocument(); | ||
}); | ||
|
||
it("displays as collapsed", () => { | ||
const { result } = renderComponent(<AppNavigation collapsed />); | ||
expect(result.container.firstChild).toHaveClass("is-collapsed"); | ||
}); | ||
|
||
it("displays as pinned", () => { | ||
const { result } = renderComponent(<AppNavigation pinned />); | ||
expect(result.container.firstChild).toHaveClass("is-pinned"); | ||
}); |
33 changes: 33 additions & 0 deletions
33
src/components/ApplicationLayout/AppNavigation/AppNavigation.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import type { PropsWithSpread } from "@canonical/react-components/dist/types"; | ||
import classNames from "classnames"; | ||
import type { HTMLProps, PropsWithChildren } from "react"; | ||
|
||
type Props = PropsWithSpread< | ||
{ | ||
collapsed?: boolean; | ||
pinned?: boolean; | ||
} & PropsWithChildren, | ||
HTMLProps<HTMLDivElement> | ||
>; | ||
|
||
const AppNavigation = ({ | ||
children, | ||
className, | ||
collapsed, | ||
pinned, | ||
...props | ||
}: Props) => { | ||
return ( | ||
<header | ||
className={classNames("l-navigation", className, { | ||
"is-collapsed": collapsed, | ||
"is-pinned": pinned, | ||
})} | ||
{...props} | ||
> | ||
<div className="l-navigation__drawer">{children}</div> | ||
</header> | ||
); | ||
}; | ||
|
||
export default AppNavigation; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from "./AppNavigation"; |
11 changes: 11 additions & 0 deletions
11
src/components/ApplicationLayout/AppNavigationBar/AppNavigationBar.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { screen } from "@testing-library/react"; | ||
|
||
import { renderComponent } from "testing/utils"; | ||
|
||
import AppNavigationBar from "./AppNavigationBar"; | ||
|
||
it("displays children", () => { | ||
const children = "Test content"; | ||
renderComponent(<AppNavigationBar>{children}</AppNavigationBar>); | ||
expect(screen.getByText(children)).toBeInTheDocument(); | ||
}); |
15 changes: 15 additions & 0 deletions
15
src/components/ApplicationLayout/AppNavigationBar/AppNavigationBar.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import type { PropsWithSpread } from "@canonical/react-components/dist/types"; | ||
import classNames from "classnames"; | ||
import type { HTMLProps, PropsWithChildren } from "react"; | ||
|
||
type Props = PropsWithSpread<PropsWithChildren, HTMLProps<HTMLDivElement>>; | ||
|
||
const AppNavigationBar = ({ children, className, ...props }: Props) => { | ||
return ( | ||
<header className={classNames("l-navigation-bar", className)} {...props}> | ||
{children} | ||
</header> | ||
); | ||
}; | ||
|
||
export default AppNavigationBar; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from "./AppNavigationBar"; |
11 changes: 11 additions & 0 deletions
11
src/components/ApplicationLayout/AppStatus/AppStatus.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { screen } from "@testing-library/react"; | ||
|
||
import { renderComponent } from "testing/utils"; | ||
|
||
import AppStatus from "./AppStatus"; | ||
|
||
it("displays children", () => { | ||
const children = "Test content"; | ||
renderComponent(<AppStatus>{children}</AppStatus>); | ||
expect(screen.getByText(children)).toBeInTheDocument(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import classNames from "classnames"; | ||
import type { HTMLProps, PropsWithChildren } from "react"; | ||
|
||
import Panel from "components/upstream/Panel"; | ||
|
||
type Props = PropsWithChildren & HTMLProps<HTMLDivElement>; | ||
|
||
const AppStatus = ({ children, className, ...props }: Props) => { | ||
return ( | ||
<aside className={classNames("l-status", className)} {...props}> | ||
<Panel wrapContent={false}>{children}</Panel> | ||
</aside> | ||
); | ||
}; | ||
|
||
export default AppStatus; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from "./AppStatus"; |
11 changes: 11 additions & 0 deletions
11
src/components/ApplicationLayout/Application/Application.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { screen } from "@testing-library/react"; | ||
|
||
import { renderComponent } from "testing/utils"; | ||
|
||
import Application from "./Application"; | ||
|
||
it("displays children", () => { | ||
const children = "Test content"; | ||
renderComponent(<Application>{children}</Application>); | ||
expect(screen.getByText(children)).toBeInTheDocument(); | ||
}); |
19 changes: 19 additions & 0 deletions
19
src/components/ApplicationLayout/Application/Application.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import type { PropsWithSpread } from "@canonical/react-components/dist/types"; | ||
import classNames from "classnames"; | ||
import type { HTMLProps, PropsWithChildren } from "react"; | ||
|
||
type Props = PropsWithSpread<PropsWithChildren, HTMLProps<HTMLDivElement>>; | ||
|
||
const Application = ({ children, className, ...props }: Props) => { | ||
return ( | ||
<div | ||
className={classNames("l-application", className)} | ||
role="presentation" | ||
{...props} | ||
> | ||
{children} | ||
</div> | ||
); | ||
}; | ||
|
||
export default Application; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from "./Application"; |
116 changes: 116 additions & 0 deletions
116
src/components/ApplicationLayout/ApplicationLayout.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import { screen, within } from "@testing-library/react"; | ||
import userEvent from "@testing-library/user-event"; | ||
|
||
import { renderComponent } from "testing/utils"; | ||
|
||
import AppAside from "./AppAside"; | ||
import ApplicationLayout from "./ApplicationLayout"; | ||
|
||
const logo = { | ||
icon: "icon.svg", | ||
href: "http://example.com", | ||
name: "name.svg", | ||
nameAlt: "Juju", | ||
}; | ||
|
||
it("displays a logo", () => { | ||
renderComponent(<ApplicationLayout logo={logo} navItems={[]} />); | ||
const link = screen.getAllByRole("link", { name: "Juju" })[0]; | ||
expect(within(link).getByRole("img", { name: "Juju" })).toHaveAttribute( | ||
"src", | ||
"name.svg", | ||
); | ||
}); | ||
|
||
it("displays as light", () => { | ||
renderComponent(<ApplicationLayout dark={false} logo={logo} navItems={[]} />); | ||
expect(document.querySelectorAll(".is-dark")).toHaveLength(0); | ||
expect(document.querySelectorAll(".is-light")).toHaveLength(0); | ||
}); | ||
|
||
it("displays as dark", () => { | ||
renderComponent(<ApplicationLayout dark logo={logo} navItems={[]} />); | ||
expect(document.querySelectorAll(".is-dark")).toHaveLength(5); | ||
// Two icons are light so that they appear over the dark background. | ||
expect(document.querySelectorAll(".is-light")).toHaveLength(2); | ||
}); | ||
|
||
it("displays main content", () => { | ||
const content = "Main content"; | ||
renderComponent( | ||
<ApplicationLayout logo={logo} navItems={[]}> | ||
{content} | ||
</ApplicationLayout>, | ||
); | ||
expect(screen.getByText(content)).toBeInTheDocument(); | ||
}); | ||
|
||
it("displays a status bar", () => { | ||
const content = "Main content"; | ||
renderComponent( | ||
<ApplicationLayout logo={logo} navItems={[]} status={content} />, | ||
); | ||
expect(screen.getByText(content)).toBeInTheDocument(); | ||
expect(screen.getByText(content).parentNode).toHaveClass("l-status"); | ||
}); | ||
|
||
it("displays an aside", () => { | ||
const content = "Aside content"; | ||
renderComponent( | ||
<ApplicationLayout | ||
logo={logo} | ||
navItems={[]} | ||
aside={<AppAside>{content}</AppAside>} | ||
/>, | ||
); | ||
expect(screen.getByText(content)).toBeInTheDocument(); | ||
expect(document.querySelector(".l-aside")).toBeInTheDocument(); | ||
}); | ||
|
||
it("pins the menu", async () => { | ||
renderComponent(<ApplicationLayout logo={logo} navItems={[]} />); | ||
expect(document.querySelector(".l-navigation")).not.toHaveClass("is-pinned"); | ||
await userEvent.click(screen.getByRole("button", { name: "Pin menu" })); | ||
expect(document.querySelector(".l-navigation")).toHaveClass("is-pinned"); | ||
}); | ||
|
||
it("pins the menu using external state", async () => { | ||
const onPinMenu = jest.fn(); | ||
renderComponent( | ||
<ApplicationLayout | ||
logo={logo} | ||
navItems={[]} | ||
menuPinned={true} | ||
onPinMenu={onPinMenu} | ||
/>, | ||
); | ||
expect(document.querySelector(".l-navigation")).toHaveClass("is-pinned"); | ||
await userEvent.click(screen.getByRole("button", { name: "Unpin menu" })); | ||
expect(onPinMenu).toHaveBeenCalledWith(false); | ||
}); | ||
|
||
it("opens and collapses the menu", async () => { | ||
renderComponent(<ApplicationLayout logo={logo} navItems={[]} />); | ||
expect(document.querySelector(".l-navigation")).toHaveClass("is-collapsed"); | ||
await userEvent.click(screen.getByRole("button", { name: "Menu" })); | ||
expect(document.querySelector(".l-navigation")).not.toHaveClass( | ||
"is-collapsed", | ||
); | ||
await userEvent.click(screen.getByRole("button", { name: "Close menu" })); | ||
expect(document.querySelector(".l-navigation")).toHaveClass("is-collapsed"); | ||
}); | ||
|
||
it("collapses the menu using external state", async () => { | ||
const onCollapseMenu = jest.fn(); | ||
renderComponent( | ||
<ApplicationLayout | ||
logo={logo} | ||
navItems={[]} | ||
menuCollapsed={true} | ||
onCollapseMenu={onCollapseMenu} | ||
/>, | ||
); | ||
expect(document.querySelector(".l-navigation")).toHaveClass("is-collapsed"); | ||
await userEvent.click(screen.getByRole("button", { name: "Menu" })); | ||
expect(onCollapseMenu).toHaveBeenCalledWith(false); | ||
}); |
Oops, something went wrong.