diff --git a/CHANGELOG.md b/CHANGELOG.md
index 276af7ccdd8..0d6227b5a69 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,7 @@
## [`master`](https://github.com/elastic/eui/tree/master)
+- Added `color` and `size` props and added support for click event to `EuiBetaBadge` ([#4798](https://github.com/elastic/eui/pull/4798))
+
**Bug fixes**
- Fixed `onBlur` and `data-test-subj` prop propagation in `EuiColorPicker` ([#4822](https://github.com/elastic/eui/pull/4822))
diff --git a/src-docs/src/views/badge/badge_example.js b/src-docs/src/views/badge/badge_example.js
index 2013d9dace4..708b12563a8 100644
--- a/src-docs/src/views/badge/badge_example.js
+++ b/src-docs/src/views/badge/badge_example.js
@@ -308,6 +308,8 @@ export const BadgeExample = {
If you pass in an iconType, only the icon will be
used in the badge itself and the label will be applied as the title.
Only use an icon when attaching the beta badge to small components.
+ Beta badges can also be made clickable by passing{' '}
+ href or onClick as needed.
They can also be used in conjunction with{' '}
diff --git a/src-docs/src/views/badge/beta_badge.js b/src-docs/src/views/badge/beta_badge.js
index b5a66e96d75..6d4de70c49d 100644
--- a/src-docs/src/views/badge/beta_badge.js
+++ b/src-docs/src/views/badge/beta_badge.js
@@ -2,23 +2,36 @@ import React from 'react';
import { EuiBetaBadge, EuiSpacer, EuiTitle } from '../../../../src/components';
+const colors = ['hollow', 'accent', 'subdued'];
+
export default () => (
-
-
-
-
-
-
-
-
+ {colors.map((item, index) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ))}
+
Beta badges will also line up nicely with titles
@@ -28,5 +41,20 @@ export default () => (
/>
+
+ Clickable beta badges
+
+
+
alert('Goes to Lens')}
+ />
+
+
);
diff --git a/src-docs/src/views/card/card_beta.js b/src-docs/src/views/card/card_beta.js
index 2397e1ad2b3..610eb50d04b 100644
--- a/src-docs/src/views/card/card_beta.js
+++ b/src-docs/src/views/card/card_beta.js
@@ -7,8 +7,8 @@ import {
EuiFlexItem,
} from '../../../../src/components';
-const icons = ['dashboard', 'monitoring', 'watches'];
-const badges = [null, 'Beta', 'Lab'];
+const icons = ['dashboard', 'monitoring'];
+const badges = [null, 'Beta'];
const cardNodes = icons.map(function (item, index) {
return (
@@ -29,4 +29,23 @@ const cardNodes = icons.map(function (item, index) {
);
});
-export default () => {cardNodes} ;
+export default () => (
+
+ {cardNodes}
+
+ }
+ title="Lens"
+ isDisabled
+ description="Disabled cards can have active links using EuiBetaBadge."
+ betaBadgeProps={{
+ href: 'http://www.elastic.co/subscriptions',
+ target: '_blank',
+ }}
+ betaBadgeLabel="Basic"
+ betaBadgeTooltipContent="This feature requires a Basic License"
+ onClick={() => {}}
+ />
+
+
+);
diff --git a/src/components/badge/beta_badge/__snapshots__/beta_badge.test.tsx.snap b/src/components/badge/beta_badge/__snapshots__/beta_badge.test.tsx.snap
index fbf03346008..6b3d4c7b8c2 100644
--- a/src/components/badge/beta_badge/__snapshots__/beta_badge.test.tsx.snap
+++ b/src/components/badge/beta_badge/__snapshots__/beta_badge.test.tsx.snap
@@ -3,10 +3,55 @@
exports[`EuiBetaBadge is rendered 1`] = `
Beta
`;
+
+exports[`EuiBetaBadge props color accent is rendered 1`] = `
+
+ Beta
+
+`;
+
+exports[`EuiBetaBadge props color hollow is rendered 1`] = `
+
+ Beta
+
+`;
+
+exports[`EuiBetaBadge props color subdued is rendered 1`] = `
+
+ Beta
+
+`;
+
+exports[`EuiBetaBadge props size m is rendered 1`] = `
+
+ Beta
+
+`;
+
+exports[`EuiBetaBadge props size s is rendered 1`] = `
+
+ Beta
+
+`;
diff --git a/src/components/badge/beta_badge/_beta_badge.scss b/src/components/badge/beta_badge/_beta_badge.scss
index e38fd0349f9..6010065f358 100644
--- a/src/components/badge/beta_badge/_beta_badge.scss
+++ b/src/components/badge/beta_badge/_beta_badge.scss
@@ -17,6 +17,17 @@
&:focus {
@include euiFocusRing;
}
+
+ &:not(.euiBetaBadge--hollow) {
+ box-shadow: none;
+ }
+
+ &.euiBetaBadge--small {
+ @include fontSize($euiFontSize * .625);
+ line-height: $euiSize + $euiSizeXS;
+ padding: 0 $euiSizeM;
+ }
+
}
// When it's just an icon, make it a circle
@@ -28,4 +39,46 @@
position: relative;
margin-top: -1px;
}
+
+ &.euiBetaBadge--small {
+ width: $euiSize + $euiSizeXS;
+ padding: 0;
+ }
+}
+
+.euiBetaBadge--singleLetter {
+ padding: 0 0 0 1px;
+ width: $euiSizeL;
+
+ &.euiBetaBadge--small {
+ width: $euiSize + $euiSizeXS;
+ padding: 0 0 0 1px;
+ }
+}
+
+.euiBetaBadge--subdued {
+ $backgroundColor: tint($euiColorLightShade, 30%);
+ background: $backgroundColor;
+ color: chooseLightOrDarkText($backgroundColor, $euiColorGhost, $euiColorInk);
+
+ &.euiBetaBadge-isClickable {
+ color: chooseLightOrDarkText($backgroundColor, $euiColorGhost, $euiColorInk);
+ }
}
+
+.euiBetaBadge--hollow {
+ &.euiBetaBadge-isClickable {
+ $backgroundColor: tint($euiColorLightShade, 30%);
+ color: chooseLightOrDarkText($backgroundColor, $euiColorGhost, $euiColorInk);
+ }
+}
+
+.euiBetaBadge--accent {
+ $backgroundColor: $euiColorAccentText;
+ background: $backgroundColor;
+ color: chooseLightOrDarkText($backgroundColor, $euiColorGhost, $euiColorInk);
+
+ &.euiBetaBadge-isClickable {
+ color: chooseLightOrDarkText($backgroundColor, $euiColorGhost, $euiColorInk);
+ }
+}
\ No newline at end of file
diff --git a/src/components/badge/beta_badge/beta_badge.test.tsx b/src/components/badge/beta_badge/beta_badge.test.tsx
index 25a01d31b32..7bd45323947 100644
--- a/src/components/badge/beta_badge/beta_badge.test.tsx
+++ b/src/components/badge/beta_badge/beta_badge.test.tsx
@@ -21,7 +21,7 @@ import React from 'react';
import { render } from 'enzyme';
import { requiredProps } from '../../../test';
-import { EuiBetaBadge } from './beta_badge';
+import { EuiBetaBadge, COLORS, SIZES } from './beta_badge';
describe('EuiBetaBadge', () => {
test('is rendered', () => {
@@ -29,4 +29,26 @@ describe('EuiBetaBadge', () => {
expect(component).toMatchSnapshot();
});
+
+ describe('props', () => {
+ describe('color', () => {
+ COLORS.forEach((color) => {
+ test(`${color} is rendered`, () => {
+ const component = render();
+
+ expect(component).toMatchSnapshot();
+ });
+ });
+ });
+
+ describe('size', () => {
+ SIZES.forEach((size) => {
+ test(`${size} is rendered`, () => {
+ const component = render();
+
+ expect(component).toMatchSnapshot();
+ });
+ });
+ });
+ });
});
diff --git a/src/components/badge/beta_badge/beta_badge.tsx b/src/components/badge/beta_badge/beta_badge.tsx
index 76026d9b9f3..58bcf2193af 100644
--- a/src/components/badge/beta_badge/beta_badge.tsx
+++ b/src/components/badge/beta_badge/beta_badge.tsx
@@ -17,25 +17,75 @@
* under the License.
*/
-import React, { FunctionComponent, HTMLAttributes, ReactNode } from 'react';
+import React, {
+ AriaAttributes,
+ Fragment,
+ FunctionComponent,
+ HTMLAttributes,
+ MouseEventHandler,
+ ReactNode,
+} from 'react';
import classNames from 'classnames';
-import { CommonProps, ExclusiveUnion } from '../../common';
+import { CommonProps, ExclusiveUnion, keysOf } from '../../common';
+
+import { getSecureRelForTarget } from '../../../services';
import { EuiToolTip, ToolTipPositions } from '../../tool_tip';
import { EuiIcon, IconType } from '../../icon';
+const colorToClassMap = {
+ accent: 'euiBetaBadge--accent',
+ subdued: 'euiBetaBadge--subdued',
+ hollow: 'euiBetaBadge--hollow',
+};
+
+export const COLORS: BetaBadgeColor[] = keysOf(colorToClassMap);
+export type BetaBadgeColor = keyof typeof colorToClassMap;
+
+export type BetaBadgeSize = 's' | 'm';
+
+export const sizeToClassMap: { [size in BetaBadgeSize]: string | null } = {
+ s: 'euiBetaBadge--small',
+ m: null,
+};
+
+export const SIZES = keysOf(sizeToClassMap);
+
+type WithButtonProps = {
+ /**
+ * Will apply an onclick to the badge itself
+ */
+ onClick?: MouseEventHandler;
+
+ /**
+ * Aria label applied to the onClick button
+ */
+ onClickAriaLabel?: AriaAttributes['aria-label'];
+} & Omit, 'onClick' | 'color'>;
+
+type WithAnchorProps = {
+ href: string;
+ target?: string;
+ rel?: string;
+} & Omit, 'href' | 'color' | 'onClick'>;
+
+type WithSpanProps = Omit<
+ HTMLAttributes,
+ 'onClick' | 'color' | 'title'
+>;
+
// `label` prop can be a `ReactNode` only if `title` or `tooltipContent` is provided
-type LabelAsNode = (
- | {
- title: string;
- tooltipContent?: ReactNode;
- }
- | {
- tooltipContent: ReactNode;
- title?: string;
- }
-) & {
+type LabelAsNode = ExclusiveUnion<
+ {
+ title: string;
+ tooltipContent?: ReactNode;
+ },
+ {
+ tooltipContent: ReactNode;
+ title?: string;
+ }
+> & {
label: ReactNode;
};
@@ -72,67 +122,133 @@ type BadgeProps = {
* otherwise the label will be used
*/
title?: string;
+ /**
+ * Accepts accent, subdued and hollow.
+ */
+ color?: BetaBadgeColor;
+ size?: BetaBadgeSize;
} & ExclusiveUnion;
export type EuiBetaBadgeProps = CommonProps &
- Omit, 'title'> &
+ ExclusiveUnion<
+ ExclusiveUnion,
+ WithSpanProps
+ > &
BadgeProps;
export const EuiBetaBadge: FunctionComponent = ({
className,
label,
+ color = 'hollow',
tooltipContent,
tooltipPosition = 'top',
title,
iconType,
+ onClick,
+ onClickAriaLabel,
+ href,
+ rel,
+ target,
+ size = 'm',
...rest
}) => {
+ let singleLetter = false;
+ if (typeof label === 'string' && label.length === 1) {
+ singleLetter = true;
+ }
+
const classes = classNames(
'euiBetaBadge',
{
'euiBetaBadge--iconOnly': iconType,
+ 'euiBetaBadge--singleLetter': singleLetter,
+ 'euiBetaBadge-isClickable': onClick || href,
},
+ colorToClassMap[color],
+ sizeToClassMap[size],
className
);
- let icon;
+ let icon: JSX.Element | undefined;
if (iconType) {
icon = (
);
}
- if (tooltipContent) {
- return (
-
-
- {icon || label}
-
-
+ const Element = href ? 'a' : 'button';
+ const relObj: {
+ href?: string;
+ target?: string;
+ rel?: string;
+ onClick?:
+ | ((event: React.MouseEvent) => void)
+ | ((event: React.MouseEvent) => void);
+ } = {};
+
+ if (href) {
+ relObj.href = href;
+ relObj.target = target;
+ relObj.rel = getSecureRelForTarget({ href, target, rel });
+ }
+ if (onClick) {
+ relObj.onClick = onClick;
+ }
+
+ let content;
+ if (onClick || href) {
+ content = (
+ )}
+ {...(rest as HTMLAttributes)}>
+ {icon || label}
+
);
+ if (tooltipContent) {
+ return (
+
+ {content}
+
+ );
+ } else {
+ return {content};
+ }
} else {
- const spanTitle = title || label;
- if (spanTitle && typeof spanTitle !== 'string') {
- console.warn(
- `Only string titles are permitted on badges that do not use tooltips. Found: ${typeof spanTitle}`
+ if (tooltipContent) {
+ return (
+
+
+ {icon || label}
+
+
+ );
+ } else {
+ const spanTitle = title || label;
+ if (spanTitle && typeof spanTitle !== 'string') {
+ console.warn(
+ `Only string titles are permitted on badges that do not use tooltips. Found: ${typeof spanTitle}`
+ );
+ }
+ return (
+
+ {icon || label}
+
);
}
- return (
-
- {icon || label}
-
- );
}
};
diff --git a/src/components/badge/notification_badge/_notification_badge.scss b/src/components/badge/notification_badge/_notification_badge.scss
index 14db7416aa2..78cdd44ca8f 100644
--- a/src/components/badge/notification_badge/_notification_badge.scss
+++ b/src/components/badge/notification_badge/_notification_badge.scss
@@ -14,7 +14,7 @@
transition: all $euiAnimSpeedFast ease-in;
cursor: default;
- $backgroundColor: $euiColorAccent;
+ $backgroundColor: $euiColorAccentText;
background: $backgroundColor;
color: chooseLightOrDarkText($backgroundColor, $euiColorGhost, $euiColorInk);
}
diff --git a/src/components/card/__snapshots__/card.test.tsx.snap b/src/components/card/__snapshots__/card.test.tsx.snap
index f2597f4b472..36de13e3b12 100644
--- a/src/components/card/__snapshots__/card.test.tsx.snap
+++ b/src/components/card/__snapshots__/card.test.tsx.snap
@@ -1,5 +1,43 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`EuiCard betaBadgeProps renders href 1`] = `
+
+`;
+
exports[`EuiCard horizontal selectable 1`] = `
{
expect(component).toMatchSnapshot();
});
+
+ test('betaBadgeProps renders href', () => {
+ const component = render(
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
});
diff --git a/src/components/card/card.tsx b/src/components/card/card.tsx
index 98964edb53a..24c74e68d04 100644
--- a/src/components/card/card.tsx
+++ b/src/components/card/card.tsx
@@ -30,7 +30,7 @@ import { CommonProps, ExclusiveUnion, keysOf } from '../common';
import { getSecureRelForTarget } from '../../services';
import { EuiText } from '../text';
import { EuiTitle } from '../title';
-import { EuiBetaBadge } from '../badge/beta_badge';
+import { EuiBetaBadge, EuiBetaBadgeProps } from '../badge/beta_badge';
import { EuiIconProps } from '../icon';
import {
EuiCardSelect,
@@ -135,18 +135,22 @@ export type EuiCardProps = Omit &
/**
* Add a badge to the card to label it as "Beta" or other non-GA state
+ * **DEPRECATED: Use `betaBadgeProps.label` instead.**
*/
betaBadgeLabel?: string;
/**
* Add a description to the beta badge (will appear in a tooltip)
+ * **DEPRECATED: Use `betaBadgeProps.tooltipContent` instead.**
*/
betaBadgeTooltipContent?: ReactNode;
/**
- * Optional title will be supplied as tooltip title or title attribute otherwise the label will be used
+ * Optional title will be supplied as tooltip title or title attribute otherwise the label will be used.
+ * **DEPRECATED: Use `betaBadgeProps.title` instead.**
*/
betaBadgeTitle?: string;
+ betaBadgeProps?: Partial;
/**
* Matches to the color property of EuiPanel. If defined, removes any border & shadow.
* Leave as `undefined` to display as a default panel.
@@ -192,6 +196,7 @@ export const EuiCard: FunctionComponent = ({
betaBadgeLabel,
betaBadgeTooltipContent,
betaBadgeTitle,
+ betaBadgeProps,
layout = 'vertical',
selectable,
display,
@@ -295,10 +300,14 @@ export const EuiCard: FunctionComponent = ({
);
diff --git a/src/global_styling/mixins/_beta_badge.scss b/src/global_styling/mixins/_beta_badge.scss
index c75f526c349..8900d3c5900 100644
--- a/src/global_styling/mixins/_beta_badge.scss
+++ b/src/global_styling/mixins/_beta_badge.scss
@@ -24,7 +24,6 @@
#{$selector}__betaBadge {
overflow: hidden;
text-overflow: ellipsis;
- background-color: $euiColorEmptyShade;
}
}
}