From 1b6335ca7788b5d312a1a8229e717bbe053ee99f Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 3 Nov 2023 13:32:09 -0700 Subject: [PATCH] [cross browser fix] Webkit state update behavior for some incredibly frustrating reason, firefox correctly runs `finishParsing` after `this.setState` after `onChange` fires, but webkit browsers run it before `onChange`, thus the state shenanigans and for some even more incredibly bizarre reason, `requestAnimationFrame` works for every browser :dead_inside: --- .../date_popover/absolute_tab.test.tsx | 6 +++++ .../date_popover/absolute_tab.tsx | 25 +++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/components/date_picker/super_date_picker/date_popover/absolute_tab.test.tsx b/src/components/date_picker/super_date_picker/date_popover/absolute_tab.test.tsx index 6bdfd69cbca..517212930a6 100644 --- a/src/components/date_picker/super_date_picker/date_popover/absolute_tab.test.tsx +++ b/src/components/date_picker/super_date_picker/date_popover/absolute_tab.test.tsx @@ -18,6 +18,12 @@ jest.mock('../../date_picker', () => ({ })); describe('EuiAbsoluteTab', () => { + // mock requestAnimationFrame to fire immediately + const rafSpy = jest + .spyOn(window, 'requestAnimationFrame') + .mockImplementation((cb: Function) => cb()); + afterAll(() => rafSpy.mockRestore()); + const props = { dateFormat: 'MMM D, YYYY @ HH:mm:ss.SSS', timeFormat: 'HH:mm', diff --git a/src/components/date_picker/super_date_picker/date_popover/absolute_tab.tsx b/src/components/date_picker/super_date_picker/date_popover/absolute_tab.tsx index 672ea85841f..8eae41674e0 100644 --- a/src/components/date_picker/super_date_picker/date_popover/absolute_tab.tsx +++ b/src/components/date_picker/super_date_picker/date_popover/absolute_tab.tsx @@ -101,9 +101,11 @@ export class EuiAbsoluteTab extends Component< parseUserDateInput = (textInputValue: string) => { this.isParsing = true; - const finishParsing = () => { + // Wait a tick for state to finish updating (whatever gets returned), + // and then allow `onChange` user input to continue setting state + requestAnimationFrame(() => { this.isParsing = false; - }; + }); const invalidDateState = { textInputValue, @@ -111,7 +113,7 @@ export class EuiAbsoluteTab extends Component< valueAsMoment: null, }; if (!textInputValue) { - return this.setState(invalidDateState, finishParsing); + return this.setState(invalidDateState); } const { onChange, dateFormat } = this.props; @@ -128,17 +130,14 @@ export class EuiAbsoluteTab extends Component< if (dateIsValid) { onChange(valueAsMoment.toISOString()); - this.setState( - { - textInputValue: valueAsMoment.format(this.props.dateFormat), - valueAsMoment: valueAsMoment, - hasUnparsedText: false, - isTextInvalid: false, - }, - finishParsing - ); + this.setState({ + textInputValue: valueAsMoment.format(this.props.dateFormat), + valueAsMoment: valueAsMoment, + hasUnparsedText: false, + isTextInvalid: false, + }); } else { - this.setState(invalidDateState, finishParsing); + this.setState(invalidDateState); } };