From 2590e5589bfade66a604fa951485ff7bc82001ca Mon Sep 17 00:00:00 2001 From: "Yuichiro Tachibana (Tsuchiya)" Date: Thu, 12 May 2022 14:50:32 +0900 Subject: [PATCH 01/10] Install date-io --- package.json | 8 +++++++- yarn.lock | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c7a7fc9..4990df2 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,13 @@ "prepare": "husky install" }, "type": "module", - "dependencies": {}, + "dependencies": { + "@date-io/date-fns": "^2.13.2", + "@date-io/date-fns-jalali": "^2.13.2", + "@date-io/dayjs": "^2.13.2", + "@date-io/jalaali": "^2.13.2", + "@date-io/luxon": "^2.13.2" + }, "devDependencies": { "@chakra-ui/icons": "^1.1.7", "@chakra-ui/react": "^1.8.6", diff --git a/yarn.lock b/yarn.lock index 2be5efe..f63c3bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -818,6 +818,53 @@ resolved "https://registry.yarnpkg.com/@cush/relative/-/relative-1.0.0.tgz#8cd1769bf9bde3bb27dac356b1bc94af40f6cc16" integrity sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA== +"@date-io/core@^2.13.2": + version "2.13.2" + resolved "https://registry.yarnpkg.com/@date-io/core/-/core-2.13.2.tgz#63983fbe2816a758d3fe51857e88d9170c40073c" + integrity sha512-lAUDhC5kpzlxa00BxfqENBgerbGI5ojuKQpXLGZCTrqT1rQR+vrp2rwf0I+H2KlM2z3N1ldyQuANmzZ+ehomog== + +"@date-io/date-fns-jalali@^2.13.2": + version "2.13.2" + resolved "https://registry.yarnpkg.com/@date-io/date-fns-jalali/-/date-fns-jalali-2.13.2.tgz#b166dd63cb8cb8f15289b90e06831f86338e8ceb" + integrity sha512-395rRc28wkmLiiMuwGOt31paQpHPXAEXbfXLTVsNL/eWi16+ndX9Jgu6RKsT9apbeK7nCT/1Xz/9LkvgFxyISw== + dependencies: + "@date-io/core" "^2.13.2" + +"@date-io/date-fns@^2.13.2": + version "2.13.2" + resolved "https://registry.yarnpkg.com/@date-io/date-fns/-/date-fns-2.13.2.tgz#d0abddc7e76dbaeff92b876b7ad839729cc682cf" + integrity sha512-Pq0xBH6cvEg5IsOs7Olkk1PHFFJFTM34OT5mk/9ND1ied4RGhLNeLYRwbyCThZ29jolqPsV2HBs9wo2QTiNIkg== + dependencies: + "@date-io/core" "^2.13.2" + +"@date-io/dayjs@^2.13.2": + version "2.13.2" + resolved "https://registry.yarnpkg.com/@date-io/dayjs/-/dayjs-2.13.2.tgz#b337e92bd9d3fe896619f82d68f23209e2b03f8f" + integrity sha512-uP/Bvr+QfzpLN3JGX/x3uJtGnnSWckn7e500Wn+pVNVvIleaXSJxDbE5IAz1P7WwQrnSuxuBI1e6Sl8J/njzKQ== + dependencies: + "@date-io/core" "^2.13.2" + +"@date-io/jalaali@^2.13.2": + version "2.13.2" + resolved "https://registry.yarnpkg.com/@date-io/jalaali/-/jalaali-2.13.2.tgz#42561a3dc32e11e6565a261fea2e4bfd5f986ff9" + integrity sha512-/diAXI3PEu4LqHiwkCY267A5lWxMH46/Q70pKuLOQx586Ix0kUNHXbCzSo5BuTsw5JdFjEwAWFS8Ik2THmrGbw== + dependencies: + "@date-io/moment" "^2.13.2" + +"@date-io/luxon@^2.13.2": + version "2.13.2" + resolved "https://registry.yarnpkg.com/@date-io/luxon/-/luxon-2.13.2.tgz#57476ff987488e12f560f5d5b2831898104ca094" + integrity sha512-/LeUXsBeM9DITZliaAzKYBu6GtaD3AT5nQR5u7AasjUz1JlYPCTjV5z8b+wnY/jm4bFz5AhgK+TMHGaZoMJW+w== + dependencies: + "@date-io/core" "^2.13.2" + +"@date-io/moment@^2.13.2": + version "2.13.2" + resolved "https://registry.yarnpkg.com/@date-io/moment/-/moment-2.13.2.tgz#2702aa27571742436efd6dd3f0b8f80745bcf1a4" + integrity sha512-6uWeCS44srr86MaeUS0mS10T1g7WKfqZ47r1rEc+8xcS3640TIPNf/pg30kwprZKAM7gtbZu6vW6pe1MEPbcKA== + dependencies: + "@date-io/core" "^2.13.2" + "@emotion/babel-plugin@^11.7.1": version "11.9.2" resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz#723b6d394c89fb2ef782229d92ba95a740576e95" From 57e0e71c7ff0c0e10d1ec4749c8601a45e6bcba2 Mon Sep 17 00:00:00 2001 From: "Yuichiro Tachibana (Tsuchiya)" Date: Thu, 12 May 2022 15:53:05 +0900 Subject: [PATCH 02/10] Install date-fns as devdep --- package.json | 1 + yarn.lock | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index 4990df2..e5535f9 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "@typescript-eslint/eslint-plugin": "^5.19.0", "@typescript-eslint/parser": "^5.19.0", "@vitejs/plugin-react": "^1.0.7", + "date-fns": "^2.28.0", "eslint": "^8.13.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-react": "^7.29.4", diff --git a/yarn.lock b/yarn.lock index f63c3bc..7ac7c84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1984,6 +1984,11 @@ csstype@3.0.10, csstype@3.0.9, csstype@^3.0.10, csstype@^3.0.11, csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== +date-fns@^2.28.0: + version "2.28.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" + integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== + debug@^4.0.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" From 309ae0df2b48d820908f6b3d3a908f82562f5162 Mon Sep 17 00:00:00 2001 From: "Yuichiro Tachibana (Tsuchiya)" Date: Thu, 12 May 2022 17:48:47 +0900 Subject: [PATCH 03/10] Implement localization functionality with powered by date-io --- .../LocalizationProvider.tsx | 62 +++++++++++++++++++ src/LocalizationProvider/index.ts | 1 + src/LocalizationProvider/useUtils.ts | 12 ++++ src/adapters/date-fns-jalali.ts | 1 + src/adapters/date-fns.ts | 1 + src/adapters/dayjs.ts | 1 + src/adapters/jalaali.ts | 1 + src/adapters/luxon.ts | 1 + src/index.ts | 1 + src/use-date-select.ts | 15 ++++- website/Main.mdx | 6 ++ website/components/CodePreview/scope.ts | 12 ++++ .../components/EyeCatchDateSelect/index.tsx | 17 ++++- website/samples/options/localization.tsx | 59 ++++++++++++++++++ 14 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 src/LocalizationProvider/LocalizationProvider.tsx create mode 100644 src/LocalizationProvider/index.ts create mode 100644 src/LocalizationProvider/useUtils.ts create mode 100644 src/adapters/date-fns-jalali.ts create mode 100644 src/adapters/date-fns.ts create mode 100644 src/adapters/dayjs.ts create mode 100644 src/adapters/jalaali.ts create mode 100644 src/adapters/luxon.ts create mode 100644 website/samples/options/localization.tsx diff --git a/src/LocalizationProvider/LocalizationProvider.tsx b/src/LocalizationProvider/LocalizationProvider.tsx new file mode 100644 index 0000000..0cd461a --- /dev/null +++ b/src/LocalizationProvider/LocalizationProvider.tsx @@ -0,0 +1,62 @@ +// Ref: https://github.com/mui/mui-x/blob/5dc5bd4b04eecf21c45cf6ea1169727ba5ab3be3/packages/x-date-pickers/src/LocalizationProvider/LocalizationProvider.tsx + +import * as React from "react"; +import { DateIOFormats } from "@date-io/core/IUtils"; +import { IUtils } from "@date-io/core/IUtils"; + +type DateAdapter = IUtils; + +export interface DateAdapterContextValue { + utils: DateAdapter; +} + +export const DateAdapterContext = + React.createContext | null>(null); +if (process.env.NODE_ENV !== "production") { + DateAdapterContext.displayName = "DateAdapterContext"; +} + +export interface LocalizationProviderProps { + children?: React.ReactNode; + /** DateIO adapter class function */ + dateAdapter: new (...args: any) => DateAdapter; + /** Formats that are used for the child dropdown */ + dateFormats?: Partial; + /** + * Date library instance you are using, if it has some global overrides + * ```jsx + * dateLibInstance={momentTimeZone} + * ``` + */ + dateLibInstance?: any; + /** Locale for the date library you are using */ + locale?: string | object; +} + +/** + * @ignore - do not document. + */ +export function LocalizationProvider(props: LocalizationProviderProps) { + const { + children, + dateAdapter: Utils, + dateFormats, + dateLibInstance, + locale, + } = props; + const utils = React.useMemo( + () => + new Utils({ locale, formats: dateFormats, instance: dateLibInstance }), + [Utils, locale, dateFormats, dateLibInstance] + ); + + const contextValue: DateAdapterContextValue = React.useMemo(() => { + return { utils }; + }, [utils]); + + return ( + + {children} + + ); +} diff --git a/src/LocalizationProvider/index.ts b/src/LocalizationProvider/index.ts new file mode 100644 index 0000000..552f8c1 --- /dev/null +++ b/src/LocalizationProvider/index.ts @@ -0,0 +1 @@ +export * from "./LocalizationProvider"; diff --git a/src/LocalizationProvider/useUtils.ts b/src/LocalizationProvider/useUtils.ts new file mode 100644 index 0000000..4e9a652 --- /dev/null +++ b/src/LocalizationProvider/useUtils.ts @@ -0,0 +1,12 @@ +import * as React from "react"; +import { DateAdapterContext } from "./LocalizationProvider"; + +export const useUtils = () => { + const localization = React.useContext(DateAdapterContext); + + if (localization == null) { + return null; + } + + return localization.utils; +}; diff --git a/src/adapters/date-fns-jalali.ts b/src/adapters/date-fns-jalali.ts new file mode 100644 index 0000000..1db0f89 --- /dev/null +++ b/src/adapters/date-fns-jalali.ts @@ -0,0 +1 @@ +export { default } from "@date-io/date-fns-jalali"; diff --git a/src/adapters/date-fns.ts b/src/adapters/date-fns.ts new file mode 100644 index 0000000..923e06b --- /dev/null +++ b/src/adapters/date-fns.ts @@ -0,0 +1 @@ +export { default } from "@date-io/date-fns"; diff --git a/src/adapters/dayjs.ts b/src/adapters/dayjs.ts new file mode 100644 index 0000000..4adf95e --- /dev/null +++ b/src/adapters/dayjs.ts @@ -0,0 +1 @@ +export { default } from "@date-io/dayjs"; diff --git a/src/adapters/jalaali.ts b/src/adapters/jalaali.ts new file mode 100644 index 0000000..48d21d9 --- /dev/null +++ b/src/adapters/jalaali.ts @@ -0,0 +1 @@ +export { default } from "@date-io/jalaali"; diff --git a/src/adapters/luxon.ts b/src/adapters/luxon.ts new file mode 100644 index 0000000..7f5718c --- /dev/null +++ b/src/adapters/luxon.ts @@ -0,0 +1 @@ +export { default } from "@date-io/luxon"; diff --git a/src/index.ts b/src/index.ts index 60f4507..d467ddf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,3 +7,4 @@ export { export * from "./use-date-select"; export { getDateString } from "./date-string"; export * from "./types"; +export * from "./LocalizationProvider"; diff --git a/src/use-date-select.ts b/src/use-date-select.ts index c754547..4b27516 100644 --- a/src/use-date-select.ts +++ b/src/use-date-select.ts @@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { range } from "./range"; import { compileDateString, parseDateString } from "./date-string"; import { Option, Options } from "./types"; +import { useUtils } from "./LocalizationProvider/useUtils"; const DEFAULT_MIN_YEAR = 1960; const DEFAULT_MAX_YEAR = new Date().getFullYear(); @@ -17,9 +18,6 @@ function compileOption(value: string): Option { return { value, label: value }; // TODO: Be customizable for localization } -const monthOptions: Options = range(1, 12).map((i) => - compileOption(convertToSelectValue(i)) -); const dayOptions: Options = range(1, 31).map((i) => compileOption(convertToSelectValue(i)) ); @@ -169,6 +167,8 @@ export const useDateSelect = ( } }, [setDate, value]); + const utils = useUtils(); + const yearOptions = useMemo(() => { const minYear = opts.minYear != null ? opts.minYear : DEFAULT_MIN_YEAR; const maxYear = opts.maxYear != null ? opts.maxYear : DEFAULT_MAX_YEAR; @@ -182,6 +182,15 @@ export const useDateSelect = ( return raw; }, [opts.minYear, opts.maxYear, state.yearValue]); + const monthOptions: Options = useMemo(() => { + return range(1, 12).map((i) => { + const label = utils + ? utils.format(new Date(1960, i - 1, 1), "monthShort") + : convertToSelectValue(i); + return { value: convertToSelectValue(i), label }; + }); + }, [utils]); + return { yearValue: state.yearValue, monthValue: state.monthValue, diff --git a/website/Main.mdx b/website/Main.mdx index 57ec38d..9dbb1d8 100644 --- a/website/Main.mdx +++ b/website/Main.mdx @@ -82,6 +82,12 @@ import HideDaySampleCode from "./samples/options/hide-day?raw"; `hideDay` prop to hide the day select. +### Localization + +import LocalizationSampleCode from "./samples/options/localization?raw"; + + + ### A custom component wrapping the preset component import ReusedPresetComponentSampleCode from "./samples/options/reused-preset-component?raw"; diff --git a/website/components/CodePreview/scope.ts b/website/components/CodePreview/scope.ts index 835960d..186c024 100644 --- a/website/components/CodePreview/scope.ts +++ b/website/components/CodePreview/scope.ts @@ -5,6 +5,12 @@ import * as reactYmdDateSelect from "react-ymd-date-select"; import * as vanillaPreset from "react-ymd-date-select/presets/vanilla"; import * as chakraPreset from "react-ymd-date-select/presets/chakra-ui"; import * as muiPreset from "react-ymd-date-select/presets/mui"; +import { default as DateFnsAdapter } from "react-ymd-date-select/adapters/date-fns"; +import dateFnsFrLocale from "date-fns/locale/fr"; +import dateFnsRuLocale from "date-fns/locale/ru"; +import dateFnsDeLocale from "date-fns/locale/de"; +import dateFnsEnLocale from "date-fns/locale/en-US"; +import dateFnsJaLocale from "date-fns/locale/ja"; export const scope = { import: { @@ -15,5 +21,11 @@ export const scope = { "react-ymd-date-select/presets/vanilla": vanillaPreset, "react-ymd-date-select/presets/chakra-ui": chakraPreset, "react-ymd-date-select/presets/material": muiPreset, + "react-ymd-date-select/adapters/date-fns": DateFnsAdapter, + "date-fns/locale/fr": dateFnsFrLocale, + "date-fns/locale/ru": dateFnsRuLocale, + "date-fns/locale/de": dateFnsDeLocale, + "date-fns/locale/en-US": dateFnsEnLocale, + "date-fns/locale/ja": dateFnsJaLocale, }, }; diff --git a/website/components/EyeCatchDateSelect/index.tsx b/website/components/EyeCatchDateSelect/index.tsx index 7fbe505..518b728 100644 --- a/website/components/EyeCatchDateSelect/index.tsx +++ b/website/components/EyeCatchDateSelect/index.tsx @@ -1,7 +1,12 @@ import { useState } from "react"; import { FormControl, FormErrorMessage, Select } from "@chakra-ui/react"; import styled from "@emotion/styled"; -import { useDateSelect, getDateString } from "react-ymd-date-select"; +import DateFnsAdapter from "@date-io/date-fns"; +import { + useDateSelect, + getDateString, + LocalizationProvider, +} from "react-ymd-date-select"; const dropdownIconColor = "#be5f6f"; const errorColor = "#fcdfff"; @@ -75,4 +80,12 @@ function EyeCatchDateSelect() { ); } -export default EyeCatchDateSelect; +function LocalizedEyeCatchDateSelect() { + return ( + + + + ); +} + +export default LocalizedEyeCatchDateSelect; diff --git a/website/samples/options/localization.tsx b/website/samples/options/localization.tsx new file mode 100644 index 0000000..2f990b6 --- /dev/null +++ b/website/samples/options/localization.tsx @@ -0,0 +1,59 @@ +import { useState } from "react"; +import frLocale from "date-fns/locale/fr"; +import ruLocale from "date-fns/locale/ru"; +import deLocale from "date-fns/locale/de"; +import enLocale from "date-fns/locale/en-US"; +import jaLocale from "date-fns/locale/ja"; +import { LocalizationProvider } from "react-ymd-date-select"; +import { DateSelect } from "react-ymd-date-select/presets/vanilla"; +/* Select the appropriate adapter for the library you are using as below. */ +import DateAdapter from "react-ymd-date-select/adapters/date-fns"; +// import DateAdapter from "react-ymd-date-select/adapters/dayjs"; +// import DateAdapter from "react-ymd-date-select/adapters/luxon"; +// import DateAdapter from "react-ymd-date-select/adapters/date-fns-jalali"; +// import DateAdapter from "react-ymd-date-select/adapters/jalaali"; + +const localeMap = { + en: enLocale, + fr: frLocale, + ru: ruLocale, + de: deLocale, + ja: jaLocale, +}; + +type Locale = keyof typeof localeMap; + +function Sample() { + const [locale, setLocale] = useState("en"); + const [date, setDate] = useState(""); + + return ( +
+
+ +
+ + + +

Selected date is: {date}

+
+
+ ); +} + +export default Sample; From 2e14aeaf6c579a7c50da9fb8c264960e90849856 Mon Sep 17 00:00:00 2001 From: "Yuichiro Tachibana (Tsuchiya)" Date: Thu, 12 May 2022 18:08:28 +0900 Subject: [PATCH 04/10] Remove jalali calendar adapters as the select values are now calculated only based on Gregorian calendar --- src/adapters/date-fns-jalali.ts | 1 - src/adapters/jalaali.ts | 1 - website/samples/options/localization.tsx | 2 -- 3 files changed, 4 deletions(-) delete mode 100644 src/adapters/date-fns-jalali.ts delete mode 100644 src/adapters/jalaali.ts diff --git a/src/adapters/date-fns-jalali.ts b/src/adapters/date-fns-jalali.ts deleted file mode 100644 index 1db0f89..0000000 --- a/src/adapters/date-fns-jalali.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "@date-io/date-fns-jalali"; diff --git a/src/adapters/jalaali.ts b/src/adapters/jalaali.ts deleted file mode 100644 index 48d21d9..0000000 --- a/src/adapters/jalaali.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "@date-io/jalaali"; diff --git a/website/samples/options/localization.tsx b/website/samples/options/localization.tsx index 2f990b6..5e2cb3d 100644 --- a/website/samples/options/localization.tsx +++ b/website/samples/options/localization.tsx @@ -10,8 +10,6 @@ import { DateSelect } from "react-ymd-date-select/presets/vanilla"; import DateAdapter from "react-ymd-date-select/adapters/date-fns"; // import DateAdapter from "react-ymd-date-select/adapters/dayjs"; // import DateAdapter from "react-ymd-date-select/adapters/luxon"; -// import DateAdapter from "react-ymd-date-select/adapters/date-fns-jalali"; -// import DateAdapter from "react-ymd-date-select/adapters/jalaali"; const localeMap = { en: enLocale, From db067bde1c08a23b4724638f7277e0014f3c541d Mon Sep 17 00:00:00 2001 From: "Yuichiro Tachibana (Tsuchiya)" Date: Thu, 12 May 2022 18:11:03 +0900 Subject: [PATCH 05/10] Add momentjs adapter --- package.json | 3 ++- src/adapters/moment.ts | 1 + website/samples/options/localization.tsx | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 src/adapters/moment.ts diff --git a/package.json b/package.json index e5535f9..193e78e 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,8 @@ "@date-io/date-fns-jalali": "^2.13.2", "@date-io/dayjs": "^2.13.2", "@date-io/jalaali": "^2.13.2", - "@date-io/luxon": "^2.13.2" + "@date-io/luxon": "^2.13.2", + "@date-io/moment": "^2.13.2" }, "devDependencies": { "@chakra-ui/icons": "^1.1.7", diff --git a/src/adapters/moment.ts b/src/adapters/moment.ts new file mode 100644 index 0000000..d0728c1 --- /dev/null +++ b/src/adapters/moment.ts @@ -0,0 +1 @@ +export { default } from "@date-io/moment"; diff --git a/website/samples/options/localization.tsx b/website/samples/options/localization.tsx index 5e2cb3d..c7e3cb7 100644 --- a/website/samples/options/localization.tsx +++ b/website/samples/options/localization.tsx @@ -10,6 +10,7 @@ import { DateSelect } from "react-ymd-date-select/presets/vanilla"; import DateAdapter from "react-ymd-date-select/adapters/date-fns"; // import DateAdapter from "react-ymd-date-select/adapters/dayjs"; // import DateAdapter from "react-ymd-date-select/adapters/luxon"; +// import DateAdapter from "react-ymd-date-select/adapters/moment"; const localeMap = { en: enLocale, From 950ea7055b56c22b6bb34c8d2601d29a8fa8ffd9 Mon Sep 17 00:00:00 2001 From: "Yuichiro Tachibana (Tsuchiya)" Date: Thu, 12 May 2022 18:16:19 +0900 Subject: [PATCH 06/10] Update to generate the labels of dayOptions via the location utils --- src/use-date-select.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/use-date-select.ts b/src/use-date-select.ts index 4b27516..204e816 100644 --- a/src/use-date-select.ts +++ b/src/use-date-select.ts @@ -18,10 +18,6 @@ function compileOption(value: string): Option { return { value, label: value }; // TODO: Be customizable for localization } -const dayOptions: Options = range(1, 31).map((i) => - compileOption(convertToSelectValue(i)) -); - interface DefaultDateOptions { defaultYear?: number | "now"; defaultMonth?: number | "now"; @@ -182,13 +178,22 @@ export const useDateSelect = ( return raw; }, [opts.minYear, opts.maxYear, state.yearValue]); - const monthOptions: Options = useMemo(() => { - return range(1, 12).map((i) => { + const [monthOptions, dayOptions] = useMemo(() => { + const monthOptions = range(1, 12).map((i) => { const label = utils ? utils.format(new Date(1960, i - 1, 1), "monthShort") - : convertToSelectValue(i); + : i.toString(); + return { value: convertToSelectValue(i), label }; + }); + + const dayOptions: Options = range(1, 31).map((i) => { + const label = utils + ? utils.format(new Date(1960, 1, i), "dayOfMonth") + : i.toString(); return { value: convertToSelectValue(i), label }; }); + + return [monthOptions, dayOptions]; }, [utils]); return { From ee86b72d542885b904c5e74f175700e7cae35734 Mon Sep 17 00:00:00 2001 From: "Yuichiro Tachibana (Tsuchiya)" Date: Thu, 12 May 2022 18:27:51 +0900 Subject: [PATCH 07/10] Update to generate the labels of yearOptions via the location utils --- src/use-date-select.ts | 51 +++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/use-date-select.ts b/src/use-date-select.ts index 204e816..c21cf30 100644 --- a/src/use-date-select.ts +++ b/src/use-date-select.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { range } from "./range"; import { compileDateString, parseDateString } from "./date-string"; -import { Option, Options } from "./types"; +import { Options } from "./types"; import { useUtils } from "./LocalizationProvider/useUtils"; const DEFAULT_MIN_YEAR = 1960; @@ -14,10 +14,6 @@ function convertToSelectValue(value: number): string { return value.toString(); } -function compileOption(value: string): Option { - return { value, label: value }; // TODO: Be customizable for localization -} - interface DefaultDateOptions { defaultYear?: number | "now"; defaultMonth?: number | "now"; @@ -163,37 +159,60 @@ export const useDateSelect = ( } }, [setDate, value]); + // Generate year, month, and day arrays using the locale. const utils = useUtils(); - const yearOptions = useMemo(() => { + const rawYearOptions = useMemo(() => { const minYear = opts.minYear != null ? opts.minYear : DEFAULT_MIN_YEAR; const maxYear = opts.maxYear != null ? opts.maxYear : DEFAULT_MAX_YEAR; - const raw = range(minYear, maxYear).map((i) => { - const s = convertToSelectValue(i); - return { value: s, label: s }; + const _yearOptions = range(minYear, maxYear).map((i) => { + const label = utils + ? utils.format(new Date(i, 0, 1), "year") + : i.toString(); + return { value: convertToSelectValue(i), label }; }); - if (!raw.some((o) => o.value === state.yearValue)) { - return raw.concat(compileOption(state.yearValue)); + return _yearOptions; + }, [opts.minYear, opts.maxYear, utils]); + + // If the value of `state.yearValue` is not included in the year select options, add it. + const yearOptions = useMemo(() => { + if ( + state.yearValue !== "" && + !rawYearOptions.some((o) => o.value === state.yearValue) + ) { + let label: string; + try { + label = utils + ? utils.format( + new Date(parseSelectValue(state.yearValue), 0, 1), + "year" + ) + : state.yearValue; + } catch { + label = state.yearValue; + } + return rawYearOptions.concat({ label, value: state.yearValue }); } - return raw; - }, [opts.minYear, opts.maxYear, state.yearValue]); + + return rawYearOptions; + }, [rawYearOptions, state.yearValue]); const [monthOptions, dayOptions] = useMemo(() => { - const monthOptions = range(1, 12).map((i) => { + const _monthOptions = range(1, 12).map((i) => { const label = utils ? utils.format(new Date(1960, i - 1, 1), "monthShort") : i.toString(); return { value: convertToSelectValue(i), label }; }); - const dayOptions: Options = range(1, 31).map((i) => { + const _dayOptions: Options = range(1, 31).map((i) => { const label = utils ? utils.format(new Date(1960, 1, i), "dayOfMonth") : i.toString(); return { value: convertToSelectValue(i), label }; }); - return [monthOptions, dayOptions]; + return [_monthOptions, _dayOptions]; }, [utils]); return { From 339040a14c68e11fdc7c75656ee1adbc36541b8c Mon Sep 17 00:00:00 2001 From: "Yuichiro Tachibana (Tsuchiya)" Date: Thu, 12 May 2022 18:38:52 +0900 Subject: [PATCH 08/10] Update the localization sample on Main.mdx --- website/Main.mdx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/website/Main.mdx b/website/Main.mdx index 9dbb1d8..98b5bd8 100644 --- a/website/Main.mdx +++ b/website/Main.mdx @@ -88,6 +88,15 @@ import LocalizationSampleCode from "./samples/options/localization?raw"; +You can set the locale through `` wrapping the component. + +It accesses the date library you are using to use locale functionality through the "adapter" object which is, in the example above, `react-ymd-date-select/adapters/date-fns` for [`date-fns`](https://date-fns.org/). +Please select an appropriate adapter for your project. + +With this design, this library can reuse the already installed date functions and can save the final bundle size. + +Note that the date library such as `date-fns` is NOT installed along with `react-ymd-date-select`, so you have to install it separately. + ### A custom component wrapping the preset component import ReusedPresetComponentSampleCode from "./samples/options/reused-preset-component?raw"; From bd63a598a8a36aaaa0a6e72fdb44408e3da02d7f Mon Sep 17 00:00:00 2001 From: "Yuichiro Tachibana (Tsuchiya)" Date: Thu, 12 May 2022 18:39:06 +0900 Subject: [PATCH 09/10] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba80e3a..a52f234 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Add + +- Localization, #70. + ## [0.0.8] - 2022-05-12 No package update. From 7c5bb241ead2f442f25a032d0c77ae164c0252b0 Mon Sep 17 00:00:00 2001 From: "Yuichiro Tachibana (Tsuchiya)" Date: Thu, 12 May 2022 18:42:42 +0900 Subject: [PATCH 10/10] Fix the order of the samples --- website/Main.mdx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/website/Main.mdx b/website/Main.mdx index 98b5bd8..914fb67 100644 --- a/website/Main.mdx +++ b/website/Main.mdx @@ -74,14 +74,6 @@ import PartialDefaultValueNowSampleCode from "./samples/options/partial-default- You can set `"now"` to `defaultYear`, `defaultMonth`, and `defaultDay`. -### Hide day - -import HideDaySampleCode from "./samples/options/hide-day?raw"; - - - -`hideDay` prop to hide the day select. - ### Localization import LocalizationSampleCode from "./samples/options/localization?raw"; @@ -97,6 +89,14 @@ With this design, this library can reuse the already installed date functions an Note that the date library such as `date-fns` is NOT installed along with `react-ymd-date-select`, so you have to install it separately. +### Hide day + +import HideDaySampleCode from "./samples/options/hide-day?raw"; + + + +`hideDay` prop to hide the day select. + ### A custom component wrapping the preset component import ReusedPresetComponentSampleCode from "./samples/options/reused-preset-component?raw";