-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(store-ui): Breadcrumb molecule (#986)
* Breadcrumb molecule * use Icon component and export level typing * reviews improvements * typing, naming and description improvements * unnecessary styles
- Loading branch information
Gabriel Antiqueira
authored
Oct 25, 2021
1 parent
87a7014
commit 325c738
Showing
7 changed files
with
236 additions
and
0 deletions.
There are no files selected for viewing
47 changes: 47 additions & 0 deletions
47
packages/store-ui/src/molecules/Breadcrumb/Breadcrumb.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,47 @@ | ||
import { render } from '@testing-library/react' | ||
import React from 'react' | ||
|
||
import Breadcrumb from './Breadcrumb' | ||
|
||
describe('Breadcrumb', () => { | ||
it('`data-store-breadcrumb` is present', () => { | ||
const { getByTestId } = render(<Breadcrumb breadcrumb={[]} />) | ||
|
||
expect(getByTestId('store-breadcrumb')).toHaveAttribute( | ||
'data-store-breadcrumb' | ||
) | ||
}) | ||
|
||
it('has the correct breadcrumb size and active item is always the last breadcrumb item', () => { | ||
const { queryAllByTestId, rerender } = render( | ||
<Breadcrumb breadcrumb={[]} /> | ||
) | ||
|
||
// Test 10 different breadcrumbs, from 1 level to 10 levels. | ||
for (let breadcrumbSize = 1; breadcrumbSize <= 10; breadcrumbSize += 1) { | ||
// Creates a generic breadcrumb data. | ||
const breadcrumb = Array.from( | ||
{ length: breadcrumbSize }, | ||
(_: undefined, index: number) => ({ href: '/', text: `Level ${index}` }) | ||
) | ||
|
||
rerender(<Breadcrumb breadcrumb={breadcrumb} />) | ||
|
||
const breadcrumbItems = queryAllByTestId('store-breadcrumb-item') | ||
|
||
// Validate that breadcrumb is rendering with the correct size. | ||
expect(breadcrumbItems).toHaveLength(breadcrumbSize) | ||
// Validate if the last element has the active attribute. | ||
expect(breadcrumbItems[breadcrumbSize - 1]).toHaveAttribute( | ||
'data-store-breadcrumb-item-active' | ||
) | ||
|
||
// Get all elements except the last one. | ||
breadcrumbItems.pop() | ||
// Validate that no other element has the 'data-store-breadcrumb-item-active' attribute | ||
breadcrumbItems.forEach((item) => { | ||
expect(item).not.toHaveAttribute('data-store-breadcrumb-item-active') | ||
}) | ||
} | ||
}) | ||
}) |
104 changes: 104 additions & 0 deletions
104
packages/store-ui/src/molecules/Breadcrumb/Breadcrumb.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,104 @@ | ||
import type { | ||
HTMLAttributes, | ||
AnchorHTMLAttributes, | ||
ElementType, | ||
ReactNode, | ||
PropsWithChildren, | ||
} from 'react' | ||
import React, { forwardRef, Fragment } from 'react' | ||
|
||
import Icon from '../../atoms/Icon' | ||
|
||
export type BreadcrumbLevelType = { | ||
href: string | ||
text: string | ||
} | ||
|
||
const DefaultLink = ({ | ||
children, | ||
...otherProps | ||
}: AnchorHTMLAttributes<HTMLAnchorElement>) => <a {...otherProps}>{children}</a> | ||
|
||
const DefaultHomeIcon = () => ( | ||
<svg width="24" height="24" viewBox="0 0 24 24"> | ||
<path d="M21 13v10h-6v-6h-6v6h-6v-10h-3l12-12 12 12h-3zm-1-5.907v-5.093h-3v2.093l3 3z" /> | ||
</svg> | ||
) | ||
|
||
const DefaultDividerIcon = () => ( | ||
<svg width="24" height="24" viewBox="0 0 180 180"> | ||
<path d="M51.707,185.343c-2.741,0-5.493-1.044-7.593-3.149c-4.194-4.194-4.194-10.981,0-15.175 l74.352-74.347L44.114,18.32c-4.194-4.194-4.194-10.987,0-15.175c4.194-4.194,10.987-4.194,15.18,0l81.934,81.934 c4.194,4.194,4.194,10.987,0,15.175l-81.934,81.939C57.201,184.293,54.454,185.343,51.707,185.343z" /> | ||
</svg> | ||
) | ||
|
||
export interface BreadcrumbProps extends HTMLAttributes<HTMLDivElement> { | ||
/** | ||
* Array with each level of the breadcrumb, containing link and text. | ||
*/ | ||
breadcrumb: BreadcrumbLevelType[] | ||
/** | ||
* A component that will be rendered as the Divider icon. | ||
*/ | ||
dividerIcon?: ReactNode | ||
/** | ||
* A component that will be rendered as the Home icon. | ||
*/ | ||
homeIcon?: ReactNode | ||
/** | ||
* A component link that will replace the HTML Anchor. | ||
*/ | ||
linkComponent?: ElementType< | ||
PropsWithChildren<{ href?: string; to?: string; 'data-testid'?: string }> | ||
> | ||
/** | ||
* ID to find this component in testing tools (e.g.: cypress, testing library, and jest). | ||
*/ | ||
testId?: string | ||
} | ||
|
||
const Breadcrumb = forwardRef<HTMLDivElement, BreadcrumbProps>( | ||
function Breadcrumb( | ||
{ | ||
breadcrumb, | ||
children, | ||
homeIcon = <DefaultHomeIcon />, | ||
dividerIcon = <DefaultDividerIcon />, | ||
linkComponent: Link = DefaultLink, | ||
testId = 'store-breadcrumb', | ||
...otherProps | ||
}, | ||
ref | ||
) { | ||
return ( | ||
<div ref={ref} data-store-breadcrumb data-testid={testId} {...otherProps}> | ||
<Link | ||
data-testid={`${testId}-home`} | ||
data-store-breadcrumb-home | ||
href="/" | ||
to="/" | ||
> | ||
<Icon component={homeIcon} /> | ||
</Link> | ||
{breadcrumb.map(({ href, text }, index) => ( | ||
<Fragment key={index}> | ||
<Icon component={dividerIcon} /> | ||
<Link | ||
data-testid={`${testId}-item`} | ||
data-store-breadcrumb-item | ||
data-store-breadcrumb-item-active={ | ||
index === breadcrumb.length - 1 || undefined | ||
} | ||
key={index} | ||
href={href} | ||
to={href} | ||
> | ||
{text} | ||
</Link> | ||
</Fragment> | ||
))} | ||
</div> | ||
) | ||
} | ||
) | ||
|
||
export default Breadcrumb |
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 './Breadcrumb' | ||
export type { BreadcrumbProps, BreadcrumbLevelType } from './Breadcrumb' |
23 changes: 23 additions & 0 deletions
23
packages/store-ui/src/molecules/Breadcrumb/stories/Breadcrumb.mdx
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,23 @@ | ||
import { Canvas, Props, Story, ArgsTable } from '@storybook/addon-docs' | ||
|
||
import Breadcrumb from '../Breadcrumb' | ||
|
||
# Bullets | ||
|
||
<Canvas> | ||
<Story id="molecules-breadcrumb--breadcrumb" /> | ||
</Canvas> | ||
|
||
## Props | ||
|
||
<ArgsTable of={Breadcrumb} /> | ||
|
||
## CSS Selectors | ||
|
||
```css | ||
[data-store-breadcrumb] {} | ||
|
||
[data-breadcrumb-item] {} | ||
|
||
[data-breadcrumb-item-active] {} | ||
``` |
44 changes: 44 additions & 0 deletions
44
packages/store-ui/src/molecules/Breadcrumb/stories/Breadcrumb.stories.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,44 @@ | ||
import type { Story } from '@storybook/react' | ||
import React from 'react' | ||
|
||
import type { ComponentArgTypes } from '../../../typings/utils' | ||
import type { BreadcrumbProps } from '../Breadcrumb' | ||
import Component from '../Breadcrumb' | ||
import mdx from './Breadcrumb.mdx' | ||
|
||
const BreadcrumbTemplate: Story<BreadcrumbProps> = ({ | ||
LinkComponent, | ||
breadcrumb, | ||
testId, | ||
}) => { | ||
return ( | ||
<Component | ||
breadcrumb={breadcrumb} | ||
LinkComponent={LinkComponent} | ||
testId={testId} | ||
/> | ||
) | ||
} | ||
|
||
export const Breadcrumb = BreadcrumbTemplate.bind({}) | ||
|
||
const argTypes: ComponentArgTypes<BreadcrumbProps> = { | ||
breadcrumb: { | ||
control: { type: 'object' }, | ||
defaultValue: [ | ||
{ href: '', text: 'Level 1' }, | ||
{ href: '', text: 'Level 2' }, | ||
{ href: '', text: 'Level 3' }, | ||
], | ||
}, | ||
} | ||
|
||
export default { | ||
title: 'Molecules/Breadcrumb', | ||
argTypes, | ||
parameters: { | ||
docs: { | ||
page: mdx, | ||
}, | ||
}, | ||
} |
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 @@ | ||
[data-store-breadcrumb] { | ||
@apply flex items-center; | ||
} | ||
|
||
[data-store-breadcrumb-home] { | ||
@apply mr-2; | ||
} | ||
|
||
[data-store-breadcrumb-item] { | ||
@apply flex text-black no-underline hover:underline mx-2; | ||
} | ||
|
||
[data-store-breadcrumb-item-active] { | ||
@apply font-bold text-xl; | ||
} |
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
@import "./breadcrumb.css"; | ||
@import "./bullets.css"; | ||
@import "./carousel.css"; | ||
@import "./icon-button.css"; | ||
|