Skip to content
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
2 changes: 2 additions & 0 deletions UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f

### Enhancements

- Updated `Navigation` badge prop to accept a react node ([#1142](https://github.com/Shopify/polaris-react/pull/1142))

### Bug fixes

- Fixed unnecessary height on `TextField` due to unhandled carriage returns ([#901](https://github.com/Shopify/polaris-react/pull/901))
Expand Down
39 changes: 26 additions & 13 deletions src/components/Navigation/components/Item/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ interface SecondaryAction {
export interface Props extends ItemURLDetails {
icon?: IconProps['source'];
iconBody?: string;
badge?: string | null;
badge?: React.ReactNode;
label: string;
disabled?: boolean;
accessibilityLabel?: string;
Expand Down Expand Up @@ -90,16 +90,16 @@ export class BaseItem extends React.Component<CombinedProps, State> {
url,
icon,
label,
badge,
subNavigationItems = [],
secondaryAction,
disabled,
onClick,
accessibilityLabel,
iconBody,
selected: selectedOverride,
badge,
new: isNew,
polaris: {intl},
selected: selectedOverride,
} = this.props;

const {location, onNavigationDismiss} = this.context;
Expand All @@ -116,15 +116,6 @@ export class BaseItem extends React.Component<CombinedProps, State> {
</span>
) : null;

const badgeMarkup =
badge || isNew ? (
<div className={styles.Badge}>
<Badge status="new" size="small">
{badge || intl.translate('Polaris.Badge.STATUS_LABELS.new')}
</Badge>
</div>
) : null;

const iconMarkup = iconBody ? (
<div className={styles.Icon}>
<Icon source={iconBody} />
Expand All @@ -137,14 +128,36 @@ export class BaseItem extends React.Component<CombinedProps, State> {
)
);

let badgeMarkup: React.ReactNode = null;
if (isNew) {
badgeMarkup = (
<Badge status="new" size="small">
{intl.translate('Polaris.Badge.STATUS_LABELS.new')}
</Badge>
);
} else if (typeof badge === 'string') {
badgeMarkup = (
<Badge status="new" size="small">
{badge}
</Badge>
);
} else {
badgeMarkup = badge;
}

const wrappedBadgeMarkup =
badgeMarkup == null ? null : (
<div className={styles.Badge}>{badgeMarkup}</div>
);

const itemContentMarkup = (
<React.Fragment>
{iconMarkup}
<span className={styles.Text}>
{label}
{indicatorMarkup}
</span>
{badgeMarkup}
{wrappedBadgeMarkup}
</React.Fragment>
);

Expand Down
28 changes: 28 additions & 0 deletions src/components/Navigation/components/Item/tests/Item.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,34 @@ describe('<Nav.Item />', () => {
const link = item.find(UnstyledLink);
expect(link.exists()).toBe(true);
});

it('renders a small badge with new status if the prop is provided with a string', () => {
const item = mountWithAppProvider(<Item label="some label" badge="1" />);

expect(item.find(Badge).props()).toMatchObject({
status: 'new',
size: 'small',
children: '1',
});
});

it('renders a badge if the prop is provided with an element', () => {
const item = mountWithAppProvider(
<Item label="some label" badge={<Badge>Custom badge</Badge>} />,
);

expect(item.find(Badge).text()).toContain('Custom badge');
});

it('renders a single new badge even if a badge prop is also provided', () => {
const item = mountWithAppProvider(
<Item label="some label" badge={<Badge>Custom badge</Badge>} new />,
);
const badge = item.find(Badge);

expect(badge).toHaveLength(1);
expect(badge.text()).toContain('New');
});
});

describe('with SubNavigationItems', () => {
Expand Down