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, DateRangePickerをdayjsでやりとりするようにwrap #1080

Merged
merged 19 commits into from
Nov 11, 2022
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
"generate": "yarn scaffdog generate"
},
"dependencies": {
"@popperjs/core": "^2.4.0",
"moment": "^2.29.3",
"react-dates": "^21.8.0",
"react-popper": "^2.3.0",
"react-select": "^5.3.0",
"react-transition-group": "^4.4.1"
"@popperjs/core": "2.4.0",
"dayjs": "1.11.6",
"moment": "2.29.3",
"react-dates": "21.8.0",
"react-popper": "2.3.0",
"react-select": "5.3.0",
"react-transition-group": "4.4.1"
},
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0",
Expand Down
25 changes: 14 additions & 11 deletions src/components/DatePicker/DatePicker.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { ArgsTable, Description, Stories, Title } from "@storybook/addon-docs";
import { Story } from "@storybook/react/types-6-0";
import moment from "moment";
import dayjs from "dayjs";
import React from "react";
import DatePicker from "./DatePicker";
import "dayjs/locale/ja";
import localeData from "dayjs/plugin/localeData";

export default {
title: "Components/Inputs/DatePicker",
Expand Down Expand Up @@ -41,9 +43,9 @@ export default {
};

export const Basic: Story = () => {
moment.locale("en");
const [date, setDate] = React.useState(moment());
const handleChangeDate = (date: moment.Moment | null) => {
dayjs.locale("en");
const [date, setDate] = React.useState(dayjs());
const handleChangeDate = (date: dayjs.Dayjs | null) => {
if (date === null) {
return;
}
Expand All @@ -57,17 +59,16 @@ export const Basic: Story = () => {
};

export const Error: Story = () => {
return <DatePicker date={moment()} error={true} onDateChange={() => {}} />;
return <DatePicker date={dayjs()} error={true} onDateChange={() => {}} />;
};

export const Localize: Story = () => {
moment.locale("ja", {
weekdaysShort: ["日", "月", "火", "水", "木", "金", "土"],
});
const renderMonthText = (day: moment.Moment) => day.format("YYYY年M月");
dayjs.locale("ja");
dayjs.extend(localeData);
const renderMonthText = (day: dayjs.Dayjs) => day.format("YYYY年M月");
const displayFormat = () => "YYYY/MM/DD";
const [date, setDate] = React.useState(moment());
const handleChangeDate = (date: moment.Moment | null) => {
const [date, setDate] = React.useState(dayjs());
const handleChangeDate = (date: dayjs.Dayjs | null) => {
if (date === null) {
return;
}
Expand All @@ -77,6 +78,8 @@ export const Localize: Story = () => {
<div style={{ height: "400px" }}>
<DatePicker
date={date}
locale={"ja"}
localeData={dayjs().localeData()}
displayFormat={displayFormat}
renderMonthText={renderMonthText}
onDateChange={handleChangeDate}
Expand Down
54 changes: 48 additions & 6 deletions src/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import * as React from "react";
import * as Styled from "./styled";
import "react-dates/initialize";
import dayjs, { InstanceLocaleDataReturn } from "dayjs";
import moment from "moment";
import {
dayjsToMoment,
momentToDayjs,
convertDayjsLocaleDataToObject,
} from "../../utils/time";
import {
RenderMonthProps,
SingleDatePicker,
Expand All @@ -16,31 +22,62 @@ function isOutsideRange() {
}

export type DatePickerProps = Partial<
Omit<SingleDatePickerShape, "date" | "onFocusChange">
Omit<
SingleDatePickerShape,
"date" | "onFocusChange" | "onDateChange" | "renderMonthText"
>
> &
// MEMO: Add RenderMonthProps to pass type check.
RenderMonthProps & {
date: moment.Moment | null;
onDateChange: (date: moment.Moment | null) => void;
Omit<RenderMonthProps, "renderMonthText"> & {
date: dayjs.Dayjs | null;
onDateChange: (date: dayjs.Dayjs | null) => void;
renderMonthText?: ((month: dayjs.Dayjs) => React.ReactNode) | null;
locale?: string;
localeData?: InstanceLocaleDataReturn;
error?: boolean;
};

const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
(inProps, ref) => {
const props = useLocaleProps({ props: inProps, name: "DatePicker" });
const { date, error = false, ...rest } = props;
const {
date,
error = false,
onDateChange,
renderMonthText,
renderMonthElement,
locale = "en",
localeData,
...rest
} = props;

const [focused, setFocused] = React.useState<boolean>(false);
const onFocusChange = ({ focused }: { focused: boolean }) => {
setFocused(focused);
};
const handleDateChange = (date: moment.Moment | null) => {
const dayjsize = momentToDayjs(date);
onDateChange(dayjsize);
};
const handleRenderMonthText = (month: moment.Moment) => {
if (renderMonthText == undefined) return;
const dayjsize = momentToDayjs(month);
if (dayjsize === null) return;
return renderMonthText(dayjsize);
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SingleDatePickerはmomentなので、外側でdayjsでlocaleを設定しても影響しない。
外からdayjsのlocale設定をコンポーネントへ持ち込むことはできなかったので locale と(必要なら) weekdayShort を渡すやり方にしてみた

if (localeData) {
moment.locale(locale, convertDayjsLocaleDataToObject(localeData));
} else {
moment.locale(locale);
}

return (
<Styled.Container ref={ref} error={error}>
<SingleDatePicker
id="datePicker"
focused={focused}
date={date}
date={dayjsToMoment(date)}
isOutsideRange={isOutsideRange}
numberOfMonths={1}
enableOutsideDays={true}
Expand All @@ -61,7 +98,12 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
</Spacer>
</Styled.NavNext>
}
renderMonthText={
renderMonthText ? handleRenderMonthText : renderMonthText
}
renderMonthElement={renderMonthElement as never}
onFocusChange={onFocusChange}
onDateChange={handleDateChange}
{...rest}
/>
</Styled.Container>
Expand Down
37 changes: 20 additions & 17 deletions src/components/DateRangePicker/DateRangePicker.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React, { useState } from "react";
import { Story } from "@storybook/react/types-6-0";
import moment from "moment";
import dayjs from "dayjs";
import { Title, Description, ArgsTable, Stories } from "@storybook/addon-docs";
import DateRangePicker, { DateRangePickerProps } from "./DateRangePicker";
import "react-dates/lib/css/_datepicker.css";
import "dayjs/locale/ja";
import localeData from "dayjs/plugin/localeData";

export default {
title: "Components/Inputs/DateRangePicker",
Expand Down Expand Up @@ -43,14 +45,14 @@ export default {

export const Basic: Story<DateRangePickerProps> = () => {
// MEMO: To be unaffected by "Localize" story.
moment.locale("en");
dayjs.locale("en");
const [date, setDate] = useState({
startDate: moment().set("date", 1),
endDate: moment(),
startDate: dayjs().set("date", 1),
endDate: dayjs(),
});
const handleChangeDates = (arg: {
startDate: moment.Moment;
endDate: moment.Moment;
startDate: dayjs.Dayjs;
endDate: dayjs.Dayjs;
}) => {
setDate(arg);
};
Expand All @@ -67,30 +69,29 @@ export const Basic: Story<DateRangePickerProps> = () => {

export const Error: Story<DateRangePickerProps> = () => {
// MEMO: To be unaffected by "Localize" story.
moment.locale("en");
dayjs.locale("en");
return (
<DateRangePicker
startDate={moment().set("date", 1)}
endDate={moment()}
startDate={dayjs().set("date", 1)}
endDate={dayjs()}
error={true}
onDatesChange={() => {}}
/>
);
};

export const Localize: Story<DateRangePickerProps> = () => {
moment.locale("ja", {
weekdaysShort: ["日", "月", "火", "水", "木", "金", "土"],
});
const renderMonthText = (day: moment.Moment) => day.format("YYYY年M月");
dayjs.locale("ja");
dayjs.extend(localeData);
const renderMonthText = (day: dayjs.Dayjs) => day.format("YYYY年M月");
const displayFormat = () => "YYYY/MM/DD";
const [date, setDate] = useState({
startDate: moment().set("date", 1),
endDate: moment(),
startDate: dayjs().set("date", 1),
endDate: dayjs(),
});
const handleChangeDates = (arg: {
startDate: moment.Moment;
endDate: moment.Moment;
startDate: dayjs.Dayjs;
endDate: dayjs.Dayjs;
}) => {
setDate(arg);
};
Expand All @@ -99,6 +100,8 @@ export const Localize: Story<DateRangePickerProps> = () => {
<DateRangePicker
startDate={date.startDate}
endDate={date.endDate}
locale={"ja"}
localeData={dayjs().localeData()}
displayFormat={displayFormat}
renderMonthText={renderMonthText}
onDatesChange={handleChangeDates}
Expand Down
70 changes: 61 additions & 9 deletions src/components/DateRangePicker/DateRangePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import * as React from "react";
import * as Styled from "./styled";
import "react-dates/initialize";
import dayjs, { InstanceLocaleDataReturn } from "dayjs";
import moment from "moment";
import {
dayjsToMoment,
momentToDayjs,
convertDayjsLocaleDataToObject,
} from "../../utils/time";
import {
FocusedInputShape,
DateRangePicker as OriginalDateRangePicker,
Expand All @@ -15,23 +21,64 @@ function isOutsideRange() {
return false;
}

export type DateRangePickerProps = Partial<DateRangePickerShape> & {
startDate: moment.Moment | null;
endDate: moment.Moment | null;
export type DateRangePickerProps = Partial<
Omit<
DateRangePickerShape,
"startDate" | "endDate" | "onDatesChange" | "renderMonthText"
>
> & {
startDate: dayjs.Dayjs | null;
endDate: dayjs.Dayjs | null;
onDatesChange: (arg: {
startDate: moment.Moment | null;
endDate: moment.Moment | null;
startDate: dayjs.Dayjs | null;
endDate: dayjs.Dayjs | null;
}) => void;
renderMonthText?: ((month: dayjs.Dayjs) => React.ReactNode) | null;
locale?: string;
localeData?: InstanceLocaleDataReturn;
error?: boolean;
};

const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
(inProps, ref) => {
const props = useLocaleProps({ props: inProps, name: "DateRangePicker" });
const { startDate, endDate, error = false, ...rest } = props;
const {
startDate,
endDate,
error = false,
onDatesChange,
renderMonthText,
renderMonthElement,
locale = "en",
localeData,
...rest
} = props;
const [focusedInput, setFocusedInput] =
React.useState<FocusedInputShape | null>(null);

const handleDatesChange = (arg: {
startDate: moment.Moment | null;
endDate: moment.Moment | null;
}) => {
const dayjsize = {
startDate: momentToDayjs(arg.startDate),
endDate: momentToDayjs(arg.endDate),
};
onDatesChange(dayjsize);
};
const handleRenderMonthText = (month: moment.Moment) => {
if (renderMonthText == undefined) return;
const dayjsize = momentToDayjs(month);
if (dayjsize === null) return;
return renderMonthText(dayjsize);
};

if (localeData) {
moment.locale(locale, convertDayjsLocaleDataToObject(localeData));
} else {
moment.locale(locale);
}

return (
<Styled.Container ref={ref} error={error}>
<OriginalDateRangePicker
Expand Down Expand Up @@ -60,11 +107,16 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
</Spacer>
</Styled.NavNext>
}
{...rest}
startDate={startDate}
endDate={endDate}
startDate={dayjsToMoment(startDate)}
endDate={dayjsToMoment(endDate)}
renderMonthText={
renderMonthText ? handleRenderMonthText : renderMonthText
}
renderMonthElement={renderMonthElement as never}
focusedInput={focusedInput}
onFocusChange={setFocusedInput}
onDatesChange={handleDatesChange}
{...rest}
/>
</Styled.Container>
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/LocaleProvider/LocaleProvider.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import * as locales from "../../constants/locale";
import FileUploader from "../FileUploader";
import ItemEmpty from "../ItemEmpty";
import { FilterPackType, ReferredFilterType } from "../MultipleFilter/types";
import moment from "moment";
import dayjs from "dayjs";

export default {
title: "Components/Utils/LocaleProvider",
Expand Down Expand Up @@ -170,7 +170,7 @@ export const Example: Story<LocaleProviderProps> = (args) => {
※ Needs locale import (e.g. import &apos;moment/locale/ja&apos;).
</Typography>
<Spacer pl={2} pt={2} pb={40}>
<DatePicker date={moment()} onDateChange={() => {}} />
<DatePicker date={dayjs()} onDateChange={() => {}} />
</Spacer>
</LocaleProvider>
);
Expand Down
Loading