Skip to content

Commit

Permalink
feat: Breadcrumbs (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
hachiojidev authored Jan 18, 2021
1 parent a9267e9 commit afd4b0e
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/__tests__/components/breadcrumbs.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import { renderWithTheme } from "../../testHelpers";
import Breadcrumbs from "../../components/Breadcrumbs/Breadcrumbs";

it("renders correctly", () => {
const { asFragment } = renderWithTheme(<Breadcrumbs>Link</Breadcrumbs>);
expect(asFragment()).toMatchInlineSnapshot(`
<DocumentFragment>
<ul
class="sc-dlfnbm leiHoE"
/>
</DocumentFragment>
`);
});
56 changes: 56 additions & 0 deletions src/components/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* eslint-disable react/no-array-index-key */
import React, { Children, isValidElement, ReactNode } from "react";
import styled from "styled-components";
import { space } from "styled-system";
import ChevronRightIcon from "../Svg/Icons/ChevronRight";
import { BreadcrumbsProps } from "./types";

const Separator = styled.li`
align-items: center;
color: currentColor;
display: flex;
justify-content: center;
padding-left: 16px;
padding-right: 16px;
`;

const StyledBreadcrumbs = styled.ul`
align-items: center;
color: ${({ theme }) => theme.colors.textDisabled};
display: flex;
list-style-type: none;
${space}
`;

const insertSeparators = (items: ReactNode[], separator: BreadcrumbsProps["separator"]) =>
items.reduce((accum: ReactNode[], item, index) => {
if (index === 0) {
return [...accum, item];
}

return [
...accum,
<Separator aria-hidden key={`seperator-${index}`}>
{separator}
</Separator>,
item,
];
}, []);

const DefaultSeparator = <ChevronRightIcon color="currentColor" width="24px" />;

const Breadcrumbs: React.FC<BreadcrumbsProps> = ({ separator = DefaultSeparator, children }) => {
const validItems = Children.toArray(children).filter((child) => isValidElement(child));
const items = insertSeparators(validItems, separator);

return (
<StyledBreadcrumbs>
{items.map((item, index) => (
<li key={`child-${index}`}>{item}</li>
))}
</StyledBreadcrumbs>
);
};

export default Breadcrumbs;
53 changes: 53 additions & 0 deletions src/components/Breadcrumbs/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from "react";
import Text from "../Text/Text";
import Link from "../Link/Link";
import LogoIcon from "../Svg/Icons/Logo";
import WonIcon from "../Svg/Icons/Won";
import BreadCrumbs from "./Breadcrumbs";

export default {
title: "Components/Breadcrumbs",
component: BreadCrumbs,
argTypes: {},
};

export const Default: React.FC = () => {
return (
<Text p="32px">
<BreadCrumbs>
<Link href="/" color="secondary" style={{ fontWeight: 400 }}>
Link
</Link>
<Text color="textDisabled">Crumb 1</Text>
<Text color="textDisabled">Crumb 2</Text>
</BreadCrumbs>
</Text>
);
};

export const CustomSeparator: React.FC = () => {
return (
<Text p="32px">
<Text mb="16px">
<BreadCrumbs separator={<LogoIcon width="24px" />}>
<Link href="/" color="secondary" style={{ fontWeight: 400 }}>
Link
</Link>
<Text color="textDisabled">Crumb 1</Text>
<Text color="textDisabled">Crumb 2</Text>
</BreadCrumbs>
</Text>
<Text mb="16px">
<BreadCrumbs separator={<WonIcon width="48px" />}>
<Link href="/" color="failure" style={{ fontWeight: 400 }}>
Link
</Link>
<Link href="/" color="primary" style={{ fontWeight: 400 }}>
Link 2
</Link>
<Text color="textDisabled">Crumb 2</Text>
</BreadCrumbs>
</Text>
</Text>
);
};
2 changes: 2 additions & 0 deletions src/components/Breadcrumbs/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as Breadcrumbs } from "./Breadcrumbs";
export type { BreadcrumbsProps } from "./types";
3 changes: 3 additions & 0 deletions src/components/Breadcrumbs/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface BreadcrumbsProps {
separator?: React.ReactNode;
}
13 changes: 13 additions & 0 deletions src/components/Svg/Icons/ChevronRight.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";
import Svg from "../Svg";
import { SvgProps } from "../types";

const Icon: React.FC<SvgProps> = (props) => {
return (
<Svg viewBox="0 0 24 24" {...props}>
<path d="M9.29006 15.88L13.1701 12L9.29006 8.12001C8.90006 7.73001 8.90006 7.10001 9.29006 6.71001C9.68006 6.32001 10.3101 6.32001 10.7001 6.71001L15.2901 11.3C15.6801 11.69 15.6801 12.32 15.2901 12.71L10.7001 17.3C10.3101 17.69 9.68006 17.69 9.29006 17.3C8.91006 16.91 8.90006 16.27 9.29006 15.88Z" />
</Svg>
);
};

export default Icon;
1 change: 1 addition & 0 deletions src/components/Svg/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { default as CardViewIcon } from "./Icons/CardView";
export { default as CheckmarkIcon } from "./Icons/Checkmark";
export { default as CheckmarkCircleIcon } from "./Icons/CheckmarkCircle";
export { default as ChevronDownIcon } from "./Icons/ChevronDown";
export { default as ChevronRightIcon } from "./Icons/ChevronRight";
export { default as ChevronUpIcon } from "./Icons/ChevronUp";
export { default as CloseIcon } from "./Icons/Close";
export { default as CogIcon } from "./Icons/Cog";
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Components
export * from "./components/Alert";
export * from "./components/Breadcrumbs";
export * from "./components/Button";
export * from "./components/ButtonMenu";
export * from "./components/Card";
Expand Down

0 comments on commit afd4b0e

Please sign in to comment.