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

now EuiBadge render anchor tags too #3009

Merged
merged 11 commits into from
Mar 16, 2020
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
@@ -1,5 +1,6 @@
## [`master`](https://github.com/elastic/eui/tree/master)

- Added `href` prop to `EuiBadge` ([#3009](https://github.com/elastic/eui/pull/3009))
- Added props descriptions for `EuiComboBox` ([#3007](https://github.com/elastic/eui/pull/3007))
- Exported `dateFormatAliases` as a part of the public API ([#3043](https://github.com/elastic/eui/pull/3043))
- Exported `EuiTextProps` type definition ([#3039](https://github.com/elastic/eui/pull/3039))
Expand Down
12 changes: 12 additions & 0 deletions src-docs/src/views/badge/badge_button.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,17 @@ export default () => (
onClick on both text and icon within badge
</EuiBadge>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiBadge
isDisabled={true}
color="danger"
onClick={() => window.alert('Badge clicked')}
onClickAriaLabel="Example of disabled button badge"
iconOnClick={() => window.alert('Disabled badge clicked')}
iconOnClickAriaLabel="Example of disabled button badge"
data-test-sub="testExample4">
disabled button badge
</EuiBadge>
</EuiFlexItem>
</EuiFlexGroup>
);
28 changes: 28 additions & 0 deletions src-docs/src/views/badge/badge_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ const badgeButtonSnippet = [
</EuiBadge>`,
];

import BadgeHref from './badge_href';
const badgeHrefSource = require('!!raw-loader!./badge_href');
const badgeHrefHtml = renderToHtml(BadgeHref);
const badgeHrefSnippet = ['<EuiBadge href="#" />'];

import BadgeTruncate from './badge_truncate';
const badgeTruncateSource = require('!!raw-loader!./badge_truncate');
const badgeTruncateHtml = renderToHtml(BadgeTruncate);
Expand Down Expand Up @@ -177,6 +182,29 @@ export const BadgeExample = {
snippet: badgeButtonSnippet,
demo: <BadgeButton />,
},
{
title: 'Badge with href',
source: [
{
type: GuideSectionTypes.JS,
code: badgeHrefSource,
},
{
type: GuideSectionTypes.HTML,
code: badgeHrefHtml,
},
],
text: (
<div>
<p>
Badges can also be made to render anchor tags by passing an{' '}
<EuiCode>href</EuiCode>.
</p>
</div>
),
snippet: badgeHrefSnippet,
demo: <BadgeHref />,
},
{
title: 'Badge groups and truncation',
source: [
Expand Down
38 changes: 38 additions & 0 deletions src-docs/src/views/badge/badge_href.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';

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

export default () => (
<EuiFlexGroup wrap responsive={false} gutterSize="xs">
<EuiFlexItem grow={false}>
<EuiBadge color="#BADA55" href="/#/display/badge">
badge as an anchor
</EuiBadge>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiBadge color="hollow" href="/#/display/badge" target="blank">
anchor with target specified
</EuiBadge>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiBadge
color="accent"
href="/#/display/badge"
iconType="bolt"
iconSide="right"
iconOnClick={() => window.alert('Icon inside badge clicked')}
iconOnClickAriaLabel="Example of onClick event for icon within the anchor">
anchor with an icon and iconOnClick
</EuiBadge>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiBadge color="secondary" href="/#/display/badge" isDisabled={true}>
disabled anchor badge
</EuiBadge>
</EuiFlexItem>
</EuiFlexGroup>
);
50 changes: 45 additions & 5 deletions src/components/badge/__snapshots__/badge.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,46 @@ exports[`EuiBadge is rendered 1`] = `
</span>
`;

exports[`EuiBadge is rendered with href provided 1`] = `
<a
aria-label="aria-label"
class="euiBadge euiBadge-isClickable euiBadge--iconLeft testClass1 testClass2"
data-test-subj="test subject string"
href="/#/"
style="background-color:#d3dae6;color:#000"
>
<span
class="euiBadge__content"
>
<span
class="euiBadge__text"
>
Content
</span>
</span>
</a>
`;

exports[`EuiBadge is rendered with iconOnClick and href provided 1`] = `
<span
class="euiBadge euiBadge--iconLeft testClass1 testClass2"
style="background-color:#d3dae6;color:#000"
>
<span
class="euiBadge__content"
>
<a
aria-label="aria-label"
class="euiBadge__childButton"
data-test-subj="test subject string"
href="/#/"
>
Content
</a>
</span>
</span>
`;

exports[`EuiBadge is rendered with iconOnClick and onClick provided 1`] = `
<span
class="euiBadge euiBadge--iconLeft testClass1 testClass2"
Expand All @@ -59,19 +99,19 @@ exports[`EuiBadge is rendered with iconOnClick and onClick provided 1`] = `

exports[`EuiBadge is rendered with iconOnClick provided 1`] = `
<span
aria-label="aria-label"
class="euiBadge euiBadge--iconLeft testClass1 testClass2"
data-test-subj="test subject string"
style="background-color:#d3dae6;color:#000"
>
<span
class="euiBadge__content"
>
<span
class="euiBadge__text"
<button
aria-label="aria-label"
class="euiBadge__childButton"
data-test-subj="test subject string"
>
Content
</span>
</button>
</span>
</span>
`;
Expand Down
3 changes: 2 additions & 1 deletion src/components/badge/_badge.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
&.euiBadge-isDisabled {
// sass-lint:disable-block no-important
// Using !important to override inline styles
color: makeHighContrastColor($euiButtonColorDisabled, $euiButtonColorDisabled, 2) !important;
background-color: $euiButtonColorDisabled !important;
color: $euiButtonColorDisabledText !important;
}

&:focus-within {
Expand All @@ -46,6 +46,7 @@
text-align: inherit;
font-weight: inherit;
line-height: inherit;
color: inherit;

&:disabled {
cursor: not-allowed;
Expand Down
24 changes: 24 additions & 0 deletions src/components/badge/badge.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ describe('EuiBadge', () => {
expect(component).toMatchSnapshot();
});

test('is rendered with href provided', () => {
const component = render(
<EuiBadge {...requiredProps} href="/#/">
Content
</EuiBadge>
);

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

test('is rendered with iconOnClick provided', () => {
const component = render(
<EuiBadge
Expand Down Expand Up @@ -62,6 +72,20 @@ describe('EuiBadge', () => {
expect(component).toMatchSnapshot();
});

test('is rendered with iconOnClick and href provided', () => {
const component = render(
<EuiBadge
{...requiredProps}
iconOnClick={jest.fn()}
iconOnClickAriaLabel="Example of onclick event for icon within the anchor"
href="/#/">
Content
</EuiBadge>
);

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

describe('props', () => {
describe('iconType', () => {
it('is rendered', () => {
Expand Down
52 changes: 39 additions & 13 deletions src/components/badge/badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {
HTMLAttributes,
MouseEventHandler,
ReactNode,
Ref,
} from 'react';
import classNames from 'classnames';
import { CommonProps, ExclusiveUnion, keysOf, PropsOf } from '../common';
Expand All @@ -26,6 +27,11 @@ type WithButtonProps = {
onClickAriaLabel: AriaAttributes['aria-label'];
} & Omit<HTMLAttributes<HTMLButtonElement>, 'onClick' | 'color'>;

type WithAnchorProps = {
href: string;
target?: string;
} & Omit<HTMLAttributes<HTMLAnchorElement>, 'href' | 'color'>;

type WithSpanProps = Omit<HTMLAttributes<HTMLSpanElement>, 'onClick' | 'color'>;

interface WithIconOnClick {
Expand Down Expand Up @@ -66,7 +72,10 @@ export type EuiBadgeProps = {
closeButtonProps?: Partial<PropsOf<EuiIcon>>;
} & CommonProps &
ExclusiveUnion<WithIconOnClick, {}> &
ExclusiveUnion<WithSpanProps, WithButtonProps>;
ExclusiveUnion<
ExclusiveUnion<WithButtonProps, WithAnchorProps>,
WithSpanProps
>;

// TODO - replace with variables once https://github.com/elastic/eui/issues/2731 is closed
const colorInk = '#000';
Expand Down Expand Up @@ -108,6 +117,8 @@ export const EuiBadge: FunctionComponent<EuiBadgeProps> = ({
onClickAriaLabel,
iconOnClickAriaLabel,
closeButtonProps,
href,
target,
...rest
}) => {
checkValidColor(color);
Expand Down Expand Up @@ -160,7 +171,7 @@ export const EuiBadge: FunctionComponent<EuiBadgeProps> = ({
const classes = classNames(
'euiBadge',
{
'euiBadge-isClickable': onClick && !iconOnClick,
'euiBadge-isClickable': (onClick || href) && !iconOnClick,
'euiBadge-isDisabled': isDisabled,
'euiBadge--hollow': color === 'hollow',
},
Expand All @@ -172,6 +183,21 @@ export const EuiBadge: FunctionComponent<EuiBadgeProps> = ({
'euiBadge__icon',
closeButtonProps && closeButtonProps.className
);
const Element = href && !isDisabled ? 'a' : 'button';
const relObj: {
href?: string;
target?: string;
onClick?:
| ((event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void)
| ((event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void);
} = {};

if (href && !isDisabled) {
relObj.href = href;
relObj.target = target;
} else if (onClick) {
relObj.onClick = onClick;
}

let optionalIcon: ReactNode = null;
if (iconType) {
Expand Down Expand Up @@ -209,46 +235,46 @@ export const EuiBadge: FunctionComponent<EuiBadgeProps> = ({
);
}

if (onClick && iconOnClick) {
if (iconOnClick) {
return (
<span className={classes} style={optionalCustomStyles}>
<span className="euiBadge__content">
<EuiInnerText>
{(ref, innerText) => (
<button
<Element
anishagg17 marked this conversation as resolved.
Show resolved Hide resolved
className="euiBadge__childButton"
disabled={isDisabled}
aria-label={onClickAriaLabel}
onClick={onClick}
ref={ref}
title={innerText}
{...rest}>
{...relObj as HTMLAttributes<HTMLElement>}
{...rest as HTMLAttributes<HTMLElement>}>
{children}
</button>
</Element>
)}
</EuiInnerText>
{optionalIcon}
</span>
</span>
);
} else if (onClick) {
} else if (onClick || href) {
return (
<EuiInnerText>
{(ref, innerText) => (
<button
<Element
disabled={isDisabled}
aria-label={onClickAriaLabel}
className={classes}
onClick={onClick}
style={optionalCustomStyles}
ref={ref}
ref={ref as Ref<HTMLButtonElement & HTMLAnchorElement>}
title={innerText}
{...rest}>
{...relObj as HTMLAttributes<HTMLElement>}
{...rest as HTMLAttributes<HTMLElement>}>
<span className="euiBadge__content">
<span className="euiBadge__text">{children}</span>
{optionalIcon}
</span>
</button>
</Element>
)}
</EuiInnerText>
);
Expand Down