diff --git a/src-docs/src/views/datagrid/additional_controls.js b/src-docs/src/views/datagrid/additional_controls.js deleted file mode 100644 index dfa50437dd4..00000000000 --- a/src-docs/src/views/datagrid/additional_controls.js +++ /dev/null @@ -1,127 +0,0 @@ -import React, { useState, useCallback, Fragment } from 'react'; -import { fake } from 'faker'; - -import { - EuiDataGrid, - EuiButtonEmpty, - EuiButtonIcon, - EuiLink, -} from '../../../../src/components/'; - -const columns = [ - { - id: 'name', - }, - { - id: 'email', - }, - { - id: 'city', - }, - { - id: 'country', - }, - { - id: 'account', - }, -]; - -const data = []; - -for (let i = 1; i < 20; i++) { - data.push({ - name: fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'), - email: fake('{{internet.email}}'), - city: ( - {fake('{{address.city}}')} - ), - country: fake('{{address.country}}'), - account: fake('{{finance.account}}'), - }); -} - -export default () => { - const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); - - const [visibleColumns, setVisibleColumns] = useState(() => - columns.map(({ id }) => id) - ); - - const setPageIndex = useCallback( - (pageIndex) => setPagination({ ...pagination, pageIndex }), - [pagination, setPagination] - ); - const setPageSize = useCallback( - (pageSize) => setPagination({ ...pagination, pageSize, pageIndex: 0 }), - [pagination, setPagination] - ); - - return ( - data[rowIndex][columnId]} - pagination={{ - ...pagination, - pageSizeOptions: [5, 10, 25], - onChangeItemsPerPage: setPageSize, - onChangePage: setPageIndex, - }} - toolbarVisibility={{ - additionalControls: { - left: ( - - {}} - > - New button - - {}} - > - Another button - - - ), - right: ( - - {}} - /> - {}} - /> - - ), - }, - }} - /> - ); -}; diff --git a/src-docs/src/views/datagrid/additional_controls.tsx b/src-docs/src/views/datagrid/additional_controls.tsx new file mode 100644 index 00000000000..1e98546c3bf --- /dev/null +++ b/src-docs/src/views/datagrid/additional_controls.tsx @@ -0,0 +1,197 @@ +import React, { useState, useCallback, Fragment } from 'react'; + +// @ts-ignore Importing from JS +import { fake } from 'faker'; + +import { + EuiDataGrid, + EuiButtonEmpty, + EuiButtonIcon, + EuiLink, + EuiToolTip, + useGeneratedHtmlId, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiText, + EuiTitle, + EuiContextMenuItem, + EuiContextMenuPanel, + EuiPopover, +} from '../../../../src'; + +const columns = [ + { + id: 'name', + }, + { + id: 'email', + }, + { + id: 'city', + }, + { + id: 'country', + }, + { + id: 'account', + }, +]; + +const data: any[] = []; + +for (let i = 1; i < 20; i++) { + data.push({ + name: fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'), + email: fake('{{internet.email}}'), + city: ( + {fake('{{address.city}}')} + ), + country: fake('{{address.country}}'), + account: fake('{{finance.account}}'), + }); +} + +export default () => { + const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); + const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); + const flyoutTitleId = useGeneratedHtmlId({ + prefix: 'dataGridAdditionalControlsFlyout', + }); + + let flyout; + if (isFlyoutVisible) { + flyout = ( + setIsFlyoutVisible(false)} + aria-labelledby={flyoutTitleId} + > + + +

Inspect

+
+
+ + +

+ This is not a real control, just an example of how to trigger a + flyout from a custom data grid control. +

+
+
+
+ ); + } + + const [isPopoverOpen, setPopover] = useState(false); + const popoverId = useGeneratedHtmlId({ + prefix: 'dataGridAdditionalControlsPopover', + }); + const alertAndClosePopover = () => { + setPopover(false); + window.alert('This is not a real control.'); + }; + + const [visibleColumns, setVisibleColumns] = useState(() => + columns.map(({ id }) => id) + ); + + const setPageIndex = useCallback( + (pageIndex) => setPagination({ ...pagination, pageIndex }), + [pagination, setPagination] + ); + const setPageSize = useCallback( + (pageSize) => setPagination({ ...pagination, pageSize, pageIndex: 0 }), + [pagination, setPagination] + ); + + return ( + <> + data[rowIndex][columnId]} + pagination={{ + ...pagination, + pageSizeOptions: [5, 10, 25], + onChangeItemsPerPage: setPageSize, + onChangePage: setPageIndex, + }} + toolbarVisibility={{ + additionalControls: { + left: ( + setPopover((open) => !open)} + > + Download + + } + isOpen={isPopoverOpen} + closePopover={() => setPopover(false)} + panelPaddingSize="none" + > + + CSV + , + + JSON + , + ]} + /> + + ), + right: ( + + + { + window.alert('This is not a real control.'); + }} + /> + + + setIsFlyoutVisible(true)} + /> + + + ), + }, + }} + /> + {flyout} + + ); +}; diff --git a/src-docs/src/views/datagrid/control_columns.js b/src-docs/src/views/datagrid/control_columns.js index bee036d8aca..434fb8e754b 100644 --- a/src-docs/src/views/datagrid/control_columns.js +++ b/src-docs/src/views/datagrid/control_columns.js @@ -27,6 +27,8 @@ import { EuiDescriptionList, EuiDescriptionListTitle, EuiDescriptionListDescription, + EuiContextMenuItem, + EuiContextMenuPanel, } from '../../../../src/components/'; const columns = [ @@ -77,6 +79,11 @@ const SelectionContext = createContext(); const SelectionButton = () => { const [selectedRows] = useContext(SelectionContext); const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const alertAndClosePopover = () => { + setIsPopoverOpen(false); + window.alert('This is not a real control.'); + }; + if (selectedRows.size > 0) { return ( { setIsPopoverOpen(!isPopoverOpen)} > {selectedRows.size} {selectedRows.size > 1 ? 'items' : 'item'}{' '} @@ -100,43 +106,25 @@ const SelectionButton = () => { {selectedRows.size} {selectedRows.size > 1 ? 'items' : 'item'} -
- - - -
+ Delete item + , + ]} + />
); } else { diff --git a/src-docs/src/views/datagrid/datagrid_styling_example.js b/src-docs/src/views/datagrid/datagrid_styling_example.js index 98a8d4802aa..332c4b1bc23 100644 --- a/src-docs/src/views/datagrid/datagrid_styling_example.js +++ b/src-docs/src/views/datagrid/datagrid_styling_example.js @@ -65,17 +65,11 @@ const gridSnippet = ` {}}> New button {}}> Another button @@ -108,17 +102,11 @@ const controlsSnippet = ` {}}> New button {}}> Another button @@ -126,22 +114,22 @@ const controlsSnippet = ` - {}} - /> - {}} - /> + + {}} + /> + + + {}} + /> + ) } @@ -273,7 +261,7 @@ export const DataGridStylingExample = { <>

Use the toolbarVisibility.additionalControls prop - to pass additional controls to the toolbar. It will respect the{' '} + to pass more buttons to the toolbar. It will respect the{' '} toolbarVisibility={'{false}'}{' '} setting and hide when appropriate.

@@ -298,9 +286,10 @@ export const DataGridStylingExample = {

Although any node is allowed, the recommendation is to use{' '} - EuiButtonEmpty for the left-side of the toolbar and{' '} - EuiButtonIcon for the right-side of the toolbar, - with the configurations shown in the snippet. + {''} for the + left-side of the toolbar and{' '} + {''} for the + right-side of the toolbar.

), diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index bd507bb4161..4bd0193a57b 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -986,34 +986,42 @@ Array [
- + +
- + +
- + +
- + +
- + +
- + +
- + +
- + +
+ + + } closePopover={[Function]} data-test-subj="dataGridStyleSelectorPopover" @@ -21,7 +28,7 @@ exports[`useDataGridStyleSelector styleSelector renders a toolbar button/popover hasArrow={true} isOpen={false} ownFocus={true} - panelClassName="euiDataGrid__controlPopover" + panelClassName="euiDataGrid__displayPopoverPanel" panelPaddingSize="s" > {
mock style selector
- + + +
`); diff --git a/src/components/datagrid/controls/data_grid_toolbar.tsx b/src/components/datagrid/controls/data_grid_toolbar.tsx index 058277a78d2..15b7ce80237 100644 --- a/src/components/datagrid/controls/data_grid_toolbar.tsx +++ b/src/components/datagrid/controls/data_grid_toolbar.tsx @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import React from 'react'; +import React, { useEffect } from 'react'; +import { EuiToolTip } from '../../tool_tip'; import { EuiButtonIcon } from '../../button'; import { useEuiI18n } from '../../i18n'; import { @@ -48,22 +49,42 @@ 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 && typeof document !== 'undefined') { + document.body.classList.add(GRID_IS_FULLSCREEN_CLASSNAME); + + return () => { + if (typeof document !== 'undefined') { + document.body.classList.remove(GRID_IS_FULLSCREEN_CLASSNAME); + } + }; + } + }, [isFullScreen]); const fullScreenSelector = ( - setIsFullScreen(!isFullScreen)} - aria-label={isFullScreen ? fullScreenButtonActive : fullScreenButton} - /> + + {fullScreenButtonActive} (esc) + + ) : ( + fullScreenButton + ) + } + delay="long" + > + setIsFullScreen(!isFullScreen)} + aria-label={isFullScreen ? fullScreenButtonActive : fullScreenButton} + /> + ); return ( diff --git a/src/components/datagrid/controls/style_selector.tsx b/src/components/datagrid/controls/style_selector.tsx index 7774af44266..694ae72b404 100644 --- a/src/components/datagrid/controls/style_selector.tsx +++ b/src/components/datagrid/controls/style_selector.tsx @@ -12,6 +12,7 @@ import { EuiI18n, useEuiI18n } from '../../i18n'; import { EuiPopover } from '../../popover'; import { EuiButtonIcon, EuiButtonGroup } from '../../button'; import { EuiFormRow } from '../../form'; +import { EuiToolTip } from '../../tool_tip'; export const startingStyles: EuiDataGridStyle = { cellPadding: 'm', @@ -64,6 +65,11 @@ export const useDataGridStyleSelector = ( ...userGridStyles, }; + const buttonLabel = useEuiI18n( + 'euiStyleSelector.buttonText', + 'Display options' + ); + const styleSelector = ( setIsOpen(false)} anchorPosition="downRight" panelPaddingSize="s" - panelClassName="euiDataGrid__controlPopover" + panelClassName="euiDataGrid__displayPopoverPanel" button={ - setIsOpen(!isOpen)} - aria-label={useEuiI18n('euiStyleSelector.buttonText', 'Grid display')} - /> + + setIsOpen(!isOpen)} + aria-label={buttonLabel} + /> + } > ` to match the existing controls on the left. */ left?: ReactNode; /** - * Will prepend the passed node into the right side of the toolbar, before the density & full screen controls. - * We recommend using `xs`-sized `EuiButtonIcons`s to match the existing controls on the right. + * Will prepend the passed node into the right side of the toolbar, **before** the density & full screen controls. + * We recommend using `` to match the existing controls on the right. */ right?: ReactNode; }