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

Feat i18n support for DatePicker and DateRangePicker #1398

Merged
merged 5 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/weak-spies-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ingred-ui": minor
---

Feat i18n support for DatePicker and DateRangePicker
13 changes: 13 additions & 0 deletions src/components/Calendar/Calendar/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ export type CalendarProps = React.HTMLAttributes<HTMLDivElement> & {
* @default dayjs()
*/
date: Dayjs;
/**
* カレンダーに表示する年月のフォーマット
*/
monthFormat?: string;
/**
* カレンダーに表示する曜日のリスト
* @memo dayjs().format("ddd") で対応したいが、階層が深くなったりするので一旦静的な値で対処
*/
weekList?: string[];
Comment on lines +20 to +24
Copy link
Contributor Author

Choose a reason for hiding this comment

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

曜日一覧も props から受け取るようにした。
dayjs を使えば指定した locale で曜日を取得することもできるけど、階層が深くなることでどこで何を扱っているかが不明瞭になったりするので、一旦 props 経由で受け取り上から流すだけの構成にする。

この PR では対応しないだけで、後でいい構成に変更するかも。

/**
* カレンダーの左に表示するアクション
*/
Expand All @@ -37,6 +46,8 @@ export type CalendarProps = React.HTMLAttributes<HTMLDivElement> & {
const Calendar = forwardRef<HTMLDivElement, CalendarProps>(function Calendar(
{
date,
monthFormat,
weekList,
actions,
onClickCloseButton,
isOutsideRange = () => false,
Expand Down Expand Up @@ -74,6 +85,8 @@ const Calendar = forwardRef<HTMLDivElement, CalendarProps>(function Calendar(
<InnerCalendar
date={date}
current={current}
monthFormat={monthFormat}
weekList={weekList}
yearIsOpen={yearIsOpen}
isOutsideRange={isOutsideRange}
onYearIsOpen={setYearIsOpen}
Expand Down
13 changes: 13 additions & 0 deletions src/components/Calendar/CalendarRange/CalendarRange.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ export type CalendarRangeProps = React.HTMLAttributes<HTMLDivElement> & {
* @default dayjs()
*/
endDate: Dayjs;
/**
* カレンダーに表示する年月のフォーマット
*/
monthFormat?: string;
/**
* カレンダーに表示する曜日のリスト
* @memo dayjs().format("ddd") で対応したいが、階層が深くなったりするので一旦静的な値で対処
*/
weekList?: string[];
/**
* カレンダーの左に表示するアクション
*/
Expand Down Expand Up @@ -60,6 +69,8 @@ export const CalendarRange = forwardRef<HTMLDivElement, CalendarRangeProps>(
{
startDate,
endDate,
monthFormat,
weekList,
actions,
onClose,
isOutsideRange = () => false,
Expand Down Expand Up @@ -131,6 +142,8 @@ export const CalendarRange = forwardRef<HTMLDivElement, CalendarRangeProps>(
<InnerCalendarRange
startDate={startDate}
endDate={endDate}
monthFormat={monthFormat}
weekList={weekList}
current={current}
yearIsOpen={yearIsOpen}
isOutsideRange={isOutsideRange}
Expand Down
36 changes: 0 additions & 36 deletions src/components/Calendar/constants.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,2 @@
// for `<ScrollArea />`
export const HEIGHT = "400px";

export const weekList = {
en: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
ja: ["日", "月", "火", "水", "木", "金", "土"],
};

export const monthList = {
en: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"June",
"July",
"Aug",
"Sept",
"Oct",
"Nov",
"Dec",
],
ja: [
"1月",
"2月",
"3月",
"4月",
"5月",
"6月",
"7月",
"8月",
"9月",
"10月",
"11月",
"12月",
],
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import dayjs, { Dayjs } from "dayjs";
import { Icon, ScrollArea } from "../../..";
import { useTheme } from "styled-components";
import { useScrollCalendar } from "../../hooks/useScrollCalendar";
import { HEIGHT, weekList } from "../../constants";
import { HEIGHT } from "../../constants";
import {
CalendarContainer,
CalendarMonth,
Expand All @@ -16,6 +16,8 @@ import { Day } from "../../Calendar/internal/Day";

type Props = {
date: Dayjs;
monthFormat?: string;
weekList?: string[];
Comment on lines 17 to +20
Copy link
Contributor

Choose a reason for hiding this comment

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

率直な疑問ですが、この辺のフォーマットは現状型を強く縛らない方針なのでしょうか?
言語の違いはあれど扱う文字列は決まってそうなのでユニオン等で表現するのもありかなと思いまして。

この辺の話で一旦リテラル型にしているのか

/**
   * カレンダーに表示する曜日のリスト
   * @memo dayjs().format("ddd") で対応したいが、階層が深くなったりするので一旦静的な値で対処
   */

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ここは useLocaleProps を通じて曜日のリストを管理するための暫定的なものであり、実質ユーザーから渡される想定ではないのであまり強く縛る必要もないかなと思ってこのようにしてます!

たしかに英語と日本語くらいしか対応するつもりもないので言われてみたら縛ってもいいかな?と思ったのですが、一旦このままでも良いかなとも思います。

current: Dayjs;
yearIsOpen: boolean;
onYearIsOpen: (yearIsOpen: boolean) => void;
Expand All @@ -24,6 +26,8 @@ type Props = {
};
export const InnerCalendar: React.FC<Props> = ({
date,
weekList,
monthFormat,
current,
yearIsOpen,
onYearIsOpen,
Expand Down Expand Up @@ -51,7 +55,7 @@ export const InnerCalendar: React.FC<Props> = ({
{/* 年月の表示 */}
<CalendarMonth expanded={yearIsOpen}>
<TitleContainer expanded={yearIsOpen} weight="bold" size="xl">
{m.format("YYYY年MM月")}
{m.format(monthFormat)}
</TitleContainer>
<IconButton
expanded={yearIsOpen}
Expand All @@ -68,9 +72,7 @@ export const InnerCalendar: React.FC<Props> = ({
{/* カレンダーの表示 */}
<CalendarContainer>
{/* 曜日の表示 */}
{weekList["ja"].map((week) => (
<DayStyle key={week}>{week}</DayStyle>
))}
{weekList?.map((week) => <DayStyle key={week}>{week}</DayStyle>)}

{/* 開始曜日まで空白をセット */}
{Array.from(new Array(m.startOf("month").day()), (_, i) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useRef } from "react";
import { HEIGHT, weekList } from "../../constants";
import { HEIGHT } from "../../constants";
import { useTheme } from "../../../../themes";
import { useScrollCalendar } from "../../hooks/useScrollCalendar";
import { Icon, ScrollArea } from "../../../";
Expand All @@ -18,6 +18,8 @@ import { Day } from "../../CalendarRange/internal/Day";
type Props = {
startDate: Dayjs;
endDate: Dayjs;
monthFormat?: string;
weekList?: string[];
current: Dayjs;
yearIsOpen: boolean;
onYearIsOpen: (yearIsOpen: boolean) => void;
Expand All @@ -28,6 +30,8 @@ type Props = {
export const InnerCalendarRange: React.FC<Props> = ({
startDate,
endDate,
monthFormat,
weekList,
current,
yearIsOpen,
onYearIsOpen,
Expand All @@ -54,7 +58,7 @@ export const InnerCalendarRange: React.FC<Props> = ({
>
<CalendarMonth expanded={yearIsOpen}>
<TitleContainer expanded={yearIsOpen} weight="bold" size="xl">
{m.format("YYYY年MM月")}
{m.format(monthFormat)}
</TitleContainer>
<IconButton
expanded={yearIsOpen}
Expand All @@ -68,9 +72,7 @@ export const InnerCalendarRange: React.FC<Props> = ({
</IconButton>
</CalendarMonth>
<CalendarContainer>
{weekList["ja"].map((week) => (
<DayStyle key={week}>{week}</DayStyle>
))}
{weekList?.map((week) => <DayStyle key={week}>{week}</DayStyle>)}
{Array.from(new Array(m.startOf("month").day()), (_, i) => (
<DayStyle key={i} />
))}
Expand Down
6 changes: 6 additions & 0 deletions src/components/LocaleProvider/LocaleProvider.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ConfirmModal,
DatePicker,
MultipleFilter,
NewDatePicker,
OptionType,
Select,
Spacer,
Expand Down Expand Up @@ -184,6 +185,11 @@ export const Example: StoryObj<LocaleProviderProps> = {
<Spacer pl={2} pt={2} pb={40}>
<DatePicker date={dayjs()} onDateChange={() => {}} />
</Spacer>

<h2>NewDatePicker</h2>
<Spacer pl={2} pt={2} pb={40}>
<NewDatePicker date={dayjs()} onDateChange={() => {}} />
</Spacer>
</LocaleProvider>
);
},
Expand Down
24 changes: 19 additions & 5 deletions src/components/NewDatePicker/NewDatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
useInteractions,
useRole,
} from "@floating-ui/react";
import { useLocaleProps } from "../../hooks/useLocaleProps";

export type NewDatePickerProps = {
/**
Expand All @@ -35,6 +36,15 @@ export type NewDatePickerProps = {
* @default false
*/
disabled?: boolean;
/**
* カレンダーに表示する年月のフォーマット
*/
monthFormat?: string;
/**
* カレンダーに表示する曜日のリスト
* @memo dayjs().format("ddd") で対応したいが、階層が深くなったりするので一旦静的な値で対処
*/
weekList?: string[];
/**
* 選択可能なカレンダーの領域を制限する
* true が返る場合は、選択不可となる
Expand All @@ -51,18 +61,20 @@ export type NewDatePickerProps = {
* @memo 次のメジャーリリースで DatePicker に変更。現行の DatePicker は削除。
*/
export const NewDatePicker = forwardRef<HTMLDivElement, NewDatePickerProps>(
function DatePicker(
{
function DatePicker(inProps, ref) {
const props = useLocaleProps({ props: inProps, name: "NewDatePicker" });
const {
date,
format = "YYYY-MM-DD",
disabled = false,
monthFormat = "MMM YYYY",
weekList = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
isOutsideRange,
errorText,
actions,
onDateChange,
},
ref,
) {
} = props;

const [open, setOpen] = useState(false);
const { context, refs, strategy, x, y } = useFloating({
placement: "right-start",
Expand Down Expand Up @@ -112,6 +124,8 @@ export const NewDatePicker = forwardRef<HTMLDivElement, NewDatePickerProps>(
<Calendar
ref={refs.setFloating}
date={date}
monthFormat={monthFormat}
weekList={weekList}
actions={actions}
isOutsideRange={isOutsideRange}
style={{
Expand Down
27 changes: 22 additions & 5 deletions src/components/NewDateRangePicker/NewDateRangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
ClickStateType,
} from "../Calendar/CalendarRange/constants";
import { useMergeRefs } from "../../hooks/useMergeRefs";
import { useLocaleProps } from "../../hooks/useLocaleProps";

export type DateRange = {
startDate: Dayjs;
Expand Down Expand Up @@ -46,6 +47,15 @@ export type NewDateRangePickerProps = {
* @default false
*/
disabled?: boolean;
/**
* カレンダーに表示する年月のフォーマット
*/
monthFormat?: string;
/**
* カレンダーに表示する曜日のリスト
* @memo dayjs().format("ddd") で対応したいが、階層が深くなったりするので一旦静的な値で対処
*/
weekList?: string[];
/**
* 選択可能なカレンダーの領域を制限する
* true が返る場合は、選択不可となる
Expand All @@ -64,18 +74,23 @@ export type NewDateRangePickerProps = {
export const DateRangePicker = forwardRef<
HTMLDivElement,
NewDateRangePickerProps
>(function DateRangePicker(
{
>(function DateRangePicker(inProps, propRef) {
const props = useLocaleProps({
props: inProps,
name: "NewDateRangePicker",
});
const {
startDate,
endDate,
errorText,
disabled = false,
monthFormat = "MMM YYYY",
weekList = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
isOutsideRange = () => false,
actions,
onDatesChange,
},
propRef,
) {
} = props;

const [open, setOpen] = useState(false);
const { context, refs, strategy, x, y } = useFloating({
placement: "right-start",
Expand Down Expand Up @@ -133,6 +148,8 @@ export const DateRangePicker = forwardRef<
startDate={startDate}
endDate={endDate}
actions={actions}
monthFormat={monthFormat}
weekList={weekList}
style={{
position: strategy,
top: y ?? 0,
Expand Down
20 changes: 19 additions & 1 deletion src/constants/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
MultipleFilterProps,
ToggleButtonProps,
} from "..";
import { SelectProps } from "../components";
import { NewDatePickerProps, SelectProps } from "../components";
import { CreatableSelectProps } from "../components/CreatableSelect";
import { FullSizeConfirmModalProps } from "../components/FullSizeConfirmModal";
import { EditFilterCardProps } from "../components/MultipleFilter/internal/EditFilterCard/EditFilterCard";
Expand Down Expand Up @@ -75,6 +75,12 @@ export interface Localization {
DateRangePicker?: {
defaultProps: Pick<DateRangePickerProps, "displayFormat" | "monthFormat">;
};
NewDatePicker?: {
defaultProps: Pick<NewDatePickerProps, "monthFormat" | "weekList">;
};
NewDateRangePicker?: {
defaultProps: Pick<NewDatePickerProps, "monthFormat" | "weekList">;
};
};
}

Expand Down Expand Up @@ -124,6 +130,18 @@ export const jaJP: Localization = {
DateRangePicker: {
defaultProps: { displayFormat: "YYYY/MM/DD", monthFormat: "YYYY年 M月" },
},
NewDatePicker: {
defaultProps: {
monthFormat: "YYYY年MM月",
weekList: ["日", "月", "火", "水", "木", "金", "土"],
},
},
NewDateRangePicker: {
defaultProps: {
monthFormat: "YYYY年MM月",
weekList: ["日", "月", "火", "水", "木", "金", "土"],
},
},
},
};

Expand Down