Skip to content
This repository has been archived by the owner on Jun 8, 2023. It is now read-only.

Commit

Permalink
fix: Navbar Brand Second Iteration (#105)
Browse files Browse the repository at this point in the history
* navbar item container return

* initial container test

* renders test

* dropdown

* cleanup test

* initial navbar item

* navbar item

* initial navbar item tests

* container test

* no props test

* custom class name test

* public api

* navbar item story
  • Loading branch information
Tiernebre authored Jul 11, 2021
1 parent 5cd8081 commit 451ab7c
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/components/navigation/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./navbar";
export * from "./navbar-brand";
export * from "./navbar-item";
27 changes: 27 additions & 0 deletions src/components/navigation/navbar-item/NavbarItem.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { screen, render } from "@testing-library/react";
import { NavbarItem } from "./NavbarItem";

it("renders a link if link props are given", () => {
const link = { href: "https://www.google.com" };
render(<NavbarItem link={link}>Link</NavbarItem>);
const navbarItem = screen.getByRole("link");
expect(navbarItem).toBeInTheDocument();
expect(navbarItem).toHaveAttribute("href", link.href);
});

it("renders a container if container props are given", () => {
const container = { dropdown: <div></div> };
const text = "Container";
render(<NavbarItem container={container}>{text}</NavbarItem>);
const navbarItem = screen.getByText(text);
expect(navbarItem).toBeInTheDocument();
expect(navbarItem.nodeName).toEqual("DIV");
});

it("renders a container even if no props are given at all", () => {
const text = "Container";
render(<NavbarItem>{text}</NavbarItem>);
const navbarItem = screen.getByText(text);
expect(navbarItem).toBeInTheDocument();
expect(navbarItem.nodeName).toEqual("DIV");
});
33 changes: 33 additions & 0 deletions src/components/navigation/navbar-item/NavbarItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { PropsWithChildren } from "react";
import {
NavbarItemContainer,
NavbarItemContainerProps,
} from "./NavbarItemContainer";
import { NavbarItemLink, NavbarItemLinkProps } from "./NavbarItemLink";

export type NavbarItemProps = PropsWithChildren<{
link?: NavbarItemLinkProps;
container?: NavbarItemContainerProps;
}>;

const className = "navbar-item";

export const NavbarItem = ({
link,
container,
children,
}: NavbarItemProps): JSX.Element => {
if (link) {
return (
<NavbarItemLink {...link} className={className}>
{children}
</NavbarItemLink>
);
} else {
return (
<NavbarItemContainer {...container} className={className}>
{children}
</NavbarItemContainer>
);
}
};
34 changes: 34 additions & 0 deletions src/components/navigation/navbar-item/NavbarItemContainer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { screen, render } from "@testing-library/react";
import { NavbarItemContainer } from "./NavbarItemContainer";

it("renders given children", () => {
const content = "Navbar Item Container";
render(<NavbarItemContainer>{content}</NavbarItemContainer>);
expect(screen.getByText(content)).toBeInTheDocument();
});

it("is rendered with a given class", () => {
const className = "some-custom-class";
const content = "Navbar Item Container";
render(
<NavbarItemContainer className={className}>{content}</NavbarItemContainer>
);
expect(screen.getByText(content)).toHaveClass(className, { exact: true });
});

it("can be rendered with a dropdown", () => {
const dropdownText = "Test Dropdown";
const dropdown = <div className="navbar-dropdown">{dropdownText}</div>;
const content = "Navbar Item Container";
render(
<NavbarItemContainer dropdown={dropdown}>{content}</NavbarItemContainer>
);
expect(screen.getByText(content)).toHaveClass("has-dropdown");
expect(screen.getByText(dropdownText)).toBeInTheDocument();
});

it("can be rendered without a dropdown", () => {
const content = "Navbar Item Container";
render(<NavbarItemContainer>{content}</NavbarItemContainer>);
expect(screen.getByText(content)).not.toHaveClass("has-dropdown");
});
32 changes: 32 additions & 0 deletions src/components/navigation/navbar-item/NavbarItemContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { PropsWithChildren, ReactNode } from "react";
import {
ClassNameTransformMap,
createClassNameFromProps,
} from "../../../utilities";

export type NavbarItemContainerProps = PropsWithChildren<{
className?: string;
dropdown?: ReactNode;
}>;

const classNameMapping: ClassNameTransformMap<NavbarItemContainerProps> =
new Map([["dropdown", () => "has-dropdown"]]);

export const NavbarItemContainer = ({
className,
children,
dropdown,
}: NavbarItemContainerProps): JSX.Element => {
const dynamicClassName = createClassNameFromProps(
classNameMapping,
{ dropdown } as Partial<NavbarItemContainerProps>,
[className ?? ""]
);
return (
<div className={dynamicClassName}>
{children}

{dropdown}
</div>
);
};
20 changes: 14 additions & 6 deletions src/components/navigation/navbar-item/NavbarItemLink.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,27 @@ import user from "@testing-library/user-event";

const getLink = () => screen.getByRole("link");

it("is rendered without opinionated styling by default for single page routing", () => {
it("is rendered with a given class name for single page routing", () => {
const className = "some-custom-class-name";
render(
<MemoryRouter>
<NavbarItemLink to="some-custom-path">Link</NavbarItemLink>
<NavbarItemLink to="some-custom-path" className={className}>
Link
</NavbarItemLink>
</MemoryRouter>
);
expect(getLink()).toHaveClass("navbar-item", { exact: true });
expect(getLink()).toHaveClass(className, { exact: true });
});

it("is rendered without opionated styling by default for server side routing", () => {
it("is rendered with a given class name for server side routing", () => {
const className = "some-custom-class-name";
const href = "https://www.google.com";
render(<NavbarItemLink href={href}>Link</NavbarItemLink>);
expect(getLink()).toHaveClass("navbar-item", { exact: true });
render(
<NavbarItemLink href={href} className={className}>
Link
</NavbarItemLink>
);
expect(getLink()).toHaveClass(className, { exact: true });
});

it("will single page route to an existing route in the page", async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/navigation/navbar-item/NavbarItemLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export type NavbarItemLinkProps = AnchorProps;
export const NavbarItemLink = (
props: NavbarItemLinkProps
): JSX.Element | null => {
return <Anchor {...props} className="navbar-item" />;
return <Anchor {...props} />;
};
2 changes: 1 addition & 1 deletion src/components/navigation/navbar-item/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "./NavbarItemLink";
export * from "./NavbarItem";
2 changes: 1 addition & 1 deletion src/stories/Anchor.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
import { Anchor, AnchorProps } from "../components";

export default {
component: Anchor,
title: "Example/Anchor",
component: Anchor,
argTypes: {
to: {
control: {
Expand Down
27 changes: 27 additions & 0 deletions src/stories/navigation/NavbarItem.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Story, Meta } from "@storybook/react";

import { NavbarItem, NavbarItemProps } from "../../components";

export default {
component: NavbarItem,
title: "Navigation/NavbarItem",
argTypes: {
link: {
control: {
type: "object",
},
},
children: {
control: {
type: "text",
},
},
},
args: {
children: "Navbar Item",
},
} as Meta<NavbarItemProps>;

const Template: Story<NavbarItemProps> = (args) => <NavbarItem {...args} />;

export const InteractiveNavbarItem = Template.bind({});

0 comments on commit 451ab7c

Please sign in to comment.