Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DatePicker with date-fns bug when typing in the date input #47241

Open
Sebastian-Debicki opened this issue Jan 30, 2024 · 7 comments
Open

DatePicker with date-fns bug when typing in the date input #47241

Sebastian-Debicki opened this issue Jan 30, 2024 · 7 comments
Labels
help wanted The suggestion or request has been accepted, we need you to help us by sending a pull request. Inactive

Comments

@Sebastian-Debicki
Copy link

Sebastian-Debicki commented Jan 30, 2024

Reproduction link

Edit on CodeSandbox

Steps to reproduce

Select date
Manually update day by typing in the input e.g. 15
DatePicker will change date after inputing 1 not allowing to enter 5
https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExM2NiNTc2aDB2NmRieGduZmEwdHk1dTk4bWhkNTZ4OGszeWNvcmUwbSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/vDCB6mBplGAziysllv/giphy.gif

What is expected?

Date should be correctly modified.

What is actually happening?

Date is not correctly modified, pointed place is jumping to the end when removing, can't modify correctly date or time.

Environment Info
antd 4.24.8
React 18.2.0
System macOS 14.0 (23A344)
Browser Google Chrome Version 120.0.6099.234
@zombieJ
Copy link
Member

zombieJ commented Jan 30, 2024

Seems date-fns match the date format not in strict check.

@zombieJ zombieJ added help wanted The suggestion or request has been accepted, we need you to help us by sending a pull request. and removed unconfirmed labels Jan 30, 2024
Copy link
Contributor

Hello @Sebastian-Debicki. We totally like your proposal/feedback, welcome to send us a Pull Request for it. Please send your Pull Request to proper branch (feature branch for the new feature, master for bugfix and other changes), fill the Pull Request Template here, provide changelog/TypeScript/documentation/test cases if needed and make sure CI passed, we will review it soon. We appreciate your effort in advance and looking forward to your contribution!

你好 @Sebastian-Debicki,我们完全同意你的提议/反馈,欢迎直接在此仓库 创建一个 Pull Request 来解决这个问题。请将 Pull Request 发到正确的分支(新特性发到 feature 分支,其他发到 master 分支),务必填写 Pull Request 内的预设模板,提供改动所需相应的 changelog、TypeScript 定义、测试用例、文档等,并确保 CI 通过,我们会尽快进行 Review,提前感谢和期待您的贡献。

giphy

@Sebastian-Debicki
Copy link
Author

Seems date-fns match the date format not in strict check.

@zombieJ Can you tell something more about this? I checked documentation and there is nothing about some strict mode. Can I fix this somehow?

@Sebastian-Debicki
Copy link
Author

Sebastian-Debicki commented Feb 5, 2024

@zombieJ thank you for help
Here is my workaround solution for this issue. Maybe it will be useful to someone:

import dateFnsGenerateConfig from 'rc-picker/lib/generate/dateFns';
import generatePicker from 'antd/es/date-picker/generatePicker';
import { isValid, parse, format } from 'date-fns';
import * as Locale from 'date-fns/locale';

import 'antd/es/date-picker/style/index';

const dealLocal = (str: string) => {
  return str.replace(/_/g, '');
};

export const DatePicker = generatePicker<Date>({
  ...dateFnsGenerateConfig,
  locale: {
    ...dateFnsGenerateConfig.locale,
    parse: (locale, text, formats) => {
      const validFormat = formats.some((currentFormat) => {
        const parsedDate = parse(text, currentFormat, new Date(), {
          locale: Locale[dealLocal(locale) as keyof typeof Locale],
        });
        return isValid(parsedDate) && format(parsedDate, currentFormat) === text;
      });

      if (validFormat) {
        return parse(text, formats[0], new Date(), {
          locale: Locale[dealLocal(locale) as keyof typeof Locale],
        });
      } else {
        return null;
      }
    },
  },
});

@xsjcTony
Copy link
Contributor

xsjcTony commented Feb 5, 2024

@Sebastian-Debicki @zombieJ I think maybe we should keep this open until it's resolved out of the box without any workaround, or at least we should post the corresponding workaround in the docs.

It generally doesn't make sense for who's new here and encounters the error after following the docs to setup.

What's your opinion?

@thomastvedt
Copy link

When using date-fns it doesn't make sense to import all locales (like this: https://github.com/react-component/picker/blob/d0f9d1d8031aff816be0cb436e52500310226cea/src/generate/dateFns.ts#L29)

I created a separate issue for this here: react-component/picker#721

I noticed this commit in the rc-input library which fixes the parse issue: react-component/picker@72ccd4b
this is basically the same as the workaround above?

I assume this is already included in the latest antd version. If I import this:
import dateFnsGenerateConfig from 'rc-picker/lib/generate/dateFns';

and create a picker:

const PickerDateFnsFromAntd = generatePicker<Date>(dateFnsGenerateConfig);

backspace works as expected 👌 Since the official documentation (https://ant.design/docs/react/use-custom-date-library#use-date-fns) references the updated code above I think this issue can be closed as completed.

For the future me, this is my variant which doesn't load all locales from date-fns (updated with workaround above / updated :
I use this to lazy load only the users selected locale.

import { Locale as DateFnsLocale } from 'date-fns/locale/types';
import {
  addDays,
  addMonths,
  addYears,
  Day,
  endOfMonth,
  format as formatDate,
  getDate,
  getDay,
  getHours,
  getMilliseconds,
  getMinutes,
  getMonth,
  getSeconds,
  getWeek,
  getYear,
  isAfter,
  isValid,
  Month,
  parse as parseDate,
  setDate,
  setHours,
  setMilliseconds,
  setMinutes,
  setMonth,
  setSeconds,
  setYear,
  startOfWeek,
} from 'date-fns';

import { GenerateConfig } from 'rc-picker/es/generate';

function localeParse(format: string) {
  return format
    .replace(/Y/g, 'y')
    .replace(/D/g, 'd')
    .replace(/gggg/, 'yyyy')
    .replace(/g/g, 'G')
    .replace(/([Ww])o/g, 'wo');
}

/**
 * Represents a date configuration object for generating dates with Ant Design.
 * This is the default config suggested by ant design (except locale)
 */
const dateFnsGenerateConfigByAntDesign: Omit<GenerateConfig<Date>, 'locale'> = {
  // get
  getNow: () => new Date(),
  getFixedDate: (string) => new Date(string),
  getEndDate: (date) => endOfMonth(date),
  getWeekDay: (date) => getDay(date),
  getYear: (date) => getYear(date),
  getMonth: (date) => getMonth(date),
  getDate: (date) => getDate(date),
  getHour: (date) => getHours(date),
  getMinute: (date) => getMinutes(date),
  getSecond: (date) => getSeconds(date),
  getMillisecond: (date) => getMilliseconds(date),

  // set
  addYear: (date, diff) => addYears(date, diff),
  addMonth: (date, diff) => addMonths(date, diff),
  addDate: (date, diff) => addDays(date, diff),
  setYear: (date, year) => setYear(date, year),
  setMonth: (date, month) => setMonth(date, month),
  setDate: (date, num) => setDate(date, num),
  setHour: (date, hour) => setHours(date, hour),
  setMinute: (date, minute) => setMinutes(date, minute),
  setSecond: (date, second) => setSeconds(date, second),
  setMillisecond: (date, ms) => setMilliseconds(date, ms),

  // Compare
  isAfter: (date1, date2) => isAfter(date1, date2),
  isValidate: (date) => isValid(date),
};

/**
 * Returns localized generate configuration object for rc-picker.
 * Based on this from ant design / rc-picker, except stupid date import: https://github.com/react-component/picker/blob/e3f8437ad9c8b280868864a56aaa722c129e354b/src/generate/dateFns.ts#L27
 * Adjusted to fix keyboard input issues according to this: https://github.com/react-component/picker/commit/72ccd4b23c7f8976311d911ea7547327315de0f4
 * @param {DateFnsLocale} dateFnsLocale - The date-fns locale to be used.
 * @returns {GenerateConfig<Date>} - The localized generate configuration.
 */
const getLocalizedGenerateConfig = (dateFnsLocale: DateFnsLocale): GenerateConfig<Date> => {
  return {
    ...dateFnsGenerateConfigByAntDesign,
    getFixedDate: (fixed: string) => {
      return parseDate(fixed, 'yyyy-MM-dd', new Date());
    },
    // NOTE: This is our rc-picker locale config. We insert our date-fns functions here + our current selected date-fns locale
    // The "locale" from ant design is discarded.
    locale: {
      getWeekFirstDay: () => dateFnsLocale.options?.weekStartsOn || 1,
      getWeekFirstDate: (locale, date) =>
        startOfWeek(date, {
          locale: dateFnsLocale,
          weekStartsOn: dateFnsLocale.options?.weekStartsOn || 1,
        }),
      getWeek: (locale, date) =>
        getWeek(date, {
          locale: dateFnsLocale,
          weekStartsOn: dateFnsLocale.options?.weekStartsOn || 1,
        }),
      getShortWeekDays: () => {
        return Array.from({ length: 7 }).map((_, day) => {
          return dateFnsLocale.localize?.day(day as Day, { width: 'short' });
        });
      },
      getShortMonths: () => {
        return Array.from({ length: 12 }).map((_, month) =>
          dateFnsLocale.localize?.month(month as Month, { width: 'abbreviated' }),
        );
      },
      format: (locale, date, format): string => {
        if (!isValid(date)) {
          return 'Invalid Date';
        }
        return formatDate(date, localeParse(format), {
          locale: dateFnsLocale,
        });
      },
      parse: (locale, text, formats) => {
        const validFormat = formats.some((currentFormat) => {
          const parsedDate = parseDate(text, currentFormat, new Date(), {
            locale: dateFnsLocale,
          });
          return isValid(parsedDate) && formatDate(parsedDate, currentFormat) === text;
        });

        if (validFormat) {
          return parseDate(text, formats[0], new Date(), {
            locale: dateFnsLocale,
          });
        } else {
          return null;
        }
      },
    },
  };
};

export default getLocalizedGenerateConfig;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted The suggestion or request has been accepted, we need you to help us by sending a pull request. Inactive
Projects
None yet
Development

No branches or pull requests

5 participants