additionalControls.right prepends the passed
@@ -299,6 +325,7 @@ export const DataGridStylingExample = {
EuiDataGrid,
EuiDataGridToolBarVisibilityOptions,
EuiDataGridToolBarAdditionalControlsOptions,
+ EuiDataGridToolBarAdditionalControlsLeftOptions,
},
demo: ,
},
diff --git a/src/components/datagrid/controls/data_grid_toolbar.test.tsx b/src/components/datagrid/controls/data_grid_toolbar.test.tsx
index 4621c2f7c95..a1c513df46b 100644
--- a/src/components/datagrid/controls/data_grid_toolbar.test.tsx
+++ b/src/components/datagrid/controls/data_grid_toolbar.test.tsx
@@ -188,67 +188,140 @@ describe('renderAdditionalControls', () => {
const mockControl = ;
it('does not render if a boolean was passed into toolbarVisibility', () => {
- expect(renderAdditionalControls(false, 'left')).toEqual(null);
- expect(renderAdditionalControls(true, 'left')).toEqual(null);
+ expect(renderAdditionalControls(false, 'right')).toEqual(null);
+ expect(renderAdditionalControls(true, 'right')).toEqual(null);
});
it('does not render if toolbarVisibility is undefined or additionalControls is undefined', () => {
- expect(renderAdditionalControls(undefined, 'left')).toEqual(null);
+ expect(renderAdditionalControls(undefined, 'right')).toEqual(null);
expect(
- renderAdditionalControls({ additionalControls: undefined }, 'left')
+ renderAdditionalControls({ additionalControls: undefined }, 'right')
).toEqual(null);
});
- describe('left', () => {
- it('renders a react node passed into the left side toolbar', () => {
+ describe('left.append', () => {
+ it('renders a react node appended into the left side toolbar', () => {
expect(
renderAdditionalControls(
- { additionalControls: { left: mockControl } },
- 'left'
+ { additionalControls: { left: { append: mockControl } } },
+ 'left.append'
)
).toEqual(mockControl);
});
- it('does not render right side positions', () => {
+ it('does not render other positions', () => {
+ expect(
+ renderAdditionalControls(
+ { additionalControls: { left: { prepend: mockControl } } },
+ 'left.append'
+ )
+ ).toEqual(null);
expect(
renderAdditionalControls(
{ additionalControls: { right: mockControl } },
- 'left'
+ 'left.append'
)
).toEqual(null);
});
+
+ describe('additionalControls.left fallback', () => {
+ it('renders `additionalControls.left` nodes into `left.append` by default', () => {
+ expect(
+ renderAdditionalControls(
+ { additionalControls: { left: mockControl } },
+ 'left.append'
+ )
+ ).toEqual(mockControl);
+ });
+
+ it('does not render other positions', () => {
+ expect(
+ renderAdditionalControls(
+ { additionalControls: { left: mockControl } },
+ 'left.prepend'
+ )
+ ).toEqual(null);
+ expect(
+ renderAdditionalControls(
+ { additionalControls: { left: mockControl } },
+ 'right'
+ )
+ ).toEqual(null);
+ });
+ });
+
+ describe('additionalControls fallback', () => {
+ it('renders `additionalControls` nodes into `left.append` by default', () => {
+ expect(
+ renderAdditionalControls(
+ { additionalControls: mockControl },
+ 'left.append'
+ )
+ ).toEqual(mockControl);
+ });
+
+ it('does not render other positions', () => {
+ expect(
+ renderAdditionalControls(
+ { additionalControls: mockControl },
+ 'left.prepend'
+ )
+ ).toEqual(null);
+ expect(
+ renderAdditionalControls({ additionalControls: mockControl }, 'right')
+ ).toEqual(null);
+ });
+ });
});
- describe('right', () => {
- it('renders a react node passed into the right side toolbar', () => {
+ describe('left.prepend', () => {
+ it('renders a react node prepended into the left side toolbar', () => {
expect(
renderAdditionalControls(
- { additionalControls: { right: mockControl } },
- 'right'
+ { additionalControls: { left: { prepend: mockControl } } },
+ 'left.prepend'
)
).toEqual(mockControl);
});
- it('does not render left side positions', () => {
+ it('does not render other positions', () => {
expect(
renderAdditionalControls(
- { additionalControls: { left: mockControl } },
- 'right'
+ { additionalControls: { left: { append: mockControl } } },
+ 'left.prepend'
+ )
+ ).toEqual(null);
+ expect(
+ renderAdditionalControls(
+ { additionalControls: { right: mockControl } },
+ 'left.prepend'
)
).toEqual(null);
});
});
- describe('single node', () => {
- it('renders into the left side of toolbar by default', () => {
+ describe('right', () => {
+ it('renders a react node passed into the right side toolbar', () => {
expect(
- renderAdditionalControls({ additionalControls: mockControl }, 'left')
+ renderAdditionalControls(
+ { additionalControls: { right: mockControl } },
+ 'right'
+ )
).toEqual(mockControl);
});
- it('does not render into the right side of the toolbar', () => {
+ it('does not render left side positions', () => {
expect(
- renderAdditionalControls({ additionalControls: mockControl }, 'right')
+ renderAdditionalControls(
+ { additionalControls: { left: { prepend: mockControl } } },
+ 'right'
+ )
+ ).toEqual(null);
+ expect(
+ renderAdditionalControls(
+ { additionalControls: { left: { append: mockControl } } },
+ 'right'
+ )
).toEqual(null);
});
});
diff --git a/src/components/datagrid/controls/data_grid_toolbar.tsx b/src/components/datagrid/controls/data_grid_toolbar.tsx
index d1b29488865..fe3e5344794 100644
--- a/src/components/datagrid/controls/data_grid_toolbar.tsx
+++ b/src/components/datagrid/controls/data_grid_toolbar.tsx
@@ -15,6 +15,7 @@ import {
EuiDataGridToolbarProps,
EuiDataGridToolBarVisibilityOptions,
EuiDataGridToolBarAdditionalControlsOptions,
+ EuiDataGridToolBarAdditionalControlsLeftOptions,
} from '../data_grid_types';
// Used to simplify some sizing logic which is difficult to account for in tests
@@ -93,6 +94,7 @@ export const EuiDataGridToolbar = ({
>
{hasRoomForGridControls && (
+ {renderAdditionalControls(toolbarVisibility, 'left.prepend')}
{checkOrDefaultToolBarDisplayOptions(
toolbarVisibility,
'showColumnSelector'
@@ -105,7 +107,7 @@ export const EuiDataGridToolbar = ({
)
? columnSorting
: null}
- {renderAdditionalControls(toolbarVisibility, 'left')}
+ {renderAdditionalControls(toolbarVisibility, 'left.append')}
)}
@@ -159,7 +161,7 @@ export function checkOrDefaultToolBarDisplayOptions<
export function renderAdditionalControls(
toolbarVisibility: EuiDataGridProps['toolbarVisibility'],
- position: 'left' | 'right'
+ position: 'left.prepend' | 'left.append' | 'right'
) {
if (typeof toolbarVisibility === 'boolean') return null;
const { additionalControls } = toolbarVisibility || {};
@@ -168,16 +170,30 @@ export function renderAdditionalControls(
// Typescript is having obj issues, so we need to force cast to EuiDataGridToolBarAdditionalControlsOptions here
const additionalControlsObj: EuiDataGridToolBarAdditionalControlsOptions =
additionalControls?.constructor === Object ? additionalControls : {};
+ // Typescript workarounds continued
+ const leftPositionObj: EuiDataGridToolBarAdditionalControlsLeftOptions =
+ additionalControlsObj.left?.constructor === Object
+ ? additionalControlsObj.left
+ : {};
if (position === 'right') {
if (additionalControlsObj?.right) {
return additionalControlsObj.right;
}
- } else if (position === 'left') {
- if (additionalControlsObj?.left) {
+ } else if (position === 'left.prepend') {
+ if (leftPositionObj?.prepend) {
+ return leftPositionObj.prepend;
+ }
+ } else if (position === 'left.append') {
+ if (leftPositionObj?.append) {
+ return leftPositionObj.append;
+ }
+ if (React.isValidElement(additionalControlsObj?.left)) {
+ // If the consumer passed a single ReactNode to `additionalControls.left`, default to the left append position
return additionalControlsObj.left;
- } else if (React.isValidElement(additionalControls)) {
- // API backwards compatability: if the user passed in a single ReactNode, default to the the left position
+ }
+ if (React.isValidElement(additionalControls)) {
+ // API backwards compatability: if the consumer passed a single ReactNode to `additionalControls`, default to the the left append position
return additionalControls;
}
}
diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts
index 0a992ffffe1..c3a5eeff132 100644
--- a/src/components/datagrid/data_grid_types.ts
+++ b/src/components/datagrid/data_grid_types.ts
@@ -617,10 +617,11 @@ export interface EuiDataGridToolBarVisibilityOptions {
export interface EuiDataGridToolBarAdditionalControlsOptions {
/**
- * Will append the passed node into the left side of the toolbar, **after** the column & sort controls.
+ * If passed a `ReactNode`, appends the passed node into the left side of the toolbar, **after** the column & sort controls.
+ * Or use #EuiDataGridToolBarAdditionalControlsLeftOptions to customize the location of your control.
* We recommend using `` to match the existing controls on the left.
*/
- left?: ReactNode;
+ left?: ReactNode | EuiDataGridToolBarAdditionalControlsLeftOptions;
/**
* 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.
@@ -628,6 +629,17 @@ export interface EuiDataGridToolBarAdditionalControlsOptions {
right?: ReactNode;
}
+export interface EuiDataGridToolBarAdditionalControlsLeftOptions {
+ /**
+ * Will prepend the passed node into the left side of the toolbar, **before** the column & sort controls.
+ */
+ prepend?: ReactNode;
+ /**
+ * Will append the passed node into the left side of the toolbar, **after** the column & sort controls.
+ */
+ append?: ReactNode;
+}
+
// ideally this would use a generic to enforce `pageSize` exists in `pageSizeOptions`,
// but TypeScript's default understanding of an array is number[] unless `as const` is used
// which defeats the generic's purpose & functionality as it would check for `number` in `number[]`