Repository: Hacker0x01/react-datepicker
Pull request #4727 (2024-04-25 07:36:23)

feat: added package manager property
---
---
name: Added package manager property
---
 Description: 

<img width="912" alt="2024-04-25 о 10 39 35" src="https://github.com/Hacker0x01/react-datepicker/assets/90615138/3780429e-b2be-42ff-94a8-3eaadcebad23">

 
**Changes**
 Added package manager property to package.json to avoid wrong behavior when you locally use yarn version 2 and newer. 
 
## Contribution checklist
- [x] I have followed the [contributing guidelines](https://github.com/Hacker0x01/react-datepicker/blob/main/CONTRIBUTING.md).
- [x] I have added sufficient test coverage for my changes.
- [x] I have formatted my code with Prettier and checked for linting issues with ESLint for code readability.


Patch:
diff --git a/package.json b/package.json
index be1dc2e9..5bda6bba 100644
--- a/package.json
+++ b/package.json
@@ -121,5 +121,6 @@
       "prettier --write",
       "git add"
     ]
-  }
+  },
+  "packageManager": "yarn@1.22.17"
 }
diff --git a/src/date_utils.ts b/src/date_utils.ts
index 7f805b27..c8a9a1d4 100644
--- a/src/date_utils.ts
+++ b/src/date_utils.ts
@@ -697,10 +697,7 @@ export function getWeekdayShortInLocale(date: Date, locale: string): string {
  * @param locale - The locale to use for formatting.
  * @returns - The month.
  */
-export function getMonthInLocale(
-  month: number,
-  locale?: string | LocaleObj,
-): string {
+export function getMonthInLocale(month: number, locale: string): string {
   return formatDate(setMonth(newDate(), month), "LLLL", locale);
 }
 
@@ -711,10 +708,7 @@ export function getMonthInLocale(
  * @param locale - The locale to use for formatting.
  * @returns - The short month.
  */
-export function getMonthShortInLocale(
-  month: number,
-  locale?: string | LocaleObj,
-): string {
+export function getMonthShortInLocale(month: number, locale: string): string {
   return formatDate(setMonth(newDate(), month), "LLL", locale);
 }
 
diff --git a/src/month_dropdown.tsx b/src/month_dropdown.jsx
similarity index 60%
rename from src/month_dropdown.tsx
rename to src/month_dropdown.jsx
index d4cc6867..2ddf1c72 100644
--- a/src/month_dropdown.tsx
+++ b/src/month_dropdown.jsx
@@ -1,41 +1,32 @@
 import React from "react";
+import PropTypes from "prop-types";
 import MonthDropdownOptions from "./month_dropdown_options";
 import onClickOutside from "react-onclickoutside";
-import type { LocaleObj } from "./date_utils";
-import { getMonthShortInLocale, getMonthInLocale } from "./date_utils";
+import * as utils from "./date_utils";
 
 const WrappedMonthDropdownOptions = onClickOutside(MonthDropdownOptions);
 
-interface MonthDropdownProps {
-  dropdownMode: "scroll" | "select";
-  locale?: string | LocaleObj;
-  month: number;
-  onChange: (month: number | string) => void;
-  useShortMonthInDropdown?: boolean;
-}
-
-interface MonthDropdownState {
-  dropdownVisible: boolean;
-}
+export default class MonthDropdown extends React.Component {
+  static propTypes = {
+    dropdownMode: PropTypes.oneOf(["scroll", "select"]).isRequired,
+    locale: PropTypes.string,
+    month: PropTypes.number.isRequired,
+    onChange: PropTypes.func.isRequired,
+    useShortMonthInDropdown: PropTypes.bool,
+  };
 
-export default class MonthDropdown extends React.Component<
-  MonthDropdownProps,
-  MonthDropdownState
-> {
-  state: MonthDropdownState = {
+  state = {
     dropdownVisible: false,
   };
 
-  renderSelectOptions = (monthNames: string[]): JSX.Element[] =>
-    monthNames.map<JSX.Element>(
-      (m: string, i: number): JSX.Element => (
-        <option key={m} value={i}>
-          {m}
-        </option>
-      ),
-    );
+  renderSelectOptions = (monthNames) =>
+    monthNames.map((M, i) => (
+      <option key={i} value={i}>
+        {M}
+      </option>
+    ));
 
-  renderSelectMode = (monthNames: string[]): JSX.Element => (
+  renderSelectMode = (monthNames) => (
     <select
       value={this.props.month}
       className="react-datepicker__month-select"
@@ -45,7 +36,7 @@ export default class MonthDropdown extends React.Component<
     </select>
   );
 
-  renderReadView = (visible: boolean, monthNames: string[]): JSX.Element => (
+  renderReadView = (visible, monthNames) => (
     <div
       key="read"
       style={{ visibility: visible ? "visible" : "hidden" }}
@@ -59,7 +50,7 @@ export default class MonthDropdown extends React.Component<
     </div>
   );
 
-  renderDropdown = (monthNames: string[]): JSX.Element => (
+  renderDropdown = (monthNames) => (
     <WrappedMonthDropdownOptions
       key="dropdown"
       month={this.props.month}
@@ -69,32 +60,32 @@ export default class MonthDropdown extends React.Component<
     />
   );
 
-  renderScrollMode = (monthNames: string[]): JSX.Element[] => {
+  renderScrollMode = (monthNames) => {
     const { dropdownVisible } = this.state;
-    const result = [this.renderReadView(!dropdownVisible, monthNames)];
+    let result = [this.renderReadView(!dropdownVisible, monthNames)];
     if (dropdownVisible) {
       result.unshift(this.renderDropdown(monthNames));
     }
     return result;
   };
 
-  onChange = (month: number | string): void => {
+  onChange = (month) => {
     this.toggleDropdown();
     if (month !== this.props.month) {
       this.props.onChange(month);
     }
   };
 
-  toggleDropdown = (): void =>
+  toggleDropdown = () =>
     this.setState({
       dropdownVisible: !this.state.dropdownVisible,
     });
 
-  render(): JSX.Element {
+  render() {
     const monthNames = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].map(
       this.props.useShortMonthInDropdown
-        ? (m) => getMonthShortInLocale(m, this.props.locale)
-        : (m) => getMonthInLocale(m, this.props.locale),
+        ? (M) => utils.getMonthShortInLocale(M, this.props.locale)
+        : (M) => utils.getMonthInLocale(M, this.props.locale),
     );
 
     let renderedDropdown;
diff --git a/src/month_dropdown_options.jsx b/src/month_dropdown_options.jsx
new file mode 100644
index 00000000..6cc04e18
--- /dev/null
+++ b/src/month_dropdown_options.jsx
@@ -0,0 +1,47 @@
+import React from "react";
+import PropTypes from "prop-types";
+
+export default class MonthDropdownOptions extends React.Component {
+  static propTypes = {
+    onCancel: PropTypes.func.isRequired,
+    onChange: PropTypes.func.isRequired,
+    month: PropTypes.number.isRequired,
+    monthNames: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,
+  };
+
+  isSelectedMonth = (i) => this.props.month === i;
+
+  renderOptions = () => {
+    return this.props.monthNames.map((month, i) => (
+      <div
+        className={
+          this.isSelectedMonth(i)
+            ? "react-datepicker__month-option react-datepicker__month-option--selected_month"
+            : "react-datepicker__month-option"
+        }
+        key={month}
+        onClick={this.onChange.bind(this, i)}
+        aria-selected={this.isSelectedMonth(i) ? "true" : undefined}
+      >
+        {this.isSelectedMonth(i) ? (
+          <span className="react-datepicker__month-option--selected">✓</span>
+        ) : (
+          ""
+        )}
+        {month}
+      </div>
+    ));
+  };
+
+  onChange = (month) => this.props.onChange(month);
+
+  handleClickOutside = () => this.props.onCancel();
+
+  render() {
+    return (
+      <div className="react-datepicker__month-dropdown">
+        {this.renderOptions()}
+      </div>
+    );
+  }
+}
diff --git a/src/month_dropdown_options.tsx b/src/month_dropdown_options.tsx
deleted file mode 100644
index 853f60a6..00000000
--- a/src/month_dropdown_options.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import React from "react";
-
-interface MonthDropdownOptionsProps {
-  onCancel: VoidFunction;
-  onChange: (month: number) => void;
-  month: number;
-  monthNames: string[];
-}
-
-export default class MonthDropdownOptions extends React.Component<MonthDropdownOptionsProps> {
-  isSelectedMonth = (i: number): boolean => this.props.month === i;
-
-  renderOptions = (): JSX.Element[] => {
-    return this.props.monthNames.map<JSX.Element>(
-      (month: string, i: number): JSX.Element => (
-        <div
-          className={
-            this.isSelectedMonth(i)
-              ? "react-datepicker__month-option react-datepicker__month-option--selected_month"
-              : "react-datepicker__month-option"
-          }
-          key={month}
-          onClick={this.onChange.bind(this, i)}
-          aria-selected={this.isSelectedMonth(i) ? "true" : undefined}
-        >
-          {this.isSelectedMonth(i) ? (
-            <span className="react-datepicker__month-option--selected">✓</span>
-          ) : (
-            ""
-          )}
-          {month}
-        </div>
-      ),
-    );
-  };
-
-  onChange = (month: number): void => this.props.onChange(month);
-
-  handleClickOutside = (): void => this.props.onCancel();
-
-  render(): JSX.Element {
-    return (
-      <div className="react-datepicker__month-dropdown">
-        {this.renderOptions()}
-      </div>
-    );
-  }
-}
diff --git a/src/month_year_dropdown.tsx b/src/month_year_dropdown.jsx
similarity index 69%
rename from src/month_year_dropdown.tsx
rename to src/month_year_dropdown.jsx
index 2df036df..44833110 100644
--- a/src/month_year_dropdown.tsx
+++ b/src/month_year_dropdown.jsx
@@ -1,7 +1,7 @@
 import React from "react";
+import PropTypes from "prop-types";
 import MonthYearDropdownOptions from "./month_year_dropdown_options";
 import onClickOutside from "react-onclickoutside";
-import type { LocaleObj } from "./date_utils";
 import {
   addMonths,
   formatDate,
@@ -13,34 +13,25 @@ import {
   getTime,
 } from "./date_utils";
 
-const WrappedMonthYearDropdownOptions = onClickOutside(
-  MonthYearDropdownOptions,
-);
-
-interface MonthYearDropdownProps {
-  dropdownMode: "scroll" | "select";
-  dateFormat: string;
-  locale?: string | LocaleObj;
-  minDate: Date;
-  maxDate: Date;
-  date: Date;
-  onChange: (monthYear: Date) => void;
-  scrollableMonthYearDropdown?: boolean;
-}
-
-interface MonthYearDropdownState {
-  dropdownVisible: boolean;
-}
+var WrappedMonthYearDropdownOptions = onClickOutside(MonthYearDropdownOptions);
+
+export default class MonthYearDropdown extends React.Component {
+  static propTypes = {
+    dropdownMode: PropTypes.oneOf(["scroll", "select"]).isRequired,
+    dateFormat: PropTypes.string.isRequired,
+    locale: PropTypes.string,
+    maxDate: PropTypes.instanceOf(Date).isRequired,
+    minDate: PropTypes.instanceOf(Date).isRequired,
+    date: PropTypes.instanceOf(Date).isRequired,
+    onChange: PropTypes.func.isRequired,
+    scrollableMonthYearDropdown: PropTypes.bool,
+  };
 
-export default class MonthYearDropdown extends React.Component<
-  MonthYearDropdownProps,
-  MonthYearDropdownState
-> {
-  state: MonthYearDropdownState = {
+  state = {
     dropdownVisible: false,
   };
 
-  renderSelectOptions = (): JSX.Element[] => {
+  renderSelectOptions = () => {
     let currDate = getStartOfMonth(this.props.minDate);
     const lastDate = getStartOfMonth(this.props.maxDate);
     const options = [];
@@ -59,11 +50,11 @@ export default class MonthYearDropdown extends React.Component<
     return options;
   };
 
-  onSelectChange = (e: React.ChangeEvent<HTMLSelectElement>): void => {
+  onSelectChange = (e) => {
     this.onChange(e.target.value);
   };
 
-  renderSelectMode = (): JSX.Element => (
+  renderSelectMode = () => (
     <select
       value={getTime(getStartOfMonth(this.props.date))}
       className="react-datepicker__month-year-select"
@@ -73,7 +64,7 @@ export default class MonthYearDropdown extends React.Component<
     </select>
   );
 
-  renderReadView = (visible: boolean): JSX.Element => {
+  renderReadView = (visible) => {
     const yearMonth = formatDate(
       this.props.date,
       this.props.dateFormat,
@@ -82,9 +73,10 @@ export default class MonthYearDropdown extends React.Component<
 
     return (
       <div
+        key="read"
         style={{ visibility: visible ? "visible" : "hidden" }}
         className="react-datepicker__month-year-read-view"
-        onClick={this.toggleDropdown}
+        onClick={(event) => this.toggleDropdown(event)}
       >
         <span className="react-datepicker__month-year-read-view--down-arrow" />
         <span className="react-datepicker__month-year-read-view--selected-month-year">
@@ -94,8 +86,9 @@ export default class MonthYearDropdown extends React.Component<
     );
   };
 
-  renderDropdown = (): JSX.Element => (
+  renderDropdown = () => (
     <WrappedMonthYearDropdownOptions
+      key="dropdown"
       date={this.props.date}
       dateFormat={this.props.dateFormat}
       onChange={this.onChange}
@@ -107,23 +100,19 @@ export default class MonthYearDropdown extends React.Component<
     />
   );
 
-  renderScrollMode = (): JSX.Element[] => {
+  renderScrollMode = () => {
     const { dropdownVisible } = this.state;
-    const result = [this.renderReadView(!dropdownVisible)];
+    let result = [this.renderReadView(!dropdownVisible)];
     if (dropdownVisible) {
       result.unshift(this.renderDropdown());
     }
     return result;
   };
 
-  onChange = (monthYearPoint: number | string): void => {
+  onChange = (monthYearPoint) => {
     this.toggleDropdown();
 
-    const changedDate = newDate(
-      typeof monthYearPoint === "string"
-        ? parseInt(monthYearPoint)
-        : monthYearPoint,
-    );
+    const changedDate = newDate(parseInt(monthYearPoint));
 
     if (
       isSameYear(this.props.date, changedDate) &&
@@ -135,12 +124,12 @@ export default class MonthYearDropdown extends React.Component<
     this.props.onChange(changedDate);
   };
 
-  toggleDropdown = (): void =>
+  toggleDropdown = () =>
     this.setState({
       dropdownVisible: !this.state.dropdownVisible,
     });
 
-  render(): JSX.Element {
+  render() {
     let renderedDropdown;
     switch (this.props.dropdownMode) {
       case "scroll":
diff --git a/src/month_year_dropdown_options.jsx b/src/month_year_dropdown_options.jsx
new file mode 100644
index 00000000..ecc5182e
--- /dev/null
+++ b/src/month_year_dropdown_options.jsx
@@ -0,0 +1,98 @@
+import React from "react";
+import PropTypes from "prop-types";
+import { clsx } from "clsx";
+import {
+  addMonths,
+  formatDate,
+  getStartOfMonth,
+  newDate,
+  isAfter,
+  isSameMonth,
+  isSameYear,
+  getTime,
+} from "./date_utils";
+
+function generateMonthYears(minDate, maxDate) {
+  const list = [];
+
+  let currDate = getStartOfMonth(minDate);
+  const lastDate = getStartOfMonth(maxDate);
+
+  while (!isAfter(currDate, lastDate)) {
+    list.push(newDate(currDate));
+
+    currDate = addMonths(currDate, 1);
+  }
+  return list;
+}
+
+export default class MonthYearDropdownOptions extends React.Component {
+  static propTypes = {
+    minDate: PropTypes.instanceOf(Date).isRequired,
+    maxDate: PropTypes.instanceOf(Date).isRequired,
+    onCancel: PropTypes.func.isRequired,
+    onChange: PropTypes.func.isRequired,
+    scrollableMonthYearDropdown: PropTypes.bool,
+    date: PropTypes.instanceOf(Date).isRequired,
+    dateFormat: PropTypes.string.isRequired,
+    locale: PropTypes.string,
+  };
+
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      monthYearsList: generateMonthYears(
+        this.props.minDate,
+        this.props.maxDate,
+      ),
+    };
+  }
+
+  renderOptions = () => {
+    return this.state.monthYearsList.map((monthYear) => {
+      const monthYearPoint = getTime(monthYear);
+      const isSameMonthYear =
+        isSameYear(this.props.date, monthYear) &&
+        isSameMonth(this.props.date, monthYear);
+
+      return (
+        <div
+          className={
+            isSameMonthYear
+              ? "react-datepicker__month-year-option--selected_month-year"
+              : "react-datepicker__month-year-option"
+          }
+          key={monthYearPoint}
+          onClick={this.onChange.bind(this, monthYearPoint)}
+          aria-selected={isSameMonthYear ? "true" : undefined}
+        >
+          {isSameMonthYear ? (
+            <span className="react-datepicker__month-year-option--selected">
+              ✓
+            </span>
+          ) : (
+            ""
+          )}
+          {formatDate(monthYear, this.props.dateFormat, this.props.locale)}
+        </div>
+      );
+    });
+  };
+
+  onChange = (monthYear) => this.props.onChange(monthYear);
+
+  handleClickOutside = () => {
+    this.props.onCancel();
+  };
+
+  render() {
+    let dropdownClass = clsx({
+      "react-datepicker__month-year-dropdown": true,
+      "react-datepicker__month-year-dropdown--scrollable":
+        this.props.scrollableMonthYearDropdown,
+    });
+
+    return <div className={dropdownClass}>{this.renderOptions()}</div>;
+  }
+}
diff --git a/src/month_year_dropdown_options.tsx b/src/month_year_dropdown_options.tsx
deleted file mode 100644
index 4b1678c7..00000000
--- a/src/month_year_dropdown_options.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-import React from "react";
-import { clsx } from "clsx";
-import type { LocaleObj } from "./date_utils";
-import {
-  addMonths,
-  formatDate,
-  getStartOfMonth,
-  newDate,
-  isAfter,
-  isSameMonth,
-  isSameYear,
-  getTime,
-} from "./date_utils";
-
-function generateMonthYears(minDate: Date, maxDate: Date): Date[] {
-  const list = [];
-
-  let currDate = getStartOfMonth(minDate);
-  const lastDate = getStartOfMonth(maxDate);
-
-  while (!isAfter(currDate, lastDate)) {
-    list.push(newDate(currDate));
-
-    currDate = addMonths(currDate, 1);
-  }
-  return list;
-}
-
-interface MonthYearDropdownOptionsProps {
-  minDate: Date;
-  maxDate: Date;
-  onCancel: VoidFunction;
-  onChange: (monthYear: number) => void;
-  scrollableMonthYearDropdown?: boolean;
-  date: Date;
-  dateFormat: string;
-  locale?: string | LocaleObj;
-}
-
-interface MonthYearDropdownOptionsState {
-  monthYearsList: Date[];
-}
-
-export default class MonthYearDropdownOptions extends React.Component<
-  MonthYearDropdownOptionsProps,
-  MonthYearDropdownOptionsState
-> {
-  constructor(props: Readonly<MonthYearDropdownOptionsProps>) {
-    super(props);
-
-    this.state = {
-      monthYearsList: generateMonthYears(
-        this.props.minDate,
-        this.props.maxDate,
-      ),
-    };
-  }
-
-  renderOptions = (): JSX.Element[] => {
-    return this.state.monthYearsList.map<JSX.Element>(
-      (monthYear: Date): JSX.Element => {
-        const monthYearPoint = getTime(monthYear);
-        const isSameMonthYear =
-          isSameYear(this.props.date, monthYear) &&
-          isSameMonth(this.props.date, monthYear);
-
-        return (
-          <div
-            className={
-              isSameMonthYear
-                ? "react-datepicker__month-year-option--selected_month-year"
-                : "react-datepicker__month-year-option"
-            }
-            key={monthYearPoint}
-            onClick={this.onChange.bind(this, monthYearPoint)}
-            aria-selected={isSameMonthYear ? "true" : undefined}
-          >
-            {isSameMonthYear ? (
-              <span className="react-datepicker__month-year-option--selected">
-                ✓
-              </span>
-            ) : (
-              ""
-            )}
-            {formatDate(monthYear, this.props.dateFormat, this.props.locale)}
-          </div>
-        );
-      },
-    );
-  };
-
-  onChange = (monthYear: number) => this.props.onChange(monthYear);
-
-  handleClickOutside = (): void => {
-    this.props.onCancel();
-  };
-
-  render(): JSX.Element {
-    const dropdownClass = clsx({
-      "react-datepicker__month-year-dropdown": true,
-      "react-datepicker__month-year-dropdown--scrollable":
-        this.props.scrollableMonthYearDropdown,
-    });
-
-    return <div className={dropdownClass}>{this.renderOptions()}</div>;
-  }
-}
diff --git a/src/time.tsx b/src/time.jsx
similarity index 67%
rename from src/time.tsx
rename to src/time.jsx
index 68b9a601..62c2e716 100644
--- a/src/time.tsx
+++ b/src/time.jsx
@@ -1,5 +1,5 @@
 import React from "react";
-import type { LocaleObj } from "./date_utils";
+import PropTypes from "prop-types";
 import {
   getHours,
   getMinutes,
@@ -12,63 +12,54 @@ import {
   timesToInjectAfter,
   getHoursInDay,
   isSameMinute,
-  getSeconds,
 } from "./date_utils";
+import { getSeconds } from "date-fns";
 
-interface TimeProps {
-  format?: string;
-  includeTimes?: Date[];
-  intervals: number;
-  selected?: Date;
-  openToDate?: Date;
-  onChange?: (time: Date) => void;
-  timeClassName?: (time: Date) => string;
-  todayButton?: React.ReactNode;
-  minTime?: Date;
-  maxTime?: Date;
-  excludeTimes?: Date[];
-  filterTime?: (time: Date) => boolean;
-  monthRef?: HTMLDivElement;
-  timeCaption?: string;
-  injectTimes?: Date[];
-  handleOnKeyDown?: React.KeyboardEventHandler<HTMLLIElement>;
-  locale?: string | LocaleObj;
-  showTimeSelectOnly?: boolean;
-}
-
-interface TimeState {
-  height: number | null;
-}
-
-export default class Time extends React.Component<TimeProps, TimeState> {
-  static get defaultProps(): Partial<TimeProps> {
+export default class Time extends React.Component {
+  static get defaultProps() {
     return {
       intervals: 30,
+      onTimeChange: () => {},
       todayButton: null,
       timeCaption: "Time",
     };
   }
 
-  static calcCenterPosition = (
-    listHeight: number,
-    centerLiRef: HTMLLIElement,
-  ): number => {
+  static calcCenterPosition = (listHeight, centerLiRef) => {
     return (
       centerLiRef.offsetTop - (listHeight / 2 - centerLiRef.clientHeight / 2)
     );
   };
 
-  state: TimeState = {
-    height: null,
+  static propTypes = {
+    format: PropTypes.string,
+    includeTimes: PropTypes.array,
+    intervals: PropTypes.number,
+    selected: PropTypes.instanceOf(Date),
+    openToDate: PropTypes.instanceOf(Date),
+    onChange: PropTypes.func,
+    timeClassName: PropTypes.func,
+    todayButton: PropTypes.node,
+    minTime: PropTypes.instanceOf(Date),
+    maxTime: PropTypes.instanceOf(Date),
+    excludeTimes: PropTypes.array,
+    filterTime: PropTypes.func,
+    monthRef: PropTypes.object,
+    timeCaption: PropTypes.string,
+    injectTimes: PropTypes.array,
+    handleOnKeyDown: PropTypes.func,
+    locale: PropTypes.oneOfType([
+      PropTypes.string,
+      PropTypes.shape({ locale: PropTypes.object }),
+    ]),
+    showTimeSelectOnly: PropTypes.bool,
   };
 
-  private header?: HTMLDivElement;
-
-  private list?: HTMLUListElement;
-
-  private centerLi?: HTMLLIElement;
+  state = {
+    height: null,
+  };
 
-  componentDidMount(): void {
+  componentDidMount() {
     // code to ensure selected time will always be in focus within time window when it first appears
     this.scrollToTheSelectedTime();
     if (this.props.monthRef && this.header) {
@@ -78,24 +69,22 @@ export default class Time extends React.Component<TimeProps, TimeState> {
     }
   }
 
-  scrollToTheSelectedTime = (): void => {
-    requestAnimationFrame((): void => {
+  scrollToTheSelectedTime = () => {
+    requestAnimationFrame(() => {
       if (!this.list) return;
 
       this.list.scrollTop =
-        (this.centerLi &&
-          Time.calcCenterPosition(
-            this.props.monthRef
-              ? this.props.monthRef.clientHeight -
-                  (this.header?.clientHeight ?? 0)
-              : this.list.clientHeight,
-            this.centerLi,
-          )) ??
-        0;
+        this.centerLi &&
+        Time.calcCenterPosition(
+          this.props.monthRef
+            ? this.props.monthRef.clientHeight - this.header.clientHeight
+            : this.list.clientHeight,
+          this.centerLi,
+        );
     });
   };
 
-  handleClick = (time: Date): void => {
+  handleClick = (time) => {
     if (
       ((this.props.minTime || this.props.maxTime) &&
         isTimeInDisabledRange(time, this.props)) ||
@@ -106,13 +95,13 @@ export default class Time extends React.Component<TimeProps, TimeState> {
     ) {
       return;
     }
-    this.props.onChange?.(time);
+    this.props.onChange(time);
   };
 
-  isSelectedTime = (time: Date) =>
+  isSelectedTime = (time) =>
     this.props.selected && isSameMinute(this.props.selected, time);
 
-  isDisabledTime = (time: Date): boolean | undefined =>
+  isDisabledTime = (time) =>
     ((this.props.minTime || this.props.maxTime) &&
       isTimeInDisabledRange(time, this.props)) ||
     ((this.props.excludeTimes ||
@@ -120,8 +109,8 @@ export default class Time extends React.Component<TimeProps, TimeState> {
       this.props.filterTime) &&
       isTimeDisabled(time, this.props));
 
-  liClasses = (time: Date): string => {
-    const classes = [
+  liClasses = (time) => {
+    let classes = [
       "react-datepicker__time-list-item",
       this.props.timeClassName ? this.props.timeClassName(time) : undefined,
     ];
@@ -147,10 +136,7 @@ export default class Time extends React.Component<TimeProps, TimeState> {
     return classes.join(" ");
   };
 
-  handleOnKeyDown = (
-    event: React.KeyboardEvent<HTMLLIElement>,
-    time: Date,
-  ): void => {
+  handleOnKeyDown = (event, time) => {
     if (event.key === " ") {
       event.preventDefault();
       event.key = "Enter";
@@ -158,31 +144,27 @@ export default class Time extends React.Component<TimeProps, TimeState> {
 
     if (
       (event.key === "ArrowUp" || event.key === "ArrowLeft") &&
-      event.target instanceof HTMLElement &&
       event.target.previousSibling
     ) {
       event.preventDefault();
-      event.target.previousSibling instanceof HTMLElement &&
-        event.target.previousSibling.focus();
+      event.target.previousSibling.focus();
     }
     if (
       (event.key === "ArrowDown" || event.key === "ArrowRight") &&
-      event.target instanceof HTMLElement &&
       event.target.nextSibling
     ) {
       event.preventDefault();
-      event.target.nextSibling instanceof HTMLElement &&
-        event.target.nextSibling.focus();
+      event.target.nextSibling.focus();
     }
 
     if (event.key === "Enter") {
       this.handleClick(time);
     }
-    this.props.handleOnKeyDown?.(event);
+    this.props.handleOnKeyDown(event);
   };
 
-  renderTimes = (): JSX.Element[] => {
-    let times: Date[] = [];
+  renderTimes = () => {
+    let times = [];
     const format = this.props.format ? this.props.format : "p";
     const intervals = this.props.intervals;
 
@@ -192,8 +174,8 @@ export default class Time extends React.Component<TimeProps, TimeState> {
     const base = getStartOfDay(activeDate);
     const sortedInjectTimes =
       this.props.injectTimes &&
-      this.props.injectTimes.sort(function (a: Date, b: Date): number {
-        return a.getTime() - b.getTime();
+      this.props.injectTimes.sort(function (a, b) {
+        return a - b;
       });
 
     const minutesInDay = 60 * getHoursInDay(activeDate);
@@ -216,25 +198,25 @@ export default class Time extends React.Component<TimeProps, TimeState> {
     }
 
     // Determine which time to focus and scroll into view when component mounts
-    const timeToFocus = times.reduce<Date | undefined>((prev, time) => {
+    const timeToFocus = times.reduce((prev, time) => {
       if (time.getTime() <= activeDate.getTime()) {
         return time;
       }
       return prev;
     }, times[0]);
 
-    return times.map<JSX.Element>((time): JSX.Element => {
+    return times.map((time, i) => {
       return (
         <li
-          key={time.valueOf()}
+          key={i}
           onClick={this.handleClick.bind(this, time)}
           className={this.liClasses(time)}
-          ref={(li: HTMLLIElement): void => {
+          ref={(li) => {
             if (time === timeToFocus) {
               this.centerLi = li;
             }
           }}
-          onKeyDown={(ev: React.KeyboardEvent<HTMLLIElement>): void => {
+          onKeyDown={(ev) => {
             this.handleOnKeyDown(ev, time);
           }}
           tabIndex={time === timeToFocus ? 0 : -1}
@@ -265,7 +247,7 @@ export default class Time extends React.Component<TimeProps, TimeState> {
               ? "react-datepicker__header--time--only"
               : ""
           }`}
-          ref={(header: HTMLDivElement) => {
+          ref={(header) => {
             this.header = header;
           }}
         >
@@ -277,7 +259,7 @@ export default class Time extends React.Component<TimeProps, TimeState> {
           <div className="react-datepicker__time-box">
             <ul
               className="react-datepicker__time-list"
-              ref={(list: HTMLUListElement) => {
+              ref={(list) => {
                 this.list = list;
               }}
               style={height ? { height } : {}}
diff --git a/src/week.tsx b/src/week.jsx
similarity index 63%
rename from src/week.tsx
rename to src/week.jsx
index e6394478..7239930e 100644
--- a/src/week.tsx
+++ b/src/week.jsx
@@ -1,68 +1,98 @@
 import React from "react";
+import PropTypes from "prop-types";
 import Day from "./day";
 import WeekNumber from "./week_number";
 import { clsx } from "clsx";
-import { addDays, getWeek, getStartOfWeek, isSameDay } from "./date_utils";
-
-interface DayProps extends React.ComponentPropsWithoutRef<typeof Day> {}
-interface WeekNumberProps
-  extends React.ComponentPropsWithoutRef<typeof WeekNumber> {}
 
-interface WeekProps
-  extends Omit<
-      DayProps,
-      | "ariaLabelPrefixWhenEnabled"
-      | "disabledDayAriaLabelPrefix"
-      | "day"
-      | "onClick"
-      | "onMouseEnter"
-    >,
-    Omit<
-      WeekNumberProps,
-      "weekNumber" | "date" | "onClick" | "handleOnKeyDown"
-    > {
-  day: Date;
-  chooseDayAriaLabelPrefix: DayProps["ariaLabelPrefixWhenEnabled"];
-  disabledDayAriaLabelPrefix: DayProps["ariaLabelPrefixWhenDisabled"];
-  onDayClick?: (day: Date, event: React.MouseEvent<HTMLDivElement>) => void;
-  onDayMouseEnter?: (day: Date) => void;
-  shouldCloseOnSelect?: boolean;
-  setOpen?: (open: boolean) => void;
-  formatWeekNumber?: (date: Date) => number;
-  onWeekSelect?: (
-    day: Date,
-    weekNumber: number,
-    event: React.MouseEvent<HTMLDivElement>,
-  ) => void;
-}
+import { addDays, getWeek, getStartOfWeek, isSameDay } from "./date_utils";
 
-export default class Week extends React.Component<WeekProps> {
-  static get defaultProps(): Partial<WeekProps> {
+export default class Week extends React.Component {
+  static get defaultProps() {
     return {
       shouldCloseOnSelect: true,
     };
   }
+  static propTypes = {
+    ariaLabelPrefix: PropTypes.string,
+    disabledKeyboardNavigation: PropTypes.bool,
+    day: PropTypes.instanceOf(Date).isRequired,
+    dayClassName: PropTypes.func,
+    disabledDayAriaLabelPrefix: PropTypes.string,
+    chooseDayAriaLabelPrefix: PropTypes.string,
+    endDate: PropTypes.instanceOf(Date),
+    excludeDates: PropTypes.arrayOf(
+      PropTypes.oneOfType([
+        PropTypes.instanceOf(Date),
+        PropTypes.shape({
+          date: PropTypes.instanceOf(Date).isRequired,
+          message: PropTypes.string,
+        }),
+      ]),
+    ),
+    excludeDateIntervals: PropTypes.arrayOf(
+      PropTypes.shape({
+        start: PropTypes.instanceOf(Date),
+        end: PropTypes.instanceOf(Date),
+      }),
+    ),
+    filterDate: PropTypes.func,
+    formatWeekNumber: PropTypes.func,
+    highlightDates: PropTypes.instanceOf(Map),
+    holidays: PropTypes.instanceOf(Map),
+    includeDates: PropTypes.array,
+    includeDateIntervals: PropTypes.array,
+    inline: PropTypes.bool,
+    shouldFocusDayInline: PropTypes.bool,
+    locale: PropTypes.oneOfType([
+      PropTypes.string,
+      PropTypes.shape({ locale: PropTypes.object }),
+    ]),
+    maxDate: PropTypes.instanceOf(Date),
+    calendarStartDay: PropTypes.number,
+    minDate: PropTypes.instanceOf(Date),
+    month: PropTypes.number,
+    onDayClick: PropTypes.func,
+    usePointerEvent: PropTypes.bool,
+    onDayMouseEnter: PropTypes.func,
+    onWeekSelect: PropTypes.func,
+    preSelection: PropTypes.instanceOf(Date),
+    selected: PropTypes.instanceOf(Date),
+    selectingDate: PropTypes.instanceOf(Date),
+    selectsEnd: PropTypes.bool,
+    selectsStart: PropTypes.bool,
+    selectsRange: PropTypes.bool,
+    selectsMultiple: PropTypes.bool,
+    selectedDates: PropTypes.arrayOf(PropTypes.instanceOf(Date)),
+    selectsDisabledDaysInRange: PropTypes.bool,
+    showWeekNumber: PropTypes.bool,
+    showWeekPicker: PropTypes.bool,
+    startDate: PropTypes.instanceOf(Date),
+    setOpen: PropTypes.func,
+    shouldCloseOnSelect: PropTypes.bool,
+    renderDayContents: PropTypes.func,
+    handleOnKeyDown: PropTypes.func,
+    isInputFocused: PropTypes.bool,
+    containerRef: PropTypes.oneOfType([
+      PropTypes.func,
+      PropTypes.shape({ current: PropTypes.object }),
+    ]),
+    monthShowsDuplicateDaysEnd: PropTypes.bool,
+    monthShowsDuplicateDaysStart: PropTypes.bool,
+  };
 
-  handleDayClick = (
-    day: Date,
-    event: React.MouseEvent<HTMLDivElement>,
-  ): void => {
+  handleDayClick = (day, event) => {
     if (this.props.onDayClick) {
       this.props.onDayClick(day, event);
     }
   };
 
-  handleDayMouseEnter = (day: Date): void => {
+  handleDayMouseEnter = (day) => {
     if (this.props.onDayMouseEnter) {
       this.props.onDayMouseEnter(day);
     }
   };
 
-  handleWeekClick = (
-    day: Date,
-    weekNumber: number,
-    event: React.MouseEvent<HTMLDivElement>,
-  ) => {
+  handleWeekClick = (day, weekNumber, event) => {
     if (typeof this.props.onWeekSelect === "function") {
       this.props.onWeekSelect(day, weekNumber, event);
     }
@@ -70,11 +100,11 @@ export default class Week extends React.Component<WeekProps> {
       this.handleDayClick(day, event);
     }
     if (this.props.shouldCloseOnSelect) {
-      this.props.setOpen?.(false);
+      this.props.setOpen(false);
     }
   };
 
-  formatWeekNumber = (date: Date): number => {
+  formatWeekNumber = (date) => {
     if (this.props.formatWeekNumber) {
       return this.props.formatWeekNumber(date);
     }
@@ -92,6 +122,7 @@ export default class Week extends React.Component<WeekProps> {
           : undefined;
       days.push(
         <WeekNumber
+          key="W"
           weekNumber={weekNumber}
           date={startOfWeek}
           onClick={onClickAction}
@@ -108,7 +139,7 @@ export default class Week extends React.Component<WeekProps> {
       );
     }
     return days.concat(
-      [0, 1, 2, 3, 4, 5, 6].map<JSX.Element>((offset: number): JSX.Element => {
+      [0, 1, 2, 3, 4, 5, 6].map((offset) => {
         const day = addDays(startOfWeek, offset);
         return (
           <Day
@@ -147,6 +178,7 @@ export default class Week extends React.Component<WeekProps> {
             renderDayContents={this.props.renderDayContents}
             disabledKeyboardNavigation={this.props.disabledKeyboardNavigation}
             handleOnKeyDown={this.props.handleOnKeyDown}
+            isInputFocused={this.props.isInputFocused}
             containerRef={this.props.containerRef}
             inline={this.props.inline}
             shouldFocusDayInline={this.props.shouldFocusDayInline}
@@ -161,19 +193,19 @@ export default class Week extends React.Component<WeekProps> {
     );
   };
 
-  startOfWeek = (): Date =>
+  startOfWeek = () =>
     getStartOfWeek(
       this.props.day,
       this.props.locale,
       this.props.calendarStartDay,
     );
 
-  isKeyboardSelected = (): boolean =>
+  isKeyboardSelected = () =>
     !this.props.disabledKeyboardNavigation &&
     !isSameDay(this.startOfWeek(), this.props.selected) &&
     isSameDay(this.startOfWeek(), this.props.preSelection);
 
-  render(): JSX.Element {
+  render() {
     const weekNumberClasses = {
       "react-datepicker__week": true,
       "react-datepicker__week--selected": isSameDay(
diff --git a/src/week_number.tsx b/src/week_number.tsx
index 5daa5780..84c57abc 100644
--- a/src/week_number.tsx
+++ b/src/week_number.tsx
@@ -9,17 +9,22 @@ interface WeekNumberProps {
   ariaLabelPrefix?: string;
   selected?: Date;
   preSelection?: Date;
-  showWeekPicker?: boolean;
-  showWeekNumber?: boolean;
-  disabledKeyboardNavigation?: boolean;
-  inline?: boolean;
-  shouldFocusDayInline?: boolean;
+  showWeekPicker: boolean;
+  showWeekNumber: boolean;
+  disabledKeyboardNavigation: boolean;
+  inline: boolean;
+  shouldFocusDayInline: boolean;
   handleOnKeyDown: React.KeyboardEventHandler<HTMLDivElement>;
   containerRef?: React.RefObject<HTMLDivElement>;
   isInputFocused?: boolean;
 }
 
-export default class WeekNumber extends React.Component<WeekNumberProps> {
+interface WeekNumberState {}
+
+export default class WeekNumber extends React.Component<
+  WeekNumberProps,
+  WeekNumberState
+> {
   static get defaultProps(): Partial<WeekNumberProps> {
     return {
       ariaLabelPrefix: "week ",


Test patch:
diff --git a/test/month_dropdown_test.test.js b/test/month_dropdown_test.test.js
index c7868652..51dca9a1 100644
--- a/test/month_dropdown_test.test.js
+++ b/test/month_dropdown_test.test.js
@@ -1,7 +1,7 @@
 import React from "react";
 import range from "lodash/range";
-import MonthDropdown from "../src/month_dropdown";
-import MonthDropdownOptions from "../src/month_dropdown_options";
+import MonthDropdown from "../src/month_dropdown.jsx";
+import MonthDropdownOptions from "../src/month_dropdown_options.jsx";
 import { render, fireEvent } from "@testing-library/react";
 import { getMonthInLocale, registerLocale } from "../src/date_utils";
 import { zhCN } from "date-fns/locale/zh-CN";
diff --git a/test/show_time_test.test.js b/test/show_time_test.test.js
index a848cc75..546177fb 100644
--- a/test/show_time_test.test.js
+++ b/test/show_time_test.test.js
@@ -1,7 +1,7 @@
 import React from "react";
 import { render, fireEvent } from "@testing-library/react";
 import DatePicker from "../src/index.jsx";
-import TimeComponent from "../src/time";
+import TimeComponent from "../src/time.jsx";
 
 describe("DatePicker", () => {
   it("should show time component when showTimeSelect prop is present", () => {