diff --git a/cspell.json b/cspell.json index 5eb7be92b..82b92c2bf 100644 --- a/cspell.json +++ b/cspell.json @@ -2,5 +2,5 @@ "import": ["@esfront/cspell-config", "@cspell/dict-lorem-ipsum/cspell-ext.json"], "dictionaries": ["lorem-ipsum"], "ignorePaths": ["**/lib/**", "**/storybook-static/**", "packages/react/src/typedoc.json", "lerna.json"], - "words": ["Svyatoslav", "Daria", "Alekhina"] + "words": ["Svyatoslav", "Daria", "Alekhina", "нояб", "полд"] } diff --git a/package.json b/package.json index 0ee3b03ae..30eb5d0cc 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "packages/configs/cspell-config", "packages/configs/eslint-config", "packages/configs/prettier-config", + "packages/date-fns", "packages/react" ], "scripts": { diff --git a/packages/date-fns/LICENSE b/packages/date-fns/LICENSE new file mode 100644 index 000000000..2d376913c --- /dev/null +++ b/packages/date-fns/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2024 Elonsoft, Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/date-fns/README.md b/packages/date-fns/README.md new file mode 100644 index 000000000..edd4857e8 --- /dev/null +++ b/packages/date-fns/README.md @@ -0,0 +1,17 @@ +# @esfront/date-fns + +## Installation + +Install the correct versions of each package, which are listed by the command: + +``` +npm info "@esfront/date-fns@latest" peerDependencies +``` + +If using npm 5+, use this shortcut: + +``` +npx install-peerdeps --dev @esfront/date-fns +``` + +## Usage diff --git a/packages/date-fns/index.ts b/packages/date-fns/index.ts new file mode 100644 index 000000000..1460defa4 --- /dev/null +++ b/packages/date-fns/index.ts @@ -0,0 +1 @@ +export * from './ru-Ru'; diff --git a/packages/date-fns/package.json b/packages/date-fns/package.json new file mode 100644 index 000000000..66b052727 --- /dev/null +++ b/packages/date-fns/package.json @@ -0,0 +1,20 @@ +{ + "name": "@esfront/date-fns", + "version": "0.0.0", + "description": "", + "private": false, + "main": "index.ts", + "repository": { + "type": "git", + "url": "git+https://github.com/Elonsoft/esfront.git" + }, + "author": "", + "license": "MIT", + "bugs": { + "url": "https://github.com/Elonsoft/esfront/issues" + }, + "homepage": "https://github.com/Elonsoft/esfront#readme", + "peerDependencies": { + "date-fns": "^2.27.0" + } +} diff --git a/packages/date-fns/ru-Ru/_lib/localize/index.ts b/packages/date-fns/ru-Ru/_lib/localize/index.ts new file mode 100644 index 000000000..3d7ee958a --- /dev/null +++ b/packages/date-fns/ru-Ru/_lib/localize/index.ts @@ -0,0 +1,173 @@ +// @ts-expect-error buildLocalizeFn implicitly has an 'any' type. +import buildLocalizeFn from 'date-fns/locale/_lib/buildLocalizeFn'; + +import { LocalizeFnOptions } from '../../../types'; + +const eraValues = { + narrow: ['до н.э.', 'н.э.'], + abbreviated: ['до н. э.', 'н. э.'], + wide: ['до нашей эры', 'нашей эры'], +}; +const quarterValues = { + narrow: ['1', '2', '3', '4'], + abbreviated: ['1-й кв.', '2-й кв.', '3-й кв.', '4-й кв.'], + wide: ['1-й квартал', '2-й квартал', '3-й квартал', '4-й квартал'], +}; + +const monthValues = { + narrow: ['Я', 'Ф', 'М', 'А', 'М', 'И', 'И', 'А', 'С', 'О', 'Н', 'Д'], + abbreviated: ['янв.', 'фев.', 'март', 'апр.', 'май', 'июнь', 'июль', 'авг.', 'сент.', 'окт.', 'нояб.', 'дек.'], + wide: [ + 'январь', + 'февраль', + 'март', + 'апрель', + 'май', + 'июнь', + 'июль', + 'август', + 'сентябрь', + 'октябрь', + 'ноябрь', + 'декабрь', + ], +}; +const formattingMonthValues = { + narrow: ['Я', 'Ф', 'М', 'А', 'М', 'И', 'И', 'А', 'С', 'О', 'Н', 'Д'], + abbreviated: ['янв.', 'фев.', 'мар.', 'апр.', 'мая', 'июн.', 'июл.', 'авг.', 'сент.', 'окт.', 'нояб.', 'дек.'], + wide: [ + 'января', + 'февраля', + 'марта', + 'апреля', + 'мая', + 'июня', + 'июля', + 'августа', + 'сентября', + 'октября', + 'ноября', + 'декабря', + ], +}; + +const dayValues = { + narrow: ['В', 'П', 'В', 'С', 'Ч', 'П', 'С'], + short: ['вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб'], + abbreviated: ['вск', 'пнд', 'втр', 'срд', 'чтв', 'птн', 'суб'], + wide: ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'], +}; + +const dayPeriodValues = { + narrow: { + am: 'ДП', + pm: 'ПП', + midnight: 'полн.', + noon: 'полд.', + morning: 'утро', + afternoon: 'день', + evening: 'веч.', + night: 'ночь', + }, + abbreviated: { + am: 'ДП', + pm: 'ПП', + midnight: 'полн.', + noon: 'полд.', + morning: 'утро', + afternoon: 'день', + evening: 'веч.', + night: 'ночь', + }, + wide: { + am: 'ДП', + pm: 'ПП', + midnight: 'полночь', + noon: 'полдень', + morning: 'утро', + afternoon: 'день', + evening: 'вечер', + night: 'ночь', + }, +}; +const formattingDayPeriodValues = { + narrow: { + am: 'ДП', + pm: 'ПП', + midnight: 'полн.', + noon: 'полд.', + morning: 'утра', + afternoon: 'дня', + evening: 'веч.', + night: 'ночи', + }, + abbreviated: { + am: 'ДП', + pm: 'ПП', + midnight: 'полн.', + noon: 'полд.', + morning: 'утра', + afternoon: 'дня', + evening: 'веч.', + night: 'ночи', + }, + wide: { + am: 'ДП', + pm: 'ПП', + midnight: 'полночь', + noon: 'полдень', + morning: 'утра', + afternoon: 'дня', + evening: 'вечера', + night: 'ночи', + }, +}; + +function ordinalNumber(dirtyNumber: any, dirtyOptions: LocalizeFnOptions) { + const options = dirtyOptions || {}; + const unit = String(options.unit); + let suffix; + + if (unit === 'date') { + suffix = '-е'; + } else if (unit === 'week' || unit === 'minute' || unit === 'second') { + suffix = '-я'; + } else { + suffix = '-й'; + } + + return dirtyNumber + suffix; +} + +const localize: Locale['localize'] = { + ordinalNumber, + era: buildLocalizeFn({ + values: eraValues, + defaultWidth: 'wide', + }), + quarter: buildLocalizeFn({ + values: quarterValues, + defaultWidth: 'wide', + argumentCallback(quarter: any) { + return Number(quarter) - 1; + }, + }), + month: buildLocalizeFn({ + values: monthValues, + defaultWidth: 'wide', + formattingValues: formattingMonthValues, + defaultFormattingWidth: 'wide', + }), + day: buildLocalizeFn({ + values: dayValues, + defaultWidth: 'wide', + }), + dayPeriod: buildLocalizeFn({ + values: dayPeriodValues, + defaultWidth: 'any', + formattingValues: formattingDayPeriodValues, + defaultFormattingWidth: 'wide', + }), +}; + +export default localize; diff --git a/packages/date-fns/ru-Ru/index.ts b/packages/date-fns/ru-Ru/index.ts new file mode 100644 index 000000000..f38749e75 --- /dev/null +++ b/packages/date-fns/ru-Ru/index.ts @@ -0,0 +1,22 @@ +import { formatDistance, formatRelative } from 'date-fns'; +// @ts-expect-error formatLong implicitly has an 'any' type. +import formatLong from 'date-fns/locale/ru/_lib/formatLong'; +// @ts-expect-error match implicitly has an 'any' type. +import match from 'date-fns/locale/ru/_lib/match'; + +import localize from './_lib/localize'; + +const locale: Locale = { + code: 'ru-Ru', + formatDistance, + formatLong, + formatRelative, + localize, + match, + options: { + weekStartsOn: 1, + firstWeekContainsDate: 1, + }, +}; + +export default locale; diff --git a/packages/date-fns/types.ts b/packages/date-fns/types.ts new file mode 100644 index 000000000..440428c0d --- /dev/null +++ b/packages/date-fns/types.ts @@ -0,0 +1,21 @@ +/** + * The units commonly used in the date formatting or parsing. + */ +export type LocaleUnit = + | 'second' + | 'minute' + | 'hour' + | 'day' + | 'dayOfYear' + | 'date' + | 'week' + | 'month' + | 'quarter' + | 'year'; + +export interface LocalizeFnOptions { + width?: 'narrow' | 'short' | 'abbreviated' | 'wide' | 'any'; + context?: 'formatting' | 'standalone'; + + unit?: LocaleUnit; +} diff --git a/packages/react/src/testing/Theme/Theme.tsx b/packages/react/src/testing/Theme/Theme.tsx index 8045bb035..423285227 100644 --- a/packages/react/src/testing/Theme/Theme.tsx +++ b/packages/react/src/testing/Theme/Theme.tsx @@ -3,7 +3,7 @@ import { useEffect, useMemo } from 'react'; import { IThemeProps } from './Theme.types'; import DateFnsAdapter from '@date-io/date-fns'; -import { enUS as dateEN, ru as dateRU } from 'date-fns/locale'; +import { enUS as dateEN } from 'date-fns/locale'; import { useColorScheme } from '@mui/material/styles'; import { enUS, ruRU } from '@mui/material/locale'; @@ -12,6 +12,10 @@ import { DateAdapterProvider, en, ru } from '../../components'; import { DialogStackProvider } from '../../components/DialogStack'; import { createTheme, palettes, ThemeProvider } from '../../theming'; +import locale from '@esfront/date-fns/ru-Ru'; + +const dateRU = locale; + function ColorScheme({ isDarkMode }: { isDarkMode?: boolean }) { const { setMode } = useColorScheme();