diff --git a/CHANGELOG.md b/CHANGELOG.md index 04d9369662d..dbd023eacfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## [`master`](https://github.com/elastic/eui/tree/master) +- Created `EuiBadgeGroup` component ([#2921](https://github.com/elastic/eui/pull/2921)) - Added SASS variables for text variants of the primary palette `$euiColorPrimaryText`, `$euiColorSecondaryText`, etc... Updated components to use these new variables. ([#2873](https://github.com/elastic/eui/pull/2873)) - Updated SASS mixin `makeHighContrastColor()` to default `$background: $euiPageBackgroundColor` and `$ratio: 4.5`. Created `makeGraphicContrastColor()` for graphic specific contrast levels of 3.0. ([#2873](https://github.com/elastic/eui/pull/2873)) diff --git a/src-docs/src/views/badge/badge_example.js b/src-docs/src/views/badge/badge_example.js index 3568874491d..ecbe056b3c9 100644 --- a/src-docs/src/views/badge/badge_example.js +++ b/src-docs/src/views/badge/badge_example.js @@ -11,10 +11,12 @@ import { EuiCode, EuiBetaBadge, EuiNotificationBadge, + EuiBadgeGroup, EuiCallOut, } from '../../../../src/components'; import Badge from './badge'; + const badgeSource = require('!!raw-loader!./badge'); const badgeHtml = renderToHtml(Badge); const badgeSnippet = [ @@ -91,6 +93,10 @@ const notificationBadgeHtml = renderToHtml(NotificationBadge); const notificationBadgeSnippet = `3 `; +import BadgeGroup from './badge_group'; +const badgeGroupSource = require('!!raw-loader!./badge_group'); +const badgeGroupHtml = renderToHtml(BadgeGroup); + export const BadgeExample = { title: 'Badge', sections: [ @@ -261,5 +267,26 @@ export const BadgeExample = { snippet: notificationBadgeSnippet, demo: , }, + { + title: 'Badge Group', + source: [ + { + type: GuideSectionTypes.JS, + code: badgeGroupSource, + }, + { + type: GuideSectionTypes.HTML, + code: badgeGroupHtml, + }, + ], + text: ( +

+ Grouping badges with EuiBadgeGroup, ensures they wrap and truncate + properly. +

+ ), + props: { EuiBadgeGroup }, + demo: , + }, ], }; diff --git a/src-docs/src/views/badge/badge_group.js b/src-docs/src/views/badge/badge_group.js new file mode 100644 index 00000000000..fcb71c53c2d --- /dev/null +++ b/src-docs/src/views/badge/badge_group.js @@ -0,0 +1,31 @@ +import React, { Fragment } from 'react'; + +import { + EuiBadge, + EuiFlexItem, + EuiBadgeGroup, +} from '../../../../src/components'; + +const badges = [ + 'default', + 'hollow', + 'primary', + 'secondary', + 'accent', + 'warning', + 'danger', +]; + +export default () => { + return ( + + + {badges.map(badge => ( + + {badge} + + ))} + + + ); +}; diff --git a/src/components/badge/__snapshots__/badge_group.test.tsx.snap b/src/components/badge/__snapshots__/badge_group.test.tsx.snap new file mode 100644 index 00000000000..d9ac5dbdf26 --- /dev/null +++ b/src/components/badge/__snapshots__/badge_group.test.tsx.snap @@ -0,0 +1,26 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EuiBadgeGroup is rendered 1`] = ` +
+ + + + Content + + + +
+`; diff --git a/src/components/badge/_badge_group.scss b/src/components/badge/_badge_group.scss new file mode 100644 index 00000000000..1d52d0931f9 --- /dev/null +++ b/src/components/badge/_badge_group.scss @@ -0,0 +1,49 @@ +$gutterTypes: ( + gutterExtraSmall: $euiSizeXS, + gutterSmall: $euiSizeS, + gutterMedium: $euiSize, + gutterLarge: $euiSizeL, + gutterExtraLarge: $euiSizeXXL, +); + +.euiBadgeGroup { + display: flex; + align-items: center; + flex-flow: row; + flex-grow: 1; + + .euiBadgeItem { + @include internetExplorerOnly { + min-width: 1px; + } + + flex-grow: 1; + flex-basis: 0%; + } +} + +// Gutter Sizes +@each $gutterName, $gutterSize in $gutterTypes { + $halfGutterSize: $gutterSize * .5; + + .euiBadgeGroup--#{$gutterName} { + margin: -$halfGutterSize; + + & > .euiBadgeItem { + margin: $halfGutterSize; + } + } +} + +// Wrap +.euiBadgeGroup--wrap { + flex-wrap: wrap; +} + +@include euiBreakpoint('xs', 's') { + .euiBadgeGroup--responsive { + flex-wrap: wrap; + margin-left: 0; + margin-right: 0; + } +} diff --git a/src/components/badge/_index.scss b/src/components/badge/_index.scss index a567f7a42de..20bda8e5f8d 100644 --- a/src/components/badge/_index.scss +++ b/src/components/badge/_index.scss @@ -1,3 +1,4 @@ @import 'badge'; +@import 'badge_group'; @import 'beta_badge/index'; @import 'notification_badge/index'; diff --git a/src/components/badge/badge_group.test.tsx b/src/components/badge/badge_group.test.tsx new file mode 100644 index 00000000000..bbf749bc599 --- /dev/null +++ b/src/components/badge/badge_group.test.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { render } from 'enzyme'; +import { requiredProps } from '../../test/required_props'; + +import { EuiBadge } from './badge'; +import { EuiBadgeGroup } from './badge_group'; + +describe('EuiBadgeGroup', () => { + test('is rendered', () => { + const component = render( + + + Content + + + ); + + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/components/badge/badge_group.tsx b/src/components/badge/badge_group.tsx new file mode 100644 index 00000000000..135f451d702 --- /dev/null +++ b/src/components/badge/badge_group.tsx @@ -0,0 +1,62 @@ +import React, { HTMLAttributes, Ref } from 'react'; +import classNames from 'classnames'; +import { CommonProps, keysOf } from '../common'; + +type BadgeGroupGutterSize = keyof typeof gutterSizeToClassNameMap; + +export interface EuiBadgeGroupProps { + /** + * Space between badges + */ + gutterSize?: BadgeGroupGutterSize; + /** + * Force each badges to be display block on smaller screens + */ + responsive?: boolean; + /** + * Force each badge to wrap if necessary + */ + wrap?: boolean; +} + +const gutterSizeToClassNameMap = { + none: null, + xs: 'euiBadgeGroup--gutterExtraSmall', + s: 'euiBadgeGroup--gutterSmall', +}; + +export const GUTTER_SIZES = keysOf(gutterSizeToClassNameMap); + +export const EuiBadgeGroup = React.forwardRef< + HTMLDivElement, + CommonProps & HTMLAttributes & EuiBadgeGroupProps +>( + ( + { + children, + className, + gutterSize = 'xs', + responsive = true, + wrap = true, + ...rest + }, + ref: Ref + ) => { + const classes = classNames( + 'euiBadgeGroup', + gutterSizeToClassNameMap[gutterSize as BadgeGroupGutterSize], + { + 'euiBadgeGroup--responsive': responsive, + 'euiBadgeGroup--wrap': wrap, + }, + className + ); + + return ( +
+ {children} +
+ ); + } +); +EuiBadgeGroup.displayName = 'EuiBadgeGroup'; diff --git a/src/components/badge/index.ts b/src/components/badge/index.ts index 6ab2cc152c3..fda8fa2acb4 100644 --- a/src/components/badge/index.ts +++ b/src/components/badge/index.ts @@ -3,3 +3,5 @@ export { EuiBadge, EuiBadgeProps } from './badge'; export { EuiBetaBadge } from './beta_badge'; export { EuiNotificationBadge } from './notification_badge'; + +export { EuiBadgeGroup } from './badge_group'; diff --git a/src/components/index.js b/src/components/index.js index f4cb7cf6652..1cb217b4f59 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -6,7 +6,12 @@ export { EuiAvatar } from './avatar'; export { EuiKeyboardAccessible, EuiScreenReaderOnly } from './accessibility'; -export { EuiBadge, EuiBetaBadge, EuiNotificationBadge } from './badge'; +export { + EuiBadge, + EuiBetaBadge, + EuiNotificationBadge, + EuiBadgeGroup, +} from './badge'; export { EuiBottomBar } from './bottom_bar';