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`] = `
>
@@ -970,7 +985,8 @@ exports[`EuiDataGrid rendering renders control columns 1`] = `
>
@@ -1592,7 +1608,7 @@ exports[`EuiDataGrid rendering renders custom column headers 1`] = `
data-test-subj="dataGridColumnSelectorPopover"
>
@@ -1601,13 +1617,20 @@ exports[`EuiDataGrid rendering renders custom column headers 1`] = `
>
Columns
+
+ 2
+
@@ -1646,7 +1669,7 @@ exports[`EuiDataGrid rendering renders custom column headers 1`] = `
>
@@ -1664,7 +1687,8 @@ exports[`EuiDataGrid rendering renders custom column headers 1`] = `
>
@@ -2010,7 +2034,7 @@ exports[`EuiDataGrid rendering renders with common and div attributes 1`] = `
data-test-subj="dataGridColumnSelectorPopover"
>
@@ -2019,13 +2043,20 @@ exports[`EuiDataGrid rendering renders with common and div attributes 1`] = `
>
Columns
+
+ 2
+
@@ -2064,7 +2095,7 @@ exports[`EuiDataGrid rendering renders with common and div attributes 1`] = `
>
@@ -2082,7 +2113,8 @@ exports[`EuiDataGrid rendering renders with common and div attributes 1`] = `
>
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 7ae7f5af061..c18c44fbb19 100644
--- a/src/components/datagrid/controls/__snapshots__/column_selector.test.tsx.snap
+++ b/src/components/datagrid/controls/__snapshots__/column_selector.test.tsx.snap
@@ -6,7 +6,7 @@ exports[`useDataGridColumnSelector columnSelector [React 16] renders a toolbar b
data-test-subj="dataGridColumnSelectorPopover"
>
@@ -15,13 +15,20 @@ exports[`useDataGridColumnSelector columnSelector [React 16] renders a toolbar b
>
Columns
+
+ 2
+
@@ -291,7 +298,7 @@ exports[`useDataGridColumnSelector columnSelector [React 17] renders a toolbar b
data-test-subj="dataGridColumnSelectorPopover"
>
@@ -300,13 +307,20 @@ exports[`useDataGridColumnSelector columnSelector [React 17] renders a toolbar b
>
Columns
+
+ 2
+
@@ -576,7 +590,7 @@ exports[`useDataGridColumnSelector columnSelector [React 18] renders a toolbar b
data-test-subj="dataGridColumnSelectorPopover"
>
@@ -585,13 +599,20 @@ exports[`useDataGridColumnSelector columnSelector [React 18] renders a toolbar b
>
Columns
+
+ 2
+
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"
>
@@ -18,9 +18,16 @@ exports[`useDataGridColumnSorting columnSorting [React 16] renders a toolbar but
data-euiicon-type="sortable"
/>
- 1 field sorted
+ Sort fields
+
+
+ 1
@@ -269,7 +276,7 @@ exports[`useDataGridColumnSorting columnSorting [React 17] renders a toolbar but
data-test-subj="dataGridColumnSortingPopover"
>
@@ -281,9 +288,16 @@ exports[`useDataGridColumnSorting columnSorting [React 17] renders a toolbar but
data-euiicon-type="sortable"
/>
- 1 field sorted
+ Sort fields
+
+
+ 1
@@ -532,7 +546,7 @@ exports[`useDataGridColumnSorting columnSorting [React 18] renders a toolbar but
data-test-subj="dataGridColumnSortingPopover"
>
@@ -544,9 +558,16 @@ exports[`useDataGridColumnSorting columnSorting [React 18] renders a toolbar but
data-euiicon-type="sortable"
/>
+ Sort fields
+
+
- 1 field sorted
+ 1
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`] = `
+
+
+
+
+ Test button text
+
+
+
+`;
+
+exports[`euiDataGridToolbarControl renders with a badge 1`] = `
+
+
+
+ Test button text
+
+
+ 5
+
+
+
+`;
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={{