* {
- margin-left: $euiSizeXS / 2;
- }
-}
-
-.euiDataGrid__controlBtn {
- border-radius: $euiBorderRadius;
-
- &:focus {
- background: shadeOrTint($euiColorLightestShade, 10%, 10%);
- }
-}
-
-.euiDataGrid__controlBtn--active,
-.euiDataGrid__controlBtn--active:focus {
- font-weight: $euiFontWeightSemiBold;
- color: $euiColorFullShade;
-}
-
-@include euiDataGridStyles(bordersNone) {
- .euiDataGrid__controls {
- border: none;
- background: $euiColorEmptyShade;
- }
-}
-
-@include euiDataGridStyles(bordersHorizontal) {
- .euiDataGrid__controls {
- border-right: none;
- border-left: none;
- border-top: none;
- background: $euiColorEmptyShade;
- }
-}
-
.euiDataGrid__pagination {
padding-top: $euiSizeXS;
diff --git a/src/components/datagrid/_index.scss b/src/components/datagrid/_index.scss
index 974597cc39c..e85006fc93e 100644
--- a/src/components/datagrid/_index.scss
+++ b/src/components/datagrid/_index.scss
@@ -5,5 +5,7 @@
@import 'body/data_grid_footer_row';
@import 'body/header/data_grid_column_resizer';
@import 'data_grid_data_row';
+@import 'controls/data_grid_toolbar';
@import 'controls/data_grid_column_selector';
@import 'controls/data_grid_column_sorting';
+@import 'controls/data_grid_display';
diff --git a/src/components/datagrid/controls/__snapshots__/column_selector.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/column_selector.test.tsx.snap
index cdea834f685..15514a6273a 100644
--- a/src/components/datagrid/controls/__snapshots__/column_selector.test.tsx.snap
+++ b/src/components/datagrid/controls/__snapshots__/column_selector.test.tsx.snap
@@ -27,7 +27,7 @@ exports[`useDataGridColumnSelector columnSelector renders a toolbar button/popov
hasArrow={true}
isOpen={true}
ownFocus={true}
- panelClassName="euiDataGridColumnSelectorPopover"
+ panelClassName="euiDataGrid__controlPopoverWithDragDrop"
panelPaddingSize="s"
>
-
-
+
}
closePopover={[Function]}
data-test-subj="dataGridStyleSelectorPopover"
@@ -25,24 +28,24 @@ exports[`useDataGridStyleSelector styleSelector renders a toolbar button/popover
hasArrow={true}
isOpen={false}
ownFocus={true}
- panelClassName="euiDataGridColumnSelectorPopover"
+ panelClassName="euiDataGrid__displayPopoverPanel"
panelPaddingSize="s"
>
diff --git a/src/components/datagrid/controls/_data_grid_column_selector.scss b/src/components/datagrid/controls/_data_grid_column_selector.scss
index f5851af52cd..0f4c0b7a541 100644
--- a/src/components/datagrid/controls/_data_grid_column_selector.scss
+++ b/src/components/datagrid/controls/_data_grid_column_selector.scss
@@ -17,13 +17,3 @@
.euiDataGridColumnSelector__itemLabel {
@include euiFontSizeXS;
}
-
-.euiDataGridColumnSelectorPopover {
- // Hack because the fixed positions of drag and drop don't work inside of transformed elements
- // sass-lint:disable-block no-important
- transform: none !important;
- transition: none !important;
- margin-top: -$euiSizeS;
- // IE11 needs a min-width
- min-width: $euiSize * 12;
-}
diff --git a/src/components/datagrid/controls/_data_grid_column_sorting.scss b/src/components/datagrid/controls/_data_grid_column_sorting.scss
index 7e2c79f1999..9f4d7e24b50 100644
--- a/src/components/datagrid/controls/_data_grid_column_sorting.scss
+++ b/src/components/datagrid/controls/_data_grid_column_sorting.scss
@@ -6,16 +6,6 @@
}
}
-.euiDataGridColumnSortingPopover {
- // Hack because the fixed positions of drag and drop don't work inside of transformed elements
- // sass-lint:disable-block no-important
- transform: none !important;
- transition: none !important;
- margin-top: -$euiSizeS;
- // IE11 needs a min-width
- min-width: $euiSize * 12;
-}
-
.euiDataGridColumnSorting__fieldList {
@include euiYScrollWithShadows;
padding-top: $euiSizeXS;
diff --git a/src/components/datagrid/controls/_data_grid_display.scss b/src/components/datagrid/controls/_data_grid_display.scss
new file mode 100644
index 00000000000..628f4c2e010
--- /dev/null
+++ b/src/components/datagrid/controls/_data_grid_display.scss
@@ -0,0 +1,3 @@
+.euiDataGrid__displayPopoverPanel {
+ width: $euiFormMaxWidth + $euiSize;
+}
diff --git a/src/components/datagrid/controls/_data_grid_toolbar.scss b/src/components/datagrid/controls/_data_grid_toolbar.scss
new file mode 100644
index 00000000000..c9144561a4f
--- /dev/null
+++ b/src/components/datagrid/controls/_data_grid_toolbar.scss
@@ -0,0 +1,61 @@
+.euiDataGrid__controls {
+ background: $euiPageBackgroundColor;
+ position: relative;
+ z-index: 3; // Needs to sit above the content blow that sits below it
+ border: $euiBorderThin;
+ padding: $euiSizeXS $euiSizeXS $euiSizeXS 0;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.euiDataGrid__rightControls {
+ // These **should** just be icon buttons and so we'll restrict them to not wrap lines
+ white-space: nowrap;
+
+ // Keep this right-aligned if hasRoomForGridControls is hiding dataControls
+ &:only-child {
+ margin-left: auto;
+ }
+
+ // Ensure there's sufficient spacing between each toolbar icon/popover
+ > * + * {
+ margin-left: $euiSizeS;
+ }
+}
+
+.euiDataGrid__leftControls {
+ // Ensure there's sufficient spacing between each toolbar button/popover
+ > * + * {
+ margin-left: $euiSizeXS / 2;
+ }
+}
+
+.euiDataGrid__controlBtn--active,
+.euiDataGrid__controlBtn--active:focus {
+ font-weight: $euiFontWeightSemiBold;
+}
+
+@include euiDataGridStyles(bordersNone) {
+ .euiDataGrid__controls {
+ border: none;
+ background: $euiColorEmptyShade;
+ }
+}
+
+@include euiDataGridStyles(bordersHorizontal) {
+ .euiDataGrid__controls {
+ border-right: none;
+ border-left: none;
+ border-top: none;
+ background: $euiColorEmptyShade;
+ }
+}
+
+.euiDataGrid__controlPopoverWithDragDrop {
+ // Hack because the fixed positions of drag and drop don't work inside of transformed elements
+ // sass-lint:disable-block no-important
+ transform: none !important;
+ transition: none !important;
+ margin-top: -$euiSizeS;
+}
diff --git a/src/components/datagrid/controls/column_selector.tsx b/src/components/datagrid/controls/column_selector.tsx
index 375c439c89f..a701bab82e6 100644
--- a/src/components/datagrid/controls/column_selector.tsx
+++ b/src/components/datagrid/controls/column_selector.tsx
@@ -155,7 +155,7 @@ export const useDataGridColumnSelector = (
closePopover={() => setIsOpen(false)}
anchorPosition="downLeft"
panelPaddingSize="s"
- panelClassName="euiDataGridColumnSelectorPopover"
+ panelClassName="euiDataGrid__controlPopoverWithDragDrop"
button={
setIsOpen(false)}
anchorPosition="downLeft"
panelPaddingSize="s"
- panelClassName="euiDataGridColumnSortingPopover"
+ panelClassName="euiDataGrid__controlPopoverWithDragDrop"
button={
{
@@ -35,25 +36,39 @@ describe('EuiDataGridToolbar', () => {
className="euiDataGrid__controls"
data-test-sub="dataGridControls"
>
-
- mock column selector
-
-
- mock style selector
-
-
- mock column sorting
+
+
+ mock column selector
+
+
+ mock column sorting
+
-
- Full screen
-
+
+ mock style selector
+
+
+
+
+
`);
});
@@ -67,7 +82,14 @@ describe('EuiDataGridToolbar', () => {
+ >
+
+
+
`);
});
@@ -80,7 +102,10 @@ describe('EuiDataGridToolbar', () => {
showStyleSelector: false,
showSortSelector: false,
showFullScreenSelector: false,
- additionalControls:
hello world
,
+ additionalControls: {
+ left:
hello
,
+ right:
world
,
+ },
}}
/>
);
@@ -90,8 +115,19 @@ describe('EuiDataGridToolbar', () => {
className="euiDataGrid__controls"
data-test-sub="dataGridControls"
>
-
`);
@@ -109,16 +145,15 @@ describe('EuiDataGridToolbar', () => {
expect(component.find('[data-test-subj="dataGridFullScreenButton"]'))
.toMatchInlineSnapshot(`
-
- Exit full screen
-
+ />
`);
});
});
@@ -148,3 +183,73 @@ describe('checkOrDefaultToolBarDisplayOptions', () => {
expect(checkOrDefaultToolBarDisplayOptions(undefined, key)).toEqual(true);
});
});
+
+describe('renderAdditionalControls', () => {
+ const mockControl =
;
+
+ it('does not render if a boolean was passed into toolbarVisibility', () => {
+ expect(renderAdditionalControls(false, 'left')).toEqual(null);
+ expect(renderAdditionalControls(true, 'left')).toEqual(null);
+ });
+
+ it('does not render if toolbarVisibility is undefined or additionalControls is undefined', () => {
+ expect(renderAdditionalControls(undefined, 'left')).toEqual(null);
+ expect(
+ renderAdditionalControls({ additionalControls: undefined }, 'left')
+ ).toEqual(null);
+ });
+
+ describe('left', () => {
+ it('renders a react node passed into the left side toolbar', () => {
+ expect(
+ renderAdditionalControls(
+ { additionalControls: { left: mockControl } },
+ 'left'
+ )
+ ).toEqual(mockControl);
+ });
+
+ it('does not render right side positions', () => {
+ expect(
+ renderAdditionalControls(
+ { additionalControls: { right: mockControl } },
+ 'left'
+ )
+ ).toEqual(null);
+ });
+ });
+
+ describe('right', () => {
+ it('renders a react node passed into the right side toolbar', () => {
+ expect(
+ renderAdditionalControls(
+ { additionalControls: { right: mockControl } },
+ 'right'
+ )
+ ).toEqual(mockControl);
+ });
+
+ it('does not render left side positions', () => {
+ expect(
+ renderAdditionalControls(
+ { additionalControls: { left: mockControl } },
+ 'right'
+ )
+ ).toEqual(null);
+ });
+ });
+
+ describe('single node', () => {
+ it('renders into the left side of toolbar by default', () => {
+ expect(
+ renderAdditionalControls({ additionalControls: mockControl }, 'left')
+ ).toEqual(mockControl);
+ });
+
+ it('does not render into the right side of the toolbar', () => {
+ expect(
+ renderAdditionalControls({ additionalControls: mockControl }, 'right')
+ ).toEqual(null);
+ });
+ });
+});
diff --git a/src/components/datagrid/controls/data_grid_toolbar.tsx b/src/components/datagrid/controls/data_grid_toolbar.tsx
index 9b4ece61c5e..d1b29488865 100644
--- a/src/components/datagrid/controls/data_grid_toolbar.tsx
+++ b/src/components/datagrid/controls/data_grid_toolbar.tsx
@@ -6,13 +6,15 @@
* Side Public License, v 1.
*/
-import React from 'react';
-import { EuiButtonEmpty } from '../../button';
+import React, { useEffect } from 'react';
+import { EuiToolTip } from '../../tool_tip';
+import { EuiButtonIcon } from '../../button';
import { useEuiI18n } from '../../i18n';
import {
EuiDataGridProps,
EuiDataGridToolbarProps,
EuiDataGridToolBarVisibilityOptions,
+ EuiDataGridToolBarAdditionalControlsOptions,
} from '../data_grid_types';
// Used to simplify some sizing logic which is difficult to account for in tests
@@ -24,31 +26,6 @@ const MINIMUM_WIDTH_FOR_GRID_CONTROLS = 479;
// When data grid is full screen, we add a class to the body to remove the extra scrollbar
const GRID_IS_FULLSCREEN_CLASSNAME = 'euiDataGrid__restrictBody';
-// Typeguards to see if toolbarVisibility has a certain boolean property assigned
-// If not, just set it to true and assume it's OK to show
-function objectHasKey
, ObjectKey extends keyof O>(
- object: O,
- key: ObjectKey
-): object is Required {
- return object.hasOwnProperty(key);
-}
-export function checkOrDefaultToolBarDisplayOptions<
- OptionKey extends keyof EuiDataGridToolBarVisibilityOptions
->(
- arg: EuiDataGridProps['toolbarVisibility'],
- option: OptionKey
-): Required[OptionKey] {
- if (arg === undefined) {
- return true;
- } else if (typeof arg === 'boolean') {
- return arg as boolean;
- } else if (objectHasKey(arg, option)) {
- return arg[option];
- } else {
- return true;
- }
-}
-
export const EuiDataGridToolbar = ({
gridWidth,
minSizeForControls = MINIMUM_WIDTH_FOR_GRID_CONTROLS,
@@ -72,23 +49,40 @@ export const EuiDataGridToolbar = ({
? true
: gridWidth > minSizeForControls || isFullScreen;
- // need to safely access those Web APIs
- if (typeof document !== 'undefined') {
- // When data grid is full screen, we add a class to the body to remove the extra scrollbar
- document.body.classList.toggle(GRID_IS_FULLSCREEN_CLASSNAME, isFullScreen);
- }
+ useEffect(() => {
+ // When data grid is full screen, we add a class to the body to remove the extra scrollbar and stay above any fixed headers
+ if (isFullScreen) {
+ document.body.classList.add(GRID_IS_FULLSCREEN_CLASSNAME);
+
+ return () => {
+ document.body.classList.remove(GRID_IS_FULLSCREEN_CLASSNAME);
+ };
+ }
+ }, [isFullScreen]);
const fullScreenSelector = (
- setIsFullScreen(!isFullScreen)}
+
+ {fullScreenButtonActive} (esc)
+ >
+ ) : (
+ fullScreenButton
+ )
+ }
+ delay="long"
>
- {isFullScreen ? fullScreenButtonActive : fullScreenButton}
-
+ setIsFullScreen(!isFullScreen)}
+ aria-label={isFullScreen ? fullScreenButtonActive : fullScreenButton}
+ />
+
);
return (
@@ -98,39 +92,95 @@ export const EuiDataGridToolbar = ({
data-test-sub="dataGridControls"
>
{hasRoomForGridControls && (
- <>
- {checkOrDefaultToolBarDisplayOptions(
- toolbarVisibility,
- 'additionalControls'
- ) && typeof toolbarVisibility !== 'boolean'
- ? toolbarVisibility.additionalControls
- : null}
+
{checkOrDefaultToolBarDisplayOptions(
toolbarVisibility,
'showColumnSelector'
)
? columnSelector
: null}
- {checkOrDefaultToolBarDisplayOptions(
- toolbarVisibility,
- 'showStyleSelector'
- )
- ? styleSelector
- : null}
{checkOrDefaultToolBarDisplayOptions(
toolbarVisibility,
'showSortSelector'
)
? columnSorting
: null}
- >
+ {renderAdditionalControls(toolbarVisibility, 'left')}
+
)}
- {checkOrDefaultToolBarDisplayOptions(
- toolbarVisibility,
- 'showFullScreenSelector'
- )
- ? fullScreenSelector
- : null}
+
+ {renderAdditionalControls(toolbarVisibility, 'right')}
+ {checkOrDefaultToolBarDisplayOptions(
+ toolbarVisibility,
+ 'showStyleSelector'
+ )
+ ? styleSelector
+ : null}
+ {checkOrDefaultToolBarDisplayOptions(
+ toolbarVisibility,
+ 'showFullScreenSelector'
+ )
+ ? fullScreenSelector
+ : null}
+
);
};
+
+/**
+ * Toolbar utilities
+ */
+
+// Typeguards to see if toolbarVisibility has a certain boolean property assigned
+// If not, just set it to true and assume it's OK to show
+function objectHasKey