Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EuiDataGrid] Refactor row height calculations to no longer need computed styles on grid init #5284

Merged
merged 17 commits into from
Nov 3, 2021

Conversation

cee-chen
Copy link
Contributor

@cee-chen cee-chen commented Oct 18, 2021

Summary

This PR ended up being a more difficult problem to solve than anticipated, and took several twists and turns - see this comment for the most recent description

Checklist

- [ ] Check against all themes for compatibility in both light and dark modes
- [ ] Checked in mobile

  • Checked in Chrome, Safari, Edge, and Firefox

- [ ] Props have proper autodocs and playground toggles
- [ ] Added documentation
- [ ] Checked Code Sandbox works for any docs examples
- [ ] Added or updated jest and cypress tests NB: Jest tests have yet to be written for row_height_utils, but it's on my radar
- [ ] Checked for breaking changes and labeled appropriately
- [ ] Checked for accessibility including keyboard-only and screenreader modes

  • A changelog entry exists and is marked appropriately

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_5284/

@chandlerprall
Copy link
Contributor

Looks like this change breaks the Setting a default height and line height for rows example.

I think this is a race condition in FF+Safari between the css stylesheets being added to the document and this test. Navigating to the auto-height example appears to always work, and when I added

if (allStyles.paddingTop === '0px') debugger;

to test with, FF will hit the debugger on a hard refresh, but by the time I can debug the allStyles.paddingTop value in the console it is correctly set at 6px

@cee-chen
Copy link
Contributor Author

Doh, I was wondering what was going on there (but thought it was some weirdness with my computer 🙈)

Race condition makes a ton of sense. Is there any way to wait to run this code until after stylesheets have loaded?

@cee-chen
Copy link
Contributor Author

Or alternatively, can we avoid using CSS for the padding calculations? For example, if we know the grid density, can we just hard code a map of padding heights (which we could later obtain from our CSS-in-JS work)?

@cee-chen cee-chen force-pushed the datagrid-computed-styles branch from 7c440a0 to 3e833d3 Compare October 21, 2021 22:29
@cee-chen
Copy link
Contributor Author

cee-chen commented Oct 21, 2021

The static map works really well, except unfortunately for lineHeight which is specifically used by calculateHeightForLineCount. The issue is that our base line height is not the same between our Amsterdam and Legacy theme, so the calculation works for one theme but not the other 😢

I have an idea for that issue that I'd like to pitch: when setting lineCount, the cell content actually already knows what height it should be when using due to our usage of CSS line-clamp. So, why not have lineCount simply take advantage of the cell content observer + height cache that we added to rowHeightUtils and use the same height logic as auto, instead of trying to calculate the height for lineCount manually?

Alternatively, if we don't anticipate DataGrid being used in the legacy theme, or if we're deprecating the legacy theme soon, we could just leave this as-is?...

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_5284/

cee-chen added a commit to cee-chen/eui that referenced this pull request Oct 25, 2021
- lineCount in elastic#5284 will shortly be using the row height cache in addition to auto, so I'm making the fn name less specific again
@cee-chen
Copy link
Contributor Author

cee-chen commented Oct 25, 2021

If converting this PR to have lineCount use the same height cache that auto does, I'll need #5281 to merge in first - going to convert this PR back to a draft in the meanwhile and pull out the first density font size fix to a separate PR.

Edit: I ended up exploring this but had to find a different solution as CSS line-clamp limits lines to a certain #, but does not expand the row height to that # of lines (sadly), which means if you had less content than the # of lines, the lineCount height was not working as it functioned previously.

@cee-chen cee-chen marked this pull request as draft October 25, 2021 20:38
cee-chen added a commit to cee-chen/eui that referenced this pull request Oct 26, 2021
- lineCount in elastic#5284 will shortly be using the row height cache in addition to auto, so I'm making the fn name less specific again
cee-chen pushed a commit that referenced this pull request Oct 28, 2021
…to` (#5281)

* Remove isHeightSame check

* Remove same height check from shouldComponentUpdate

- if we're not checking for sameHeight in componentDidUpdate, we also likely don't need this anymore, and all dynamic user changes appear to work without this code

* [Proposed refactors]

- Rename `recalculateRowHeight` to `setAutoRowHeight`

- DRY out setAutoRowHeight to be reusable by both the resize observer and during props update (NB: This leads to some repetition with the height being obtained twice, but will not be an issue shortly as I'll be refactoring/removing the cell wrapper observer in a future PR)

- Refactor rowHeightUtils.isAutoHeight to accept an undefined rowHeightsOptions

* Improve unit tests

* Add changelog entry

* [PR feedback] Fix `isAutoHeight` false positive
- occurs if the `defaultHeight` is auto but a specific `rowHeights` line override is not auto

TODO: Write a unit test for this in the future

* [PR feedback/Discover testing] Trigger component update when rowHeightsOptions changes

* [cleanup] Remove now-unused compareHeights util

+ clean up mock rowHeightUtils as well

* [revert] rename setAutoRowHeight back to recalculateRowHeight

- lineCount in #5284 will shortly be using the row height cache in addition to auto, so I'm making the fn name less specific again

* Add enqueue/timeout to recalculateRowHeight updates

- to avoid race conditions with cache being cleared

* Remove clearHeightsCache completely

* Unset row+column height values on unmount (#3)

* Add unit test for new unsetRowHeight

+ add optional isAutoHeight check

* Remove hidden columns from row height cache

* Early return in getRowHeight

Co-authored-by: Chandler Prall <[email protected]>
@cee-chen cee-chen force-pushed the datagrid-computed-styles branch from c359430 to 8cbe865 Compare October 28, 2021 19:45
ym pushed a commit to ym/eui that referenced this pull request Oct 29, 2021
…to` (elastic#5281)

* Remove isHeightSame check

* Remove same height check from shouldComponentUpdate

- if we're not checking for sameHeight in componentDidUpdate, we also likely don't need this anymore, and all dynamic user changes appear to work without this code

* [Proposed refactors]

- Rename `recalculateRowHeight` to `setAutoRowHeight`

- DRY out setAutoRowHeight to be reusable by both the resize observer and during props update (NB: This leads to some repetition with the height being obtained twice, but will not be an issue shortly as I'll be refactoring/removing the cell wrapper observer in a future PR)

- Refactor rowHeightUtils.isAutoHeight to accept an undefined rowHeightsOptions

* Improve unit tests

* Add changelog entry

* [PR feedback] Fix `isAutoHeight` false positive
- occurs if the `defaultHeight` is auto but a specific `rowHeights` line override is not auto

TODO: Write a unit test for this in the future

* [PR feedback/Discover testing] Trigger component update when rowHeightsOptions changes

* [cleanup] Remove now-unused compareHeights util

+ clean up mock rowHeightUtils as well

* [revert] rename setAutoRowHeight back to recalculateRowHeight

- lineCount in elastic#5284 will shortly be using the row height cache in addition to auto, so I'm making the fn name less specific again

* Add enqueue/timeout to recalculateRowHeight updates

- to avoid race conditions with cache being cleared

* Remove clearHeightsCache completely

* Unset row+column height values on unmount (elastic#3)

* Add unit test for new unsetRowHeight

+ add optional isAutoHeight check

* Remove hidden columns from row height cache

* Early return in getRowHeight

Co-authored-by: Chandler Prall <[email protected]>
NB: Saving this commit for historical purposes; but the issue with this solution is that lineHeight & fontSize change between legacy and Amsterdam theme and thus the calculations are wrong on the legacy theme

- Switch to static padding/fontSize/lineHeights maps instead of classes

- Undefined line height will NaN without euiDataGridRow CSS

- Remove this.fakeCell class instance since it's only used in one place
- Export single default/initial row height const which data_grid_body imports, instead of declaring 2 slightly different heights in 2 different locations

- fix rowIndex check that would fail on a rowIndex of 0
…nto a getRowHeightOption helper

- this helper DRYs out returning either a specific row's height config or the defaultHeight - we had this logic essentially repeated in multiple places
@cee-chen cee-chen force-pushed the datagrid-computed-styles branch from 2655093 to 2d9edf4 Compare October 29, 2021 13:04
- Pull out shared/same props into a single obj instead of repeating it 3x & making it less clear which props are different depending on the cell type

- remove getRowHeight fn from being passed down; it's not being used

- pass setRowHeight only to first column as a performance optimization; this will be used for lineCount heights and since lineCount heights are all the same, we really only need to run it once

- clean up footer row cells as well while we're here
…_grid_body

- IIRC this is what the state was originally used for; might as well go back to using it for lineCount
- Those were only being used for lineCount calculations; otherwise only padding is needed

+ remove numberFromPx in favor of a map with existing numbers
…les & remove getComputedCellStyles

- re: getComputedCellStyles - I'm not seeing this affect either numeric, lineCount, or auto heights when changing grid density, hence me removing this
Now that we aren't using this CSS for computed styles any longer, we can remove them
- we're exclusively watching the cell content now for both auto and line count heights
- to make it more specific and clearer from the fn name what row height behavior this belongs to
- add unit tests for recalculateLineCountHeight,

- mockRowHeightUtils - allow some generic methods to return their actual fns for expedience

- Remove jest.mock from data_grid.test.tsx - the __mocks__ folder automatically mocks it

- update snapshots/returns accordingly
@cee-chen cee-chen force-pushed the datagrid-computed-styles branch from 2d9edf4 to e4a77cf Compare October 29, 2021 14:08
@cee-chen cee-chen marked this pull request as ready for review October 29, 2021 14:23
@cee-chen cee-chen changed the title [EuiDataGrid] Fix Firefox & Safari not correctly calculating cell heights based on computed styles [EuiDataGrid] Refactor row height calculations to no longer need computed styles on grid init Oct 29, 2021
@cee-chen
Copy link
Contributor Author

jenkins test this

Copy link
Contributor Author

@cee-chen cee-chen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR ended up being a whole lot of cleanup mixed in with the actual functionality fixes 🙈 I recommend following along by commit (the cleanups in particular I tried to separate out into their own commits), but I'll also attempt to walk through the actual functionality changes/fixes below!

Comment on lines +20 to 25
// TODO: Once JS variables are available, use them here instead of hard-coded maps
const cellPaddingsMap: Record<EuiDataGridStyleCellPaddings, number> = {
s: 4,
m: 6,
l: 8,
};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This static padding map is what solves the issue for auto height rows:

Before

After

Comment on lines +147 to 155
calculateHeightForLineCount(cellRef: HTMLElement, lineCount: number) {
const computedStyles = window.getComputedStyle(cellRef, null);
const lineHeight = parseInt(computedStyles.lineHeight, 10) || 24;

return Math.ceil(
lineCount * this.styles.lineHeight +
lineCount * lineHeight +
this.styles.paddingTop +
this.styles.paddingBottom
);
Copy link
Contributor Author

@cee-chen cee-chen Oct 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change here (getting the computed line-height from the cell rather than on grid init) is what makes the lineCount height calculation work as before. In particular, the key to solving the 'styles not available on load' bug is that calculateHeightForLineCount gets called by the cell content resizeObserver, which means that if styles load after grid init, the resizeObserver fires and row height will get calculated & updated after. This also applies to/works for density changes!

The full commit is here for reference: 905031a

Here's an example of this working locally on a demo with a lineCount: 10:

lineCount.mp4

Copy link
Contributor Author

@cee-chen cee-chen Oct 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should also mention the way lineCount cells now get and set their height also is from the minRowHeight/setRowHeights state set in data_grid_body.tsx:

const [minRowHeight, setRowHeight] = useState(DEFAULT_ROW_HEIGHT);

I believe this was also originally the way it worked previously on datagrid's first inception, so what's old becomes new, etc. 😅 (but I was able to clean up the cell wrapper observer so we're now down to just 1 observer!)

@cee-chen

This comment has been minimized.

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_5284/

@cee-chen
Copy link
Contributor Author

cee-chen commented Nov 2, 2021

FYI, once this PR lands, I have a follow-up PR for right after it that does some minor organization/clean up of row_height_utils.ts and adds unit tests! 🧹

Copy link
Contributor

@chandlerprall chandlerprall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes LGreatTM! Lots of good refactoring into more followable code paths, couple extra bug fixes, solves the loading issue, etc. 🎉

Tested the published changes across Chrome, Firefox, and Safari, saw no issues with intermittent loading, flash of content or styles, virtualization, or performance.

@cee-chen
Copy link
Contributor Author

cee-chen commented Nov 3, 2021

Wahoo, thanks Chandler! 🎉

@cee-chen cee-chen enabled auto-merge (squash) November 3, 2021 15:37
@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_5284/

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_5284/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants