Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Breadcrumbs to accept a single breadcrumb instead of an array #7990

Merged
merged 1 commit into from
Jan 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/afraid-scissors-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/polaris': major
---

Change breadcrumbs from an array to a single breadcrumb since only one is supported.
2 changes: 1 addition & 1 deletion polaris-react/playground/DetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ export function DetailsPage() {
const actualPageMarkup = (
<Page
fullWidth
breadcrumbs={[{content: 'Products', url: '/products/31'}]}
breadcrumb={{content: 'Products', url: '/products/31'}}
title={title}
titleMetadata={<Badge status="success">Success badge</Badge>}
primaryAction={{
Expand Down
11 changes: 3 additions & 8 deletions polaris-react/src/components/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,11 @@ import {Text} from '../Text';
import styles from './Breadcrumbs.scss';

export interface BreadcrumbsProps {
/** Collection of breadcrumbs */
breadcrumbs: (CallbackAction | LinkAction)[];
/** Breadcrumb link */
breadcrumb: CallbackAction | LinkAction;
}

export function Breadcrumbs({breadcrumbs}: BreadcrumbsProps) {
const breadcrumb = breadcrumbs[breadcrumbs.length - 1];
if (breadcrumb == null) {
return null;
}

export function Breadcrumbs({breadcrumb}: BreadcrumbsProps) {
const {content} = breadcrumb;

const contentMarkup = (
Expand Down
87 changes: 32 additions & 55 deletions polaris-react/src/components/Breadcrumbs/tests/Breadcrumbs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,25 @@ import {Text} from '../../Text';
describe('<Breadcrumbs />', () => {
describe('url', () => {
it('uses <a> tags when passed a LinkAction', () => {
const linkBreadcrumbs: LinkAction[] = [
{
content: 'Products',
url: 'https://www.shopify.com',
},
];

const linkBreadcrumb: LinkAction = {
content: 'Products',
url: 'https://www.shopify.com',
};
const breadcrumbs = mountWithApp(
<Breadcrumbs breadcrumbs={linkBreadcrumbs} />,
<Breadcrumbs breadcrumb={linkBreadcrumb} />,
);

expect(breadcrumbs).toContainReactComponentTimes('a', 1);
});

it('passes the accessibilityLabel through to <a> tag', () => {
const linkBreadcrumbs: LinkAction[] = [
{
content: 'Products',
url: 'https://shopify.com',
accessibilityLabel: 'Go to Products',
},
];

const linkBreadcrumb: LinkAction = {
content: 'Products',
url: 'https://shopify.com',
accessibilityLabel: 'Go to Products',
};
const breadcrumbs = mountWithApp(
<Breadcrumbs breadcrumbs={linkBreadcrumbs} />,
<Breadcrumbs breadcrumb={linkBreadcrumb} />,
);

expect(breadcrumbs).toContainReactComponent('a', {
Expand All @@ -43,31 +37,25 @@ describe('<Breadcrumbs />', () => {

describe('onAction()', () => {
it('uses <button> tags when passed a CallbackAction', () => {
const callbackBreadcrumbs: CallbackAction[] = [
{
content: 'Products',
onAction: noop,
},
];

const callbackBreadcrumb: CallbackAction = {
content: 'Products',
onAction: noop,
};
const breadcrumbs = mountWithApp(
<Breadcrumbs breadcrumbs={callbackBreadcrumbs} />,
<Breadcrumbs breadcrumb={callbackBreadcrumb} />,
);

expect(breadcrumbs).toContainReactComponentTimes('button', 1);
});

it('passes accessibilityLabel through to <button> tag', () => {
const callbackBreadcrumbs: CallbackAction[] = [
{
content: 'Products',
onAction: noop,
accessibilityLabel: 'Go to Products',
},
];

const callbackBreadcrumb: CallbackAction = {
content: 'Products',
onAction: noop,
accessibilityLabel: 'Go to Products',
};
const breadcrumbs = mountWithApp(
<Breadcrumbs breadcrumbs={callbackBreadcrumbs} />,
<Breadcrumbs breadcrumb={callbackBreadcrumb} />,
);

expect(breadcrumbs).toContainReactComponent('button', {
Expand All @@ -77,43 +65,32 @@ describe('<Breadcrumbs />', () => {

it('triggers the callback function when clicked', () => {
const spy = jest.fn();
const callbackBreadcrumbs: CallbackAction[] = [
{
content: 'Products',
onAction: spy,
},
];

const callbackBreadcrumb: CallbackAction = {
content: 'Products',
onAction: spy,
};
const breadcrumbs = mountWithApp(
<Breadcrumbs breadcrumbs={callbackBreadcrumbs} />,
<Breadcrumbs breadcrumb={callbackBreadcrumb} />,
);

breadcrumbs.find('button')!.trigger('onClick');
expect(spy).toHaveBeenCalled();
});
});

const linkBreadcrumbs: LinkAction[] = [
{
content: 'Products',
url: 'https://www.shopify.com',
},
];
const linkBreadcrumb: LinkAction = {
content: 'Products',
url: 'https://www.shopify.com',
};

it('renders breadcrumb content as a visually hidden label when the new design language is enabled', () => {
const wrapper = mountWithApp(<Breadcrumbs breadcrumbs={linkBreadcrumbs} />);
const wrapper = mountWithApp(<Breadcrumbs breadcrumb={linkBreadcrumb} />);

expect(wrapper).toContainReactComponent(Text, {
children: 'Products',
visuallyHidden: true,
});
});

it('renders nothing when empty', () => {
const wrapper = mountWithApp(<Breadcrumbs breadcrumbs={[]} />);

expect(wrapper.html()).toBe('');
});
});

function noop() {}
17 changes: 8 additions & 9 deletions polaris-react/src/components/Page/Page.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default {
export function Default() {
return (
<Page
breadcrumbs={[{content: 'Products', url: '/products'}]}
breadcrumb={{content: 'Products', url: '/products'}}
title="3/4 inch Leather pet collar"
titleMetadata={<Badge status="success">Paid</Badge>}
subtitle="Perfect for any pet"
Expand All @@ -30,7 +30,6 @@ export function Default() {
actionGroups={[
{
title: 'Promote',
accessibilityLabel: 'Action group label',
actions: [
{
content: 'Share on Facebook',
Expand All @@ -55,7 +54,7 @@ export function Default() {
export function WithCustomPrimaryAction() {
return (
<Page
breadcrumbs={[{content: 'Settings', url: '/settings'}]}
breadcrumb={{content: 'Settings', url: '/settings'}}
title="General"
primaryAction={
<Button
Expand All @@ -79,7 +78,7 @@ export function WithCustomPrimaryAction() {
export function WithoutPrimaryActionInHeader() {
return (
<Page
breadcrumbs={[{content: 'Orders', url: '/orders'}]}
breadcrumb={{content: 'Orders', url: '/orders'}}
title="#1085"
secondaryActions={[
{content: 'Print'},
Expand Down Expand Up @@ -159,7 +158,7 @@ export function WithToolTipAction() {
export function WithSubtitle() {
return (
<Page
breadcrumbs={[{content: 'Products', url: '/products'}]}
breadcrumb={{content: 'Products', url: '/products'}}
title="Invoice"
subtitle="Statement period: May 3, 2019 to June 2, 2019"
secondaryActions={[{content: 'Download', icon: ArrowDownMinor}]}
Expand Down Expand Up @@ -195,7 +194,7 @@ export function WithExternalLink() {
export function WithoutPagination() {
return (
<Page
breadcrumbs={[{content: 'Settings', url: '/settings'}]}
breadcrumb={{content: 'Settings', url: '/settings'}}
title="General"
primaryAction={{content: 'Save'}}
>
Expand Down Expand Up @@ -228,7 +227,7 @@ export function NarrowWidth() {
return (
<Page
narrowWidth
breadcrumbs={[{content: 'Orders', url: '/orders'}]}
breadcrumb={{content: 'Orders', url: '/orders'}}
title="Add payment method"
primaryAction={{content: 'Save', disabled: true}}
>
Expand Down Expand Up @@ -282,7 +281,7 @@ export function WithActionGroups() {
export function WithContentAfterTitle() {
return (
<Page
breadcrumbs={[{content: 'Products', url: '/products'}]}
breadcrumb={{content: 'Products', url: '/products'}}
title="Jar With Lock-Lid"
titleMetadata={<Badge status="attention">Verified</Badge>}
primaryAction={{content: 'Save', disabled: true}}
Expand All @@ -305,7 +304,7 @@ export function WithContentAfterTitle() {
export function WithDivider() {
return (
<Page
breadcrumbs={[{content: 'Settings', url: '/settings'}]}
breadcrumb={{content: 'Settings', url: '/settings'}}
title="General"
divider
>
Expand Down
2 changes: 1 addition & 1 deletion polaris-react/src/components/Page/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function Page({
rest.secondaryActions.length > 0) ||
isReactElement(rest.secondaryActions))) ||
(rest.actionGroups != null && rest.actionGroups.length > 0) ||
(rest.breadcrumbs != null && rest.breadcrumbs.length > 0);
rest.breadcrumb != null;

const contentClassName = classNames(
!hasHeaderContent && styles.Content,
Expand Down
19 changes: 9 additions & 10 deletions polaris-react/src/components/Page/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export interface HeaderProps extends TitleProps {
primaryAction?: PrimaryAction | React.ReactNode;
/** Page-level pagination */
pagination?: PaginationProps;
/** Collection of breadcrumbs */
breadcrumbs?: BreadcrumbsProps['breadcrumbs'];
/** Breadcrumb link */
breadcrumb?: BreadcrumbsProps['breadcrumb'];
/** Collection of secondary page-level actions */
secondaryActions?: MenuActionDescriptor[] | React.ReactNode;
/** Collection of page-level groups of secondary actions */
Expand All @@ -74,7 +74,7 @@ export function Header({
primaryAction,
pagination,
additionalNavigation,
breadcrumbs = [],
breadcrumb,
secondaryActions = [],
actionGroups = [],
compactTitle = false,
Expand All @@ -97,12 +97,11 @@ export function Header({
isReactElement(secondaryActions)) &&
!actionGroups.length;

const breadcrumbMarkup =
breadcrumbs.length > 0 ? (
<div className={styles.BreadcrumbWrapper}>
<Breadcrumbs breadcrumbs={breadcrumbs} />
</div>
) : null;
const breadcrumbMarkup = breadcrumb ? (
<div className={styles.BreadcrumbWrapper}>
<Breadcrumbs breadcrumb={breadcrumb} />
</div>
) : null;

const paginationMarkup =
pagination && !isNavigationCollapsed ? (
Expand Down Expand Up @@ -178,7 +177,7 @@ export function Header({
navigationMarkup && styles.hasNavigation,
actionMenuMarkup && styles.hasActionMenu,
isNavigationCollapsed && styles.mobileView,
!breadcrumbs.length && styles.noBreadcrumbs,
!breadcrumb && styles.noBreadcrumbs,
title && title.length < LONG_TITLE && styles.mediumTitle,
title && title.length > LONG_TITLE && styles.longTitle,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,17 @@ describe('<Header />', () => {
});

describe('breadcrumbs', () => {
const breadcrumbs: LinkAction[] = [
{
content: 'Products',
url: 'https://www.google.com',
},
];
const breadcrumb: LinkAction = {
content: 'Products',
url: 'https://www.google.com',
};

it('get passed into Breadcrumbs', () => {
const header = mountWithApp(
<Header {...mockProps} breadcrumbs={breadcrumbs} />,
<Header {...mockProps} breadcrumb={breadcrumb} />,
);
expect(header).toContainReactComponent(Breadcrumbs, {
breadcrumbs,
breadcrumb,
});
});
});
Expand Down Expand Up @@ -291,12 +289,10 @@ describe('<Header />', () => {
{content: 'mock content 2'},
];

const breadcrumbs: LinkAction[] = [
{
content: 'Products',
url: 'https://www.google.com',
},
];
const breadcrumb: LinkAction = {
content: 'Products',
url: 'https://www.google.com',
};

it('does not render primary and secondary action wrapper divs', () => {
const header = mountWithApp(
Expand Down Expand Up @@ -341,7 +337,7 @@ describe('<Header />', () => {

it('renders a default mobile layout', () => {
const header = mountWithApp(
<Header title="mmmmmmmmm" breadcrumbs={breadcrumbs} />,
<Header title="mmmmmmmmm" breadcrumb={breadcrumb} />,
{
mediaQuery: {isNavigationCollapsed: true},
},
Expand Down
16 changes: 7 additions & 9 deletions polaris-react/src/components/Page/tests/Page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,26 +234,24 @@ describe('<Page />', () => {
});

describe('breadcrumbs', () => {
const breadcrumbs = [
{
content: 'Products',
onAction: noop,
},
];
const breadcrumb = {
content: 'Products',
onAction: noop,
};

it('renders a <Header /> when defined', () => {
const page = mountWithApp(
<Page {...mockProps} breadcrumbs={breadcrumbs} />,
<Page {...mockProps} breadcrumb={breadcrumb} />,
);
expect(page).toContainReactComponent(Header);
});

it('gets passed into the <Header />', () => {
const page = mountWithApp(
<Page {...mockProps} breadcrumbs={breadcrumbs} />,
<Page {...mockProps} breadcrumb={breadcrumb} />,
);
expect(page).toContainReactComponent(Header, {
breadcrumbs,
breadcrumb,
});
});
});
Expand Down