diff --git a/CHANGELOG.md b/CHANGELOG.md
index e3c6f232418..6969e83e9fe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
**Bug fixes**
- Fixed multiple bugs with `EuiDataGrid` keyboard focus restoration ([#5530](https://github.com/elastic/eui/pull/5530))
+- Fixed `EuiDataGrid`'s display toolbar control to update initial UI state when developer `gridStyle` or `rowHeightsOptions` props are updated ([#5525](https://github.com/elastic/eui/pull/5525))
**Breaking changes**
diff --git a/src/components/datagrid/controls/display_selector.test.tsx b/src/components/datagrid/controls/display_selector.test.tsx
index a4d3f5d66ac..0990a39bd9e 100644
--- a/src/components/datagrid/controls/display_selector.test.tsx
+++ b/src/components/datagrid/controls/display_selector.test.tsx
@@ -121,7 +121,7 @@ describe('useDataGridDisplaySelector', () => {
).toHaveLength(0);
});
- describe('convertGridStylesToSelection (loading initial state from passed gridStyles', () => {
+ describe('convertGridStylesToSelection', () => {
it('should set compact state if both fontSize and cellPadding are s', () => {
const component = mount(
@@ -155,6 +155,18 @@ describe('useDataGridDisplaySelector', () => {
});
});
+ it('updates grid density whenever new developer styles are passed in', () => {
+ const component = mount(
+
+ );
+ openPopover(component);
+ expect(getSelection(component)).toEqual('expanded');
+
+ component.setProps({ gridStyles: { fontSize: 's', cellPadding: 's' } });
+ component.update();
+ expect(getSelection(component)).toEqual('compact');
+ });
+
it('correctly resets density to initial developer-passed state', () => {
const component = mount(
@@ -216,7 +228,7 @@ describe('useDataGridDisplaySelector', () => {
).toHaveLength(0);
});
- describe('convertRowHeightsOptionsToSelection (loading initial state from passed rowHeightsOptions)', () => {
+ describe('convertRowHeightsOptionsToSelection', () => {
test('auto', () => {
const component = mount(
@@ -260,6 +272,20 @@ describe('useDataGridDisplaySelector', () => {
});
});
+ it('updates row height whenever new developer settings are passed in', () => {
+ const component = mount(
+
+ );
+ openPopover(component);
+ expect(getSelection(component)).toEqual('auto');
+
+ component.setProps({
+ rowHeightsOptions: { defaultHeight: { lineCount: 3 } },
+ });
+ component.update();
+ expect(getSelection(component)).toEqual('lineCount');
+ });
+
it('correctly resets row height to initial developer-passed state', () => {
const component = mount(
@@ -380,9 +406,10 @@ describe('useDataGridDisplaySelector', () => {
component.find('[data-test-subj="resetDisplaySelector"]').exists()
).toBe(true);
- // Should hide the reset button again when changing back to the initial configuration
- component.find('[data-test-subj="normal"]').simulate('change');
- component.find('[data-test-subj="undefined"]').simulate('change');
+ // Should hide the reset button again after it's been clicked
+ component
+ .find('button[data-test-subj="resetDisplaySelector"]')
+ .simulate('click');
expect(
component.find('[data-test-subj="resetDisplaySelector"]').exists()
).toBe(false);
@@ -447,11 +474,6 @@ describe('useDataGridDisplaySelector', () => {
.find('[data-test-subj="rowHeightButtonGroup"]')
.simulate('change', selection);
};
- const setLineCount = (component: ShallowWrapper, lineCount = 1) => {
- diveIntoEuiI18n(component)
- .find('[data-test-subj="lineCountNumber"]')
- .simulate('change', { target: { value: lineCount } });
- };
const getOutput = (component: ShallowWrapper) => {
return JSON.parse(component.find('[data-test-subj="output"]').text());
};
@@ -481,11 +503,10 @@ describe('useDataGridDisplaySelector', () => {
);
setRowHeight(component, 'lineCount');
- setLineCount(component, 5);
expect(getOutput(component)).toEqual({
lineHeight: '2em',
- defaultHeight: { lineCount: 5 },
+ defaultHeight: { lineCount: 2 },
rowHeights: {},
});
});
diff --git a/src/components/datagrid/controls/display_selector.tsx b/src/components/datagrid/controls/display_selector.tsx
index d7be1d2d0af..62fc651280a 100644
--- a/src/components/datagrid/controls/display_selector.tsx
+++ b/src/components/datagrid/controls/display_selector.tsx
@@ -6,7 +6,13 @@
* Side Public License, v 1.
*/
-import React, { ReactNode, useState, useMemo, useCallback } from 'react';
+import React, {
+ ReactNode,
+ useState,
+ useMemo,
+ useCallback,
+ useEffect,
+} from 'react';
import { useUpdateEffect } from '../../../services';
import { EuiI18n, useEuiI18n } from '../../i18n';
@@ -51,11 +57,11 @@ const densityStyles: { [key: string]: Partial } = {
},
};
const convertGridStylesToSelection = (gridStyles: EuiDataGridStyle) => {
- if (gridStyles?.fontSize === 's' && gridStyles?.cellPadding === 's')
+ if (gridStyles.fontSize === 's' && gridStyles.cellPadding === 's')
return 'compact';
- if (gridStyles?.fontSize === 'm' && gridStyles?.cellPadding === 'm')
+ if (gridStyles.fontSize === 'm' && gridStyles.cellPadding === 'm')
return 'normal';
- if (gridStyles?.fontSize === 'l' && gridStyles?.cellPadding === 'l')
+ if (gridStyles.fontSize === 'l' && gridStyles.cellPadding === 'l')
return 'expanded';
return '';
};
@@ -66,23 +72,21 @@ const capitalizeDensityString = (s: string) => s[0].toUpperCase() + s.slice(1);
// Row height options and utilities
const rowHeightButtonOptions: string[] = ['undefined', 'auto', 'lineCount'];
const convertRowHeightsOptionsToSelection = (
- rowHeightsOptions?: EuiDataGridRowHeightsOptions
+ rowHeightsOptions: EuiDataGridRowHeightsOptions
) => {
- if (rowHeightsOptions) {
- const { defaultHeight } = rowHeightsOptions;
+ const { defaultHeight } = rowHeightsOptions;
- if (defaultHeight === 'auto') {
- return rowHeightButtonOptions[1];
- }
- if (typeof defaultHeight === 'object' && defaultHeight?.lineCount) {
- return rowHeightButtonOptions[2];
- }
- if (
- typeof defaultHeight === 'number' ||
- (typeof defaultHeight === 'object' && defaultHeight.height)
- ) {
- return '';
- }
+ if (defaultHeight === 'auto') {
+ return rowHeightButtonOptions[1];
+ }
+ if (typeof defaultHeight === 'object' && defaultHeight?.lineCount) {
+ return rowHeightButtonOptions[2];
+ }
+ if (
+ typeof defaultHeight === 'number' ||
+ (typeof defaultHeight === 'object' && defaultHeight.height)
+ ) {
+ return '';
}
return rowHeightButtonOptions[0];
};
@@ -104,37 +108,17 @@ export const useDataGridDisplaySelector = (
'allowRowHeight'
);
- // Get initial state (also used when resetting)
- const initialDensity = useMemo(
- () => convertGridStylesToSelection(initialStyles),
- [initialStyles]
- );
- const initialRowHeight = useMemo(
- () => convertRowHeightsOptionsToSelection(initialRowHeightsOptions),
- [initialRowHeightsOptions]
- );
- const initialLineCount = useMemo(
- // @ts-ignore - optional chaining operator handles types & cases that aren't lineCount
- () => initialRowHeightsOptions?.defaultHeight?.lineCount || 2,
- [initialRowHeightsOptions?.defaultHeight]
- );
-
// Track styles specified by the user at run time
const [userGridStyles, setUserGridStyles] = useState({});
const [userRowHeightsOptions, setUserRowHeightsOptions] = useState({});
- // Density state
- const [gridDensity, _setGridDensity] = useState(initialDensity);
- const setGridDensity = (density: string) => {
- _setGridDensity(density);
+ // Density logic
+ const setGridStyles = useCallback((density: string) => {
setUserGridStyles(densityStyles[density]);
- };
+ }, []);
- // Row height state
- const [lineCount, setLineCount] = useState(initialLineCount);
- const [rowHeightSelection, setRowHeightSelection] = useState(
- initialRowHeight
- );
+ // Row height logic
+ const [lineCount, setLineCount] = useState(2);
const setRowHeight = useCallback(
(option: string) => {
const rowHeightsOptions: EuiDataGridRowHeightsOptions = {
@@ -149,7 +133,6 @@ export const useDataGridDisplaySelector = (
rowHeightsOptions.defaultHeight = undefined;
}
- setRowHeightSelection(option);
setUserRowHeightsOptions(rowHeightsOptions);
},
[lineCount]
@@ -180,39 +163,47 @@ export const useDataGridDisplaySelector = (
};
}, [initialRowHeightsOptions, userRowHeightsOptions]);
- // Invoke onChange callbacks on user input (removing the callback value itself, so that only configuration values are returned)
+ // Set UI controls based on current configurations, on init & when either developer or user settings change
+ const gridDensity = useMemo(() => {
+ return convertGridStylesToSelection(gridStyles);
+ }, [gridStyles]);
+
+ const rowHeightSelection = useMemo(() => {
+ return convertRowHeightsOptionsToSelection(rowHeightsOptions);
+ }, [rowHeightsOptions]);
+
+ useEffect(() => {
+ // @ts-ignore - optional chaining operator handles types & cases that aren't lineCount
+ setLineCount(rowHeightsOptions?.defaultHeight?.lineCount || 2);
+ // @ts-ignore - same as above
+ }, [rowHeightsOptions?.defaultHeight?.lineCount]);
+
+ // Show a reset button whenever users manually change settings, and
+ // invoke onChange callbacks (removing the callback value itself, so that only configuration values are returned)
+ const [showResetButton, setShowResetButton] = useState(false);
+
useUpdateEffect(() => {
+ const hasUserChanges = Object.keys(userGridStyles).length > 0;
+ if (hasUserChanges) setShowResetButton(true);
+
const { onChange, ...currentGridStyles } = gridStyles;
initialStyles?.onChange?.(currentGridStyles);
}, [userGridStyles]);
useUpdateEffect(() => {
+ const hasUserChanges = Object.keys(userRowHeightsOptions).length > 0;
+ if (hasUserChanges) setShowResetButton(true);
+
const { onChange, ...currentRowHeightsOptions } = rowHeightsOptions;
initialRowHeightsOptions?.onChange?.(currentRowHeightsOptions);
}, [userRowHeightsOptions]);
// Allow resetting to initial developer-specified configurations
const resetToInitialState = useCallback(() => {
- setGridDensity(initialDensity);
setUserGridStyles({});
- setRowHeightSelection(initialRowHeight);
setUserRowHeightsOptions({});
- setLineCount(initialLineCount);
- }, [initialDensity, initialRowHeight, initialLineCount]);
-
- const showResetButton = useMemo(() => {
- if (initialDensity !== gridDensity) return true;
- if (initialRowHeight !== rowHeightSelection) return true;
- if (initialLineCount !== lineCount) return true;
- return false;
- }, [
- initialDensity,
- gridDensity,
- initialRowHeight,
- rowHeightSelection,
- initialLineCount,
- lineCount,
- ]);
+ setShowResetButton(false);
+ }, []);
const buttonLabel = useEuiI18n(
'euiDisplaySelector.buttonText',
@@ -285,7 +276,7 @@ export const useDataGridDisplaySelector = (
label: labelExpanded,
},
]}
- onChange={setGridDensity}
+ onChange={setGridStyles}
idSelected={gridDensity}
data-test-subj="densityButtonGroup"
/>
diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx
index 09b7c82fef6..15f49ec113d 100644
--- a/src/components/datagrid/data_grid.tsx
+++ b/src/components/datagrid/data_grid.tsx
@@ -130,7 +130,10 @@ export const EuiDataGrid: FunctionComponent = (props) => {
/**
* Merge consumer settings with defaults
*/
- const gridStyleWithDefaults = { ...startingStyles, ...gridStyle };
+ const gridStyleWithDefaults = useMemo(
+ () => ({ ...startingStyles, ...gridStyle }),
+ [gridStyle]
+ );
const mergedPopoverContents = useMemo(
() => ({