Skip to content

Commit

Permalink
Refactor EuiBreadcrumbCollapsed into separate component
Browse files Browse the repository at this point in the history
- Remove unnecessary `--collapsed` modifier class

- DRY out `<li>` and `__content` logic/styles by reusing the `EuiBreadcrumb` and `EuiBreadcrumbContent` components, passing props/overrides as necessary

- Allow any children as `EuiBreadcrumb` child to support this behavior/the popover

- Pass EuiBreadcrumbContent in at the EuiBreadcrumbs level as a result
  • Loading branch information
cee-chen committed Jul 21, 2022
1 parent a455722 commit 8aa914e
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 87 deletions.
2 changes: 1 addition & 1 deletion src-docs/src/views/breadcrumbs/breadcrumbs_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export const BreadcrumbsExample = {
<>
<p>
Use the <EuiCode>max</EuiCode> prop to collapse breadcrumbs beyond a
certain number. The center breadcrumbs will collpase into a single
certain number. The center breadcrumbs will collapse into a single
item allowing the user to navigate these items from within a
popover.
</p>
Expand Down
28 changes: 14 additions & 14 deletions src/components/breadcrumbs/__snapshots__/breadcrumbs.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ exports[`EuiBreadcrumbs is rendered 1`] = `
</span>
</li>
<li
class="euiBreadcrumb euiBreadcrumb--collapsed emotion-EuiBreadcrumbCollapsed"
class="euiBreadcrumb emotion-euiBreadcrumb-isCollapsed"
>
<div
class="euiPopover euiPopover--anchorDownCenter"
Expand All @@ -41,7 +41,7 @@ exports[`EuiBreadcrumbs is rendered 1`] = `
>
<button
aria-label="See collapsed breadcrumbs"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued-euiBreadcrumb__content"
title="See collapsed breadcrumbs"
type="button"
>
Expand Down Expand Up @@ -120,7 +120,7 @@ exports[`EuiBreadcrumbs is rendered with final item as link 1`] = `
</span>
</li>
<li
class="euiBreadcrumb euiBreadcrumb--collapsed emotion-EuiBreadcrumbCollapsed"
class="euiBreadcrumb emotion-euiBreadcrumb-isCollapsed"
>
<div
class="euiPopover euiPopover--anchorDownCenter"
Expand All @@ -130,7 +130,7 @@ exports[`EuiBreadcrumbs is rendered with final item as link 1`] = `
>
<button
aria-label="See collapsed breadcrumbs"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued-euiBreadcrumb__content"
title="See collapsed breadcrumbs"
type="button"
>
Expand Down Expand Up @@ -283,7 +283,7 @@ exports[`EuiBreadcrumbs props max renders 1 item 1`] = `
class="euiBreadcrumbs__list emotion-euiBreadcrumbs__list-isTruncated"
>
<li
class="euiBreadcrumb euiBreadcrumb--collapsed emotion-EuiBreadcrumbCollapsed"
class="euiBreadcrumb emotion-euiBreadcrumb-isCollapsed"
>
<div
class="euiPopover euiPopover--anchorDownCenter"
Expand All @@ -293,7 +293,7 @@ exports[`EuiBreadcrumbs props max renders 1 item 1`] = `
>
<button
aria-label="See collapsed breadcrumbs"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued-euiBreadcrumb__content"
title="See collapsed breadcrumbs"
type="button"
>
Expand Down Expand Up @@ -444,7 +444,7 @@ exports[`EuiBreadcrumbs props responsive is rendered 1`] = `
</span>
</li>
<li
class="euiBreadcrumb euiBreadcrumb--collapsed emotion-EuiBreadcrumbCollapsed"
class="euiBreadcrumb emotion-euiBreadcrumb-isCollapsed"
>
<div
class="euiPopover euiPopover--anchorDownCenter"
Expand All @@ -454,7 +454,7 @@ exports[`EuiBreadcrumbs props responsive is rendered 1`] = `
>
<button
aria-label="See collapsed breadcrumbs"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued-euiBreadcrumb__content"
title="See collapsed breadcrumbs"
type="button"
>
Expand Down Expand Up @@ -533,7 +533,7 @@ exports[`EuiBreadcrumbs props responsive is rendered as false 1`] = `
</span>
</li>
<li
class="euiBreadcrumb euiBreadcrumb--collapsed emotion-EuiBreadcrumbCollapsed"
class="euiBreadcrumb emotion-euiBreadcrumb-isCollapsed"
>
<div
class="euiPopover euiPopover--anchorDownCenter"
Expand All @@ -543,7 +543,7 @@ exports[`EuiBreadcrumbs props responsive is rendered as false 1`] = `
>
<button
aria-label="See collapsed breadcrumbs"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued-euiBreadcrumb__content"
title="See collapsed breadcrumbs"
type="button"
>
Expand Down Expand Up @@ -601,7 +601,7 @@ exports[`EuiBreadcrumbs props responsive is rendered with custom breakpoints 1`]
class="euiBreadcrumbs__list emotion-euiBreadcrumbs__list-isTruncated"
>
<li
class="euiBreadcrumb euiBreadcrumb--collapsed emotion-EuiBreadcrumbCollapsed"
class="euiBreadcrumb emotion-euiBreadcrumb-isCollapsed"
>
<div
class="euiPopover euiPopover--anchorDownCenter"
Expand All @@ -611,7 +611,7 @@ exports[`EuiBreadcrumbs props responsive is rendered with custom breakpoints 1`]
>
<button
aria-label="See collapsed breadcrumbs"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued-euiBreadcrumb__content"
title="See collapsed breadcrumbs"
type="button"
>
Expand Down Expand Up @@ -667,7 +667,7 @@ exports[`EuiBreadcrumbs props truncate as false is rendered 1`] = `
</span>
</li>
<li
class="euiBreadcrumb euiBreadcrumb--collapsed emotion-EuiBreadcrumbCollapsed"
class="euiBreadcrumb emotion-euiBreadcrumb-isCollapsed"
>
<div
class="euiPopover euiPopover--anchorDownCenter"
Expand All @@ -677,7 +677,7 @@ exports[`EuiBreadcrumbs props truncate as false is rendered 1`] = `
>
<button
aria-label="See collapsed breadcrumbs"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued"
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued-euiBreadcrumb__content"
title="See collapsed breadcrumbs"
type="button"
>
Expand Down
59 changes: 54 additions & 5 deletions src/components/breadcrumbs/breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ import React, {
AriaAttributes,
MouseEventHandler,
ReactNode,
useState,
} from 'react';
import classNames from 'classnames';

import { useEuiTheme } from '../../services';
import { CommonProps } from '../common';
import { EuiInnerText } from '../inner_text';
import { EuiLink, EuiLinkColor } from '../link';
import { EuiPopover } from '../popover';
import { EuiIcon } from '../icon';
import { useEuiI18n } from '../i18n';

import {
euiBreadcrumbStyles,
Expand Down Expand Up @@ -60,9 +64,9 @@ interface _EuiBreadcrumbProps {
}

export const EuiBreadcrumb: FunctionComponent<
EuiBreadcrumbProps & _EuiBreadcrumbProps
> = (props) => {
const { isHeaderBreadcrumb } = props;
HTMLAttributes<HTMLLIElement> & _EuiBreadcrumbProps
> = ({ children, className, isHeaderBreadcrumb, ...rest }) => {
const classes = classNames('euiBreadcrumb', className);

const euiTheme = useEuiTheme();
const styles = euiBreadcrumbStyles(euiTheme);
Expand All @@ -72,8 +76,8 @@ export const EuiBreadcrumb: FunctionComponent<
];

return (
<li className="euiBreadcrumb" css={cssStyles}>
<EuiBreadcrumbContent {...props} />
<li className={classes} css={cssStyles} {...rest}>
{children}
</li>
);
};
Expand Down Expand Up @@ -150,3 +154,48 @@ export const EuiBreadcrumbContent: FunctionComponent<
</EuiInnerText>
);
};

export const EuiBreadcrumbCollapsed: FunctionComponent<_EuiBreadcrumbProps> = ({
children,
isFirstBreadcrumb,
isHeaderBreadcrumb,
}) => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);

const euiTheme = useEuiTheme();
const styles = euiBreadcrumbStyles(euiTheme);
const cssStyles = [styles.isCollapsed];

const ariaLabel = useEuiI18n(
'euiBreadcrumb.collapsedBadge.ariaLabel',
'See collapsed breadcrumbs'
);

const ellipsisButton = (
<EuiBreadcrumbContent
aria-label={ariaLabel}
title={ariaLabel}
onClick={() => setIsPopoverOpen(!isPopoverOpen)}
truncate={false}
text={
<>
&hellip; <EuiIcon type="arrowDown" size="s" />
</>
}
isFirstBreadcrumb={isFirstBreadcrumb}
isHeaderBreadcrumb={isHeaderBreadcrumb}
/>
);

return (
<EuiBreadcrumb css={cssStyles} isHeaderBreadcrumb={isHeaderBreadcrumb}>
<EuiPopover
button={ellipsisButton}
isOpen={isPopoverOpen}
closePopover={() => setIsPopoverOpen(false)}
>
{children}
</EuiPopover>
</EuiBreadcrumb>
);
};
97 changes: 30 additions & 67 deletions src/components/breadcrumbs/breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,21 @@ import classNames from 'classnames';

import { CommonProps } from '../common';
import { useEuiI18n } from '../i18n';
import { EuiLink } from '../link';
import { EuiPopover } from '../popover';
import { EuiIcon } from '../icon';
import { throttle, useEuiTheme } from '../../services';
import { EuiBreakpointSize, getBreakpoint } from '../../services/breakpoint';

import { EuiBreadcrumb, EuiBreadcrumbProps } from './breadcrumb';
import {
EuiBreadcrumb,
EuiBreadcrumbContent,
EuiBreadcrumbCollapsed,
EuiBreadcrumbProps,
} from './breadcrumb';

import {
euiBreadcrumbsListStyles,
euiBreadcrumbsInPopoverStyles,
} from './breadcrumbs.styles';

const CONTENT_CLASSNAME = 'euiBreadcrumb__content';

export type EuiBreadcrumbResponsiveMaxCount = {
/**
* Any of the following keys are allowed: `'xs' | 's' | 'm' | 'l' | 'xl'`
Expand Down Expand Up @@ -168,75 +168,38 @@ export const EuiBreadcrumbs: FunctionComponent<EuiBreadcrumbsProps> = ({
}
}

const EuiBreadcrumbCollapsed = () => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const ariaLabel = useEuiI18n(
'euiBreadcrumbs.collapsedBadge.ariaLabel',
'See collapsed breadcrumbs'
);

// Emotion styles for collapsed breadcrumb list items.
// Declared here because the collapsed breadcrumb is determined
// conditionally by number of breadcrumbs instead of a prop.
const cssBreadcrumbStylesCollapsed = [
// TODO: Fix/DRY out in future commit
// breadcrumbStyles.euiBreadcrumb,
// breadcrumbStyles.isCollapsed,
// isHeaderBreadcrumb && breadcrumbStyles.isHeaderBreadcrumb,
];

const ellipsisButton = (
<EuiLink
className={CONTENT_CLASSNAME}
color="subdued"
aria-label={ariaLabel}
title={ariaLabel}
onClick={() => setIsPopoverOpen(!isPopoverOpen)}
>
&hellip; <EuiIcon type="arrowDown" size="s" />
</EuiLink>
);

return (
<li
className="euiBreadcrumb euiBreadcrumb--collapsed"
css={cssBreadcrumbStylesCollapsed}
if (max < breadcrumbs.length) {
breadcrumbsAtStart.push(
<EuiBreadcrumbCollapsed
key="collapsed"
isHeaderBreadcrumb={isHeaderBreadcrumb}
isFirstBreadcrumb={breadcrumbsAtStart.length === 0}
>
<EuiPopover
button={ellipsisButton}
isOpen={isPopoverOpen}
closePopover={() => setIsPopoverOpen(false)}
>
<EuiBreadcrumbs
className="euiBreadcrumbs__inPopover"
css={cssBreadcrumbsInPopoverStyles}
breadcrumbs={overflowBreadcrumbs}
responsive={false}
truncate={false}
max={0}
/>
</EuiPopover>
</li>
<EuiBreadcrumbs
css={cssBreadcrumbsInPopoverStyles}
breadcrumbs={overflowBreadcrumbs}
responsive={false}
truncate={false}
max={0}
/>
</EuiBreadcrumbCollapsed>
);
};

if (max < breadcrumbs.length) {
breadcrumbsAtStart.push(<EuiBreadcrumbCollapsed key="collapsed" />);
}

return [...breadcrumbsAtStart, ...breadcrumbsAtEnd];
};

const breadcrumbElements = breadcrumbs.map((breadcrumb, index) => (
<EuiBreadcrumb
key={index}
truncate={truncate}
isHeaderBreadcrumb={isHeaderBreadcrumb}
isFirstBreadcrumb={index === 0}
isLastBreadcrumb={index === breadcrumbs.length - 1}
isOnlyBreadcrumb={breadcrumbs.length === 1}
{...breadcrumb}
/>
<EuiBreadcrumb key={index} isHeaderBreadcrumb={isHeaderBreadcrumb}>
<EuiBreadcrumbContent
truncate={truncate}
isHeaderBreadcrumb={isHeaderBreadcrumb}
isFirstBreadcrumb={index === 0}
isLastBreadcrumb={index === breadcrumbs.length - 1}
isOnlyBreadcrumb={breadcrumbs.length === 1}
{...breadcrumb}
/>
</EuiBreadcrumb>
));

// Use the default object if they simply passed `true` for responsive
Expand Down

0 comments on commit 8aa914e

Please sign in to comment.