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 @@ -8,6 +8,8 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f

### Enhancements

- Updated `MediaCard` to accept ReactNode as title and make `primaryAction` optional ([#3552](https://github.com/Shopify/polaris-react/pull/3552))

### Bug fixes

### Documentation
Expand Down
19 changes: 12 additions & 7 deletions src/components/MediaCard/MediaCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ interface MediaCardProps {
/** The visual media to display in the card */
children: React.ReactNode;
/** Heading content */
title: string;
title: React.ReactNode;
/** Body content */
description: string;
/** Main call to action, rendered as a basic button */
primaryAction: Action;
primaryAction?: Action;
/** Secondary call to action, rendered as a plain button */
secondaryAction?: Action;
/** Action list items to render in ellipsis popover */
Expand Down Expand Up @@ -53,6 +53,13 @@ export function MediaCard({
const i18n = useI18n();
const {value: popoverActive, toggle: togglePopoverActive} = useToggle(false);

let headerMarkup = null;
if (title) {
const headerContent =
typeof title === 'string' ? <Heading>{title}</Heading> : title;
headerMarkup = <div className={styles.Heading}>{headerContent}</div>;
}

const popoverActivator = (
<Button
icon={HorizontalDotsMinor}
Expand Down Expand Up @@ -81,9 +88,9 @@ export function MediaCard({
</div>
) : null;

const primaryActionMarkup = (
const primaryActionMarkup = primaryAction ? (
<div className={styles.PrimaryAction}>{buttonFrom(primaryAction)}</div>
);
) : null;

const secondaryActionMarkup = secondaryAction ? (
<div className={styles.SecondaryAction}>
Expand Down Expand Up @@ -130,9 +137,7 @@ export function MediaCard({
<Card.Section>
{popoverActionsMarkup}
<Stack vertical spacing="tight">
<div className={styles.Heading}>
<Heading>{title}</Heading>
</div>
{headerMarkup}
<p className={styles.Description}>{description}</p>
{actionMarkup}
</Stack>
Expand Down
2 changes: 1 addition & 1 deletion src/components/MediaCard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ See Apple’s Human Interface Guidelines and API documentation about accessibili

<!-- content-for: web -->

The required `title` prop gives the media card a level 2 heading (`<h2>`). This helps with readability and provides structure to screen reader users.
The required `title` prop gives the media card a level 2 heading (`<h2>`). This helps with readability and provides structure to screen reader users. It can also accept a ReactNode.

Use [actionable language](https://polaris.shopify.com/content/actionable-language#navigation) to ensure that the purpose of the media card is clear to all merchants, including those with issues related to reading and language.

Expand Down
23 changes: 22 additions & 1 deletion src/components/MediaCard/tests/MediaCard.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from 'react';
import {Heading, Popover, Button, ActionList} from 'components';
import {Heading, Popover, Button, ActionList, Badge} from 'components';
import {mountWithApp} from 'test-utilities';
// eslint-disable-next-line no-restricted-imports
import {mountWithAppProvider} from 'test-utilities/legacy';

import {MediaCard} from '../MediaCard';

Expand All @@ -22,6 +24,25 @@ describe('<MediaCard>', () => {
expect(videoCard).toContainReactComponent(Heading, {children: title});
});

it('title can have any valid react element', () => {
const titleString = 'Online store';
const badgeString = 'I am a badge';
const title = (
<h2>
{titleString}
<Badge>{badgeString}</Badge>
</h2>
);
const videoCard = mountWithAppProvider(
<MediaCard {...mockProps} title={title} />,
);

const headerMarkup = videoCard.find('h2');

expect(headerMarkup.text()).toContain(titleString);
expect(headerMarkup.find('Badge').text()).toBe(badgeString);
});

it('renders the description as a paragraph', () => {
const description = 'test';
const videoCard = mountWithApp(
Expand Down