From 19b15180e43a83c36b45641f26058c262ee72573 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 22 Nov 2023 00:35:16 +0100 Subject: [PATCH] [EuiDataGrid] Badges in grid toolbar (#7369) Co-authored-by: Cee Chen <549407+cee-chen@users.noreply.github.com> Co-authored-by: Cee Chen --- changelogs/upcoming/7369.md | 3 + .../datagrid/toolbar/additional_controls.tsx | 6 +- .../toolbar/datagrid_toolbar_example.js | 30 +++++-- .../toolbar/render_custom_toolbar.tsx | 12 ++- .../_button_display_content.test.tsx | 10 +++ .../_button_display_content.tsx | 20 +++-- .../button/button_empty/button_empty.test.tsx | 10 +++ .../button/button_empty/button_empty.tsx | 10 ++- .../__snapshots__/data_grid.test.tsx.snap | 72 ++++++++++----- .../column_selector.test.tsx.snap | 39 +++++++-- .../column_sorting.test.tsx.snap | 39 +++++++-- .../data_grid_toolbar_control.test.tsx.snap | 48 ++++++++++ .../display_selector.test.tsx.snap | 1 - .../datagrid/controls/_data_grid_toolbar.scss | 5 -- .../controls/column_selector.test.tsx | 18 ++-- .../datagrid/controls/column_selector.tsx | 62 +++++-------- .../datagrid/controls/column_sorting.test.tsx | 2 +- .../datagrid/controls/column_sorting.tsx | 29 ++----- .../data_grid_toolbar_control.test.tsx | 65 ++++++++++++++ .../controls/data_grid_toolbar_control.tsx | 87 +++++++++++++++++++ .../datagrid/controls/display_selector.tsx | 1 - .../datagrid/controls/fullscreen_selector.tsx | 9 +- src/components/datagrid/controls/index.ts | 4 + src/components/datagrid/data_grid.test.tsx | 20 +++-- src/components/datagrid/index.ts | 1 + .../super_date_picker/super_update_button.tsx | 2 +- src/components/filter_group/filter_button.tsx | 4 +- 27 files changed, 451 insertions(+), 158 deletions(-) create mode 100644 changelogs/upcoming/7369.md create mode 100644 src/components/datagrid/controls/__snapshots__/data_grid_toolbar_control.test.tsx.snap create mode 100644 src/components/datagrid/controls/data_grid_toolbar_control.test.tsx create mode 100644 src/components/datagrid/controls/data_grid_toolbar_control.tsx diff --git a/changelogs/upcoming/7369.md b/changelogs/upcoming/7369.md new file mode 100644 index 00000000000..f23fc30080f --- /dev/null +++ b/changelogs/upcoming/7369.md @@ -0,0 +1,3 @@ +- Added a new `EuiDataGridToolbarControl` subcomponent, which is useful for rendering your own custom `EuiDataGrid` toolbar buttons while matching the look of the default controls +- Updated `EuiDataGrid`'s toolbar controls to show active/current counts in badges, and updated the Columns button icon +- Updated `EuiButtonEmpty` to allow passing `false` to `textProps`, which allows rendering custom button content without an extra text wrapper diff --git a/src-docs/src/views/datagrid/toolbar/additional_controls.tsx b/src-docs/src/views/datagrid/toolbar/additional_controls.tsx index d91c17d43d8..b45ba919abc 100644 --- a/src-docs/src/views/datagrid/toolbar/additional_controls.tsx +++ b/src-docs/src/views/datagrid/toolbar/additional_controls.tsx @@ -3,6 +3,7 @@ import { faker } from '@faker-js/faker'; import { EuiDataGrid, + EuiDataGridToolbarControl, EuiButtonEmpty, EuiButtonIcon, EuiLink, @@ -149,13 +150,12 @@ export default () => { setPopover((open) => !open)} > Download - + } isOpen={isPopoverOpen} closePopover={() => setPopover(false)} diff --git a/src-docs/src/views/datagrid/toolbar/datagrid_toolbar_example.js b/src-docs/src/views/datagrid/toolbar/datagrid_toolbar_example.js index 9998f094434..fe92a60e883 100644 --- a/src-docs/src/views/datagrid/toolbar/datagrid_toolbar_example.js +++ b/src-docs/src/views/datagrid/toolbar/datagrid_toolbar_example.js @@ -1,7 +1,11 @@ import React, { Fragment } from 'react'; import { GuideSectionTypes } from '../../../components'; -import { EuiCode } from '../../../../../src'; +import { + EuiDataGridToolbarControl, + EuiCode, + EuiCallOut, +} from '../../../../../src'; import DataGridToolbarVisibility from './visibility'; const dataGridToolbarVisibilitySource = require('!!raw-loader!./_grid'); @@ -174,7 +178,7 @@ export const DataGridToolbarExample = {

Although any node is allowed, the recommendation is to use{' '} - {''} for the + {''} for the left-side of the toolbar and{' '} {''} for the right-side of the toolbar. @@ -186,6 +190,7 @@ export const DataGridToolbarExample = { EuiDataGridToolBarVisibilityOptions, EuiDataGridToolBarAdditionalControlsOptions, EuiDataGridToolBarAdditionalControlsLeftOptions, + EuiDataGridToolbarControl, }, demo: , }, @@ -211,18 +216,27 @@ export const DataGridToolbarExample = { renderCustomToolbar should only be used when a very custom layout (e.g. moving default buttons between sides, interspering custom controls between default controls, custom - responsive behavior, etc.) is required. We would caution you to keep - consistency in mind also when customizing the toolbar: if using - multiple datagrid instances across your app, users will typically - want to reach for the same controls for each grid. Changing the - available controls inconsistently across your app may result in user - frustration. + responsive behavior, etc.) is required. For consistent visuals, we + recommend using the{' '} + {''} subcomponent + when rendering custom controls.

+ + If using multiple datagrid instances across your app, users will + typically want to reach for the same controls for each grid. + Changing the available controls inconsistently across your app may + result in user frustration. + ), demo: , props: { EuiDataGridCustomToolbarProps, + EuiDataGridToolbarControl, }, snippet: ` {hasRoomForGridControls && ( - + {}} + > Custom left side - + )} diff --git a/src/components/button/button_display/_button_display_content.test.tsx b/src/components/button/button_display/_button_display_content.test.tsx index 5f275e457c7..1a6f7cbcace 100644 --- a/src/components/button/button_display/_button_display_content.test.tsx +++ b/src/components/button/button_display/_button_display_content.test.tsx @@ -98,6 +98,16 @@ describe('EuiButtonDisplayContent', () => { expect(container.querySelector('.eui-textTruncate')).toBeTruthy(); }); + it('does not render a text span wrapper if textProps is explicitly set to false', () => { + const { container } = render( + + Text + + ); + + expect(container.querySelector('.eui-textTruncate')).toBeFalsy(); + }); + it('does not render a text span wrapper if custom child with no textProps are passed', () => { const { getByTestSubject, container } = render( diff --git a/src/components/button/button_display/_button_display_content.tsx b/src/components/button/button_display/_button_display_content.tsx index 88ca51b1df4..48c50e59bed 100644 --- a/src/components/button/button_display/_button_display_content.tsx +++ b/src/components/button/button_display/_button_display_content.tsx @@ -37,13 +37,17 @@ export interface EuiButtonDisplayContentProps extends CommonProps { iconSide?: ButtonContentIconSide; isLoading?: boolean; /** - * Object of props passed to the wrapping the content's text/children only (not icon) + * Object of props passed to the `` wrapping the content's text/children only (not icon) + * + * This span wrapper can be removed by passing `textProps={false}`. */ - textProps?: HTMLAttributes & - CommonProps & { - ref?: Ref; - 'data-text'?: string; - }; + textProps?: + | (HTMLAttributes & + CommonProps & { + ref?: Ref; + 'data-text'?: string; + }) + | false; iconSize?: ButtonContentIconSize; isDisabled?: boolean; } @@ -90,11 +94,13 @@ export const EuiButtonDisplayContent: FunctionComponent< } const isText = typeof children === 'string'; + const doNotRenderTextWrapper = textProps === false; + const renderTextWrapper = (isText || textProps) && !doNotRenderTextWrapper; return ( {iconSide === 'left' && icon} - {isText || textProps ? ( + {renderTextWrapper ? ( { expect(container.firstChild).toMatchSnapshot(); }); + + it('does not render the text wrapper when textProps is set to false', () => { + const { container } = render( + Content + ); + + expect( + container.querySelector('.euiButtonEmpty__text') + ).not.toBeInTheDocument(); + }); }); }); diff --git a/src/components/button/button_empty/button_empty.tsx b/src/components/button/button_empty/button_empty.tsx index 960544f848f..12db368b473 100644 --- a/src/components/button/button_empty/button_empty.tsx +++ b/src/components/button/button_empty/button_empty.tsx @@ -72,7 +72,7 @@ export interface CommonEuiButtonEmptyProps type?: 'button' | 'submit'; buttonRef?: Ref; /** - * Object of props passed to the wrapping the button's content + * Object of props passed to the `` wrapping the button's content */ contentProps?: CommonProps & EuiButtonDisplayContentType; } @@ -139,7 +139,7 @@ export const EuiButtonEmpty: FunctionComponent = ({ const textClassNames = classNames( 'euiButtonEmpty__text', - textProps?.className + textProps && textProps.className ); const innerNode = ( @@ -149,7 +149,11 @@ export const EuiButtonEmpty: FunctionComponent = ({ iconType={iconType} iconSide={iconSide} iconSize={size === 'xs' ? 's' : iconSize} - textProps={{ ...textProps, className: textClassNames }} + textProps={ + textProps === false + ? false + : { ...textProps, className: textClassNames } + } {...{ ...contentProps, className: contentClassNames }} > {children} diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index e35c3781496..e0433fb8303 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -476,7 +476,7 @@ exports[`EuiDataGrid rendering renders additional toolbar controls 1`] = ` data-test-subj="dataGridColumnSelectorPopover" > @@ -533,7 +540,7 @@ exports[`EuiDataGrid rendering renders additional toolbar controls 1`] = ` > @@ -952,7 +967,7 @@ exports[`EuiDataGrid rendering renders control columns 1`] = ` > @@ -1646,7 +1669,7 @@ exports[`EuiDataGrid rendering renders custom column headers 1`] = ` > @@ -2064,7 +2095,7 @@ exports[`EuiDataGrid rendering renders with common and div attributes 1`] = ` > @@ -291,7 +298,7 @@ exports[`useDataGridColumnSelector columnSelector [React 17] renders a toolbar b data-test-subj="dataGridColumnSelectorPopover" > @@ -576,7 +590,7 @@ exports[`useDataGridColumnSelector columnSelector [React 18] renders a toolbar b data-test-subj="dataGridColumnSelectorPopover" > diff --git a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap index b562f7a2182..cd7eee17d4d 100644 --- a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap +++ b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap @@ -6,7 +6,7 @@ exports[`useDataGridColumnSorting columnSorting [React 16] renders a toolbar but data-test-subj="dataGridColumnSortingPopover" > @@ -269,7 +276,7 @@ exports[`useDataGridColumnSorting columnSorting [React 17] renders a toolbar but data-test-subj="dataGridColumnSortingPopover" > @@ -532,7 +546,7 @@ exports[`useDataGridColumnSorting columnSorting [React 18] renders a toolbar but data-test-subj="dataGridColumnSortingPopover" > diff --git a/src/components/datagrid/controls/__snapshots__/data_grid_toolbar_control.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/data_grid_toolbar_control.test.tsx.snap new file mode 100644 index 00000000000..64dd49abd84 --- /dev/null +++ b/src/components/datagrid/controls/__snapshots__/data_grid_toolbar_control.test.tsx.snap @@ -0,0 +1,48 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`euiDataGridToolbarControl passes props to the underlying EuiButtonEmpty 1`] = ` + +`; + +exports[`euiDataGridToolbarControl renders with a badge 1`] = ` + +`; diff --git a/src/components/datagrid/controls/__snapshots__/display_selector.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/display_selector.test.tsx.snap index d806098b349..a690d2e23c4 100644 --- a/src/components/datagrid/controls/__snapshots__/display_selector.test.tsx.snap +++ b/src/components/datagrid/controls/__snapshots__/display_selector.test.tsx.snap @@ -13,7 +13,6 @@ exports[`useDataGridDisplaySelector displaySelector renders a toolbar button/pop > { describe('column visibility', () => { const showColumnSelector = { allowHide: true, allowReorder: false }; + const getButtonText = (component: ReactWrapper) => { + return component.find('span.euiDataGridToolbarControl__text').text(); + }; + const getBadgeText = (component: ReactWrapper) => { + return component.find('span.euiDataGridToolbarControl__badge').text(); + }; + it('shows the number of columns hidden as the toolbar button text', () => { const component = mount( { /> ); - expect(component.text()).toEqual('2 columns hidden'); + expect(getButtonText(component)).toEqual('Columns'); + expect(getBadgeText(component)).toEqual('0/2'); }); it('toggles column visibility on switch interaction', () => { @@ -207,7 +215,7 @@ describe('useDataGridColumnSelector', () => { ).simulate('click'); forceUpdate(component); - expect(component.text()).toEqual('1 column hidden'); + expect(getBadgeText(component)).toEqual('1/2'); findTestSubject( component, @@ -215,7 +223,7 @@ describe('useDataGridColumnSelector', () => { ).simulate('click'); forceUpdate(component); - expect(component.text()).not.toEqual('1 column hidden'); + expect(getBadgeText(component)).toEqual('2'); }); it('toggles all column visibility with the show/hide all buttons', () => { @@ -230,7 +238,7 @@ describe('useDataGridColumnSelector', () => { ).simulate('click'); forceUpdate(component); - expect(component.text()).toEqual('2 columns hidden'); + expect(getBadgeText(component)).toEqual('0/2'); findTestSubject( component, @@ -238,7 +246,7 @@ describe('useDataGridColumnSelector', () => { ).simulate('click'); forceUpdate(component); - expect(component.text()).toEqual('Columns'); + expect(getBadgeText(component)).toEqual('2'); }); }); }); diff --git a/src/components/datagrid/controls/column_selector.tsx b/src/components/datagrid/controls/column_selector.tsx index 0218f1f1560..e61de0c29c8 100644 --- a/src/components/datagrid/controls/column_selector.tsx +++ b/src/components/datagrid/controls/column_selector.tsx @@ -36,6 +36,7 @@ import { EuiDataGridToolBarVisibilityOptions, } from '../data_grid_types'; import { getNestedObjectOptions } from './data_grid_toolbar'; +import { EuiDataGridToolbarControl } from './data_grid_toolbar_control'; export const useDataGridColumnSelector = ( availableColumns: EuiDataGridColumn[], @@ -101,10 +102,6 @@ export const useDataGridColumnSelector = ( const [columnSearchText, setColumnSearchText] = useState(''); - const controlBtnClasses = classNames('euiDataGrid__controlBtn', { - 'euiDataGrid__controlBtn--active': numberOfHiddenFields > 0, - }); - const filteredColumns = useMemo( () => sortedColumns.filter( @@ -122,27 +119,22 @@ export const useDataGridColumnSelector = ( 'Drag handle' ); - let buttonText = ( + const buttonText = ( ); - if (numberOfHiddenFields === 1) { - buttonText = ( - - ); - } else if (numberOfHiddenFields > 1) { - buttonText = ( - - ); - } + const orderedVisibleColumns = useMemo( + () => + visibleColumns + .map( + (columnId) => + availableColumns.find( + ({ id }) => id === columnId + ) as EuiDataGridColumn // cast to avoid `undefined`, it filters those out next + ) + .filter((column) => column != null), + [availableColumns, visibleColumns] + ); const columnSelector = allowColumnHiding || allowColumnReorder ? ( @@ -154,16 +146,18 @@ export const useDataGridColumnSelector = ( panelPaddingSize="s" hasDragDrop button={ - 0 + ? `${orderedVisibleColumns.length}/${availableColumns.length}` + : availableColumns.length + } + iconType="tableDensityNormal" data-test-subj="dataGridColumnSelectorButton" onClick={() => setIsOpen(!isOpen)} > {buttonText} - + } > {allowColumnHiding && ( @@ -313,18 +307,6 @@ export const useDataGridColumnSelector = (
) : null; - const orderedVisibleColumns = useMemo( - () => - visibleColumns - .map( - (columnId) => - availableColumns.find( - ({ id }) => id === columnId - ) as EuiDataGridColumn // cast to avoid `undefined`, it filters those out next - ) - .filter((column) => column != null), - [availableColumns, visibleColumns] - ); /** * Used for moving columns left/right, available in the headers actions menu */ diff --git a/src/components/datagrid/controls/column_sorting.test.tsx b/src/components/datagrid/controls/column_sorting.test.tsx index 2ce2ea61c1f..47d40e36005 100644 --- a/src/components/datagrid/controls/column_sorting.test.tsx +++ b/src/components/datagrid/controls/column_sorting.test.tsx @@ -84,7 +84,7 @@ describe('useDataGridColumnSorting', () => { component.find('[data-popover-panel]').first().render() ).toMatchSnapshot(); closePopover(component); - expect(component.text()).toEqual('1 field sorted'); + expect(component.text()).toEqual('Sort fields1'); } ); diff --git a/src/components/datagrid/controls/column_sorting.tsx b/src/components/datagrid/controls/column_sorting.tsx index 714b96e4f51..e2beb1845cb 100644 --- a/src/components/datagrid/controls/column_sorting.tsx +++ b/src/components/datagrid/controls/column_sorting.tsx @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -import classNames from 'classnames'; import React, { ReactNode, useEffect, useState } from 'react'; import { DropResult } from '@hello-pangea/dnd'; import { EuiButtonEmpty } from '../../button'; @@ -20,6 +19,7 @@ import { EuiI18n, useEuiI18n } from '../../i18n'; import { EuiPopover, EuiPopoverFooter } from '../../popover'; import { EuiText } from '../../text'; import { EuiToken } from '../../token'; +import { EuiDataGridToolbarControl } from './data_grid_toolbar_control'; import { EuiDataGridColumnSortingDraggable } from './column_sorting_draggable'; import { getDetailsForSchema } from '../utils/data_grid_schema'; import { @@ -63,17 +63,6 @@ export const useDataGridColumnSorting = ( 'Sort fields' ); - const sortingButtonTextActive = useEuiI18n( - 'euiColumnSorting.buttonActive', - ({ numberOfSortedFields }) => - `${numberOfSortedFields} field${ - numberOfSortedFields === 1 ? '' : 's' - } sorted`, - { - numberOfSortedFields: sorting != null ? sorting.columns.length : 0, - } - ); - if (sorting == null) return null; const activeColumnIds = new Set(sorting.columns.map(({ id }) => id)); @@ -110,10 +99,6 @@ export const useDataGridColumnSorting = ( } }; - const controlBtnClasses = classNames('euiDataGrid__controlBtn', { - 'euiDataGrid__controlBtn--active': sorting.columns.length > 0, - }); - const schemaDetails = (id: string | number) => schema.hasOwnProperty(id) && schema[id].columnType != null ? getDetailsForSchema(schemaDetectors, schema[id].columnType) @@ -143,18 +128,14 @@ export const useDataGridColumnSorting = ( panelPaddingSize="s" hasDragDrop button={ - setIsOpen(!isOpen)} > - {sorting.columns.length > 0 - ? sortingButtonTextActive - : sortingButtonText} - + {sortingButtonText} + } > {sorting.columns.length > 0 ? ( diff --git a/src/components/datagrid/controls/data_grid_toolbar_control.test.tsx b/src/components/datagrid/controls/data_grid_toolbar_control.test.tsx new file mode 100644 index 00000000000..8fab0d361f1 --- /dev/null +++ b/src/components/datagrid/controls/data_grid_toolbar_control.test.tsx @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { render } from '../../../test/rtl'; +import { shouldRenderCustomStyles } from '../../../test/internal'; +import { requiredProps } from '../../../test'; + +import { EuiDataGridToolbarControl } from './data_grid_toolbar_control'; + +describe('euiDataGridToolbarControl', () => { + shouldRenderCustomStyles(); + + it('passes props to the underlying EuiButtonEmpty', () => { + const { container } = render( + + Test button text + + ); + + expect(container.firstChild).toMatchSnapshot(); + }); + + it('renders with a badge', () => { + const { container } = render( + + Test button text + + ); + + expect(container.firstChild).toMatchSnapshot(); + expect( + container.querySelector('.euiDataGridToolbarControl__badge') + ).toBeInTheDocument(); + }); + + it('renders textProps onto the custom text wrapper', () => { + const { container } = render( + + Test button text + + ); + + expect(container.querySelector('.euiDataGridToolbarControl__text')) + .toMatchInlineSnapshot(` + + Test button text + + `); + }); +}); diff --git a/src/components/datagrid/controls/data_grid_toolbar_control.tsx b/src/components/datagrid/controls/data_grid_toolbar_control.tsx new file mode 100644 index 00000000000..3bbddcf9bea --- /dev/null +++ b/src/components/datagrid/controls/data_grid_toolbar_control.tsx @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { FunctionComponent } from 'react'; +import classNames from 'classnames'; +import { css } from '@emotion/react'; + +import { EuiButtonEmpty, EuiButtonEmptyProps } from '../../button'; +import { EuiNotificationBadge } from '../../badge'; +import { useEuiI18n } from '../../i18n'; + +export type EuiDataGridToolbarControlProps = EuiButtonEmptyProps & { + badgeContent?: number | string; +}; + +export const EuiDataGridToolbarControl: FunctionComponent< + EuiDataGridToolbarControlProps +> = ({ children, className, badgeContent, textProps, ...rest }) => { + const classes = classNames('euiDataGridToolbarControl', className); + + const badgeAriaLabel = useEuiI18n( + 'euiDataGridToolbarControl.badgeAriaLabel', + 'Active: {count}', + { + count: + typeof badgeContent === 'string' + ? betterScreenReaderSlashes(badgeContent) + : badgeContent, + } + ); + + return ( + + + {children} + + + {Boolean(badgeContent) && ( + + {badgeContent} + + )} + + ); +}; + +// The columns control specifically passes (e.g.) `5/10` when some columns +// are being hidden. We can make this a bit more legible to SRs with this quick util +const betterScreenReaderSlashes = (badgeContent: string) => + badgeContent.replaceAll('/', ' out of '); diff --git a/src/components/datagrid/controls/display_selector.tsx b/src/components/datagrid/controls/display_selector.tsx index 55b1c6f0984..1664ea7c9df 100644 --- a/src/components/datagrid/controls/display_selector.tsx +++ b/src/components/datagrid/controls/display_selector.tsx @@ -248,7 +248,6 @@ export const useDataGridDisplaySelector = ( setIsOpen(!isOpen)} diff --git a/src/components/datagrid/controls/fullscreen_selector.tsx b/src/components/datagrid/controls/fullscreen_selector.tsx index c76ba9931ee..d151e7f2f59 100644 --- a/src/components/datagrid/controls/fullscreen_selector.tsx +++ b/src/components/datagrid/controls/fullscreen_selector.tsx @@ -15,7 +15,7 @@ import React, { KeyboardEvent, KeyboardEventHandler, } from 'react'; -import classNames from 'classnames'; + import { keys } from '../../../services'; import { EuiToolTip } from '../../tool_tip'; import { EuiButtonIcon } from '../../button'; @@ -38,9 +38,6 @@ export const useDataGridFullScreenSelector = (): { ], ['Enter fullscreen', 'Exit fullscreen'] ); - const controlBtnClasses = classNames('euiDataGrid__controlBtn', { - 'euiDataGrid__controlBtn--active': isFullScreen, - }); const fullScreenSelector = useMemo( () => ( setIsFullScreen(!isFullScreen)} aria-label={isFullScreen ? fullScreenButtonActive : fullScreenButton} /> ), - [isFullScreen, controlBtnClasses, fullScreenButton, fullScreenButtonActive] + [isFullScreen, fullScreenButton, fullScreenButtonActive] ); const handleGridKeyDown = useCallback( diff --git a/src/components/datagrid/controls/index.ts b/src/components/datagrid/controls/index.ts index 5c4a98c398d..8b17b80bb86 100644 --- a/src/components/datagrid/controls/index.ts +++ b/src/components/datagrid/controls/index.ts @@ -15,3 +15,7 @@ export { checkOrDefaultToolBarDisplayOptions, EuiDataGridToolbar, } from './data_grid_toolbar'; +export { + EuiDataGridToolbarControl, + type EuiDataGridToolbarControlProps, +} from './data_grid_toolbar_control'; diff --git a/src/components/datagrid/data_grid.test.tsx b/src/components/datagrid/data_grid.test.tsx index 337c1a083e6..2eb963f13dd 100644 --- a/src/components/datagrid/data_grid.test.tsx +++ b/src/components/datagrid/data_grid.test.tsx @@ -1901,13 +1901,15 @@ describe('EuiDataGrid', () => { /> ); - // Get column sorting button - const sortColumn = component.find( - 'EuiButtonEmpty[data-test-subj="dataGridColumnSortingButton"]' - ); - const getButtonText = (): string => - sortColumn.find('span[className~="euiButtonEmpty__text"]').text(); - expect(getButtonText()).toEqual('Sort fields'); + // Get column sort count + const getBadgeText = () => { + const button = component.find( + 'EuiButtonEmpty[data-test-subj="dataGridColumnSortingButton"]' + ); + const badge = button.find('span.euiDataGridToolbarControl__badge'); + return badge.length ? badge.text() : false; + }; + expect(getBadgeText()).toBeFalsy(); // Update sorted columns component.setProps({ @@ -1916,7 +1918,7 @@ describe('EuiDataGrid', () => { onSort: () => {}, }, }); - expect(getButtonText()).toEqual('1 field sorted'); + expect(getBadgeText()).toEqual('1'); // Update sorted columns again component.setProps({ @@ -1928,7 +1930,7 @@ describe('EuiDataGrid', () => { onSort: () => {}, }, }); - expect(getButtonText()).toEqual('2 fields sorted'); + expect(getBadgeText()).toEqual('2'); }); }); diff --git a/src/components/datagrid/index.ts b/src/components/datagrid/index.ts index 7d32fd2d869..8a70ba76b17 100644 --- a/src/components/datagrid/index.ts +++ b/src/components/datagrid/index.ts @@ -11,6 +11,7 @@ export { useDataGridColumnSelector, useDataGridColumnSorting, useDataGridDisplaySelector, + EuiDataGridToolbarControl, } from './controls'; export * from './data_grid_types'; diff --git a/src/components/date_picker/super_date_picker/super_update_button.tsx b/src/components/date_picker/super_date_picker/super_update_button.tsx index dab442fe5ee..8c67f437ca8 100644 --- a/src/components/date_picker/super_date_picker/super_update_button.tsx +++ b/src/components/date_picker/super_date_picker/super_update_button.tsx @@ -185,7 +185,7 @@ export class EuiSuperUpdateButton extends Component< ...restTextProps, className: classNames( 'euiScreenReaderOnly', - restTextProps?.className + restTextProps && restTextProps.className ), }} {...rest} diff --git a/src/components/filter_group/filter_button.tsx b/src/components/filter_group/filter_button.tsx index fd2636dc4b9..3f7354a28da 100644 --- a/src/components/filter_group/filter_button.tsx +++ b/src/components/filter_group/filter_button.tsx @@ -119,7 +119,7 @@ export const EuiFilterButton: FunctionComponent = ({ const buttonTextClassNames = classNames( 'euiFilterButton__text', { 'euiFilterButton__text-hasNotification': showBadge }, - textProps?.className + textProps && textProps.className ); const badgeContent = showBadge && ( @@ -171,7 +171,7 @@ export const EuiFilterButton: FunctionComponent = ({ css: [ textStyles.euiFilterButton__text, showBadge && textStyles.hasNotification, - textProps?.css, + textProps && textProps.css, ], }} contentProps={{