diff --git a/CHANGELOG.md b/CHANGELOG.md index de557caa998..ca859fda394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ No public interface changes since `38.2.0`. - Updated `EuiRangeLevel` `color` property to accept CSS color values ([#5171](https://github.com/elastic/eui/pull/5171)) - Added optional visual line highlighting to `EuiCodeBlock` ([#5207](https://github.com/elastic/eui/pull/5207)) - Added `popoverProps` to `EuiSuperSelect` and deprecated `popoverClassName` & `repositionOnScroll` ([#5214](https://github.com/elastic/eui/pull/5214)) +- Added `lineHeight` configuration to `rowHeightsOptions` in `EuiDataGrid` ([#5221](https://github.com/elastic/eui/pull/5221)) **Bug fixes** diff --git a/src-docs/src/views/datagrid/datagrid_example.js b/src-docs/src/views/datagrid/datagrid_example.js index 0084d15f759..5e6123c2446 100644 --- a/src-docs/src/views/datagrid/datagrid_example.js +++ b/src-docs/src/views/datagrid/datagrid_example.js @@ -9,6 +9,7 @@ import { EuiDescriptionList, EuiCodeBlock, EuiText, + EuiLink, EuiSpacer, } from '../../../../src/components'; @@ -107,6 +108,14 @@ const gridSnippet = ` rowHover: 'highlight', header: 'shade', }} + // Optional. Allows configuring the heights of grid rows + rowHeightsOptions={{ + defaultHeight: 34, + rowHeights: { + 0: auto + }, + lineHeight: '1em', + }} // Optional. Provide additional schemas to use in the grid. // This schema 'franchise' essentially acts like a boolean, looking for Star Wars or Star Trek in a column. schemaDetectors={[ @@ -222,6 +231,20 @@ const gridConcepts = [ description: 'The total number of rows in the dataset (used by e.g. pagination to know how many pages to list).', }, + { + title: 'rowHeightsOptions', + description: ( + + Allows configuring both default and specific heights of grid rows. + Accepts a partial EuiDataGridRowHeightsOptions object. + See{' '} + + Data grid row heights options + {' '} + for more details and examples. + + ), + }, { title: 'gridStyle', description: ( diff --git a/src-docs/src/views/datagrid/datagrid_height_options_example.js b/src-docs/src/views/datagrid/datagrid_height_options_example.js index 4799ab28685..596d9d2afd9 100644 --- a/src-docs/src/views/datagrid/datagrid_height_options_example.js +++ b/src-docs/src/views/datagrid/datagrid_height_options_example.js @@ -12,26 +12,55 @@ import { import { EuiDataGridRowHeightsOptions } from '!!prop-loader!../../../../src/components/datagrid/data_grid_types'; +import DataGridRowLineHeight from './row_line_height'; +const dataGridRowLineHeightSource = require('!!raw-loader!./row_height_auto'); import DataGridRowHeightOptions from './row_height_fixed'; const dataGridRowHeightOptionsSource = require('!!raw-loader!./row_height_fixed'); import DataGridRowAutoHeight from './row_height_auto'; const dataGridRowAutoHeightSource = require('!!raw-loader!./row_height_auto'); +const lineHeightSnippet = `rowHeightsOptions = { + defaultHeight: { + lineCount: 3 // default every row to 3 lines of text + }, + lineHeight: '2em', // default every cell line-height to 2em +}`; + +const lineHeightFullSnippet = `const rowHeightsOptions = useMemo( + () => ({ + defaultHeight: { + lineCount: 3, + }, + lineHeight: '2em'; + }), + [] +); + + +`; + const rowHeightsSnippet = `rowHeightsOptions = { defaultHeight: 140, // default every row to 140px rowHeights: { 1: { - lineCount: 5, // for row which have index 1 we allow to show 5 lines after that we truncate + lineCount: 5, // row at index 1 will show 5 lines }, - 4: 200, // for row which have index 4 we set 140 pixel + 4: 200, // row at index 4 will adjust the height to 200px 5: 80, }, }`; const rowHeightsFullSnippet = `const rowHeightsOptions = useMemo( () => ({ - defaultHeight: { - lineCount: 2, + defaultHeight: 140, }), [] ); @@ -110,24 +139,44 @@ export const DataGridRowHeightOptionsExample = { By default, all rows get a height of 34 pixels, but there are scenarios where you might want to adjust the height to fit more content. To do that, you can pass an object to the{' '} - rowHeightsOptions prop. This object accepts two + rowHeightsOptions prop. This object accepts three properties:

-

- Each of these can be configured with an exact pixel height, a line - count, or "auto" to fit all of the - content. See the examples below for more details. -

@@ -145,19 +194,55 @@ export const DataGridRowHeightOptionsExample = { source: [ { type: GuideSectionTypes.JS, - code: dataGridRowHeightOptionsSource, + code: dataGridRowLineHeightSource, }, ], - title: 'Fixed heights for rows', + title: 'Setting a default height and line height for rows', text: (

You can change the default height for all rows by passing a line count or pixel value to the defaultHeight{' '} - property. + property, and customize the line height of all cells with the{' '} + lineHeight property.

+ + {lineHeightSnippet} + + +

+ If you wrap your cell content with CSS that overrides/sets + line-height (e.g. in an EuiText), your row + heights will not be calculated correctly! Make sure to match or + inherit the passed lineHeight property to the + actual cell content line height. +

+
+
+ ), + components: { DataGridRowLineHeight }, + props: { + EuiDataGrid, + EuiDataGridRowHeightsOptions, + }, + demo: , + snippet: lineHeightFullSnippet, + }, + { + source: [ + { + type: GuideSectionTypes.JS, + code: dataGridRowHeightOptionsSource, + }, + ], + title: 'Overriding specific row heights', + text: ( +

- You can also override the height of a specific row by passing a + You can override the default height of a specific row by passing a rowHeights object associating the row's index with a specific height configuration.

diff --git a/src-docs/src/views/datagrid/row_height_auto.tsx b/src-docs/src/views/datagrid/row_height_auto.tsx index 5771102da0d..0951408c859 100644 --- a/src-docs/src/views/datagrid/row_height_auto.tsx +++ b/src-docs/src/views/datagrid/row_height_auto.tsx @@ -136,7 +136,7 @@ const RenderCellValue: EuiDataGridProps['renderCellValue'] = ({ content = {item.body ?? ''}; } else { // a full issue description is a *lot* to shove into a cell - content = content = ( + content = ( {(item.body ?? '').slice(0, 300)} diff --git a/src-docs/src/views/datagrid/row_height_fixed.tsx b/src-docs/src/views/datagrid/row_height_fixed.tsx index d2f0f330cae..91df500a1ca 100644 --- a/src-docs/src/views/datagrid/row_height_fixed.tsx +++ b/src-docs/src/views/datagrid/row_height_fixed.tsx @@ -136,7 +136,7 @@ const RenderCellValue: EuiDataGridProps['renderCellValue'] = ({ content = {item.body ?? ''}; } else { // a full issue description is a *lot* to shove into a cell - content = content = ( + content = ( {(item.body ?? '').slice(0, 300)} diff --git a/src-docs/src/views/datagrid/row_line_height.tsx b/src-docs/src/views/datagrid/row_line_height.tsx new file mode 100644 index 00000000000..d79b9b86326 --- /dev/null +++ b/src-docs/src/views/datagrid/row_line_height.tsx @@ -0,0 +1,182 @@ +import React, { + useCallback, + useState, + createContext, + useContext, + useMemo, + ReactNode, +} from 'react'; +// @ts-ignore not configured to import json +import githubData from './row_auto_height_data.json'; + +import { formatDate } from '../../../../src/services'; + +import { + EuiDataGrid, + EuiDataGridProps, +} from '../../../../src/components/datagrid'; + +interface DataShape { + html_url: string; + title: string; + user: { + login: string; + avatar_url: string; + }; + labels: Array<{ + name: string; + color: string; + }>; + comments: number; + created_at: string; + body?: string; +} + +// convert strings to Date objects +for (let i = 0; i < githubData.length; i++) { + githubData[i].created_at = new Date(githubData[i].created_at); +} + +type DataContextShape = + | undefined + | { + data: DataShape[]; + }; +const DataContext = createContext(undefined); + +const columns = [ + { + id: 'index', + displayAsText: 'Index', + isExpandable: false, + initialWidth: 80, + }, + { + id: 'issue', + displayAsText: 'Issue', + isExpandable: false, + }, + { + id: 'body', + displayAsText: 'Description', + }, +]; + +// it is expensive to compute 10000 rows of fake data +// instead of loading up front, generate entries on the fly +const raw_data: DataShape[] = githubData; + +const RenderCellValue: EuiDataGridProps['renderCellValue'] = ({ + rowIndex, + columnId, + isDetails, +}) => { + const { data } = useContext(DataContext)!; + + const item = data[rowIndex]; + let content: ReactNode = ''; + + if (columnId === 'index') { + content = <>{rowIndex}; + } else if (columnId === 'issue') { + content = ( + <> + {item.title} +
+ Opened by {item.user.login} on {formatDate(item.created_at, 'dobLong')} +
+ {item.comments} comment{item.comments !== 1 ? 's' : ''} + + ); + } else if (columnId === 'body') { + if (isDetails) { + // expanded in a popover + content = item.body; + } else { + // a full issue description is a *lot* to shove into a cell + content = (item.body ?? '').slice(0, 300); + } + } + + return content; +}; + +export default () => { + // ** Pagination config + const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 50 }); + + // ** Sorting config + const [sortingColumns, setSortingColumns] = useState([]); + const onSort = useCallback( + (sortingColumns) => { + setSortingColumns(sortingColumns); + }, + [setSortingColumns] + ); + + const onChangeItemsPerPage = useCallback( + (pageSize) => + setPagination((pagination) => ({ + ...pagination, + pageSize, + pageIndex: 0, + })), + [setPagination] + ); + + const onChangePage = useCallback( + (pageIndex) => + setPagination((pagination) => ({ ...pagination, pageIndex })), + [setPagination] + ); + + // Column visibility + const [visibleColumns, setVisibleColumns] = useState(() => + columns.map(({ id }) => id) + ); // initialize to the full set of columns + + // matches the snippet example + const rowHeightsOptions = useMemo( + () => ({ + defaultHeight: { + lineCount: 3, + }, + lineHeight: '2em', + }), + [] + ); + + const dataContext = useMemo( + () => ({ + data: raw_data, + }), + [] + ); + + return ( + + + + ); +}; diff --git a/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap b/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap index f9378b7c4dc..6293227a1cb 100644 --- a/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap +++ b/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap @@ -38,6 +38,7 @@ exports[`EuiDataGridCell renders 1`] = ` role="gridcell" style={ Object { + "lineHeight": undefined, "width": undefined, } } diff --git a/src/components/datagrid/body/data_grid_cell.tsx b/src/components/datagrid/body/data_grid_cell.tsx index f5eca7ff69e..0260120b12f 100644 --- a/src/components/datagrid/body/data_grid_cell.tsx +++ b/src/components/datagrid/body/data_grid_cell.tsx @@ -406,7 +406,7 @@ export class EuiDataGridCell extends Component< style, ...rest } = this.props; - const { rowIndex } = rest; + const { rowIndex, rowHeightsOptions } = rest; const showCellButtons = this.state.isFocused || @@ -432,7 +432,12 @@ export class EuiDataGridCell extends Component< className: classNames(cellClasses, this.state.cellProps.className), }; - cellProps.style = { ...style, width, ...cellProps.style }; + cellProps.style = { + ...style, // from react-window + width, // column width, can be undefined + lineHeight: rowHeightsOptions?.lineHeight ?? undefined, // lineHeight configuration + ...cellProps.style, // apply anything from setCellProps({style}) + }; const handleCellKeyDown = (event: KeyboardEvent) => { if (isExpandable) { diff --git a/src/components/datagrid/data_grid.test.tsx b/src/components/datagrid/data_grid.test.tsx index 18966b6046d..3c8e019537f 100644 --- a/src/components/datagrid/data_grid.test.tsx +++ b/src/components/datagrid/data_grid.test.tsx @@ -545,6 +545,7 @@ describe('EuiDataGrid', () => { "color": "red", "height": 34, "left": 0, + "lineHeight": undefined, "position": "absolute", "top": "100px", "width": 100, @@ -564,6 +565,7 @@ describe('EuiDataGrid', () => { "color": "blue", "height": 34, "left": 100, + "lineHeight": undefined, "position": "absolute", "top": "100px", "width": 100, @@ -583,6 +585,7 @@ describe('EuiDataGrid', () => { "color": "red", "height": 34, "left": 0, + "lineHeight": undefined, "position": "absolute", "top": "134px", "width": 100, @@ -602,6 +605,7 @@ describe('EuiDataGrid', () => { "color": "blue", "height": 34, "left": 100, + "lineHeight": undefined, "position": "absolute", "top": "134px", "width": 100, diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index b41984e7079..09e959c19d9 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -693,11 +693,19 @@ export const EuiDataGrid: FunctionComponent = (props) => { }, [focusedCell, contentRef]); useEffect(() => { - rowHeightUtils.computeStylesForGridCell({ - cellPadding: gridStyles.cellPadding, - fontSize: gridStyles.fontSize, - }); - }, [gridStyles.cellPadding, gridStyles.fontSize, rowHeightUtils]); + rowHeightUtils.computeStylesForGridCell( + { + cellPadding: gridStyles.cellPadding, + fontSize: gridStyles.fontSize, + }, + rowHeightsOptions?.lineHeight + ); + }, [ + gridStyles.cellPadding, + gridStyles.fontSize, + rowHeightsOptions?.lineHeight, + rowHeightUtils, + ]); const classes = classNames( 'euiDataGrid', diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index 3ab5c00d620..cd367e31372 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -719,4 +719,8 @@ export interface EuiDataGridRowHeightsOptions { * Defines the height for a specific row. It can be line count or just height. */ rowHeights?: Record; + /** + * Defines a global lineHeight style to apply to all cells + */ + lineHeight?: string; } diff --git a/src/components/datagrid/row_height_utils.ts b/src/components/datagrid/row_height_utils.ts index 862eb9355ff..8ade9c469b4 100644 --- a/src/components/datagrid/row_height_utils.ts +++ b/src/components/datagrid/row_height_utils.ts @@ -136,12 +136,19 @@ export class RowHeightUtils { return false; } - computeStylesForGridCell(gridStyles: EuiDataGridStyle) { + computeStylesForGridCell( + gridStyles: EuiDataGridStyle, + lineHeight: string | undefined + ) { this.fakeCell.className = ` euiDataGridRowCell ${cellPaddingsToClassMap[gridStyles.cellPadding!]} ${fontSizesToClassMap[gridStyles.fontSize!]} `; + + // @ts-ignore it is valid to set `lineHeight` to undefined + this.fakeCell.style.lineHeight = lineHeight; + document.body.appendChild(this.fakeCell); const allStyles = getComputedStyle(this.fakeCell); this.styles = {