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

Added layout prop to EuiCard #885

Merged
merged 7 commits into from
May 29, 2018
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- Added `textStyle="reverse"` prop to `EuiDescriptionList` as well as a class (`.eui-definitionListReverse`) for `dl`'s within `EuiText` ([#882](https://github.com/elastic/eui/pull/882))
- Added `inspect` icon ([#886](https://github.com/elastic/eui/pull/886))
- Added `layout` prop to `EuiCard` ([#885](https://github.com/elastic/eui/pull/885))

## [`0.0.50`](https://github.com/elastic/eui/tree/v0.0.50)

Expand Down
35 changes: 32 additions & 3 deletions src-docs/src/views/card/card_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import {
EuiCode,
EuiCard,
EuiCallOut,
} from '../../../../src/components';

import Card from './card';
Expand All @@ -27,6 +28,10 @@ import CardBeta from './card_beta';
const cardBetaSource = require('!!raw-loader!./card_beta');
const cardBetaHtml = renderToHtml(CardBeta);

import CardLayout from './card_layout';
const cardLayoutSource = require('!!raw-loader!./card_layout');
const cardLayoutHtml = renderToHtml(CardLayout);

export const CardExample = {
title: 'Card',
sections: [{
Expand Down Expand Up @@ -54,6 +59,30 @@ export const CardExample = {
props: { EuiCard },
demo: <Card />,
},
{
title: 'Layout',
source: [{
type: GuideSectionTypes.JS,
code: cardLayoutSource,
}, {
type: GuideSectionTypes.HTML,
code: cardLayoutHtml,
}],
text: (
<div>
<p>
Most of the time, cards should read from top to bottom (vertical). However, in some cases, you may
want the icon to be to the left of the content. In this case, add the prop <EuiCode>layout=&quot;horizontal&quot;</EuiCode>.
</p>
<EuiCallOut
color="danger"
title={<span>Horizontal layouts <strong>do not</strong> work with images, footers or <EuiCode>textAlign</EuiCode>. Therefore, these properties will be ignored.</span>}
/>
</div>
),
components: { EuiCard },
demo: <CardLayout />,
},
{
title: 'Images',
source: [{
Expand All @@ -69,9 +98,9 @@ export const CardExample = {
Images can be added in place of, or in conjuction with, icons.
Just pass a url into the <EuiCode>image</EuiCode> prop and it will expand to to edges of the card.
</p>
<p>
Make sure that all images are the <strong>same proportions</strong> when used in a singular row.
</p>
<EuiCallOut
title={<span>Make sure that all images are the <strong>same proportions</strong> when used in a singular row.</span>}
/>
</div>
),
components: { EuiCard },
Expand Down
39 changes: 39 additions & 0 deletions src-docs/src/views/card/card_layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';

import {
EuiCard,
EuiIcon,
EuiFlexGroup,
EuiFlexItem,
} from '../../../../src/components';

export default () => (
<EuiFlexGroup gutterSize="l">
<EuiFlexItem>
<EuiCard
layout="horizontal"
icon={<EuiIcon size="xxl" type={`logoBeats`} />}
title={`Elastic Beats`}
description="Example of a card's description. Stick to one or two sentences."
onClick={() => window.alert('Card clicked')}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiCard
layout="horizontal"
icon={<EuiIcon size="xxl" type={`logoCloud`} />}
title={`Elastic Cloud`}
description="Example of a card's description. Stick to one or two sentences."
onClick={() => window.alert('Card clicked')}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiCard
layout="horizontal"
title={`No icon example`}
description="Example of a card's description. Stick to one or two sentences."
onClick={() => window.alert('Card clicked')}
/>
</EuiFlexItem>
</EuiFlexGroup>
);
25 changes: 24 additions & 1 deletion src/components/card/__snapshots__/card.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,8 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`EuiCard horizontal 1`] = `
<div
class="euiCard euiCard--centerAligned euiCard--horizontal"
>
<span
class="euiCard__content"
>
<span
class="euiTitle euiTitle--medium euiCard__title"
>
Card title
</span>
<div
class="euiText euiText--small euiCard__description"
>
<p>
Card description
</p>
</div>
</span>
</div>
`;

exports[`EuiCard icon 1`] = `
<div
class="euiCard euiCard--centerAligned"
class="euiCard euiCard--centerAligned euiCard--hasIcon"
>
<span
class="euiCard__top"
Expand Down
26 changes: 26 additions & 0 deletions src/components/card/_card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ $euiCardTitleSize: 18px; // Hardcoded pixel value for theme parity.
* 3. Fix for IE to ensure badges are visible outside of a <button> tag
* 4. Fix for IE where the image correctly resizes in width but doesn't collapse it's height
(https://github.com/philipwalton/flexbugs/issues/75#issuecomment-134702421)
* 5. Horizontal layouts should always top left align no matter the textAlign prop
*/

// EuiCard specific
Expand Down Expand Up @@ -138,3 +139,28 @@ $euiCardTitleSize: 18px; // Hardcoded pixel value for theme parity.
flex-grow: 0; /* 1 */
margin-top: $euiCardSpacing;
}

.euiCard.euiCard--horizontal {
.euiCard__content {
padding-top: $euiSizeS; // Aligns title and text a bit better and adds spacing in case of beta badge
text-align: left; /* 5 */
}
}

// Only change the flex direction if the card has an icon
// otherwise the button tag won't properly align contents to top
.euiCard.euiCard--horizontal.euiCard--hasIcon {
flex-direction: row;
align-items: flex-start !important; /* 5 */

.euiCard__top,
.euiCard__content {
width: auto; // Makes sure the top shrinks and the content grows
margin-top: 0;
}

.euiCard__top .euiCard__icon {
margin-top: 0;
margin-right: $euiSize;
}
}
42 changes: 37 additions & 5 deletions src/components/card/card.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@ const textAlignToClassNameMap = {

export const ALIGNMENTS = Object.keys(textAlignToClassNameMap);

const layoutToClassNameMap = {
vertical: '',
horizontal: 'euiCard--horizontal',
};

export const LAYOUT_ALIGNMENTS = Object.keys(layoutToClassNameMap);
const oneOfLayouts = PropTypes.oneOf(LAYOUT_ALIGNMENTS);

const cardLayout = (props, propName, componentName, ...rest) => {
const oneOfResult = oneOfLayouts(props, propName, componentName, ...rest);
if (oneOfResult) return oneOfResult;

if (props[propName] === 'horizontal' ) {
if (props.image || props.footer) {
return new Error(
`${componentName}: '${propName} = horizontal' cannot be used in conjunction with 'image', 'footer', or 'textAlign'.`
);
}
}
};

export const EuiCard = ({
className,
description,
Expand All @@ -28,20 +49,23 @@ export const EuiCard = ({
betaBadgeLabel,
betaBadgeTooltipContent,
betaBadgeTitle,
layout,
...rest,
}) => {
const classes = classNames(
'euiCard',
textAlignToClassNameMap[textAlign],
layoutToClassNameMap[layout],
{
'euiCard--isClickable': onClick || href || isClickable,
'euiCard--hasBetaBadge': betaBadgeLabel,
'euiCard--hasIcon': icon,
},
className,
);

let imageNode;
if (image) {
if (image && layout === 'vertical') {
imageNode = (
<img className="euiCard__image" src={image} alt="" />
);
Expand All @@ -63,7 +87,7 @@ export const EuiCard = ({
}

let optionalCardTop;
if (image || icon) {
if (imageNode || iconNode) {
optionalCardTop = (
<span className="euiCard__top">
{imageNode}
Expand Down Expand Up @@ -102,9 +126,11 @@ export const EuiCard = ({
</EuiText>
</span>

<span className="euiCard__footer">
{footer}
</span>
{layout === 'vertical' &&
<span className="euiCard__footer">
{footer}
</span>
}
</OuterElement>
);
};
Expand Down Expand Up @@ -136,6 +162,11 @@ EuiCard.propTypes = {
href: PropTypes.string,
textAlign: PropTypes.oneOf(ALIGNMENTS),

/**
* Change to "horizontal" if you need the icon to be left of the content
*/
layout: cardLayout,

/**
* Add a badge to the card to label it as "Beta" or other non-GA state
*/
Expand All @@ -154,4 +185,5 @@ EuiCard.propTypes = {

EuiCard.defaultProps = {
textAlign: 'center',
layout: 'vertical',
};
13 changes: 13 additions & 0 deletions src/components/card/card.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ describe('EuiCard', () => {
.toMatchSnapshot();
});

test('horizontal', () => {
const component = render(
<EuiCard
title="Card title"
description="Card description"
layout="horizontal"
/>
);

expect(component)
.toMatchSnapshot();
});

describe('onClick', () => {
it('supports onClick as a link', () => {
const handler = jest.fn();
Expand Down
1 change: 1 addition & 0 deletions src/components/text/_text.scss
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
content: "";
height: 2px;
width: 50%;
right: 0;
transform: translateX(-50%);
background: $euiColorDarkShade;
}
Expand Down