From e6e3168c7b988221388d480270ee058e5839a3a5 Mon Sep 17 00:00:00 2001 From: Caroline Horn <549577+cchaos@users.noreply.github.com> Date: Tue, 26 Feb 2019 10:44:19 -0500 Subject: [PATCH] Align Filter and Facet button styles (#1589) --- CHANGELOG.md | 4 + src-docs/src/views/facet/facet_example.js | 5 + .../src/views/filter_group/filter_group.js | 3 +- .../filter_group/filter_group_example.js | 6 +- src/components/avatar/_avatar.scss | 5 +- .../badge_notification.test.tsx.snap | 36 +++- .../_notification_badge.scss | 15 ++ .../badge_notification.test.tsx | 32 +++- .../notification_badge/badge_notification.tsx | 31 ++- .../__snapshots__/facet_button.test.js.snap | 28 ++- src/components/facet/_facet_button.scss | 59 ++---- src/components/facet/facet_button.js | 21 +- src/components/facet/facet_button.test.js | 12 +- src/components/facet/index.d.ts | 44 +++++ .../__snapshots__/filter_button.test.js.snap | 180 +++++++++++++++++- .../filter_group/_filter_button.scss | 57 +++--- src/components/filter_group/filter_button.js | 24 ++- .../filter_group/filter_button.test.js | 90 +++++++++ src/components/filter_group/index.d.ts | 20 +- src/components/icon/_icon.scss | 1 + src/components/index.d.ts | 1 + src/components/loading/_loading_spinner.scss | 1 + src/global_styling/mixins/_typography.scss | 19 ++ 23 files changed, 588 insertions(+), 106 deletions(-) create mode 100644 src/components/facet/index.d.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d4ed5883c3b..3f259e3ecec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ - Added `mobileOptions` object prop for handling of all the mobile specific options of `EuiBasicTable` ([#1462](https://github.com/elastic/eui/pull/1462)) - Table headers now accept `React.node` types ([#1462](https://github.com/elastic/eui/pull/1462)) +- Added `displayOnly` prop to `EuiFormRow` ([#1582](https://github.com/elastic/eui/pull/1582)) +- Added `numActiveFilters` prop to `EuiFilterButton` ([#1589](https://github.com/elastic/eui/pull/1589)) +- Updated style of `EuiFilterButton` to match `EuiFacetButton` ([#1589](https://github.com/elastic/eui/pull/1589)) +- Added `size` and `color` props to `EuiNotificationBadge` ([#1589](https://github.com/elastic/eui/pull/1589)) **Bug fixes** diff --git a/src-docs/src/views/facet/facet_example.js b/src-docs/src/views/facet/facet_example.js index aff17211a68..514d2d049ad 100644 --- a/src-docs/src/views/facet/facet_example.js +++ b/src-docs/src/views/facet/facet_example.js @@ -69,6 +69,11 @@ export const FacetExample = { ), props: { EuiFacetGroup }, demo: , + snippet: `// Restrict the width of default (vertical) if not restricted by parent +{facets} + +// Horizontal +{facets}`, }, ], }; diff --git a/src-docs/src/views/filter_group/filter_group.js b/src-docs/src/views/filter_group/filter_group.js index 8901e84d607..4e7acbdad4a 100644 --- a/src-docs/src/views/filter_group/filter_group.js +++ b/src-docs/src/views/filter_group/filter_group.js @@ -88,8 +88,9 @@ export default class extends Component { iconType="arrowDown" onClick={this.onButtonClick.bind(this)} isSelected={this.state.isPopoverOpen} + numFilters={items.length} hasActiveFilters={true} - numFilters={2} + numActiveFilters={2} grow={true} > Composers diff --git a/src-docs/src/views/filter_group/filter_group_example.js b/src-docs/src/views/filter_group/filter_group_example.js index c9593f0d234..cdd25361847 100644 --- a/src-docs/src/views/filter_group/filter_group_example.js +++ b/src-docs/src/views/filter_group/filter_group_example.js @@ -1,5 +1,9 @@ import React, { Fragment } from 'react'; +import { + Link, +} from 'react-router'; + import { renderToHtml } from '../../services'; import { @@ -31,7 +35,7 @@ export const FilterGroupExample = { This documents a visual pattern used for filtering (usually page heads next to search). The individual components themselves are very simple and do not have much functionality on their own. If you are looking for expanded usage - examples please check out the Table of Records component which uses this more fully and + examples please check out the Search Bar component which uses this more fully and can give you a better example of its usage when applied to filtering.

diff --git a/src/components/avatar/_avatar.scss b/src/components/avatar/_avatar.scss index 7590180480a..0414e4534e1 100644 --- a/src/components/avatar/_avatar.scss +++ b/src/components/avatar/_avatar.scss @@ -1,10 +1,11 @@ .euiAvatar { + flex-shrink: 0; // Ensures it never scales down below it's intended size display: inline-block; background-size: cover; text-align: center; vertical-align: middle; overflow-x: hidden; - font-weight: $euiFontWeightRegular; // Explicitly state so it doesn't get overridden by inheritence + font-weight: $euiFontWeightMedium; // Explicitly state so it doesn't get overridden by inheritence } .euiAvatar--user { @@ -21,7 +22,7 @@ $avatarSizing: ( s: ( size: $euiSizeL, - font-size: $euiSizeM*.9 + font-size: $euiSizeM ), m: ( size: $euiSizeXL, diff --git a/src/components/badge/notification_badge/__snapshots__/badge_notification.test.tsx.snap b/src/components/badge/notification_badge/__snapshots__/badge_notification.test.tsx.snap index 45529816764..1e7152aca1b 100644 --- a/src/components/badge/notification_badge/__snapshots__/badge_notification.test.tsx.snap +++ b/src/components/badge/notification_badge/__snapshots__/badge_notification.test.tsx.snap @@ -5,5 +5,39 @@ exports[`EuiNotificationBadge is rendered 1`] = ` aria-label="aria-label" class="euiNotificationBadge testClass1 testClass2" data-test-subj="test subject string" -/> +> + 5 + +`; + +exports[`EuiNotificationBadge props color accent is rendered 1`] = ` + + 5 + +`; + +exports[`EuiNotificationBadge props color subdued is rendered 1`] = ` + + 5 + +`; + +exports[`EuiNotificationBadge props size m is rendered 1`] = ` + + 5 + +`; + +exports[`EuiNotificationBadge props size s is rendered 1`] = ` + + 5 + `; diff --git a/src/components/badge/notification_badge/_notification_badge.scss b/src/components/badge/notification_badge/_notification_badge.scss index a5960cebd0d..598ac182b64 100644 --- a/src/components/badge/notification_badge/_notification_badge.scss +++ b/src/components/badge/notification_badge/_notification_badge.scss @@ -1,4 +1,5 @@ .euiNotificationBadge { + flex-shrink: 0; // Ensures it never scales down below it's intended size display: inline-block; border-radius: $euiBorderRadius; background: $euiColorAccent; @@ -12,4 +13,18 @@ padding-right: $euiSizeXS; vertical-align: middle; text-align: center; + transition: all $euiAnimSpeedFast ease-in; +} + +.euiNotificationBadge--medium { + // Increase the default size a bit + $size: $euiSize + $euiSizeXS; + line-height: $size; + height: $size; + min-width: $euiSizeL; +} + +.euiNotificationBadge--subdued { + background-color: tint($euiColorLightShade, 30%); + color: $euiColorFullShade; } diff --git a/src/components/badge/notification_badge/badge_notification.test.tsx b/src/components/badge/notification_badge/badge_notification.test.tsx index b48e588c0fb..76062005f4b 100644 --- a/src/components/badge/notification_badge/badge_notification.test.tsx +++ b/src/components/badge/notification_badge/badge_notification.test.tsx @@ -2,12 +2,40 @@ import React from 'react'; import { render } from 'enzyme'; import { requiredProps } from '../../../test/required_props'; -import { EuiNotificationBadge } from './badge_notification'; +import { EuiNotificationBadge, COLORS, SIZES } from './badge_notification'; describe('EuiNotificationBadge', () => { test('is rendered', () => { - const component = render(); + const component = render( + 5 + ); expect(component).toMatchSnapshot(); }); + + describe('props', () => { + describe('color', () => { + COLORS.forEach(color => { + test(`${color} is rendered`, () => { + const component = render( + 5 + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); + + describe('size', () => { + SIZES.forEach(size => { + test(`${size} is rendered`, () => { + const component = render( + 5 + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); + }); }); diff --git a/src/components/badge/notification_badge/badge_notification.tsx b/src/components/badge/notification_badge/badge_notification.tsx index eb8a99b4c24..107973a2deb 100644 --- a/src/components/badge/notification_badge/badge_notification.tsx +++ b/src/components/badge/notification_badge/badge_notification.tsx @@ -1,17 +1,40 @@ import React, { HTMLAttributes, ReactNode, FunctionComponent } from 'react'; import classNames from 'classnames'; -import { CommonProps } from '../../common'; +import { CommonProps, keysOf } from '../../common'; + +const colorToClassMap: { [color: string]: string | null } = { + accent: null, + subdued: 'euiNotificationBadge--subdued', +}; + +export const COLORS: BadgeNotificationColor[] = keysOf(colorToClassMap); +export type BadgeNotificationColor = keyof typeof colorToClassMap; + +const sizeToClassNameMap = { + s: null, + m: 'euiNotificationBadge--medium', +}; + +export const SIZES: BadgeNotificationSize[] = keysOf(sizeToClassNameMap); +export type BadgeNotificationSize = keyof typeof sizeToClassNameMap; export interface EuiNotificationBadgeProps extends CommonProps, HTMLAttributes { - children?: ReactNode; + children: ReactNode; + size?: BadgeNotificationSize; + color?: BadgeNotificationColor; } export const EuiNotificationBadge: FunctionComponent< EuiNotificationBadgeProps -> = ({ children, className, ...rest }) => { - const classes = classNames('euiNotificationBadge', className); +> = ({ children, className, size = 's', color = 'accent', ...rest }) => { + const classes = classNames( + 'euiNotificationBadge', + sizeToClassNameMap[size], + colorToClassMap[color], + className + ); return ( diff --git a/src/components/facet/__snapshots__/facet_button.test.js.snap b/src/components/facet/__snapshots__/facet_button.test.js.snap index 909c2d66cd2..f2f77e2e805 100644 --- a/src/components/facet/__snapshots__/facet_button.test.js.snap +++ b/src/components/facet/__snapshots__/facet_button.test.js.snap @@ -12,6 +12,7 @@ exports[`EuiFacetButton is rendered 1`] = ` > Content @@ -50,7 +51,10 @@ exports[`EuiFacetButton props icon is rendered 1`] = ` + data-text="Content" + > + Content + `; @@ -66,7 +70,10 @@ exports[`EuiFacetButton props isDisabled is rendered 1`] = ` > + data-text="Content" + > + Content + `; @@ -82,7 +89,10 @@ exports[`EuiFacetButton props isLoading is rendered 1`] = ` > + data-text="Content" + > + Content +
@@ -100,7 +110,10 @@ exports[`EuiFacetButton props isSelected is rendered 1`] = ` > + data-text="Content" + > + Content + `; @@ -115,9 +128,12 @@ exports[`EuiFacetButton props quantity is rendered 1`] = ` > + data-text="Content" + > + Content + 60 diff --git a/src/components/facet/_facet_button.scss b/src/components/facet/_facet_button.scss index a0eec55056c..886d6f26d00 100644 --- a/src/components/facet/_facet_button.scss +++ b/src/components/facet/_facet_button.scss @@ -12,45 +12,7 @@ border: none; transform: none !important; /* 1 */ animation: none !important; /* 1 */ - transition-timing-function: ease-in; /* 2 */ - transition-duration: $euiAnimSpeedFast; /* 2 */ - - .euiFacetButton__content { - @include euiButtonContent; - } - - .euiFacetButton__text { - flex-grow: 1; - text-overflow: ellipsis; - overflow: hidden; - line-height: $euiButtonHeight; // For better alignment with icon/quantity - } - - .euiFacetButton__spinner, - .euiFacetButton__quantity, - .euiFacetButton__icon { - flex-shrink: 0; // Ensures they don't scale down below their intended size - } - - .euiFacetButton__quantity, - .euiFacetButton__icon { - transition: all $euiAnimSpeedFast ease-in; - } - - .euiFacetButton__quantity { - // Increase the default size a bit - $size: $euiSize + $euiSizeXS; - line-height: $size; - height: $size; - min-width: $euiSizeL; - } - - &.euiFacetButton--unSelected .euiFacetButton__quantity, - &:disabled .euiFacetButton__quantity { - // Change the default coloring when it's not selected - background-color: tint($euiColorLightShade, 30%); - color: $euiColorFullShade; - } + transition: all $euiAnimSpeedFast ease-in; /* 2 */ &:hover, &:focus { @@ -91,6 +53,21 @@ } } -.euiFacetButton--isSelected .euiFacetButton__text { - font-weight: $euiFontWeightBold; +.euiFacetButton__content { + @include euiButtonContent; +} + +.euiFacetButton__text { + @include euiTextShift; + @include euiTextTruncate; + flex-grow: 1; + vertical-align: middle; + + .euiFacetButton--isSelected & { + font-weight: $euiFontWeightBold; + } +} + +.euiFacetButton__icon { + transition: all $euiAnimSpeedFast ease-in; } diff --git a/src/components/facet/facet_button.js b/src/components/facet/facet_button.js index 3fe6d9f7150..91066b1b487 100644 --- a/src/components/facet/facet_button.js +++ b/src/components/facet/facet_button.js @@ -48,6 +48,8 @@ export const EuiFacetButton = ({ buttonQuantity = ( {quantity} @@ -64,18 +66,22 @@ export const EuiFacetButton = ({ ); } + let dataText; + if (typeof children === 'string') { + dataText = children; + } return ( @@ -83,11 +89,16 @@ export const EuiFacetButton = ({ }; EuiFacetButton.propTypes = { - children: PropTypes.node, + children: PropTypes.node.isRequired, className: PropTypes.string, - icon: PropTypes.node, isDisabled: PropTypes.bool, onClick: PropTypes.func, + buttonRef: PropTypes.func, + + /** + * Any node, but preferrably a `EuiIcon` or `EuiAvatar` + */ + icon: PropTypes.node, /** * Adds/swaps for loading spinner & disables @@ -103,8 +114,6 @@ EuiFacetButton.propTypes = { * Adds a notification indicator for displaying the quantity provided */ quantity: PropTypes.number, - - buttonRef: PropTypes.func, }; EuiFacetButton.defaultProps = { diff --git a/src/components/facet/facet_button.test.js b/src/components/facet/facet_button.test.js index fa6cea37bc8..9e1608e449b 100644 --- a/src/components/facet/facet_button.test.js +++ b/src/components/facet/facet_button.test.js @@ -21,7 +21,7 @@ describe('EuiFacetButton', () => { describe('isDisabled', () => { it('is rendered', () => { const component = render( - + Content ); expect(component) @@ -32,7 +32,7 @@ describe('EuiFacetButton', () => { describe('isLoading', () => { it('is rendered', () => { const component = render( - + Content ); expect(component) @@ -43,7 +43,7 @@ describe('EuiFacetButton', () => { describe('isSelected', () => { it('is rendered', () => { const component = render( - + Content ); expect(component) @@ -54,7 +54,7 @@ describe('EuiFacetButton', () => { describe('quantity', () => { it('is rendered', () => { const component = render( - + Content ); expect(component) @@ -65,7 +65,7 @@ describe('EuiFacetButton', () => { describe('icon', () => { it('is rendered', () => { const component = render( - } /> + }>Content ); expect(component) @@ -77,7 +77,7 @@ describe('EuiFacetButton', () => { it('supports onClick', () => { const handler = jest.fn(); const component = mount( - + Content ); component.find('button').simulate('click'); expect(handler.mock.calls.length).toEqual(1); diff --git a/src/components/facet/index.d.ts b/src/components/facet/index.d.ts new file mode 100644 index 00000000000..ed89258135e --- /dev/null +++ b/src/components/facet/index.d.ts @@ -0,0 +1,44 @@ +import React, { + ButtonHTMLAttributes, + HTMLAttributes, + ReactNode, + MouseEventHandler, + FunctionComponent, +} from 'react'; +import { CommonProps, RefCallback } from '../common'; +/// + +declare module '@elastic/eui' { + /** + * Facet button type defs + * + * @see './facet_button.js' + */ + + export interface EuiFacetButtonProps { + children: ReactNode; + icon?: ReactNode; + isDisabled?: boolean; + onClick?: MouseEventHandler; + isLoading?: boolean; + isSelected?: boolean; + quantity: number; + buttonRef: RefCallback; + } + export const EuiFacetButton: FunctionComponent & EuiFacetButtonProps>; + + /** + * Facet group type defs + * + * @see './facet_group.js' + */ + + export type FacetGroupLayouts = 'vertical' | 'horizontal'; + export interface EuiFacetGroupProps { + layout?: FacetGroupLayouts + } + + export const EuiFacetGroup: FunctionComponent & EuiFacetGroupProps>; +} diff --git a/src/components/filter_group/__snapshots__/filter_button.test.js.snap b/src/components/filter_group/__snapshots__/filter_button.test.js.snap index c1d92976156..46d37d80893 100644 --- a/src/components/filter_group/__snapshots__/filter_button.test.js.snap +++ b/src/components/filter_group/__snapshots__/filter_button.test.js.snap @@ -21,6 +21,184 @@ exports[`EuiFilterButton is rendered 1`] = ` `; +exports[`EuiFilterButton props grow is rendered 1`] = ` + +`; + +exports[`EuiFilterButton props iconType and iconSide is rendered 1`] = ` + +`; + +exports[`EuiFilterButton props isDisabled is rendered 1`] = ` + +`; + +exports[`EuiFilterButton props isSelected is rendered 1`] = ` + +`; + +exports[`EuiFilterButton props noDivider is rendered 1`] = ` + +`; + +exports[`EuiFilterButton props numActiveFilters and hasActiveFilters is rendered 1`] = ` + +`; + +exports[`EuiFilterButton props numFilters is rendered 1`] = ` + +`; + +exports[`EuiFilterButton props type is rendered 1`] = ` + +`; + exports[`EuiFilterButton renders zero properly 1`] = `