diff --git a/CHANGELOG.md b/CHANGELOG.md index 32cb9f63277..c9ee6cd8b99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,12 @@ ## [`main`](https://github.com/elastic/eui/tree/main) +- Updated the organization of `EuiDataGrid`'s toolbar/grid controls ([#5334](https://github.com/elastic/eui/pull/5334)) + **Bug fixes** - Fixed an `EuiDataGrid` race condition where grid rows had incorrect heights if loaded in before CSS ([#5284](https://github.com/elastic/eui/pull/5284)) - Fixed an accessibility issue where `EuiDataGrid` cells weren't owned by `role=row` elements ([#5285](https://github.com/elastic/eui/pull/5285)) +- Fixed persistent `EuiDataGrid` full screen `` class ([#5354](https://github.com/elastic/eui/pull/5354)) ## [`41.0.0`](https://github.com/elastic/eui/tree/v41.0.0) 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 b2a5c20dc7a..00000000000 --- a/src-docs/src/views/datagrid/additional_controls.js +++ /dev/null @@ -1,104 +0,0 @@ -import React, { useState, useCallback, Fragment } from 'react'; -import { fake } from 'faker'; - -import { - EuiDataGrid, - EuiButtonEmpty, - 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: ( - - {}} - > - New button - - {}} - > - Another button - - - ), - }} - /> - ); -}; 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_example.js b/src-docs/src/views/datagrid/datagrid_example.js index ec42cef60bc..4c5e4285dad 100644 --- a/src-docs/src/views/datagrid/datagrid_example.js +++ b/src-docs/src/views/datagrid/datagrid_example.js @@ -27,6 +27,7 @@ import { EuiDataGridInMemory, EuiDataGridStyle, EuiDataGridToolBarVisibilityOptions, + EuiDataGridToolBarAdditionalControlsOptions, EuiDataGridColumnVisibility, EuiDataGridColumnActions, EuiDataGridPopoverContentProps, @@ -94,10 +95,14 @@ const gridSnippet = ` // Optional. Allows you to configure what features the toolbar shows. // The prop also accepts a boolean if you want to toggle the entire toolbar on/off. toolbarVisibility={{ - showColumnSelector: false - showStyleSelector: false - showSortSelector: false - showFullScreenSelector: false + showColumnSelector: false, + showStyleSelector: false, + showSortSelector: false, + showFullScreenSelector: false, + additionalControls: { + left: , + right: , + }, }} // Optional. Change the initial style of the grid. gridStyle={{ @@ -399,6 +404,7 @@ export const DataGridExample = { EuiDataGridStyle, EuiDataGridToolBarVisibilityOptions, EuiDataGridToolBarVisibilityColumnSelectorOptions, + EuiDataGridToolBarAdditionalControlsOptions, EuiDataGridPopoverContentProps, EuiDataGridRowHeightsOptions, }, diff --git a/src-docs/src/views/datagrid/datagrid_styling_example.js b/src-docs/src/views/datagrid/datagrid_styling_example.js index 73e8bed5bb3..332c4b1bc23 100644 --- a/src-docs/src/views/datagrid/datagrid_styling_example.js +++ b/src-docs/src/views/datagrid/datagrid_styling_example.js @@ -42,6 +42,7 @@ import { EuiDataGridColumnCellActionProps, EuiDataGridStyle, EuiDataGridToolBarVisibilityOptions, + EuiDataGridToolBarAdditionalControlsOptions, } from '!!prop-loader!../../../../src/components/datagrid/data_grid_types'; const gridSnippet = ` - {}}> - New button - - {}}> - Another button - - - ) + additionalControls: { + left: ( + + {}}> + New button + + {}}> + Another button + + + ) + } }} // Or as a boolean to turn everything off. toolbarVisibility={false} @@ -100,26 +97,42 @@ const controlsSnippet = ` - {}}> - New button - - {}}> - Another button - - - ) + additionalControls: { + left: ( + + {}}> + New button + + {}}> + Another button + + + ), + right: ( + + + {}} + /> + + + {}} + /> + + + ) + } }} /> `; @@ -245,18 +258,48 @@ export const DataGridStylingExample = { ], title: 'Additional controls in the toolbar', text: ( -

- Use the toolbarVisibility.additionalControls prop - to pass additional controls to the toolbar. These will always live to - the left of the full screen button. It will respect the{' '} - toolbarVisibility={'{false}'} setting - and hide when appropriate. Although any node can fit in this space, - the recommendation is to use EuiButtonEmpty{' '} - components with the configuration shown in the snippet. -

+ <> +

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

+

+ Passing a single node to additionalControls will + default to being appended to the left side of the toolbar. To + configure which side of the toolbar your controls display in, pass + an object with either the left or{' '} + right properties: +

+
    +
  • + additionalControls.left appends the passed + custom control into the left side of the toolbar, after the column + & sort controls. +
  • +
  • + additionalControls.right prepends the passed + node into the right side of the toolbar, before the density & full + screen controls. +
  • +
+

+ Although any node is allowed, the recommendation is to use{' '} + {''} for the + left-side of the toolbar and{' '} + {''} for the + right-side of the toolbar. +

+ ), components: { DataGridControls }, snippet: controlsSnippet, + props: { + EuiDataGrid, + EuiDataGridToolBarVisibilityOptions, + EuiDataGridToolBarAdditionalControlsOptions, + }, demo: , }, { diff --git a/src-docs/src/views/datagrid/styling.js b/src-docs/src/views/datagrid/styling.js index fc1d16a6b9e..0750486c839 100644 --- a/src-docs/src/views/datagrid/styling.js +++ b/src-docs/src/views/datagrid/styling.js @@ -362,6 +362,12 @@ const DataGrid = () => { const handleVisibleColumns = (visibleColumns) => setVisibleColumns(visibleColumns); + const [sortingColumns, setSortingColumns] = useState([]); + const onSort = useCallback( + (sortingColumns) => setSortingColumns(sortingColumns), + [setSortingColumns] + ); + const styleButton = ( { visibleColumns: visibleColumns, setVisibleColumns: handleVisibleColumns, }} + sorting={{ columns: sortingColumns, onSort }} rowCount={data.length} gridStyle={{ border: borderSelected, diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index cd3b13a872c..02f793e0220 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -940,87 +940,89 @@ Array [ class="euiDataGrid__controls" data-test-sub="dataGridControls" > -
- + +
+
- - +
- - - +
-
- + +
+
- - +
- - - +
- + +
- - +
- - - +
- + +
- - +
- - - +
* { - 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" >