diff --git a/CHANGELOG.md b/CHANGELOG.md
index 16de1e2a913..1735d9cb690 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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)
diff --git a/src-docs/src/views/card/card_example.js b/src-docs/src/views/card/card_example.js
index d8baa7dee52..c0492290371 100644
--- a/src-docs/src/views/card/card_example.js
+++ b/src-docs/src/views/card/card_example.js
@@ -9,6 +9,7 @@ import {
import {
EuiCode,
EuiCard,
+ EuiCallOut,
} from '../../../../src/components';
import Card from './card';
@@ -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: [{
@@ -54,6 +59,30 @@ export const CardExample = {
props: { EuiCard },
demo: ,
},
+ {
+ title: 'Layout',
+ source: [{
+ type: GuideSectionTypes.JS,
+ code: cardLayoutSource,
+ }, {
+ type: GuideSectionTypes.HTML,
+ code: cardLayoutHtml,
+ }],
+ text: (
+
+
+ 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 layout="horizontal".
+
+
Horizontal layouts do not work with images, footers or textAlign. Therefore, these properties will be ignored.}
+ />
+
+ ),
+ components: { EuiCard },
+ demo: ,
+ },
{
title: 'Images',
source: [{
@@ -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 image prop and it will expand to to edges of the card.
-
- Make sure that all images are the same proportions when used in a singular row.
-
+ Make sure that all images are the same proportions when used in a singular row.}
+ />
),
components: { EuiCard },
diff --git a/src-docs/src/views/card/card_layout.js b/src-docs/src/views/card/card_layout.js
new file mode 100644
index 00000000000..d4b6854dad2
--- /dev/null
+++ b/src-docs/src/views/card/card_layout.js
@@ -0,0 +1,39 @@
+import React from 'react';
+
+import {
+ EuiCard,
+ EuiIcon,
+ EuiFlexGroup,
+ EuiFlexItem,
+} from '../../../../src/components';
+
+export default () => (
+
+
+ }
+ title={`Elastic Beats`}
+ description="Example of a card's description. Stick to one or two sentences."
+ onClick={() => window.alert('Card clicked')}
+ />
+
+
+ }
+ title={`Elastic Cloud`}
+ description="Example of a card's description. Stick to one or two sentences."
+ onClick={() => window.alert('Card clicked')}
+ />
+
+
+ window.alert('Card clicked')}
+ />
+
+
+);
diff --git a/src/components/card/__snapshots__/card.test.js.snap b/src/components/card/__snapshots__/card.test.js.snap
index 1746900d97e..dcb7ed2c7de 100644
--- a/src/components/card/__snapshots__/card.test.js.snap
+++ b/src/components/card/__snapshots__/card.test.js.snap
@@ -1,8 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`EuiCard horizontal 1`] = `
+
+`;
+
exports[`EuiCard icon 1`] = `
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
@@ -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;
+ }
+}
diff --git a/src/components/card/card.js b/src/components/card/card.js
index 80687543b50..789c09257cd 100644
--- a/src/components/card/card.js
+++ b/src/components/card/card.js
@@ -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,
@@ -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 = (
);
@@ -63,7 +87,7 @@ export const EuiCard = ({
}
let optionalCardTop;
- if (image || icon) {
+ if (imageNode || iconNode) {
optionalCardTop = (
{imageNode}
@@ -102,9 +126,11 @@ export const EuiCard = ({
-
- {footer}
-
+ {layout === 'vertical' &&
+
+ {footer}
+
+ }
);
};
@@ -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
*/
@@ -154,4 +185,5 @@ EuiCard.propTypes = {
EuiCard.defaultProps = {
textAlign: 'center',
+ layout: 'vertical',
};
diff --git a/src/components/card/card.test.js b/src/components/card/card.test.js
index 649127076cf..b31fb6ee137 100644
--- a/src/components/card/card.test.js
+++ b/src/components/card/card.test.js
@@ -33,6 +33,19 @@ describe('EuiCard', () => {
.toMatchSnapshot();
});
+ test('horizontal', () => {
+ const component = render(
+
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
describe('onClick', () => {
it('supports onClick as a link', () => {
const handler = jest.fn();
diff --git a/src/components/text/_text.scss b/src/components/text/_text.scss
index 74b3cf24208..9802edf818c 100644
--- a/src/components/text/_text.scss
+++ b/src/components/text/_text.scss
@@ -141,6 +141,7 @@
content: "";
height: 2px;
width: 50%;
+ right: 0;
transform: translateX(-50%);
background: $euiColorDarkShade;
}