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
1 change: 1 addition & 0 deletions UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f
- Set `Collapsible` to use `overflow: visible;` once fully open ([#951](https://github.com/Shopify/polaris-react/pull/951))
- Removes `TopBar` logo background ([#957](https://github.com/Shopify/polaris-react/pull/957))
- Adopt width of `TopBar` search results to search input and add a minimum width ([#969](https://github.com/Shopify/polaris-react/pull/969))
- Update `Card.Section` to accept `React.ReactNode` as `title` ([#781](https://github.com/Shopify/polaris-react/pull/781))

### Bug fixes

Expand Down
24 changes: 24 additions & 0 deletions src/components/Card/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,30 @@ Use to be able to use custom React elements as header content.
</Card>
```

### Card section with custom React Node title

<!-- example-for: web -->

Use to render custom content such as icons, links, or buttons in a card section's header.

```jsx
<Card title="Products">
<Card.Section
title={
<Stack>
<Icon source="products" />
<Subheading>New Products</Subheading>
</Stack>
}
>
<List>
<List.Item>Socks</List.Item>
<List.Item>Super Shoes</List.Item>
</List>
</Card.Section>
</Card>
```

---

## Related components
Expand Down
17 changes: 9 additions & 8 deletions src/components/Card/components/Section/Section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,29 @@ import Subheading from '../../../Subheading';
import styles from '../../Card.scss';

export interface Props {
title?: string;
title?: React.ReactNode;
children?: React.ReactNode;
subdued?: boolean;
fullWidth?: boolean;
}

export default function Section({children, title, subdued, fullWidth}: Props) {
const headerContent = title ? (
<div className={styles.SectionHeader}>
<Subheading>{title}</Subheading>
</div>
) : null;

const className = classNames(
styles.Section,
subdued && styles['Section-subdued'],
fullWidth && styles['Section-fullWidth'],
);

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

return (
<div className={className}>
{headerContent}
{headerMarkup}
{children}
</div>
);
Expand Down
33 changes: 33 additions & 0 deletions src/components/Card/components/Section/tests/Section.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from 'react';
import {mountWithAppProvider} from 'test-utilities';
import {Badge, Subheading} from 'components';
import Section from '../Section';

describe('<Card.Section />', () => {
it('can have any valid react element as the card section title', () => {
const titleString = 'Online store';
const badgeString = 'I am a badge';
const titleMarkup = (
<h2>
{titleString}
<Badge>{badgeString}</Badge>
</h2>
);

const card = mountWithAppProvider(<Section title={titleMarkup} />);
const headerMarkup = card.find('h2');

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

it('wraps plain string titles in a <Subheading />', () => {
const titleString = 'Online store';

const card = mountWithAppProvider(<Section title={titleString} />);
const headerMarkup = card.find(Subheading);

expect(headerMarkup.exists()).toBeTruthy();
expect(headerMarkup.text()).toEqual(titleString);
});
});