Skip to content

Commit

Permalink
fix: dateFns wrong format when typing date (#817)
Browse files Browse the repository at this point in the history
* fix: dateFns wrong format when typing date

* test(date fns): typing a date should not parse it if not complete
  • Loading branch information
jvnm-dev authored Jul 9, 2024
1 parent 7cf70bf commit 72ccd4b
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 7 deletions.
33 changes: 27 additions & 6 deletions src/generate/dateFns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,30 @@ const localeParse = (format: string) => {
.replace(/([Ww])o/g, 'wo');
};

const parse = (text: string, format: string, locale: string) => {
return parseDate(text, localeParse(format), new Date(), { locale: getLocale(locale) });
}

/**
* Check if the text is a valid date considering the format and locale
*
* This is a strict check, the date string must match the format exactly.
* Date-fns allows some flexibility in parsing dates, for example, it will parse "30/01/2" as "30/01/002".
* This behavior is not desirable in our case, so we need to check if the date string matches the format exactly.
*
* @param text the date string
* @param format the date format to use
* @param locale the locale to use
*/
const isStrictValidDate = (text: string, format: string, locale: string) => {
const date = parse(text, format, locale);
if (!isValid(date)) {
return false;
}
const formattedDate = formatDate(date, format, { locale: getLocale(locale) });
return text === formattedDate;
}

const generateConfig: GenerateConfig<Date> = {
// get
getNow: () => new Date(),
Expand Down Expand Up @@ -106,12 +130,9 @@ const generateConfig: GenerateConfig<Date> = {
parse: (locale, text, formats) => {
for (let i = 0; i < formats.length; i += 1) {
const format = localeParse(formats[i]);
const formatText = text;
const date = parseDate(formatText, format, new Date(), {
locale: getLocale(locale),
});
if (isValid(date)) {
return date;

if (isStrictValidDate(text, format, locale)) {
return parse(text, format, locale);
}
}
return null;
Expand Down
18 changes: 17 additions & 1 deletion tests/keyboard.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import KeyCode from 'rc-util/lib/KeyCode';
import { resetWarned } from 'rc-util/lib/warning';
import React from 'react';
import {
closePicker,
closePicker, DateFnsSinglePicker,
DayPicker,
DayPickerPanel,
DayRangePicker,
Expand Down Expand Up @@ -130,6 +130,22 @@ describe('Picker.Keyboard', () => {
});
});

describe('typing date with date-fns', () => {
it('should not parse date if not matching format', () => {
const { container } = render(<DateFnsSinglePicker format="dd/MM/YYYY" />);
const input = container.querySelector('input');

fireEvent.change(input, {
target: {
// Typing date partially. Picker should not try to parse it as a valid date
value: "01/01/20",
},
});

expect(input.value).toEqual("01/01/20");
});
})

return;
it('open to select', () => {
const onChange = jest.fn();
Expand Down
18 changes: 18 additions & 0 deletions tests/util/commonUtil.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {
import dayGenerateConfig from '../../src/generate/dayjs';
import enUS from '../../src/locale/en_US';
import zh_CN from '../../src/locale/zh_CN';
import enGB from '../../src/locale/en_GB';

import type { PickerBaseProps, PickerDateProps, PickerTimeProps } from '../../src/Picker';
import type {
PickerPanelBaseProps,
Expand All @@ -35,6 +37,8 @@ import {
type RangePickerDateProps,
type RangePickerTimeProps,
} from '../../src/RangePicker';
import dateFnsGenerateConfig from '../../src/generate/dateFns';
import SinglePicker from '../../src/PickerInput/SinglePicker';

dayjs.locale('zh-cn');
dayjs.extend(buddhistEra);
Expand Down Expand Up @@ -226,3 +230,17 @@ export function getDay(str: string): Dayjs {
}
throw new Error(`Format not match with: ${str}`);
}
// ===================================== Date fns =====================================
const dateFnsLocale = {
locale: enGB,
generateConfig: dateFnsGenerateConfig,
};

type DateFnsSinglePickerProps = Omit<PickerProps<Date>, 'locale' | 'generateConfig'> & React.RefAttributes<PickerRef>;

export const DateFnsSinglePicker = (props: DateFnsSinglePickerProps) => {
return <SinglePicker
{...dateFnsLocale}
{...props}
/>
}

0 comments on commit 72ccd4b

Please sign in to comment.