@snack-uikit/calendar 0.13.13 → 0.13.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## <small>0.13.14 (2026-02-18)</small>
7
+
8
+ * feat(PDS-2680)!: added mode "month-range" and "year-range" for calendar & rename "range" in "date-ra ([6fbf360](https://github.com/cloud-ru-tech/snack-uikit/commit/6fbf360))
9
+
10
+
11
+
12
+
13
+
6
14
  ## <small>0.13.13 (2026-01-19)</small>
7
15
 
8
16
  * chore(FF-6693): migrate tests from TestCafe to Playwright ([f32aff8](https://github.com/cloud-ru-tech/snack-uikit/commit/f32aff8))
package/README.md CHANGED
@@ -16,10 +16,10 @@
16
16
 
17
17
  ### Description
18
18
 
19
- - `Calendar` — основной компонент для выбора дат и периодов: он может работать в режимах `date`, `range`, `month`, `year` и `date-time` (дата и время).
19
+ - `Calendar` — основной компонент для выбора дат и периодов: он может работать в режимах `date`, `date-range`, `month`, `month-range`, `year-range`, `year` и `date-time` (дата и время).
20
20
  - Компонент поддерживает как контролируемый (`value` + `onChangeValue`), так и неконтролируемый (`defaultValue`) режимы и умеет подстраиваться под разные размеры через проп `size` (`s`, `m`, `l`).
21
21
  - С помощью колбека `buildCellProps` можно управлять доступностью и подсветкой отдельных ячеек (например, отключить прошлые даты или выделить праздничные дни), а опция `showHolidays` автоматически раскрашивает выходные.
22
- - Проп `presets` позволяет добавить панель с пресетами для быстрого выбора периода в режиме `range`, в том числе с собственным списком вариантов.
22
+ - Проп `presets` позволяет добавить панель с пресетами для быстрого выбора периода в режиме `date-range`, в том числе с собственным списком вариантов.
23
23
  - Локаль (`locale`) задаёт язык подписей и первый день недели, при отсутствии явно переданного значения используется язык браузера пользователя.
24
24
  - Figma: [`Calendar`](https://www.figma.com/file/jtGxAPvFJOMir7V0eQFukN/Snack-UI-Kit-1.1.0?node-id=41%3A27244&mode=design).
25
25
 
@@ -41,7 +41,7 @@ function CalendarExample() {
41
41
 
42
42
  {/* Выбор периода c пресетами */}
43
43
  <Calendar
44
- mode='range'
44
+ mode='date-range'
45
45
  presets={{
46
46
  enabled: true,
47
47
  title: true,
@@ -102,7 +102,7 @@ function TimePickerExample() {
102
102
  ### Props
103
103
  | name | type | default value | description |
104
104
  |------|------|---------------|-------------|
105
- | mode* | "date" \| "date-time" \| "range" \| "month" \| "year" | - | Режим работы календаря: <br> - `date` - режим выбора даты <br> - `range` - режим выбора периода <br> - `month` - режим выбора месяца <br> - `date-time` - режим выбора даты и времени <br> - `year` - режим выбора года |
105
+ | mode* | "date" \| "date-time" \| "date-range" \| "month" \| "month-range" \| "year" \| "year-range" | - | Режим работы календаря: <br> - `date` - режим выбора даты <br> - `date-range` - режим выбора периода <br> - `month-range` - режим выбора периода из месяцев <br> - `year-range` - режим выбора периода из лет <br> - `month` - режим выбора месяца <br> - `date-time` - режим выбора даты и времени <br> - `year` - режим выбора года |
106
106
  | size | enum Size: `"s"`, `"m"`, `"l"` | m | Размер |
107
107
  | today | `number \| Date` | - | Дата сегодняшнего дня |
108
108
  | showHolidays | `boolean` | - | Раскрашивает субботу и воскресенье |
@@ -114,10 +114,10 @@ function TimePickerExample() {
114
114
  | locale | `Intl.Locale` | Проставляется в соответствие с языком в настройках браузера | Локаль, в соответствие с которой выставляется язык названий и первый день недели |
115
115
  | onFocusLeave | `(direction: FocusDirection) => void` | - | Колбек потери фокуса. Вызывается со значением `next`, когда фокус покидает компонент, передвигаясь вперед, по клавише `tab`. Со значением `prev` - по клавише стрелки вверх или `shift + tab`. |
116
116
  | navigationStartRef | `RefObject<{ focus(): void; }>` | - | Ссылка на управление первым элементом навигации |
117
- | presets | `PresetsOptions` | - | Настройки секции с пресетами быстрого выбора периода. Доступны только при mode === 'range' и отсутствии buildCellProps (временно PDS-3139) |
118
- | value | `Date \| Range` | - | Выбранное значение.<br> - в режиме date тип `Date` <br> - в режиме range тип `Range` (`[Date, Date]`) <br> - в режиме month тип `Date` <br> - в режиме date-time тип `Date` <br> - в режиме year тип `Date` |
119
- | defaultValue | `Date \| Range` | - | Значение по-умолчанию для uncontrolled.<br> - в режиме date тип `Date` <br> - в режиме range тип `Range` (`[Date, Date]`) <br> - в режиме month тип `Date` <br> - в режиме date-time тип `Date` <br> - в режиме year тип `Date` |
120
- | onChangeValue | `((value: Date) => void) \| ((value: Range) => void) \| ((value: Date) => void) \| ((value: Date) => void) \| ((value: Date) => void)` | - | Колбек выбора значения.<br> - в режиме date принимает тип `Date` <br> - в режиме range принимает тип `Range` <br> - в режиме month принимает тип `Date` <br> - в режиме date-time принимает тип `Date` <br> - в режиме year принимает тип `Date` |
117
+ | presets | `PresetsOptions` | - | Настройки секции с пресетами быстрого выбора периода. Доступны только при mode === 'date-range' и отсутствии buildCellProps (временно PDS-3139) |
118
+ | value | `Date \| Range` | - | Выбранное значение.<br> - в режиме date тип `Date` <br> - в режиме date-range тип `Range` (`[Date, Date]`) <br> - в режиме month-range тип `Range` (`[Date, Date]`) <br> - в режиме year-range тип `Range` (`[Date, Date]`) <br> - в режиме month тип `Date` <br> - в режиме date-time тип `Date` <br> - в режиме year тип `Date` |
119
+ | defaultValue | `Date \| Range` | - | Значение по-умолчанию для uncontrolled.<br> - в режиме date тип `Date` <br> - в режиме date-range тип `Range` (`[Date, Date]`) <br> - в режиме month-range тип `Range` (`[Date, Date]`) <br> - в режиме year-range тип `Range` (`[Date, Date]`) <br> - в режиме month тип `Date` <br> - в режиме date-time тип `Date` <br> - в режиме year тип `Date` |
120
+ | onChangeValue | `((value: Date) => void) \| ((value: Range) => void) \| ((value: Range) => void) \| ((value: Range) => void) \| ((value: Date) => void) \| ((value: Date) => void) \| ((value: Date) => void)` | - | Колбек выбора значения.<br> - в режиме date принимает тип `Date` <br> - в режиме date-range принимает тип `Range` <br> - в режиме month-range принимает тип `Range` <br> - в режиме year-range принимает тип `Range` <br> - в режиме month принимает тип `Date` <br> - в режиме date-time принимает тип `Date` <br> - в режиме year принимает тип `Date` |
121
121
  | showSeconds | `boolean` | - | Показывать ли секунды (только в режиме date-time) |
122
122
  ## TimePicker
123
123
  ### Props
@@ -46,7 +46,7 @@ type CommonCalendarProps = {
46
46
  navigationStartRef?: RefObject<{
47
47
  focus(): void;
48
48
  }>;
49
- /** Настройки секции с пресетами быстрого выбора периода. Доступны только при mode === 'range' и отсутствии buildCellProps (временно PDS-3139) */
49
+ /** Настройки секции с пресетами быстрого выбора периода. Доступны только при mode === 'date-range' и отсутствии buildCellProps (временно PDS-3139) */
50
50
  presets?: PresetsOptions;
51
51
  };
52
52
  type DateCalendarProps = CommonCalendarProps & {
@@ -92,15 +92,35 @@ type DateTimeCalendarProps = CommonCalendarProps & {
92
92
  showSeconds?: boolean;
93
93
  };
94
94
  type RangeCalendarProps = CommonCalendarProps & {
95
- /** <br> - `range` - режим выбора периода */
96
- mode: typeof CALENDAR_MODE.Range;
97
- /** <br> - в режиме range тип `Range` (`[Date, Date]`) */
95
+ /** <br> - `date-range` - режим выбора периода */
96
+ mode: typeof CALENDAR_MODE.DateRange;
97
+ /** <br> - в режиме date-range тип `Range` (`[Date, Date]`) */
98
98
  value?: Range;
99
- /** <br> - в режиме range тип `Range` (`[Date, Date]`) */
99
+ /** <br> - в режиме date-range тип `Range` (`[Date, Date]`) */
100
100
  defaultValue?: Range;
101
- /** <br> - в режиме range принимает тип `Range` */
101
+ /** <br> - в режиме date-range принимает тип `Range` */
102
102
  onChangeValue?(value: Range): void;
103
103
  };
104
- export type CalendarProps = WithSupportProps<DateCalendarProps | RangeCalendarProps | MonthCalendarProps | DateTimeCalendarProps | YearCalendarProps>;
104
+ type MonthRangeCalendarProps = CommonCalendarProps & {
105
+ /** <br> - `month-range` - режим выбора периода из месяцев */
106
+ mode: typeof CALENDAR_MODE.MonthRange;
107
+ /** <br> - в режиме month-range тип `Range` (`[Date, Date]`) */
108
+ value?: Range;
109
+ /** <br> - в режиме month-range тип `Range` (`[Date, Date]`) */
110
+ defaultValue?: Range;
111
+ /** <br> - в режиме month-range принимает тип `Range` */
112
+ onChangeValue?(value: Range): void;
113
+ };
114
+ type YearRangeCalendarProps = CommonCalendarProps & {
115
+ /** <br> - `year-range` - режим выбора периода из лет */
116
+ mode: typeof CALENDAR_MODE.YearRange;
117
+ /** <br> - в режиме year-range тип `Range` (`[Date, Date]`) */
118
+ value?: Range;
119
+ /** <br> - в режиме year-range тип `Range` (`[Date, Date]`) */
120
+ defaultValue?: Range;
121
+ /** <br> - в режиме year-range принимает тип `Range` */
122
+ onChangeValue?(value: Range): void;
123
+ };
124
+ export type CalendarProps = WithSupportProps<DateCalendarProps | RangeCalendarProps | MonthRangeCalendarProps | YearRangeCalendarProps | MonthCalendarProps | DateTimeCalendarProps | YearCalendarProps>;
105
125
  export declare function Calendar(props: CalendarProps): import("react/jsx-runtime").JSX.Element;
106
126
  export {};
@@ -6,9 +6,11 @@ export declare const VIEW_MODE: {
6
6
  export declare const CALENDAR_MODE: {
7
7
  readonly Date: "date";
8
8
  readonly DateTime: "date-time";
9
- readonly Range: "range";
9
+ readonly DateRange: "date-range";
10
10
  readonly Month: "month";
11
+ readonly MonthRange: "month-range";
11
12
  readonly Year: "year";
13
+ readonly YearRange: "year-range";
12
14
  };
13
15
  export declare const IN_RANGE_POSITION: {
14
16
  readonly Out: "out";
@@ -12,9 +12,11 @@ exports.VIEW_MODE = {
12
12
  exports.CALENDAR_MODE = {
13
13
  Date: 'date',
14
14
  DateTime: 'date-time',
15
- Range: 'range',
15
+ DateRange: 'date-range',
16
16
  Month: 'month',
17
- Year: 'year'
17
+ MonthRange: 'month-range',
18
+ Year: 'year',
19
+ YearRange: 'year-range'
18
20
  };
19
21
  exports.IN_RANGE_POSITION = {
20
22
  Out: 'out',
@@ -50,8 +50,10 @@ const CALENDAR_SIZE_MAP = {
50
50
  const CALENDAR_DEFAULT_MODE_MAP = {
51
51
  [constants_1.CALENDAR_MODE.Date]: constants_1.VIEW_MODE.Month,
52
52
  [constants_1.CALENDAR_MODE.DateTime]: constants_1.VIEW_MODE.Month,
53
- [constants_1.CALENDAR_MODE.Range]: constants_1.VIEW_MODE.Month,
53
+ [constants_1.CALENDAR_MODE.DateRange]: constants_1.VIEW_MODE.Month,
54
+ [constants_1.CALENDAR_MODE.MonthRange]: constants_1.VIEW_MODE.Year,
54
55
  [constants_1.CALENDAR_MODE.Month]: constants_1.VIEW_MODE.Year,
56
+ [constants_1.CALENDAR_MODE.YearRange]: constants_1.VIEW_MODE.Decade,
55
57
  [constants_1.CALENDAR_MODE.Year]: constants_1.VIEW_MODE.Decade
56
58
  };
57
59
  function CalendarBase(_a) {
@@ -111,8 +113,16 @@ function CalendarBase(_a) {
111
113
  });
112
114
  const setValue = (0, react_1.useCallback)(dates => {
113
115
  const [first, last] = (0, utils_2.sortDates)(dates);
116
+ if (mode === constants_1.CALENDAR_MODE.MonthRange) {
117
+ setValueState([(0, utils_2.getStartOfTheMonth)(first), (0, utils_2.getEndOfTheMonth)(last)]);
118
+ return;
119
+ }
120
+ if (mode === constants_1.CALENDAR_MODE.YearRange) {
121
+ setValueState([(0, utils_2.getStartOfTheYear)(first), (0, utils_2.getEndOfTheYear)(last)]);
122
+ return;
123
+ }
114
124
  setValueState([first, (0, utils_2.getEndOfTheDay)(last)]);
115
- }, [setValueState]);
125
+ }, [mode, setValueState]);
116
126
  const {
117
127
  preselectedRange,
118
128
  continuePreselect,
@@ -137,7 +147,7 @@ function CalendarBase(_a) {
137
147
  }
138
148
  return (0, utils_3.getDefaultPresets)(t, today);
139
149
  }, [presets === null || presets === void 0 ? void 0 : presets.items, t, today]);
140
- const arePeriodPresetsDisplayed = mode === 'range' && (presets === null || presets === void 0 ? void 0 : presets.enabled) && !buildCellProps; // TODO PDS-3139
150
+ const arePeriodPresetsDisplayed = mode === constants_1.CALENDAR_MODE.DateRange && (presets === null || presets === void 0 ? void 0 : presets.enabled) && !buildCellProps; // TODO PDS-3139
141
151
  const onPresetClick = (0, react_1.useCallback)(selectedPeriod => {
142
152
  setValue(selectedPeriod);
143
153
  }, [setValue]);
@@ -21,7 +21,9 @@ function DecadeView() {
21
21
  continuePreselect,
22
22
  restartPreselect,
23
23
  mode,
24
- setValue
24
+ setValue,
25
+ startPreselect,
26
+ completePreselect
25
27
  } = (0, react_1.useContext)(CalendarContext_1.CalendarContext);
26
28
  const grid = (0, hooks_1.useGrid)({
27
29
  buildGrid: utils_2.buildDecadeGrid,
@@ -29,6 +31,10 @@ function DecadeView() {
29
31
  isInPeriod: utils_1.isTheSameDecade,
30
32
  getItemLabel: utils_1.getYearLabel,
31
33
  onSelect(date) {
34
+ if (mode === constants_1.CALENDAR_MODE.YearRange) {
35
+ preselectedRange ? completePreselect(date) : startPreselect(date);
36
+ return;
37
+ }
32
38
  if (mode === constants_1.CALENDAR_MODE.Year) {
33
39
  setValue([date, date]);
34
40
  return;
@@ -61,7 +61,7 @@ function MonthView() {
61
61
  onDateChange(date);
62
62
  return;
63
63
  }
64
- if (mode === constants_1.CALENDAR_MODE.Range) {
64
+ if (mode === constants_1.CALENDAR_MODE.DateRange) {
65
65
  preselectedRange ? completePreselect(date) : startPreselect(date);
66
66
  return;
67
67
  }
@@ -23,7 +23,9 @@ function YearView() {
23
23
  restartPreselect,
24
24
  locale,
25
25
  setValue,
26
- mode
26
+ mode,
27
+ startPreselect,
28
+ completePreselect
27
29
  } = (0, react_1.useContext)(CalendarContext_1.CalendarContext);
28
30
  const grid = (0, hooks_1.useGrid)({
29
31
  buildGrid: utils_2.buildYearGrid,
@@ -35,6 +37,10 @@ function YearView() {
35
37
  setValue([date, date]);
36
38
  return;
37
39
  }
40
+ if (mode === constants_1.CALENDAR_MODE.MonthRange) {
41
+ preselectedRange ? completePreselect(date) : startPreselect(date);
42
+ return;
43
+ }
38
44
  setFocus(constants_1.AUTOFOCUS);
39
45
  setViewShift((0, utils_1.getMonthShift)(referenceDate, date));
40
46
  setViewMode(constants_1.VIEW_MODE.Month);
package/dist/cjs/hooks.js CHANGED
@@ -66,7 +66,8 @@ function useGrid(_ref) {
66
66
  }
67
67
  }
68
68
  const dateTimeSelectedValue = isDateFilled() ? new Date((_b = dateAndTime === null || dateAndTime === void 0 ? void 0 : dateAndTime.year) !== null && _b !== void 0 ? _b : 0, (_c = dateAndTime === null || dateAndTime === void 0 ? void 0 : dateAndTime.month) !== null && _c !== void 0 ? _c : 0, (_d = dateAndTime === null || dateAndTime === void 0 ? void 0 : dateAndTime.day) !== null && _d !== void 0 ? _d : 0) : undefined;
69
- const inRangePosition = mode === constants_1.CALENDAR_MODE.Range ? (0, utils_2.getInRangePosition)(date, viewMode, preselectedRange || value) : constants_1.IN_RANGE_POSITION.Out;
69
+ const isRangeMode = mode === constants_1.CALENDAR_MODE.DateRange || mode === constants_1.CALENDAR_MODE.MonthRange || mode === constants_1.CALENDAR_MODE.YearRange;
70
+ const inRangePosition = isRangeMode ? (0, utils_2.getInRangePosition)(date, viewMode, preselectedRange || value) : constants_1.IN_RANGE_POSITION.Out;
70
71
  const isSelectedValue = value && !preselectedRange && !dateTimeSelectedValue ? isTheSameItem(value[0], date) || isTheSameItem(value[1], date) : false;
71
72
  const isPreselected = preselectedRange ? isTheSameItem(preselectedRange[0], date) : false;
72
73
  const isDateTimeValueSelected = dateTimeSelectedValue ? isTheSameItem(dateTimeSelectedValue, date) : false;
@@ -15,6 +15,10 @@ export declare const isTheSameItem: (viewMode: ViewMode, date1: Date, date2: Dat
15
15
  export declare const sortDates: (dates: Date[]) => Date[];
16
16
  export declare const getInRangePosition: (date: Date, viewMode: ViewMode, range?: Range) => InRangePosition;
17
17
  export declare const getEndOfTheDay: (date: Date) => Date;
18
+ export declare const getStartOfTheMonth: (date: Date) => Date;
19
+ export declare const getEndOfTheMonth: (date: Date) => Date;
20
+ export declare const getStartOfTheYear: (date: Date) => Date;
21
+ export declare const getEndOfTheYear: (date: Date) => Date;
18
22
  export declare const getTestIdBuilder: (testId?: string) => (prefix: string) => string | undefined;
19
23
  export declare const getLocale: ({ localeProp, ctxLang }?: {
20
24
  localeProp?: Intl.Locale;
package/dist/cjs/utils.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isWeekend = exports.getStartOfWeek = exports.getLocale = exports.getTestIdBuilder = exports.getEndOfTheDay = exports.getInRangePosition = exports.sortDates = exports.isTheSameItem = exports.getDecadeShift = exports.getYearShift = exports.getMonthShift = exports.getYearLabel = exports.getDateLabel = exports.getMonthName = exports.capitalize = exports.isTheSameMonth = exports.isTheSameYear = exports.isTheSameDecade = void 0;
6
+ exports.isWeekend = exports.getStartOfWeek = exports.getLocale = exports.getTestIdBuilder = exports.getEndOfTheYear = exports.getStartOfTheYear = exports.getEndOfTheMonth = exports.getStartOfTheMonth = exports.getEndOfTheDay = exports.getInRangePosition = exports.sortDates = exports.isTheSameItem = exports.getDecadeShift = exports.getYearShift = exports.getMonthShift = exports.getYearLabel = exports.getDateLabel = exports.getMonthName = exports.capitalize = exports.isTheSameMonth = exports.isTheSameYear = exports.isTheSameDecade = void 0;
7
7
  exports.isTheSameDate = isTheSameDate;
8
8
  const weekstart_1 = require("weekstart");
9
9
  const utils_1 = require("@snack-uikit/utils");
@@ -77,6 +77,14 @@ const getInRangePosition = (date, viewMode, range) => {
77
77
  exports.getInRangePosition = getInRangePosition;
78
78
  const getEndOfTheDay = date => new Date(new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1).valueOf() - 1);
79
79
  exports.getEndOfTheDay = getEndOfTheDay;
80
+ const getStartOfTheMonth = date => new Date(new Date(date.getFullYear(), date.getMonth(), 1).valueOf());
81
+ exports.getStartOfTheMonth = getStartOfTheMonth;
82
+ const getEndOfTheMonth = date => new Date(new Date(date.getFullYear(), date.getMonth() + 1, 1).valueOf() - 1);
83
+ exports.getEndOfTheMonth = getEndOfTheMonth;
84
+ const getStartOfTheYear = date => new Date(new Date(date.getFullYear(), 0, 1).valueOf());
85
+ exports.getStartOfTheYear = getStartOfTheYear;
86
+ const getEndOfTheYear = date => new Date(new Date(date.getFullYear() + 1, 0, 1).valueOf() - 1);
87
+ exports.getEndOfTheYear = getEndOfTheYear;
80
88
  const getTestIdBuilder = testId => prefix => testId ? `${prefix}-${testId}` : undefined;
81
89
  exports.getTestIdBuilder = getTestIdBuilder;
82
90
  const getNavigatorLocale = () => {
@@ -46,7 +46,7 @@ type CommonCalendarProps = {
46
46
  navigationStartRef?: RefObject<{
47
47
  focus(): void;
48
48
  }>;
49
- /** Настройки секции с пресетами быстрого выбора периода. Доступны только при mode === 'range' и отсутствии buildCellProps (временно PDS-3139) */
49
+ /** Настройки секции с пресетами быстрого выбора периода. Доступны только при mode === 'date-range' и отсутствии buildCellProps (временно PDS-3139) */
50
50
  presets?: PresetsOptions;
51
51
  };
52
52
  type DateCalendarProps = CommonCalendarProps & {
@@ -92,15 +92,35 @@ type DateTimeCalendarProps = CommonCalendarProps & {
92
92
  showSeconds?: boolean;
93
93
  };
94
94
  type RangeCalendarProps = CommonCalendarProps & {
95
- /** <br> - `range` - режим выбора периода */
96
- mode: typeof CALENDAR_MODE.Range;
97
- /** <br> - в режиме range тип `Range` (`[Date, Date]`) */
95
+ /** <br> - `date-range` - режим выбора периода */
96
+ mode: typeof CALENDAR_MODE.DateRange;
97
+ /** <br> - в режиме date-range тип `Range` (`[Date, Date]`) */
98
98
  value?: Range;
99
- /** <br> - в режиме range тип `Range` (`[Date, Date]`) */
99
+ /** <br> - в режиме date-range тип `Range` (`[Date, Date]`) */
100
100
  defaultValue?: Range;
101
- /** <br> - в режиме range принимает тип `Range` */
101
+ /** <br> - в режиме date-range принимает тип `Range` */
102
102
  onChangeValue?(value: Range): void;
103
103
  };
104
- export type CalendarProps = WithSupportProps<DateCalendarProps | RangeCalendarProps | MonthCalendarProps | DateTimeCalendarProps | YearCalendarProps>;
104
+ type MonthRangeCalendarProps = CommonCalendarProps & {
105
+ /** <br> - `month-range` - режим выбора периода из месяцев */
106
+ mode: typeof CALENDAR_MODE.MonthRange;
107
+ /** <br> - в режиме month-range тип `Range` (`[Date, Date]`) */
108
+ value?: Range;
109
+ /** <br> - в режиме month-range тип `Range` (`[Date, Date]`) */
110
+ defaultValue?: Range;
111
+ /** <br> - в режиме month-range принимает тип `Range` */
112
+ onChangeValue?(value: Range): void;
113
+ };
114
+ type YearRangeCalendarProps = CommonCalendarProps & {
115
+ /** <br> - `year-range` - режим выбора периода из лет */
116
+ mode: typeof CALENDAR_MODE.YearRange;
117
+ /** <br> - в режиме year-range тип `Range` (`[Date, Date]`) */
118
+ value?: Range;
119
+ /** <br> - в режиме year-range тип `Range` (`[Date, Date]`) */
120
+ defaultValue?: Range;
121
+ /** <br> - в режиме year-range принимает тип `Range` */
122
+ onChangeValue?(value: Range): void;
123
+ };
124
+ export type CalendarProps = WithSupportProps<DateCalendarProps | RangeCalendarProps | MonthRangeCalendarProps | YearRangeCalendarProps | MonthCalendarProps | DateTimeCalendarProps | YearCalendarProps>;
105
125
  export declare function Calendar(props: CalendarProps): import("react/jsx-runtime").JSX.Element;
106
126
  export {};
@@ -6,9 +6,11 @@ export declare const VIEW_MODE: {
6
6
  export declare const CALENDAR_MODE: {
7
7
  readonly Date: "date";
8
8
  readonly DateTime: "date-time";
9
- readonly Range: "range";
9
+ readonly DateRange: "date-range";
10
10
  readonly Month: "month";
11
+ readonly MonthRange: "month-range";
11
12
  readonly Year: "year";
13
+ readonly YearRange: "year-range";
12
14
  };
13
15
  export declare const IN_RANGE_POSITION: {
14
16
  readonly Out: "out";
@@ -6,9 +6,11 @@ export const VIEW_MODE = {
6
6
  export const CALENDAR_MODE = {
7
7
  Date: 'date',
8
8
  DateTime: 'date-time',
9
- Range: 'range',
9
+ DateRange: 'date-range',
10
10
  Month: 'month',
11
+ MonthRange: 'month-range',
11
12
  Year: 'year',
13
+ YearRange: 'year-range',
12
14
  };
13
15
  export const IN_RANGE_POSITION = {
14
16
  Out: 'out',
@@ -18,7 +18,7 @@ import { useLocale } from '@snack-uikit/locale';
18
18
  import { extractSupportProps } from '@snack-uikit/utils';
19
19
  import { AUTOFOCUS, CALENDAR_MODE, SIZE, VIEW_MODE } from '../../constants';
20
20
  import { useDateAndTime } from '../../hooks';
21
- import { getEndOfTheDay, getLocale, getTestIdBuilder, sortDates } from '../../utils';
21
+ import { getEndOfTheDay, getEndOfTheMonth, getEndOfTheYear, getLocale, getStartOfTheMonth, getStartOfTheYear, getTestIdBuilder, sortDates, } from '../../utils';
22
22
  import { CalendarBody } from '../CalendarBody';
23
23
  import { CalendarContext } from '../CalendarContext';
24
24
  import { CalendarNavigation } from '../CalendarNavigation';
@@ -42,8 +42,10 @@ const CALENDAR_SIZE_MAP = {
42
42
  const CALENDAR_DEFAULT_MODE_MAP = {
43
43
  [CALENDAR_MODE.Date]: VIEW_MODE.Month,
44
44
  [CALENDAR_MODE.DateTime]: VIEW_MODE.Month,
45
- [CALENDAR_MODE.Range]: VIEW_MODE.Month,
45
+ [CALENDAR_MODE.DateRange]: VIEW_MODE.Month,
46
+ [CALENDAR_MODE.MonthRange]: VIEW_MODE.Year,
46
47
  [CALENDAR_MODE.Month]: VIEW_MODE.Year,
48
+ [CALENDAR_MODE.YearRange]: VIEW_MODE.Decade,
47
49
  [CALENDAR_MODE.Year]: VIEW_MODE.Decade,
48
50
  };
49
51
  export function CalendarBase(_a) {
@@ -64,8 +66,16 @@ export function CalendarBase(_a) {
64
66
  const secondsKeyboardNavigationRef = useRef({ focusItem: () => { } });
65
67
  const setValue = useCallback((dates) => {
66
68
  const [first, last] = sortDates(dates);
69
+ if (mode === CALENDAR_MODE.MonthRange) {
70
+ setValueState([getStartOfTheMonth(first), getEndOfTheMonth(last)]);
71
+ return;
72
+ }
73
+ if (mode === CALENDAR_MODE.YearRange) {
74
+ setValueState([getStartOfTheYear(first), getEndOfTheYear(last)]);
75
+ return;
76
+ }
67
77
  setValueState([first, getEndOfTheDay(last)]);
68
- }, [setValueState]);
78
+ }, [mode, setValueState]);
69
79
  const { preselectedRange, continuePreselect, completePreselect, restartPreselect, startPreselect } = useRange({
70
80
  setValue,
71
81
  });
@@ -79,7 +89,7 @@ export function CalendarBase(_a) {
79
89
  }
80
90
  return getDefaultPresets(t, today);
81
91
  }, [presets === null || presets === void 0 ? void 0 : presets.items, t, today]);
82
- const arePeriodPresetsDisplayed = mode === 'range' && (presets === null || presets === void 0 ? void 0 : presets.enabled) && !buildCellProps; // TODO PDS-3139
92
+ const arePeriodPresetsDisplayed = mode === CALENDAR_MODE.DateRange && (presets === null || presets === void 0 ? void 0 : presets.enabled) && !buildCellProps; // TODO PDS-3139
83
93
  const onPresetClick = useCallback((selectedPeriod) => {
84
94
  setValue(selectedPeriod);
85
95
  }, [setValue]);
@@ -7,13 +7,17 @@ import { CalendarContext } from '../CalendarContext';
7
7
  import { Grid } from '../Grid';
8
8
  import { buildDecadeGrid } from './utils';
9
9
  export function DecadeView() {
10
- const { referenceDate, setViewMode, setViewShift, preselectedRange, continuePreselect, restartPreselect, mode, setValue, } = useContext(CalendarContext);
10
+ const { referenceDate, setViewMode, setViewShift, preselectedRange, continuePreselect, restartPreselect, mode, setValue, startPreselect, completePreselect, } = useContext(CalendarContext);
11
11
  const grid = useGrid({
12
12
  buildGrid: buildDecadeGrid,
13
13
  isTheSameItem: isTheSameYear,
14
14
  isInPeriod: isTheSameDecade,
15
15
  getItemLabel: getYearLabel,
16
16
  onSelect(date) {
17
+ if (mode === CALENDAR_MODE.YearRange) {
18
+ preselectedRange ? completePreselect(date) : startPreselect(date);
19
+ return;
20
+ }
17
21
  if (mode === CALENDAR_MODE.Year) {
18
22
  setValue([date, date]);
19
23
  return;
@@ -39,7 +39,7 @@ export function MonthView() {
39
39
  onDateChange(date);
40
40
  return;
41
41
  }
42
- if (mode === CALENDAR_MODE.Range) {
42
+ if (mode === CALENDAR_MODE.DateRange) {
43
43
  preselectedRange ? completePreselect(date) : startPreselect(date);
44
44
  return;
45
45
  }
@@ -7,7 +7,7 @@ import { CalendarContext } from '../CalendarContext';
7
7
  import { Grid } from '../Grid';
8
8
  import { buildYearGrid } from './utils';
9
9
  export function YearView() {
10
- const { referenceDate, setViewMode, setViewShift, setFocus, preselectedRange, continuePreselect, restartPreselect, locale, setValue, mode, } = useContext(CalendarContext);
10
+ const { referenceDate, setViewMode, setViewShift, setFocus, preselectedRange, continuePreselect, restartPreselect, locale, setValue, mode, startPreselect, completePreselect, } = useContext(CalendarContext);
11
11
  const grid = useGrid({
12
12
  buildGrid: buildYearGrid,
13
13
  isTheSameItem: isTheSameMonth,
@@ -18,6 +18,10 @@ export function YearView() {
18
18
  setValue([date, date]);
19
19
  return;
20
20
  }
21
+ if (mode === CALENDAR_MODE.MonthRange) {
22
+ preselectedRange ? completePreselect(date) : startPreselect(date);
23
+ return;
24
+ }
21
25
  setFocus(AUTOFOCUS);
22
26
  setViewShift(getMonthShift(referenceDate, date));
23
27
  setViewMode(VIEW_MODE.Month);
package/dist/esm/hooks.js CHANGED
@@ -31,7 +31,8 @@ export function useGrid({ onSelect, onPreselect, onLeave, buildGrid, isTheSameIt
31
31
  const dateTimeSelectedValue = isDateFilled()
32
32
  ? new Date((_b = dateAndTime === null || dateAndTime === void 0 ? void 0 : dateAndTime.year) !== null && _b !== void 0 ? _b : 0, (_c = dateAndTime === null || dateAndTime === void 0 ? void 0 : dateAndTime.month) !== null && _c !== void 0 ? _c : 0, (_d = dateAndTime === null || dateAndTime === void 0 ? void 0 : dateAndTime.day) !== null && _d !== void 0 ? _d : 0)
33
33
  : undefined;
34
- const inRangePosition = mode === CALENDAR_MODE.Range
34
+ const isRangeMode = mode === CALENDAR_MODE.DateRange || mode === CALENDAR_MODE.MonthRange || mode === CALENDAR_MODE.YearRange;
35
+ const inRangePosition = isRangeMode
35
36
  ? getInRangePosition(date, viewMode, preselectedRange || value)
36
37
  : IN_RANGE_POSITION.Out;
37
38
  const isSelectedValue = value && !preselectedRange && !dateTimeSelectedValue
@@ -15,6 +15,10 @@ export declare const isTheSameItem: (viewMode: ViewMode, date1: Date, date2: Dat
15
15
  export declare const sortDates: (dates: Date[]) => Date[];
16
16
  export declare const getInRangePosition: (date: Date, viewMode: ViewMode, range?: Range) => InRangePosition;
17
17
  export declare const getEndOfTheDay: (date: Date) => Date;
18
+ export declare const getStartOfTheMonth: (date: Date) => Date;
19
+ export declare const getEndOfTheMonth: (date: Date) => Date;
20
+ export declare const getStartOfTheYear: (date: Date) => Date;
21
+ export declare const getEndOfTheYear: (date: Date) => Date;
18
22
  export declare const getTestIdBuilder: (testId?: string) => (prefix: string) => string | undefined;
19
23
  export declare const getLocale: ({ localeProp, ctxLang }?: {
20
24
  localeProp?: Intl.Locale;
package/dist/esm/utils.js CHANGED
@@ -54,6 +54,10 @@ export const getInRangePosition = (date, viewMode, range) => {
54
54
  return date.valueOf() >= start && date.valueOf() <= end ? IN_RANGE_POSITION.In : IN_RANGE_POSITION.Out;
55
55
  };
56
56
  export const getEndOfTheDay = (date) => new Date(new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1).valueOf() - 1);
57
+ export const getStartOfTheMonth = (date) => new Date(new Date(date.getFullYear(), date.getMonth(), 1).valueOf());
58
+ export const getEndOfTheMonth = (date) => new Date(new Date(date.getFullYear(), date.getMonth() + 1, 1).valueOf() - 1);
59
+ export const getStartOfTheYear = (date) => new Date(new Date(date.getFullYear(), 0, 1).valueOf());
60
+ export const getEndOfTheYear = (date) => new Date(new Date(date.getFullYear() + 1, 0, 1).valueOf() - 1);
57
61
  export const getTestIdBuilder = (testId) => (prefix) => (testId ? `${prefix}-${testId}` : undefined);
58
62
  const getNavigatorLocale = () => { var _a; return (isBrowser() ? ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.language) !== null && _a !== void 0 ? _a : 'ru-RU') : 'ru-RU'); };
59
63
  export const getLocale = ({ localeProp, ctxLang } = {}) => localeProp || new Intl.Locale(ctxLang ? ctxLang.replace('_', '-') : getNavigatorLocale());
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Calendar",
7
- "version": "0.13.13",
7
+ "version": "0.13.14",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -38,8 +38,8 @@
38
38
  "dependencies": {
39
39
  "@snack-uikit/button": "0.19.17",
40
40
  "@snack-uikit/divider": "3.2.11",
41
- "@snack-uikit/icons": "0.27.5",
42
- "@snack-uikit/list": "0.32.12",
41
+ "@snack-uikit/icons": "0.27.6",
42
+ "@snack-uikit/list": "0.32.13",
43
43
  "@snack-uikit/utils": "4.0.1",
44
44
  "classnames": "2.5.1",
45
45
  "uncontrollable": "8.0.4",
@@ -48,5 +48,5 @@
48
48
  "peerDependencies": {
49
49
  "@snack-uikit/locale": "*"
50
50
  },
51
- "gitHead": "84371bbf91915f650a852df849cd71d416c5b7b2"
51
+ "gitHead": "17b72086167d3d6503e4e74142358765230478c8"
52
52
  }
@@ -49,7 +49,7 @@ type CommonCalendarProps = {
49
49
  onFocusLeave?(direction: FocusDirection): void;
50
50
  /** Ссылка на управление первым элементом навигации */
51
51
  navigationStartRef?: RefObject<{ focus(): void }>;
52
- /** Настройки секции с пресетами быстрого выбора периода. Доступны только при mode === 'range' и отсутствии buildCellProps (временно PDS-3139) */
52
+ /** Настройки секции с пресетами быстрого выбора периода. Доступны только при mode === 'date-range' и отсутствии buildCellProps (временно PDS-3139) */
53
53
  presets?: PresetsOptions;
54
54
  };
55
55
 
@@ -100,18 +100,46 @@ type DateTimeCalendarProps = CommonCalendarProps & {
100
100
  };
101
101
 
102
102
  type RangeCalendarProps = CommonCalendarProps & {
103
- /** <br> - `range` - режим выбора периода */
104
- mode: typeof CALENDAR_MODE.Range;
105
- /** <br> - в режиме range тип `Range` (`[Date, Date]`) */
103
+ /** <br> - `date-range` - режим выбора периода */
104
+ mode: typeof CALENDAR_MODE.DateRange;
105
+ /** <br> - в режиме date-range тип `Range` (`[Date, Date]`) */
106
106
  value?: Range;
107
- /** <br> - в режиме range тип `Range` (`[Date, Date]`) */
107
+ /** <br> - в режиме date-range тип `Range` (`[Date, Date]`) */
108
108
  defaultValue?: Range;
109
- /** <br> - в режиме range принимает тип `Range` */
109
+ /** <br> - в режиме date-range принимает тип `Range` */
110
+ onChangeValue?(value: Range): void;
111
+ };
112
+
113
+ type MonthRangeCalendarProps = CommonCalendarProps & {
114
+ /** <br> - `month-range` - режим выбора периода из месяцев */
115
+ mode: typeof CALENDAR_MODE.MonthRange;
116
+ /** <br> - в режиме month-range тип `Range` (`[Date, Date]`) */
117
+ value?: Range;
118
+ /** <br> - в режиме month-range тип `Range` (`[Date, Date]`) */
119
+ defaultValue?: Range;
120
+ /** <br> - в режиме month-range принимает тип `Range` */
121
+ onChangeValue?(value: Range): void;
122
+ };
123
+
124
+ type YearRangeCalendarProps = CommonCalendarProps & {
125
+ /** <br> - `year-range` - режим выбора периода из лет */
126
+ mode: typeof CALENDAR_MODE.YearRange;
127
+ /** <br> - в режиме year-range тип `Range` (`[Date, Date]`) */
128
+ value?: Range;
129
+ /** <br> - в режиме year-range тип `Range` (`[Date, Date]`) */
130
+ defaultValue?: Range;
131
+ /** <br> - в режиме year-range принимает тип `Range` */
110
132
  onChangeValue?(value: Range): void;
111
133
  };
112
134
 
113
135
  export type CalendarProps = WithSupportProps<
114
- DateCalendarProps | RangeCalendarProps | MonthCalendarProps | DateTimeCalendarProps | YearCalendarProps
136
+ | DateCalendarProps
137
+ | RangeCalendarProps
138
+ | MonthRangeCalendarProps
139
+ | YearRangeCalendarProps
140
+ | MonthCalendarProps
141
+ | DateTimeCalendarProps
142
+ | YearCalendarProps
115
143
  >;
116
144
 
117
145
  export function Calendar(props: CalendarProps) {
package/src/constants.ts CHANGED
@@ -7,9 +7,11 @@ export const VIEW_MODE = {
7
7
  export const CALENDAR_MODE = {
8
8
  Date: 'date',
9
9
  DateTime: 'date-time',
10
- Range: 'range',
10
+ DateRange: 'date-range',
11
11
  Month: 'month',
12
+ MonthRange: 'month-range',
12
13
  Year: 'year',
14
+ YearRange: 'year-range',
13
15
  } as const;
14
16
 
15
17
  export const IN_RANGE_POSITION = {
@@ -18,7 +18,16 @@ import {
18
18
  Size,
19
19
  ViewMode,
20
20
  } from '../../types';
21
- import { getEndOfTheDay, getLocale, getTestIdBuilder, sortDates } from '../../utils';
21
+ import {
22
+ getEndOfTheDay,
23
+ getEndOfTheMonth,
24
+ getEndOfTheYear,
25
+ getLocale,
26
+ getStartOfTheMonth,
27
+ getStartOfTheYear,
28
+ getTestIdBuilder,
29
+ sortDates,
30
+ } from '../../utils';
22
31
  import { CalendarBody } from '../CalendarBody';
23
32
  import { CalendarContext } from '../CalendarContext';
24
33
  import { CalendarNavigation } from '../CalendarNavigation';
@@ -65,8 +74,10 @@ const CALENDAR_SIZE_MAP: Record<Size, string> = {
65
74
  const CALENDAR_DEFAULT_MODE_MAP: Record<CalendarMode, ViewMode> = {
66
75
  [CALENDAR_MODE.Date]: VIEW_MODE.Month,
67
76
  [CALENDAR_MODE.DateTime]: VIEW_MODE.Month,
68
- [CALENDAR_MODE.Range]: VIEW_MODE.Month,
77
+ [CALENDAR_MODE.DateRange]: VIEW_MODE.Month,
78
+ [CALENDAR_MODE.MonthRange]: VIEW_MODE.Year,
69
79
  [CALENDAR_MODE.Month]: VIEW_MODE.Year,
80
+ [CALENDAR_MODE.YearRange]: VIEW_MODE.Decade,
70
81
  [CALENDAR_MODE.Year]: VIEW_MODE.Decade,
71
82
  };
72
83
 
@@ -113,16 +124,27 @@ export function CalendarBase({
113
124
 
114
125
  const applyButtonRef = useRef<HTMLButtonElement>(null);
115
126
  const currentButtonRef = useRef<HTMLButtonElement>(null);
116
- const hoursKeyboardNavigationRef: ListProps['keyboardNavigationRef'] = useRef({ focusItem: () => {} });
117
- const minutesKeyboardNavigationRef: ListProps['keyboardNavigationRef'] = useRef({ focusItem: () => {} });
118
- const secondsKeyboardNavigationRef: ListProps['keyboardNavigationRef'] = useRef({ focusItem: () => {} });
127
+ const hoursKeyboardNavigationRef: ListProps['keyboardNavigationRef'] = useRef({ focusItem: () => { } });
128
+ const minutesKeyboardNavigationRef: ListProps['keyboardNavigationRef'] = useRef({ focusItem: () => { } });
129
+ const secondsKeyboardNavigationRef: ListProps['keyboardNavigationRef'] = useRef({ focusItem: () => { } });
119
130
 
120
131
  const setValue = useCallback(
121
132
  (dates: Range) => {
122
133
  const [first, last] = sortDates(dates);
134
+
135
+ if (mode === CALENDAR_MODE.MonthRange) {
136
+ setValueState([getStartOfTheMonth(first), getEndOfTheMonth(last)]);
137
+ return;
138
+ }
139
+
140
+ if (mode === CALENDAR_MODE.YearRange) {
141
+ setValueState([getStartOfTheYear(first), getEndOfTheYear(last)]);
142
+ return;
143
+ }
144
+
123
145
  setValueState([first, getEndOfTheDay(last)]);
124
146
  },
125
- [setValueState],
147
+ [mode, setValueState],
126
148
  );
127
149
 
128
150
  const { preselectedRange, continuePreselect, completePreselect, restartPreselect, startPreselect } = useRange({
@@ -145,7 +167,7 @@ export function CalendarBase({
145
167
  return getDefaultPresets(t, today);
146
168
  }, [presets?.items, t, today]);
147
169
 
148
- const arePeriodPresetsDisplayed = mode === 'range' && presets?.enabled && !buildCellProps; // TODO PDS-3139
170
+ const arePeriodPresetsDisplayed = mode === CALENDAR_MODE.DateRange && presets?.enabled && !buildCellProps; // TODO PDS-3139
149
171
 
150
172
  const onPresetClick = useCallback(
151
173
  (selectedPeriod: Range) => {
@@ -17,6 +17,8 @@ export function DecadeView() {
17
17
  restartPreselect,
18
18
  mode,
19
19
  setValue,
20
+ startPreselect,
21
+ completePreselect,
20
22
  } = useContext(CalendarContext);
21
23
 
22
24
  const grid = useGrid({
@@ -26,6 +28,11 @@ export function DecadeView() {
26
28
  getItemLabel: getYearLabel,
27
29
 
28
30
  onSelect(date: Date) {
31
+ if (mode === CALENDAR_MODE.YearRange) {
32
+ preselectedRange ? completePreselect(date) : startPreselect(date);
33
+ return;
34
+ }
35
+
29
36
  if (mode === CALENDAR_MODE.Year) {
30
37
  setValue([date, date]);
31
38
  return;
@@ -62,7 +62,7 @@ export function MonthView() {
62
62
  return;
63
63
  }
64
64
 
65
- if (mode === CALENDAR_MODE.Range) {
65
+ if (mode === CALENDAR_MODE.DateRange) {
66
66
  preselectedRange ? completePreselect(date) : startPreselect(date);
67
67
  return;
68
68
  }
@@ -19,6 +19,8 @@ export function YearView() {
19
19
  locale,
20
20
  setValue,
21
21
  mode,
22
+ startPreselect,
23
+ completePreselect,
22
24
  } = useContext(CalendarContext);
23
25
 
24
26
  const grid = useGrid({
@@ -33,6 +35,11 @@ export function YearView() {
33
35
  return;
34
36
  }
35
37
 
38
+ if (mode === CALENDAR_MODE.MonthRange) {
39
+ preselectedRange ? completePreselect(date) : startPreselect(date);
40
+ return;
41
+ }
42
+
36
43
  setFocus(AUTOFOCUS);
37
44
  setViewShift(getMonthShift(referenceDate, date));
38
45
  setViewMode(VIEW_MODE.Month);
package/src/hooks.ts CHANGED
@@ -72,10 +72,11 @@ export function useGrid({
72
72
  ? new Date(dateAndTime?.year ?? 0, dateAndTime?.month ?? 0, dateAndTime?.day ?? 0)
73
73
  : undefined;
74
74
 
75
- const inRangePosition =
76
- mode === CALENDAR_MODE.Range
77
- ? getInRangePosition(date, viewMode, preselectedRange || value)
78
- : IN_RANGE_POSITION.Out;
75
+ const isRangeMode =
76
+ mode === CALENDAR_MODE.DateRange || mode === CALENDAR_MODE.MonthRange || mode === CALENDAR_MODE.YearRange;
77
+ const inRangePosition = isRangeMode
78
+ ? getInRangePosition(date, viewMode, preselectedRange || value)
79
+ : IN_RANGE_POSITION.Out;
79
80
 
80
81
  const isSelectedValue =
81
82
  value && !preselectedRange && !dateTimeSelectedValue
package/src/utils.ts CHANGED
@@ -85,6 +85,15 @@ export const getInRangePosition = (date: Date, viewMode: ViewMode, range?: Range
85
85
  export const getEndOfTheDay = (date: Date) =>
86
86
  new Date(new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1).valueOf() - 1);
87
87
 
88
+ export const getStartOfTheMonth = (date: Date) => new Date(new Date(date.getFullYear(), date.getMonth(), 1).valueOf());
89
+
90
+ export const getEndOfTheMonth = (date: Date) =>
91
+ new Date(new Date(date.getFullYear(), date.getMonth() + 1, 1).valueOf() - 1);
92
+
93
+ export const getStartOfTheYear = (date: Date) => new Date(new Date(date.getFullYear(), 0, 1).valueOf());
94
+
95
+ export const getEndOfTheYear = (date: Date) => new Date(new Date(date.getFullYear() + 1, 0, 1).valueOf() - 1);
96
+
88
97
  export const getTestIdBuilder = (testId?: string) => (prefix: string) => (testId ? `${prefix}-${testId}` : undefined);
89
98
 
90
99
  const getNavigatorLocale = () => (isBrowser() ? (navigator?.language ?? 'ru-RU') : 'ru-RU');