From 23cdf8606a80c90d5d725d2453b6cc3d56255fd0 Mon Sep 17 00:00:00 2001 From: Cee Chen <549407+cee-chen@users.noreply.github.com> Date: Sat, 2 Dec 2023 17:01:55 -0800 Subject: [PATCH] [EuiSelectable] Fix text truncation when a scrollbar is present (#7392) --- src/components/selectable/selectable.spec.tsx | 17 +++++++++++++ .../selectable_list/selectable_list.test.tsx | 16 +++++++++++++ .../selectable_list/selectable_list.tsx | 24 ++++++++++++------- upcoming_changelogs/7392.md | 3 +++ 4 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 upcoming_changelogs/7392.md diff --git a/src/components/selectable/selectable.spec.tsx b/src/components/selectable/selectable.spec.tsx index 30cb60cb987..6c43f3a6957 100644 --- a/src/components/selectable/selectable.spec.tsx +++ b/src/components/selectable/selectable.spec.tsx @@ -284,6 +284,23 @@ describe('EuiSelectable', () => { ); }); + it('correctly accounts for scrollbar width', () => { + const multipleOptions = Array.from({ length: 5 }).map( + () => sharedProps.options[0] + ); + cy.realMount( + + ); + + cy.get('[data-test-subj="truncatedText"]') + .first() + .should('have.text', 'Lorem ipsum …iscing elit.'); + }); + it('correctly accounts for the keyboard focus badge', () => { cy.realMount(); diff --git a/src/components/selectable/selectable_list/selectable_list.test.tsx b/src/components/selectable/selectable_list/selectable_list.test.tsx index 140fa0ce454..847ed388948 100644 --- a/src/components/selectable/selectable_list/selectable_list.test.tsx +++ b/src/components/selectable/selectable_list/selectable_list.test.tsx @@ -362,6 +362,13 @@ describe('EuiSelectableListItem', () => { }); describe('truncation performance optimization', () => { + // Mock requestAnimationFrame + beforeEach(() => { + jest + .spyOn(window, 'requestAnimationFrame') + .mockImplementation((cb: Function) => cb()); + }); + it('does not render EuiTextTruncate if not virtualized and text is wrapping', () => { const { container } = render( { }); it('attempts to use a default optimized option width calculated from the wrapping EuiAutoSizer', () => { + // jsdom doesn't return valid element offsetWidths, so we have to mock it here + Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { + configurable: true, + value: 600, + }); + const { container } = render( { expect( container.querySelector('[data-resize-observer]') ).not.toBeInTheDocument(); + + // Reset jsdom mock + Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { value: 0 }); }); it('falls back to individual resize observers if options have append/prepend nodes', () => { diff --git a/src/components/selectable/selectable_list/selectable_list.tsx b/src/components/selectable/selectable_list/selectable_list.tsx index 7e907e050e9..9812d3a9e77 100644 --- a/src/components/selectable/selectable_list/selectable_list.tsx +++ b/src/components/selectable/selectable_list/selectable_list.tsx @@ -479,15 +479,23 @@ export class EuiSelectableList extends Component< const checkedIconOffset = this.props.showIcons === false ? 0 : 28; // Defaults to true this.focusBadgeOffset = this.props.onFocusBadge === false ? 0 : 46; - this.setState({ - defaultOptionWidth: containerWidth - paddingOffset - checkedIconOffset, - }); + // Wait a tick for the listbox ref to update before proceeding + requestAnimationFrame(() => { + const scrollbarOffset = this.listBoxRef + ? containerWidth - this.listBoxRef.offsetWidth + : 0; - // Potentially force list rows to rerender on dynamic resize as well, - // but try to do it as lightly as possible - if (truncationProps || (searchable && searchValue)) { - this.forceVirtualizedListRowRerender(); - } + this.setState({ + defaultOptionWidth: + containerWidth - scrollbarOffset - paddingOffset - checkedIconOffset, + }); + + // Potentially force list rows to rerender on dynamic resize as well, + // but try to do it as lightly as possible + if (truncationProps || (searchable && searchValue)) { + this.forceVirtualizedListRowRerender(); + } + }); }; getTruncationProps = (option: EuiSelectableOption, isFocused: boolean) => { diff --git a/upcoming_changelogs/7392.md b/upcoming_changelogs/7392.md new file mode 100644 index 00000000000..4b87c9f6f8b --- /dev/null +++ b/upcoming_changelogs/7392.md @@ -0,0 +1,3 @@ +**Bug fixes** + +- Fixed a bug with `EuiSelectable`s with custom `truncationProps`, where scrollbar widths were not being accounted for