epam / epam/UUI

Add `Breadcrumbs` component(s)

Open
#2,125 1 comment 0 reactions 1 assignee Claimed by @DzmitryTrubchyk View on GitHub
Design needed feature
Dominant language
TypeScript
Stars
247
Forks
78
Avg merge
14h 27m
Merged PRs (30d)
15

Description

## Description

Right now, we have a custom implementation of breadcrumbs. It is used to display tree-structured data in a more compact way (see screenshot below).

![image_2024-04-05_19-00-50](https://github.com/epam/UUI/assets/10310491/f160cd5c-970e-4496-aa55-6265301bc9a6)

In our case, all the items are not clickable, but in usual cases (links to application pages) they are, so if you decide to implement that, it would be great to support both cases.

Looks like `LinkButton` is the best candidate for individual breadcrumbs. If so, it will be necessary to only implement the wrapper.

The wrapper, `Breadcrumbs` component, would do two stylistic things:
* Add forward slash between the elements
* Render the last and the rest elements differently

## Describe the solution you'd like

* Add `Breadcrumbs` wrapper component
* Add `Breadcrumb` component (or provide example, where already existing components can be used instead, like `LinkButton`)
* Decide, how the breadcrumbs should be passed to `Breadcrumbs` component. `MainMenu` approach looks the most suitable (array of objects with `render` function)
* Add documentation for the component(s)

Crude implementation example:

```typescript
import {
type LinkButton,
Text,
} from "@epam/loveship";
import {
type ComponentProps,
type FC,
Fragment,
} from "react";

type LinkButtonProps = ComponentProps;

// Or `Partial`.
type BreadcrumProps = Pick<
LinkButtonProps,
| "color"
| "size"
>;

interface BreadcrumbInfo {
id: string;
render: FC;
}

interface BreadcrumbsProps {
size?: LinkButtonProps["size"];
items: Array;
}

const Breadcrumbs: FC = ({
size,
items,
}) => {
return (
<>
{
items.map((item, index) => {
const isLast = index === items.length - 1;

const {
id,
// Allows to use hooks if rendered and not just called as a regular function (see usage below).
render: Breadcrumb,
} = item;

return (


{
!isLast
? (

{" / "}

)
: null
}

);
})
}

);
};
```

Usage example:

```typescript
import {
Breadcrumbs,
LinkButton,
} from "@epam/loveship";

const Example: FC = () => {
return (
{
return (

);
},
},
{
id: "projects",
render: (props) => {
return (

);
},
},
{
id: "project",
render: (props) => {
return (

);
},
},
]}
/>
);
};

export {
Example,
};
```

Also, if it will be necessary to filter props before passing them to render (for example, not passing `link` and `onClick` to the last element, or changing color depending on their presence), it would make sense to require passing them to the `BreadcrumbInfo` object, like this:

```typescript
import {
type LinkButton,
} from "@epam/loveship";
import {
type ComponentProps,
} from "react";

type LinkButtonProps = ComponentProps;

// Option 1.
interface BreadcrumbInfo extends LinkButtonProps {
id: string;
render: LinkButton;
}

// Option 2.
interface BreadcrumbInfo {
id: string;
props: LinkButtonProps,
render: LinkButton;
}

// Usage.

```

And to avoid typing `render: LinkButton` all the time, `render` property can be defined as optional, and `LinkButton` can be used as a default value, if the property is absent.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.