Skip to content

Commit

Permalink
Fix EuiBadge truncation (#2190)
Browse files Browse the repository at this point in the history
* Fix badge truncation when a `<button>`
* Added innerText to title attribute
* Fix truncation if button is the child
* Max width accounts for padding, etc.
* Some more fixes
- Added docs example for truncations
- Duplicated the `aria-label` as the `title` on the clickable icon
- Keeping the `ref` and `title` attributes to the same element as `…rest` so they can be overridden
- Fix max width of badges with onClick and iconOnClick
- Fix text alignment
- Change cursor to default unless clickable
  • Loading branch information
cchaos authored Aug 1, 2019
1 parent bac577d commit 263e7c9
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 32 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## [`master`](https://github.com/elastic/eui/tree/master)

No public interface changes since `13.1.1`.
**Bug fixes**

- Fixed `EuiBadge` truncation and auto-applied `title` attribute with `innerText` ([#2190](https://github.com/elastic/eui/pull/2190))

## [`13.1.1`](https://github.com/elastic/eui/tree/v13.1.1)

Expand Down
34 changes: 33 additions & 1 deletion src-docs/src/views/badge/badge_example.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { Fragment } from 'react';

import { Link } from 'react-router';

Expand Down Expand Up @@ -34,6 +34,10 @@ import NotificationBadge from './notification_badge';
const notificationBadgeSource = require('!!raw-loader!./notification_badge');
const notificationBadgeHtml = renderToHtml(NotificationBadge);

import BadgeTruncate from './badge_truncate';
const badgeTruncateSource = require('!!raw-loader!./badge_truncate');
const badgeTruncateHtml = renderToHtml(BadgeTruncate);

export const BadgeExample = {
title: 'Badge',
sections: [
Expand Down Expand Up @@ -109,6 +113,34 @@ export const BadgeExample = {
),
demo: <BadgeButton />,
},
{
title: 'Badge truncation',
source: [
{
type: GuideSectionTypes.JS,
code: badgeTruncateSource,
},
{
type: GuideSectionTypes.HTML,
code: badgeTruncateHtml,
},
],
text: (
<Fragment>
<p>
Badges, like buttons, will only every be a single line of text. This
means text will not wrap, but be truncated if the badge&apos;s width
reaches that of its parent&apos;s.
</p>
<p>
For this reason, badges also auto-apply the inner text of the badge
to the <EuiCode>title</EuiCode> attribute of the element to provide
default browser tooltips with the full badge text.
</p>
</Fragment>
),
demo: <BadgeTruncate />,
},
{
title: 'Beta badge type',
source: [
Expand Down
41 changes: 41 additions & 0 deletions src-docs/src/views/badge/badge_truncate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';

import { EuiBadge, EuiPanel, EuiSpacer } from '../../../../src/components';

export default () => (
<EuiPanel style={{ maxWidth: 200 }}>
<EuiBadge>Badge with simple text being truncated</EuiBadge>

<EuiSpacer size="s" />

<EuiBadge iconType="clock">Badge with icon being truncated</EuiBadge>

<EuiSpacer size="s" />

<EuiBadge onClick={() => {}} onClickAriaLabel="Click this badge to...">
Badge with onClick being truncated
</EuiBadge>

<EuiSpacer size="s" />

<EuiBadge
iconType="cross"
iconSide="right"
iconOnClick={() => {}}
iconOnClickAriaLabel="Click this icon to...">
Badge with iconOnClick being truncated
</EuiBadge>

<EuiSpacer size="s" />

<EuiBadge
iconType="cross"
iconSide="right"
onClick={() => {}}
onClickAriaLabel="Click this badge to..."
iconOnClick={() => {}}
iconOnClickAriaLabel="Click this icon to...">
Badge with both onClicks being truncated
</EuiBadge>
</EuiPanel>
);
4 changes: 3 additions & 1 deletion src/components/badge/__snapshots__/badge.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ exports[`EuiBadge is rendered with onClick provided 1`] = `
<span
class="euiBadge__content"
>
<span>
<span
class="euiBadge__text"
>
Content
</span>
</span>
Expand Down
16 changes: 13 additions & 3 deletions src/components/badge/_badge.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@
background-color: transparent;
white-space: nowrap;
vertical-align: middle;
text-align: center;
overflow: hidden;
max-width: calc(100% - #{($euiSizeS * 2) + 2px}); // Padding plus border
// The badge will only ever be as wide as it's content
// So, make the text left aligned to ensure all badges line up the same
text-align: left;

&:focus-within {
@include euiFocusRing('small');
}

+ .euiBadge {
margin-left: $euiSizeXS;
max-width: calc(100% - #{($euiSizeS * 2) + 2px + $euiSizeXS}); // Padding plus border plus margin
}

.euiBadge__content {
Expand All @@ -32,6 +36,8 @@
}

.euiBadge__childButton {
@include euiTextTruncate;
max-width: calc(100% - #{$euiSizeM + $euiSizeXS}); // Subtract the icon and icon's margin
flex: 0 0 auto;
font-weight: inherit;
line-height: inherit;
Expand Down Expand Up @@ -60,9 +66,9 @@
}

.euiBadge__text {
overflow: hidden;
text-overflow: ellipsis;
@include euiTextTruncate;
flex: 1 1 auto;
cursor: default;
}

.euiBadge__icon {
Expand Down Expand Up @@ -90,6 +96,10 @@
&:focus {
@include euiFocusRing('small');
}

.euiBadge__text {
cursor: inherit;
}
}


Expand Down
76 changes: 50 additions & 26 deletions src/components/badge/badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import React, {
FunctionComponent,
MouseEventHandler,
HTMLAttributes,
ReactNode,
} from 'react';
import classNames from 'classnames';
import { CommonProps, ExclusiveUnion, keysOf, PropsOf, Omit } from '../common';

import { isColorDark, hexToRgb } from '../../services/color';
import { EuiInnerText } from '../inner_text';

import { EuiIcon, IconColor, IconType } from '../icon';

Expand Down Expand Up @@ -97,7 +99,7 @@ export const EuiBadge: FunctionComponent<EuiBadgeProps> = ({
checkValidColor(color);

let optionalColorClass = null;
let optionalCustomStyles = undefined;
let optionalCustomStyles: object | undefined = undefined;
let textColor = null;

if (COLORS.indexOf(color) > -1) {
Expand Down Expand Up @@ -127,7 +129,7 @@ export const EuiBadge: FunctionComponent<EuiBadgeProps> = ({
closeButtonProps && closeButtonProps.className
);

let optionalIcon = null;
let optionalIcon: ReactNode = null;
if (iconType) {
if (iconOnClick) {
if (!iconOnClickAriaLabel) {
Expand All @@ -139,6 +141,7 @@ export const EuiBadge: FunctionComponent<EuiBadgeProps> = ({
<button
className="euiBadge__iconButton"
aria-label={iconOnClickAriaLabel}
title={iconOnClickAriaLabel}
onClick={iconOnClick}>
<EuiIcon
type={iconType}
Expand All @@ -165,39 +168,60 @@ export const EuiBadge: FunctionComponent<EuiBadgeProps> = ({
return (
<span className={classes} style={optionalCustomStyles}>
<span className="euiBadge__content">
<button
className="euiBadge__childButton"
aria-label={onClickAriaLabel}
onClick={onClick}
{...rest}>
{children}
</button>
<EuiInnerText>
{(ref, innerText) => (
<button
className="euiBadge__childButton"
aria-label={onClickAriaLabel}
onClick={onClick}
ref={ref}
title={innerText}
{...rest}>
{children}
</button>
)}
</EuiInnerText>
{optionalIcon}
</span>
</span>
);
} else if (onClick) {
return (
<button
aria-label={onClickAriaLabel}
className={classes}
onClick={onClick}
style={optionalCustomStyles}
{...rest}>
<span className="euiBadge__content">
<span>{children}</span>
{optionalIcon}
</span>
</button>
<EuiInnerText>
{(ref, innerText) => (
<button
aria-label={onClickAriaLabel}
className={classes}
onClick={onClick}
style={optionalCustomStyles}
ref={ref}
title={innerText}
{...rest}>
<span className="euiBadge__content">
<span className="euiBadge__text">{children}</span>
{optionalIcon}
</span>
</button>
)}
</EuiInnerText>
);
} else {
return (
<span className={classes} style={optionalCustomStyles} {...rest}>
<span className="euiBadge__content">
<span className="euiBadge__text">{children}</span>
{optionalIcon}
</span>
</span>
<EuiInnerText>
{(ref, innerText) => (
<span
className={classes}
style={optionalCustomStyles}
ref={ref}
title={innerText}
{...rest}>
<span className="euiBadge__content">
<span className="euiBadge__text">{children}</span>
{optionalIcon}
</span>
</span>
)}
</EuiInnerText>
);
}
};
Expand Down

0 comments on commit 263e7c9

Please sign in to comment.