diff --git a/CHANGELOG.md b/CHANGELOG.md
index cb5ad3d36ff..925d6b618fb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@
- Added default prompt text to `aria-describedby` for `EuiFilePicker` ([#2919](https://github.com/elastic/eui/pull/2919))
- 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))
+- Added `arrowDisplay` prop to `EuiAccordion` for changing side or hiding completely ([#2914](https://github.com/elastic/eui/pull/2914))
+- Added `prepend` and `append` ability to `EuiFieldSearch` ([#2914](https://github.com/elastic/eui/pull/2914))
+- Added `notification` and `notificationColor` props to `EuiHeaderSectionItemButton` ([#2914](https://github.com/elastic/eui/pull/2914))
- Added `folderCheck`, `folderExclamation`, `push`, `quote`, `reporter` and `users` icons ([#2935](https://github.com/elastic/eui/pull/2935))
- Updated `folderClosed` and `folderOpen` to match new additions and sit better on the pixel grid ([#2935](https://github.com/elastic/eui/pull/2935))
@@ -12,6 +15,7 @@
- Fixed `EuiTitle` not rendering child classes ([#2926](https://github.com/elastic/eui/pull/2926))
- Added TypeScript definition for `EuiCodeEditor`'s accepting `react-ace` props ([#2926](https://github.com/elastic/eui/pull/2926))
+- Extended `div` element in `EuiFlyout` type ([#2914](https://github.com/elastic/eui/pull/2914))
**Theme: Amsterdam**
diff --git a/src-docs/src/views/accordion/accordion_arrow.js b/src-docs/src/views/accordion/accordion_arrow.js
new file mode 100644
index 00000000000..0b14cba00cd
--- /dev/null
+++ b/src-docs/src/views/accordion/accordion_arrow.js
@@ -0,0 +1,50 @@
+import React from 'react';
+
+import {
+ EuiAccordion,
+ EuiText,
+ EuiCode,
+ EuiSpacer,
+} from '../../../../src/components';
+
+export default () => (
+
+
+
+
+ Any content inside of EuiAccordion will appear
+ here.
+
+
+
+
+
+
+
+ Any content inside of EuiAccordion will appear
+ here.
+
+
+
+
+
+
+
+ Any content inside of EuiAccordion will appear
+ here.
+
+
+
+
+);
diff --git a/src-docs/src/views/accordion/accordion_example.js b/src-docs/src/views/accordion/accordion_example.js
index a4252a360b8..8a75230bf06 100644
--- a/src-docs/src/views/accordion/accordion_example.js
+++ b/src-docs/src/views/accordion/accordion_example.js
@@ -22,6 +22,18 @@ const accordionSnippet = `
`;
+import AccordionArrow from './accordion_arrow';
+const accordionArrowSource = require('!!raw-loader!./accordion_arrow');
+const accordionArrowHtml = renderToHtml(AccordionArrow);
+const accordionArrowSnippet = `
+
+
+`;
+
import AccordionMultiple from './accordion_multiple';
const accordionMultipleSource = require('!!raw-loader!./accordion_multiple');
const accordionMultipleHtml = renderToHtml(AccordionMultiple);
@@ -142,6 +154,32 @@ export const AccordionExample = {
snippet: accordionSnippet,
demo: ,
},
+ {
+ title: 'Arrow display',
+ source: [
+ {
+ type: GuideSectionTypes.JS,
+ code: accordionArrowSource,
+ },
+ {
+ type: GuideSectionTypes.HTML,
+ code: accordionArrowHtml,
+ },
+ ],
+ text: (
+
+
+ The arrow helps indicate the current state of the accordion (open or
+ not) and points to the main triggering button text. If you must hide
+ or change the side in which the arrow appears, use{' '}
+ arrowDisplay: 'right' or{' '}
+ 'none'
+
+
+ ),
+ snippet: accordionArrowSnippet,
+ demo: ,
+ },
{
title: 'Multiple accordions',
source: [
diff --git a/src-docs/src/views/form_controls/display_toggles.js b/src-docs/src/views/form_controls/display_toggles.js
index c126cd96f56..d0f2e2c7a51 100644
--- a/src-docs/src/views/form_controls/display_toggles.js
+++ b/src-docs/src/views/form_controls/display_toggles.js
@@ -84,7 +84,11 @@ export class DisplayToggles extends Component {
}>
-
+
{(canDisabled || canIsDisabled) && (
@@ -74,7 +75,7 @@ export default class extends Component {
-
+
diff --git a/src-docs/src/views/header/header_updates.js b/src-docs/src/views/header/header_updates.js
index 526a03c3a62..14dfc87bc03 100755
--- a/src-docs/src/views/header/header_updates.js
+++ b/src-docs/src/views/header/header_updates.js
@@ -8,7 +8,6 @@ import {
EuiFlyoutBody,
EuiFlyoutHeader,
EuiTitle,
- EuiNotificationBadge,
EuiLink,
EuiFlyoutFooter,
EuiFlexGroup,
@@ -121,15 +120,12 @@ export default class extends Component {
aria-controls="headerNewsFeed"
aria-expanded={this.state.isFlyoutVisible}
aria-haspopup="true"
- aria-label="News feed"
- onClick={this.showFlyout}>
+ aria-label={`News feed: ${
+ this.state.showBadge ? 'Updates available' : 'No updates'
+ }`}
+ onClick={this.showFlyout}
+ notification={this.state.showBadge && '•'}>
-
- {this.state.showBadge ? (
-
- ▪
-
- ) : null}
);
diff --git a/src/components/accordion/__snapshots__/accordion.test.tsx.snap b/src/components/accordion/__snapshots__/accordion.test.tsx.snap
index 492bcd03be8..4f49249582f 100644
--- a/src/components/accordion/__snapshots__/accordion.test.tsx.snap
+++ b/src/components/accordion/__snapshots__/accordion.test.tsx.snap
@@ -2,7 +2,8 @@
exports[`EuiAccordion behavior closes when clicked twice 1`] = `
@@ -13,7 +14,7 @@ exports[`EuiAccordion behavior closes when clicked twice 1`] = `
className="euiAccordion__triggerWrapper"
>
@@ -77,7 +79,7 @@ exports[`EuiAccordion behavior opens when clicked once 1`] = `
className="euiAccordion__triggerWrapper"
>
`;
+exports[`EuiAccordion props arrowDisplay none is rendered 1`] = `
+
+`;
+
+exports[`EuiAccordion props arrowDisplay right is rendered 1`] = `
+
+`;
+
exports[`EuiAccordion props buttonContent is rendered 1`] = `
{
expect(component).toMatchSnapshot();
});
});
+
+ describe('arrowDisplay', () => {
+ it('right is rendered', () => {
+ const component = render(
+
+ You can see me.
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('none is rendered', () => {
+ const component = render(
+
+ You can see me.
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+ });
});
describe('behavior', () => {
diff --git a/src/components/accordion/accordion.tsx b/src/components/accordion/accordion.tsx
index 6d6df43a694..54a052ad921 100644
--- a/src/components/accordion/accordion.tsx
+++ b/src/components/accordion/accordion.tsx
@@ -52,6 +52,11 @@ export type EuiAccordionProps = HTMLAttributes
&
* The padding around the exposed accordion content.
*/
paddingSize?: EuiAccordionSize;
+ /**
+ * Placement of the arrow indicator, or 'none' to hide it.
+ * Placing on the `right` doesn't work with `extraAction` and so it will be ignored
+ */
+ arrowDisplay?: 'left' | 'right' | 'none';
};
export class EuiAccordion extends Component<
@@ -61,6 +66,7 @@ export class EuiAccordion extends Component<
static defaultProps = {
initialIsOpen: false,
paddingSize: 'none',
+ arrowDisplay: 'left',
};
childContent: HTMLDivElement | null = null;
@@ -128,6 +134,7 @@ export class EuiAccordion extends Component<
extraAction,
paddingSize,
initialIsOpen,
+ arrowDisplay,
...rest
} = this.props;
@@ -143,13 +150,26 @@ export class EuiAccordion extends Component<
? classNames(paddingSizeToClassNameMap[paddingSize])
: undefined;
- const buttonClasses = classNames('euiAccordion__button', buttonClassName);
+ const buttonClasses = classNames(
+ 'euiAccordion__button',
+ {
+ euiAccordion__buttonReverse: !extraAction && arrowDisplay === 'right',
+ },
+ buttonClassName
+ );
const iconClasses = classNames('euiAccordion__icon', {
'euiAccordion__icon-isOpen': this.state.isOpen,
});
- const icon = ;
+ let icon;
+ if (arrowDisplay !== 'none') {
+ icon = (
+
+
+
+ );
+ }
let optionalAction = null;
@@ -168,7 +188,7 @@ export class EuiAccordion extends Component<
onClick={this.onToggle}
className={buttonClasses}
type="button">
- {icon}
+ {icon}
{buttonContent}
diff --git a/src/components/color_picker/color_picker.tsx b/src/components/color_picker/color_picker.tsx
index 901ec8588fe..825816d9171 100644
--- a/src/components/color_picker/color_picker.tsx
+++ b/src/components/color_picker/color_picker.tsx
@@ -77,11 +77,13 @@ export interface EuiColorPickerProps
/**
* Creates an input group with element(s) coming before input. It only shows when the `display` is set to `default`.
+ * `string` | `ReactElement` or an array of these
*/
prepend?: EuiFormControlLayoutProps['prepend'];
/**
* Creates an input group with element(s) coming after input. It only shows when the `display` is set to `default`.
+ * `string` | `ReactElement` or an array of these
*/
append?: EuiFormControlLayoutProps['append'];
}
diff --git a/src/components/flyout/flyout.test.tsx b/src/components/flyout/flyout.test.tsx
index 76c9d84436f..eb32c45275f 100644
--- a/src/components/flyout/flyout.test.tsx
+++ b/src/components/flyout/flyout.test.tsx
@@ -46,6 +46,12 @@ describe('EuiFlyout', () => {
expect(label).toBe('Closes specific flyout');
});
});
+
+ test('accepts div props', () => {
+ const component = render( {}} id="imaflyout" />);
+
+ expect(component).toMatchSnapshot();
+ });
});
describe('size', () => {
diff --git a/src/components/flyout/flyout.tsx b/src/components/flyout/flyout.tsx
index ea1d90d73b3..2efa0afc718 100644
--- a/src/components/flyout/flyout.tsx
+++ b/src/components/flyout/flyout.tsx
@@ -1,4 +1,9 @@
-import React, { Component, CSSProperties, Fragment } from 'react';
+import React, {
+ Component,
+ CSSProperties,
+ Fragment,
+ HTMLAttributes,
+} from 'react';
import classnames from 'classnames';
import { keyCodes, EuiWindowEvent } from '../../services';
@@ -16,7 +21,9 @@ const sizeToClassNameMap: { [size in EuiFlyoutSize]: string } = {
l: 'euiFlyout--large',
};
-export interface EuiFlyoutProps extends CommonProps {
+export interface EuiFlyoutProps
+ extends CommonProps,
+ HTMLAttributes {
onClose: () => void;
size?: EuiFlyoutSize;
/**
diff --git a/src/components/form/field_number/field_number.tsx b/src/components/form/field_number/field_number.tsx
index a9ee1e21895..a5ceefc4280 100644
--- a/src/components/form/field_number/field_number.tsx
+++ b/src/components/form/field_number/field_number.tsx
@@ -25,12 +25,14 @@ export type EuiFieldNumberProps = InputHTMLAttributes &
inputRef?: Ref;
/**
- * Creates an input group with element(s) coming before input
+ * Creates an input group with element(s) coming before input.
+ * `string` | `ReactElement` or an array of these
*/
prepend?: EuiFormControlLayoutProps['prepend'];
/**
- * Creates an input group with element(s) coming after input
+ * Creates an input group with element(s) coming after input.
+ * `string` | `ReactElement` or an array of these
*/
append?: EuiFormControlLayoutProps['append'];
diff --git a/src/components/form/field_search/__snapshots__/field_search.test.tsx.snap b/src/components/form/field_search/__snapshots__/field_search.test.tsx.snap
index 6d3eb2848ea..60591378e8d 100644
--- a/src/components/form/field_search/__snapshots__/field_search.test.tsx.snap
+++ b/src/components/form/field_search/__snapshots__/field_search.test.tsx.snap
@@ -23,6 +23,23 @@ exports[`EuiFieldSearch is rendered 1`] = `
`;
+exports[`EuiFieldSearch props append is rendered 1`] = `
+
+
+
+
+
+`;
+
exports[`EuiFieldSearch props fullWidth is rendered 1`] = `
`;
+
+exports[`EuiFieldSearch props prepend is rendered 1`] = `
+
+
+
+
+
+`;
diff --git a/src/components/form/field_search/field_search.test.tsx b/src/components/form/field_search/field_search.test.tsx
index c44ec4a02aa..68715328fe8 100644
--- a/src/components/form/field_search/field_search.test.tsx
+++ b/src/components/form/field_search/field_search.test.tsx
@@ -45,5 +45,17 @@ describe('EuiFieldSearch', () => {
expect(component).toMatchSnapshot();
});
+
+ test('prepend is rendered', () => {
+ const component = render( );
+
+ expect(component).toMatchSnapshot();
+ });
+
+ test('append is rendered', () => {
+ const component = render( );
+
+ expect(component).toMatchSnapshot();
+ });
});
});
diff --git a/src/components/form/field_search/field_search.tsx b/src/components/form/field_search/field_search.tsx
index b88728504b1..2047cf46aa1 100644
--- a/src/components/form/field_search/field_search.tsx
+++ b/src/components/form/field_search/field_search.tsx
@@ -4,7 +4,10 @@ import { Browser } from '../../../services/browser';
import { ENTER } from '../../../services/key_codes';
import { CommonProps } from '../../common';
-import { EuiFormControlLayout } from '../form_control_layout';
+import {
+ EuiFormControlLayout,
+ EuiFormControlLayoutProps,
+} from '../form_control_layout';
import { EuiValidatableControl } from '../validatable_control';
@@ -37,6 +40,17 @@ export interface EuiFieldSearchProps
* Shows a button that quickly clears any input
*/
isClearable?: boolean;
+ /**
+ * Creates an input group with element(s) coming before input
+ * `string` | `ReactElement` or an array of these
+ */
+ prepend?: EuiFormControlLayoutProps['prepend'];
+
+ /**
+ * Creates an input group with element(s) coming after input.
+ * `string` | `ReactElement` or an array of these
+ */
+ append?: EuiFormControlLayoutProps['append'];
}
export class EuiFieldSearch extends Component {
@@ -154,6 +168,8 @@ export class EuiFieldSearch extends Component {
compressed,
onSearch,
isClearable,
+ append,
+ prepend,
...rest
} = this.props;
@@ -163,6 +179,7 @@ export class EuiFieldSearch extends Component {
'euiFieldSearch--fullWidth': fullWidth,
'euiFieldSearch--compressed': compressed,
'euiFieldSearch-isLoading': isLoading,
+ 'euiFieldText--inGroup': prepend || append,
},
className
);
@@ -177,7 +194,9 @@ export class EuiFieldSearch extends Component {
? { onClick: this.onClear }
: undefined
}
- compressed={compressed}>
+ compressed={compressed}
+ append={append}
+ prepend={prepend}>
&
inputRef?: Ref;
/**
- * Creates an input group with element(s) coming before input
+ * Creates an input group with element(s) coming before input.
+ * `string` | `ReactElement` or an array of these
*/
prepend?: EuiFormControlLayoutProps['prepend'];
/**
- * Creates an input group with element(s) coming after input
+ * Creates an input group with element(s) coming after input.
+ * `string` | `ReactElement` or an array of these
*/
append?: EuiFormControlLayoutProps['append'];
diff --git a/src/components/form/form_control_layout/form_control_layout.tsx b/src/components/form/form_control_layout/form_control_layout.tsx
index 8a01f0c6073..b53629c5840 100644
--- a/src/components/form/form_control_layout/form_control_layout.tsx
+++ b/src/components/form/form_control_layout/form_control_layout.tsx
@@ -22,11 +22,13 @@ type PrependAppendType = StringOrReactElement | StringOrReactElement[];
export type EuiFormControlLayoutProps = CommonProps &
HTMLAttributes & {
/**
- * Creates an input group with element(s) coming before children
+ * Creates an input group with element(s) coming before children.
+ * `string` | `ReactElement` or an array of these
*/
prepend?: PrependAppendType;
/**
- * Creates an input group with element(s) coming after children
+ * Creates an input group with element(s) coming after children.
+ * `string` | `ReactElement` or an array of these
*/
append?: PrependAppendType;
children?: ReactNode;
diff --git a/src/components/form/range/dual_range.tsx b/src/components/form/range/dual_range.tsx
index 7edba3ac3b1..7296e7dbffb 100644
--- a/src/components/form/range/dual_range.tsx
+++ b/src/components/form/range/dual_range.tsx
@@ -45,14 +45,37 @@ export interface EuiDualRangeProps
) => void;
fullWidth?: boolean;
isInvalid?: boolean;
+ /**
+ * Create colored indicators for certain intervals
+ */
levels?: EuiRangeLevel[];
+ /**
+ * Shows static min/max labels on the sides of the range slider
+ */
showLabels?: boolean;
+ /**
+ * Pass `true` to displays an extra input control for direct manipulation.
+ * Pass `'inputWithPopover'` to only show the input but show the range in a dropdown.
+ */
showInput?: EuiRangeProps['showInput'];
+ /**
+ * Modifies the number of tick marks and at what interval
+ */
tickInterval?: number;
+ /**
+ * Specified ticks at specified values
+ */
ticks?: EuiRangeTick[];
- append?: EuiFormControlLayoutProps['append'];
+ /**
+ * Creates an input group with element(s) coming before input. Will only show if `showInput = inputWithPopver`.
+ * `string` | `ReactElement` or an array of these
+ */
prepend?: EuiFormControlLayoutProps['prepend'];
-
+ /**
+ * Creates an input group with element(s) coming after input. Will only show if `showInput = inputWithPopver`.
+ * `string` | `ReactElement` or an array of these
+ */
+ append?: EuiFormControlLayoutProps['append'];
/**
* Intended to be uses with aria attributes. Some attributes may be overwritten.
*/
diff --git a/src/components/form/select/select.tsx b/src/components/form/select/select.tsx
index 6eb141b48a6..301e070cf86 100644
--- a/src/components/form/select/select.tsx
+++ b/src/components/form/select/select.tsx
@@ -37,11 +37,13 @@ export type EuiSelectProps = SelectHTMLAttributes &
compressed?: boolean;
/**
- * Creates an input group with element(s) coming before select
+ * Creates an input group with element(s) coming before select.
+ * `string` | `ReactElement` or an array of these
*/
prepend?: EuiFormControlLayoutProps['prepend'];
/**
- * Creates an input group with element(s) coming after select
+ * Creates an input group with element(s) coming after select.
+ * `string` | `ReactElement` or an array of these
*/
append?: EuiFormControlLayoutProps['append'];
};
diff --git a/src/components/header/header_section/__snapshots__/header_section_item_button.test.tsx.snap b/src/components/header/header_section/__snapshots__/header_section_item_button.test.tsx.snap
index 407fafc9b2f..a92f0259a33 100644
--- a/src/components/header/header_section/__snapshots__/header_section_item_button.test.tsx.snap
+++ b/src/components/header/header_section/__snapshots__/header_section_item_button.test.tsx.snap
@@ -19,3 +19,29 @@ exports[`EuiHeaderSectionItemButton renders children 1`] = `
`;
+
+exports[`EuiHeaderSectionItemButton renders notification children 1`] = `
+
+`;
+
+exports[`EuiHeaderSectionItemButton renders notification color 1`] = `
+
+`;
diff --git a/src/components/header/header_section/_header_section_item.scss b/src/components/header/header_section/_header_section_item.scss
index b694e4f9e57..098b6a98667 100644
--- a/src/components/header/header_section/_header_section_item.scss
+++ b/src/components/header/header_section/_header_section_item.scss
@@ -43,7 +43,11 @@
}
}
-.euiHeaderNotification {
+// SET FOR DEPRECATION: 2/21/20
+// The `euiHeaderNotification` class was needed to be manually applied
+// Now notifications can be automatically added to the buttons via props
+.euiHeaderNotification,
+.euiHeaderSectionItemButton__notification {
position: absolute;
top: 9%;
right: 9%;
@@ -64,7 +68,8 @@
}
// On small screens just show a small dot indicating there are notifications
- .euiHeaderNotification {
+ .euiHeaderNotification,
+ .euiHeaderSectionItemButton__notification {
@include size($euiSizeS);
top: 20%;
min-width: 0;
diff --git a/src/components/header/header_section/header_section_item_button.test.tsx b/src/components/header/header_section/header_section_item_button.test.tsx
index 817519bf34f..1481ebf62e3 100644
--- a/src/components/header/header_section/header_section_item_button.test.tsx
+++ b/src/components/header/header_section/header_section_item_button.test.tsx
@@ -21,6 +21,25 @@ describe('EuiHeaderSectionItemButton', () => {
expect(component).toMatchSnapshot();
});
+ describe('renders notification', () => {
+ test('children', () => {
+ const component = render( );
+
+ expect(component).toMatchSnapshot();
+ });
+
+ test('color', () => {
+ const component = render(
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+ });
+
describe('onClick', () => {
test("isn't called upon instantiation", () => {
const onClickHandler = jest.fn();
diff --git a/src/components/header/header_section/header_section_item_button.tsx b/src/components/header/header_section/header_section_item_button.tsx
index 413c288a479..648553fc859 100644
--- a/src/components/header/header_section/header_section_item_button.tsx
+++ b/src/components/header/header_section/header_section_item_button.tsx
@@ -2,20 +2,48 @@ import React, { ButtonHTMLAttributes, FunctionComponent } from 'react';
import classNames from 'classnames';
import { CommonProps } from '../../common';
+import {
+ EuiNotificationBadgeProps,
+ EuiNotificationBadge,
+} from '../../badge/notification_badge/badge_notification';
-type Props = CommonProps & ButtonHTMLAttributes;
+type Props = CommonProps &
+ ButtonHTMLAttributes & {
+ /**
+ * Inserts the node into a EuiBadgeNotification and places it appropriately against the button
+ */
+ notification?: EuiNotificationBadgeProps['children'];
+ /**
+ * Changes the color of the notification background
+ */
+ notificationColor?: EuiNotificationBadgeProps['color'];
+ };
export const EuiHeaderSectionItemButton: FunctionComponent = ({
onClick,
children,
className,
+ notification,
+ notificationColor,
...rest
}) => {
const classes = classNames('euiHeaderSectionItem__button', className);
+ let notificationBadge;
+ if (notification) {
+ notificationBadge = (
+
+ {notification}
+
+ );
+ }
+
return (
{children}
+ {notificationBadge}
);
};