Skip to content

Commit

Permalink
feat(Breadcrumbs): replace navigate with custom item component
Browse files Browse the repository at this point in the history
  • Loading branch information
ValeraS committed Jan 21, 2025
1 parent 64a0eda commit 79b06d3
Show file tree
Hide file tree
Showing 15 changed files with 1,008 additions and 346 deletions.
96 changes: 0 additions & 96 deletions src/components/Breadcrumbs/BreadcrumbItem.tsx

This file was deleted.

37 changes: 17 additions & 20 deletions src/components/Breadcrumbs/Breadcrumbs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ $block: '.#{variables.$ns}breadcrumbs';
&:last-child {
font-weight: var(--g-text-accent-font-weight);
overflow: hidden;
margin: -2px;
padding: 2px;

#{$block}__link {
@include mixins.overflow-ellipsis();
Expand Down Expand Up @@ -65,6 +67,7 @@ $block: '.#{variables.$ns}breadcrumbs';

&:focus-visible {
outline: 2px solid var(--g-color-line-focus);
outline-offset: 0;
}
}

Expand All @@ -77,34 +80,28 @@ $block: '.#{variables.$ns}breadcrumbs';

&__more-button {
--g-button-border-radius: var(--g-focus-border-radius);
--g-button-focus-outline-offset: -2px;
}

&__menu {
margin-inline: calc(-1 * var(--g-spacing-2));
}

&__item:first-child &__menu {
margin-inline-start: 0;
}
&-popup {
--g-list-item-view-spacer-size: 8px;
max-width: 320px;
padding: var(--g-spacing-1);
}

&__popup_staircase {
$menu: '.#{variables.$ns}menu';
$staircaseLength: 10;
#{$menu} {
#{$menu}__list-item {
#{$menu}__item[class] {
padding-inline-start: 8px * $staircaseLength;
}
}
&-link {
text-decoration: none;
cursor: default;

@for $i from 0 through $staircaseLength {
#{$menu}__list-item:nth-child(#{$i}) {
#{$menu}__item[class] {
padding-inline-start: 8px * $i;
}
}
&:not([aria-disabled]) {
cursor: pointer;
}
}
}

&__item:first-child &__menu {
margin-inline-start: 0;
}
}
122 changes: 46 additions & 76 deletions src/components/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,42 @@
import * as React from 'react';

import {useForkRef, useResizeObserver} from '../../hooks';
import {Button} from '../Button';
import {DropdownMenu} from '../DropdownMenu';
import type {PopupPlacement} from '../Popup';
import type {AriaLabelingProps, DOMProps, Href, Key, QAProps, RouterOptions} from '../types';
import type {AriaLabelingProps, DOMProps, Key, QAProps} from '../types';
import {filterDOMProps} from '../utils/filterDOMProps';

import {BreadcrumbItem} from './BreadcrumbItem';
import {BreadcrumbsDropdownMenu} from './BreadcrumbsDropdownMenu';
import {BreadcrumbsItemView} from './BreadcrumbsItemView';
import {BreadcrumbsSeparator} from './BreadcrumbsSeparator';
import i18n from './i18n';
import {b, shouldClientNavigate} from './utils';
import {b} from './utils';

import './Breadcrumbs.scss';

export interface BreadcrumbsItemProps {
children: React.ReactNode;
title?: string;
href?: Href;
hrefLang?: string;
target?: React.HTMLAttributeAnchorTarget;
rel?: string;
download?: boolean | string;
ping?: string;
referrerPolicy?: React.HTMLAttributeReferrerPolicy;
'aria-label'?: string;
'aria-current'?: React.AriaAttributes['aria-current'];
routerOptions?: RouterOptions;
disabled?: boolean;
}
export type BreadcrumbsItemProps<T extends React.ElementType> =
React.ComponentPropsWithoutRef<T> & {
component?: T;
disabled?: boolean;
};

function Item(_props: BreadcrumbsItemProps): React.ReactElement | null {
function Item<T extends React.ElementType = 'a'>(
_props: BreadcrumbsItemProps<T>,
): React.ReactElement | null {
return null;
}

export interface BreadcrumbsProps extends DOMProps, AriaLabelingProps, QAProps {
export interface BreadcrumbsProps<T extends React.ElementType = 'a'>
extends DOMProps,
AriaLabelingProps,
QAProps {
id?: string;
showRoot?: boolean;
separator?: React.ReactNode;
maxItems?: number;
popupStyle?: 'staircase';
popupPlacement?: PopupPlacement;
children: React.ReactElement<BreadcrumbsItemProps> | React.ReactElement<BreadcrumbsItemProps>[];
navigate?: (href: Href, routerOptions: RouterOptions | undefined) => void;
children:
| React.ReactElement<BreadcrumbsItemProps<T>>
| React.ReactElement<BreadcrumbsItemProps<T>>[];
disabled?: boolean;
onAction?: (key: Key) => void;
}
Expand Down Expand Up @@ -155,7 +149,6 @@ export const Breadcrumbs = React.forwardRef(function Breadcrumbs(
}
});

const {navigate} = props;
let contents = items;
if (items.length > visibleItemsCount) {
contents = [];
Expand All @@ -170,53 +163,30 @@ export const Breadcrumbs = React.forwardRef(function Breadcrumbs(
}
const hiddenItems = breadcrumbs.slice(0, -endItems);
const menuItem = (
<BreadcrumbItem itemType="menu">
<DropdownMenu
items={hiddenItems.map((el, index) => {
return {
...el.props,
text: el.props.children,
disabled: props.disabled,
items: [],
action: (event) => {
<BreadcrumbsDropdownMenu
disabled={props.disabled}
popupStyle={props.popupStyle}
component={BreadcrumbsDropdownMenu}
>
{hiddenItems.map((child, index) => {
const Component = child.props.component ?? BreadcrumbsItemView;
return (
<Component
{...child.props}
index={index}
key={child.key}
disabled={props.disabled || child.props.disabled}
onAction={() => {
if (typeof props.onAction === 'function') {
props.onAction(el.key ?? index);
}

// TODO: move this logic to DropdownMenu
const target = event.currentTarget;
if (
typeof navigate === 'function' &&
target instanceof HTMLAnchorElement
) {
if (el.props.href && shouldClientNavigate(target, event)) {
event.preventDefault();
navigate(el.props.href, el.props.routerOptions);
}
props.onAction(child.key ?? index);
}
},
};
})}
popupProps={{
className: b('popup', {
staircase: props.popupStyle === 'staircase',
}),
placement: props.popupPlacement,
}}
renderSwitcher={({onClick}) => (
<Button
title={i18n('label_more')}
className={b('more-button')}
onClick={onClick}
size="s"
view="flat"
disabled={props.disabled}
}}
>
<Button.Icon>...</Button.Icon>
</Button>
)}
/>
</BreadcrumbItem>
{child.props.children}
</Component>
);
})}
</BreadcrumbsDropdownMenu>
);

contents.push(menuItem);
Expand All @@ -233,18 +203,18 @@ export const Breadcrumbs = React.forwardRef(function Breadcrumbs(
}
};

const {component: Component = BreadcrumbsItemView, ...childProps} = child.props;
return (
<li key={index} className={b('item', {calculating: !calculated})}>
<BreadcrumbItem
{...child.props}
<Component
{...childProps}
key={key}
current={isCurrent}
disabled={props.disabled || child.props.disabled}
disabled={props.disabled || childProps.disabled}
onAction={handleAction}
navigate={navigate}
>
{child.props.children}
</BreadcrumbItem>
{childProps.children}
</Component>
{isCurrent ? null : <BreadcrumbsSeparator separator={props.separator} />}
</li>
);
Expand Down
Loading

0 comments on commit 79b06d3

Please sign in to comment.