Skip to content

Commit

Permalink
Feat(web-react): Introduce BreadcrumbsItem component
Browse files Browse the repository at this point in the history
  * and refactor Breadcrumbs to use it

refs #DS-835
  • Loading branch information
literat committed Sep 13, 2023
1 parent 8b0255f commit db67213
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 26 deletions.
36 changes: 18 additions & 18 deletions packages/web-react/src/components/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useBreadcrumbsStyleProps } from './useBreadcrumbsStyleProps';
import { SpiritBreadcrumbsProps } from '../../types';
import { useStyleProps } from '../../hooks/styleProps';
import { Icon } from '../Icon';
import { Link } from '../Link';
import BreadcrumbsItem from './BreadcrumbsItem';

const defaultProps = {
items: [],
Expand All @@ -31,24 +31,17 @@ export const Breadcrumbs = <T extends ElementType = 'nav'>(props: SpiritBreadcru
items?.map((item, index) => (
<React.Fragment key={`BreadcrumbsItem_${item.title}`}>
{index === items.length - 2 && goBackTitle && (
<li className="d-tablet-none">
<Icon name="chevron-left" />
<Link href={item.url} color="primary" isUnderlined>
{goBackTitle}
</Link>
</li>
<BreadcrumbsItem href={item.url} iconStart={<Icon name="chevron-left" />} isGoBackOnly>
{goBackTitle}
</BreadcrumbsItem>
)}
<li className="d-none d-tablet-flex">
{index !== 0 && <Icon name="chevron-right" />}
<Link
href={item.url}
color={isLast(index, items?.length) ? 'secondary' : 'primary'}
isUnderlined={!isLast(index, items?.length)}
aria-current={isLast(index, items?.length) ? 'page' : undefined}
>
{item.title}
</Link>
</li>
<BreadcrumbsItem
key={`BreadcrumbsItem_${item.title}`}
href={item.url}
isCurrent={isLast(index, items?.length)}
>
{item.title}
</BreadcrumbsItem>
</React.Fragment>
))}
</ol>
Expand All @@ -59,3 +52,10 @@ export const Breadcrumbs = <T extends ElementType = 'nav'>(props: SpiritBreadcru
Breadcrumbs.defaultProps = defaultProps;

export default Breadcrumbs;

/* {/* <li className="d-tablet-none">
<Icon name="chevron-left" />
<Link href={item.url} color="primary" isUnderlined>
{goBackTitle}
</Link>
</li> */
52 changes: 52 additions & 0 deletions packages/web-react/src/components/Breadcrumbs/BreadcrumbsItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import classNames from 'classnames';
import React from 'react';
import { useClassNamePrefix } from '../../hooks';
import { useStyleProps } from '../../hooks/styleProps';
import { SpiritBreadcrumbsItemProps } from '../../types';
import { Icon } from '../Icon';
import { Link } from '../Link';

const defaultProps = {
iconStart: undefined,
iconEnd: <Icon name="chevron-right" />,
isCurrent: false,
isGoBackOnly: false,
};

const BreadcrumbsItem = (props: SpiritBreadcrumbsItemProps) => {
const { children, href, isCurrent, iconStart, iconEnd, isGoBackOnly, ...restProps } = props;
const { styleProps, props: otherProps } = useStyleProps(restProps);
const displayNoneClassName = useClassNamePrefix('d-none');
const displayTabletFlexClassName = useClassNamePrefix('d-tablet-flex');
const displayTabletNoneClassName = useClassNamePrefix('d-tablet-none');

return (
<li
{...otherProps}
{...styleProps}
className={classNames(
{
[displayNoneClassName]: !isGoBackOnly,
[displayTabletFlexClassName]: !isGoBackOnly,
[displayTabletNoneClassName]: isGoBackOnly,
},
styleProps.className,
)}
>
{iconStart}
<Link
href={href}
color={isCurrent ? 'secondary' : 'primary'}
isUnderlined={!isCurrent}
aria-current={isCurrent ? 'page' : undefined}
>
{children}
</Link>
{!isCurrent && !isGoBackOnly && iconEnd}
</li>
);
};

BreadcrumbsItem.defaultProps = defaultProps;

export default BreadcrumbsItem;
41 changes: 35 additions & 6 deletions packages/web-react/src/components/Breadcrumbs/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Breadcrumbs

## Usage

### Basic

```jsx
import { Breadcrumbs } from '@lmc-eu/spirit-web-react/components';
```

Define breadcrumb items as array type of `BreadcrumbsItem[]`.
Define breadcrumb items as an array type of `BreadcrumbsItem[]`.

```jsx
const items = [
Expand All @@ -27,17 +31,15 @@ const items = [
];
```

## Basic example usage

Simply pass the breadcrumbs array as a prop:

```jsx
<Breadcrumbs items={items} goBackTitle="Custom back link translation" />
```

## Example of custom usage
### Custom usage

Use custom content for ordered list as component's children instead of passing breadcrumb items array via props:
Use custom content for the ordered list as component's children instead of passing breadcrumb items array via props:

```jsx
<Breadcrumbs>
Expand All @@ -51,7 +53,7 @@ Use custom content for ordered list as component's children instead of passing b
</Breadcrumbs>
```

## API
### API

| Name | Type | Default | Required | Description |
| ------------------ | ------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
Expand All @@ -62,4 +64,31 @@ Use custom content for ordered list as component's children instead of passing b
| `UNSAFE_className` | `string` ||| Wrapper custom class name |
| `UNSAFE_style` | `CSSProperties` ||| Wrapper custom style |

## BreadcrumbsItem

Use the `BreadcrumbsItem` component for the ordered list as the component's children instead of passing the breadcrumb items array via props:

```jsx
<Breadcrumbs>
{items.map((item, index) => (
<BreadcrumbsItem key={`BreadcrumbsItem_${item.title}` isCurrent={items.length === index - 1}} href={item.url}>
{item.title}
</BreadcrumbsItem>
))}
</Breadcrumbs>
```

### API

| Name | Type | Default | Required | Description |
| ------------------ | --------------- | ------------------------------- | -------- | ----------------------------------------------------- |
| `children` | `ReactNode` ||| Custom content to override items rendering from array |
| `href` | `string` ||| URL |
| `iconEnd` | `ReactNode` | `<Icon name="chevron-right" />` || Icon element on the end of the item wrapper |
| `iconStart` | `ReactNode` | - || Icon component on the start of the item |
| `isCurrent` | `boolean` | `false` || Whether is the item the current page |
| `isGoBackOnly` | `boolean` | `fasle` || Whether should be displayed in go back mode |
| `UNSAFE_className` | `string` ||| Wrapper custom class name |
| `UNSAFE_style` | `CSSProperties` ||| Wrapper custom style |

For detailed information see [Breadcrumbs](https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web/src/scss/components/Breadcrumbs/README.md) component
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const BreadcrumbsDefault = () => {
},
];

return <Breadcrumbs items={items} goBackTitle="Custom back link translation" />;
return <Breadcrumbs items={items} goBackTitle="Back" />;
};

export default BreadcrumbsDefault;
10 changes: 9 additions & 1 deletion packages/web-react/src/types/breadcrumbs.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import { ElementType, JSXElementConstructor } from 'react';
import { ElementType, JSXElementConstructor, ReactNode } from 'react';
import { ChildrenProps, StyleProps, TransferProps } from './shared';

export type BreadcrumbsItem = {
title: string;
url: string;
};

export interface SpiritBreadcrumbsItemProps extends ChildrenProps {
href: string;
iconStart?: ReactNode;
iconEnd?: ReactNode;
isCurrent: boolean;
isGoBackOnly: boolean;
}

export interface AriaBreadcrumbsElementTypeProps<T extends ElementType = 'nav'> {
/**
* The HTML element or React element used to render the breadcrumbs, e.g. 'div', 'span'.
Expand Down

0 comments on commit db67213

Please sign in to comment.