Skip to content

Commit

Permalink
fix(DatePicker): fix flushSync and onBlur on mobile (#3556)
Browse files Browse the repository at this point in the history
  • Loading branch information
lossir authored Dec 20, 2024
1 parent 1b76455 commit 87b990e
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 17 deletions.
12 changes: 10 additions & 2 deletions packages/react-ui/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,16 @@ export class DatePicker extends React.PureComponent<DatePickerProps, DatePickerS
}
}

public componentDidUpdate() {
public componentDidUpdate(prevProps: DatePickerProps, prevState: DatePickerState) {
const { disabled } = this.props;
const { opened } = this.state;
if (disabled && opened) {
this.close();
}

if (prevState.opened && !opened && this.isMobileLayout) {
this.handleBlur();
}
}

/**
Expand Down Expand Up @@ -295,7 +299,7 @@ export class DatePicker extends React.PureComponent<DatePickerProps, DatePickerS
onValueChange={this.props.onValueChange}
enableTodayLink={this.props.enableTodayLink}
isHoliday={this.props.isHoliday}
onCloseRequest={this.handleBlur}
onCloseRequest={this.handleMobileCloseRequest}
renderDay={props.renderDay}
onMonthChange={props.onMonthChange}
/>
Expand Down Expand Up @@ -472,4 +476,8 @@ export class DatePicker extends React.PureComponent<DatePickerProps, DatePickerS
this.props.onValueChange(value);
}
};

private handleMobileCloseRequest = () => {
this.close();
};
}
27 changes: 12 additions & 15 deletions packages/react-ui/components/DatePicker/MobilePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,26 @@ export interface MobilePickerProps

export const MobilePicker: React.FC<MobilePickerProps> = (props) => {
const locale = useLocaleForControl('DatePicker', DatePickerLocaleHelper);

const theme = getMobilePickerTheme(useContext(ThemeContext));

const calendarRef = useRef<Calendar>(null);
const inputRef = useRef<DateInput>(null);

const [{ month: monthNative, year }] = useState(() => getTodayDate());
const month = getMonthInHumanFormat(monthNative);

const onValueChange = (date: string) => {
if (props.onValueChange) {
props.onValueChange(date);
}
if (props.onCloseRequest) {
props.onCloseRequest();
}
props.onValueChange?.(date);
props.onCloseRequest?.();
};

const inputRef = useRef<DateInput>(null);
useLayoutEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
}
// fix DateInput flushSync warning in React 18
setTimeout(() => {
inputRef.current?.focus();
});
}, []);

const calendarRef = useRef<Calendar>(null);
const [{ month: monthNative, year }] = useState(() => getTodayDate());
const month = getMonthInHumanFormat(monthNative);

const onTodayClick = () => {
if (calendarRef.current) {
calendarRef.current.scrollToMonth(month, year);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { LIGHT_THEME } from '../../../lib/theming/themes/LightTheme';
import { MobilePickerDataTids } from '../MobilePicker';
import { DateSelectDataTids } from '../../../internal/DateSelect';
import { MenuDataTids } from '../../../internal/Menu';
import { componentsLocales as DayCellViewLocalesRu } from '../../Calendar/locale/locales/ru';

describe('DatePicker', () => {
describe('validate', () => {
Expand Down Expand Up @@ -553,5 +554,31 @@ describe('DatePicker', () => {
const input = within(screen.getByTestId(DatePickerDataTids.input)).getByTestId(InputLikeTextDataTids.input);
expect(input).toHaveTextContent(expectedDate);
});

it('should call onBlur after value was changed when date picked on click', async () => {
const initialDate = '10.10.2010';
const expectedDate = '20.10.2010';
let blurredDate = '';
const MobilePickerWithOnBlur = () => {
const [date, setDate] = useState(initialDate);
const handleBlur = () => {
blurredDate = date;
};
return (
<DatePicker enableTodayLink width="auto" value={date || null} onValueChange={setDate} onBlur={handleBlur} />
);
};
render(<MobilePickerWithOnBlur />);
await userEvent.click(screen.getByTestId(DatePickerDataTids.input));

const ariaLabel = `${DayCellViewLocalesRu.dayCellChooseDateAriaLabel}: ${new InternalDate({
value: expectedDate,
}).toA11YFormat()}`;

const expectedDateButton = screen.getByLabelText(ariaLabel);
await userEvent.click(expectedDateButton);

expect(blurredDate).toBe(expectedDate);
});
});
});

0 comments on commit 87b990e

Please sign in to comment.