From c94c67680fb0c87ed9708042ffec421223166828 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 1 Dec 2023 09:34:40 -0800 Subject: [PATCH 1/5] [REVERT ME] Update demo to show bug --- src-docs/src/views/selectable/selectable_truncation.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src-docs/src/views/selectable/selectable_truncation.tsx b/src-docs/src/views/selectable/selectable_truncation.tsx index 81863d3f954..15c7ffb9a66 100644 --- a/src-docs/src/views/selectable/selectable_truncation.tsx +++ b/src-docs/src/views/selectable/selectable_truncation.tsx @@ -131,6 +131,7 @@ export default () => { searchable={true} options={options} onChange={(updatedOptions) => setOptions(updatedOptions)} + height={100} listProps={{ isVirtualized: textWrap !== 'wrap', textWrap, From de96e8ed704e615a55ca1d7cd9cdfac23c9beb80 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 1 Dec 2023 09:35:55 -0800 Subject: [PATCH 2/5] Add optimization affordance for scrollbars --- src/components/selectable/selectable.spec.tsx | 17 +++++++++++++ .../selectable_list/selectable_list.tsx | 24 ++++++++++++------- 2 files changed, 33 insertions(+), 8 deletions(-) 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.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) => { From afb81ebb9bd20172fc356014e29aedcd0d23fe5e Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 1 Dec 2023 09:51:10 -0800 Subject: [PATCH 3/5] Update unit tests - to work around new non-jest/jsdom-friendly behavior --- .../selectable_list/selectable_list.test.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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', () => { From 0d08f5f96033f17c4735e12d6a661529c345e726 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 1 Dec 2023 14:53:11 -0800 Subject: [PATCH 4/5] changleog --- changelogs/upcoming/7392.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelogs/upcoming/7392.md diff --git a/changelogs/upcoming/7392.md b/changelogs/upcoming/7392.md new file mode 100644 index 00000000000..4b87c9f6f8b --- /dev/null +++ b/changelogs/upcoming/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 From 2e271fb6c13948089791476863060fdac22f73a1 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Sat, 2 Dec 2023 16:33:36 -0800 Subject: [PATCH 5/5] Revert "[REVERT ME] Update demo to show bug" This reverts commit c94c67680fb0c87ed9708042ffec421223166828. --- src-docs/src/views/selectable/selectable_truncation.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src-docs/src/views/selectable/selectable_truncation.tsx b/src-docs/src/views/selectable/selectable_truncation.tsx index 15c7ffb9a66..81863d3f954 100644 --- a/src-docs/src/views/selectable/selectable_truncation.tsx +++ b/src-docs/src/views/selectable/selectable_truncation.tsx @@ -131,7 +131,6 @@ export default () => { searchable={true} options={options} onChange={(updatedOptions) => setOptions(updatedOptions)} - height={100} listProps={{ isVirtualized: textWrap !== 'wrap', textWrap,