Repository: salute-developers/plasma
Pull request #1932: PLASMA-4680: make min/max for TimePicker optional
Author: login: TitanKuzmich
Created: 2025-04-21T13:58:15Z | Merged: 2025-04-25T12:19:25Z

## PLASMA-UI

### TimePicker

- min и max теперь необязательные пропсы

### What/why changed

min и max теперь необязательные пропсы
<!-- GITHUB_RELEASE PR BODY: canary-version -->
<details>
  <summary>📦 Published PR as canary version: <code>Canary Versions</code></summary>
  <br />

  :sparkles: Test out this PR locally via:
  
  ```bash
  npm install @salutejs/plasma-asdk@0.336.0-canary.1932.14660991122.0
  npm install @salutejs/plasma-b2c@1.578.0-canary.1932.14660991122.0
  npm install @salutejs/plasma-giga@0.305.0-canary.1932.14660991122.0
  npm install @salutejs/plasma-hope@1.340.0-canary.1932.14660991122.0
  npm install @salutejs/plasma-new-hope@0.322.0-canary.1932.14660991122.0
  npm install @salutejs/plasma-ui@1.316.0-canary.1932.14660991122.0
  npm install @salutejs/plasma-web@1.580.0-canary.1932.14660991122.0
  npm install @salutejs/sdds-clfd-auto@0.309.0-canary.1932.14660991122.0
  npm install @salutejs/sdds-cs@0.314.0-canary.1932.14660991122.0
  npm install @salutejs/sdds-dfa@0.308.0-canary.1932.14660991122.0
  npm install @salutejs/sdds-finportal@0.301.0-canary.1932.14660991122.0
  npm install @salutejs/sdds-insol@0.305.0-canary.1932.14660991122.0
  npm install @salutejs/sdds-serv@0.309.0-canary.1932.14660991122.0
  npm install @salutejs/plasma-themes@0.33.0-canary.1932.14660991122.0
  npm install @salutejs/sdds-themes@0.36.0-canary.1932.14660991122.0
  npm install @salutejs/plasma-sb-utils@0.197.0-canary.1932.14660991122.0
  # or 
  yarn add @salutejs/plasma-asdk@0.336.0-canary.1932.14660991122.0
  yarn add @salutejs/plasma-b2c@1.578.0-canary.1932.14660991122.0
  yarn add @salutejs/plasma-giga@0.305.0-canary.1932.14660991122.0
  yarn add @salutejs/plasma-hope@1.340.0-canary.1932.14660991122.0
  yarn add @salutejs/plasma-new-hope@0.322.0-canary.1932.14660991122.0
  yarn add @salutejs/plasma-ui@1.316.0-canary.1932.14660991122.0
  yarn add @salutejs/plasma-web@1.580.0-canary.1932.14660991122.0
  yarn add @salutejs/sdds-clfd-auto@0.309.0-canary.1932.14660991122.0
  yarn add @salutejs/sdds-cs@0.314.0-canary.1932.14660991122.0
  yarn add @salutejs/sdds-dfa@0.308.0-canary.1932.14660991122.0
  yarn add @salutejs/sdds-finportal@0.301.0-canary.1932.14660991122.0
  yarn add @salutejs/sdds-insol@0.305.0-canary.1932.14660991122.0
  yarn add @salutejs/sdds-serv@0.309.0-canary.1932.14660991122.0
  yarn add @salutejs/plasma-themes@0.33.0-canary.1932.14660991122.0
  yarn add @salutejs/sdds-themes@0.36.0-canary.1932.14660991122.0
  yarn add @salutejs/plasma-sb-utils@0.197.0-canary.1932.14660991122.0
  ```
</details>
<!-- GITHUB_RELEASE PR BODY: canary-version -->



Diff:
diff --git a/packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.tsx b/packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.tsx
index 8f69de25fd1..3bb7fe46591 100644
--- a/packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.tsx
+++ b/packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.tsx
@@ -18,6 +18,11 @@ import {
     getTimeFromStructure,
 } from './utils';
 
+// NOTE: 1000 * 3600 * 24
+const timeToDayCoef = 86_400_000;
+export const MIN_TIME = new Date(1970, 0, 0, 0, 0, 0);
+export const MAX_TIME = new Date(1970, 0, 0, 23, 59, 59);
+
 /**
  * Компонент для выбора времени.
  */
@@ -26,9 +31,10 @@ export const TimePicker = ({
     options = defaultOptions,
     step,
     size,
-    value,
+    value: innerValue,
     min,
     max,
+    maxDateDayDiff = 100,
     disabled,
     controls,
     autofocus,
@@ -48,14 +54,30 @@ export const TimePicker = ({
     hasLabel = false,
     ...rest
 }: TimePickerProps) => {
-    const normalizeValues = useMemo(() => getNormalizeValues(value, min, max, step), [value]);
+    const minTime = !min || !max ? MIN_TIME : min;
+    const maxTime = !min || !max ? MAX_TIME : max;
+
+    const dateDayDiff = Math.abs((maxTime.getTime() - minTime.getTime()) / timeToDayCoef);
+
+    if (dateDayDiff > maxDateDayDiff) {
+        console.error(
+            `Время привязано к определенной дате в TimePicker. Сейчас разница составляет больше ${maxDateDayDiff} дней: ${dateDayDiff}. Генерация такого промежутка значений может повлиять на производительность.`,
+        );
+    }
+
+    const value =
+        !min || !max
+            ? new Date(1970, 0, 0, innerValue.getHours(), innerValue.getMinutes(), innerValue.getSeconds())
+            : innerValue;
+
+    const normalizeValues = useMemo(() => getNormalizeValues(value, minTime, maxTime, step), [value]);
     const [{ year, month, day, hours, minutes, seconds }, setState] = useState(normalizeValues);
-    const minDateStructure = getDateStructure(min);
-    const maxDateStructure = getDateStructure(max);
+    const minDateStructure = getDateStructure(minTime);
+    const maxDateStructure = getDateStructure(maxTime);
 
     const [secondsFrom, secondsTo] = useMemo(() => {
-        const minSecondsDate = new Date(min);
-        const maxSecondsDate = new Date(max);
+        const minSecondsDate = new Date(minTime);
+        const maxSecondsDate = new Date(maxTime);
 
         const currentSecondsDate = new Date(year, month, day, hours, minutes);
 
@@ -82,11 +104,11 @@ export const TimePicker = ({
         }
 
         return [MIN_SECONDS, MAX_SECONDS];
-    }, [min, max, year, month, day, hours, minutes]);
+    }, [minTime, maxTime, year, month, day, hours, minutes]);
 
     const [minutesFrom, minutesTo] = useMemo(() => {
-        const minMinutesDate = new Date(min);
-        const maxMinutesDate = new Date(max);
+        const minMinutesDate = new Date(minTime);
+        const maxMinutesDate = new Date(maxTime);
         const currentMinutesDate = new Date(year, month, day, hours);
 
         const minMinutesValue = getMinutes(minMinutesDate);
@@ -115,7 +137,7 @@ export const TimePicker = ({
         }
 
         return [MIN_MINUTES, MAX_MINUTES];
-    }, [min, max, year, month, day, hours]);
+    }, [minTime, maxTime, year, month, day, hours]);
 
     const secondsRange = useMemo(() => {
         const secondsStep = step ? (step % 3600) % 60 : 1;
@@ -150,8 +172,8 @@ export const TimePicker = ({
 
     const getNextDateStructure = useCallback(
         (currentDate: Date) => {
-            const minDate = new Date(min);
-            const maxDate = new Date(max);
+            const minDate = new Date(minTime);
+            const maxDate = new Date(maxTime);
 
             const nextDate = new Date(currentDate);
             nextDate.setMinutes(minutes);
@@ -171,7 +193,7 @@ export const TimePicker = ({
 
             return { nextMinute: minutes, nextSecond: seconds };
         },
-        [min, max, hours, minutes, seconds],
+        [minTime, maxTime, hours, minutes, seconds],
     );
 
     const onSecondsChange = ({ date }: PickerItem) => {
diff --git a/packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.types.ts b/packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.types.ts
index c0bdd826fdc..692b6ec3739 100644
--- a/packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.types.ts
+++ b/packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.types.ts
@@ -25,11 +25,16 @@ export interface TimePickerProps
     /**
      * Максимальное значение даты
      */
-    max: Date;
+    max?: Date;
     /**
      * Минимальное значение даты
      */
-    min: Date;
+    min?: Date;
+    /**
+     * Допустимая разница между максимальной и минимальной датами,
+     * при которой не вызывается предупреждение о генерации массивов часов, минут и секунд
+     */
+    maxDateDayDiff?: number;
     /**
      * Формат выводимого значения
      */


Reviews:
user: login: Yakutoc
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T04:36:56Z
user: login: TitanKuzmich
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T07:39:11Z
user: login: iljs
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T07:31:49Z
user: login: neretin-trike
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-24T14:09:23Z
user: login: neretin-trike
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-24T14:10:08Z
user: login: neretin-trike
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-24T14:11:18Z

Review comments:
diff_hunk: @@ -25,11 +25,11 @@ export interface TimePickerProps
     /**
      * Максимальное значение даты
      */
-    max: Date;
+    max?: Date;
path: packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.types.ts
user: login: Yakutoc
body: @TitanKuzmich Почему? Можешь тезисно объяснить?   
created_at: 2025-04-22T04:36:56Z
author_association: COLLABORATOR
diff_hunk: @@ -25,11 +25,11 @@ export interface TimePickerProps
     /**
      * Максимальное значение даты
      */
-    max: Date;
+    max?: Date;
path: packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.types.ts
user: login: TitanKuzmich
body: Увидел при применении этого компонента каст значений к Date со стороны пользователя (через as Date). Так безопаснее
created_at: 2025-04-22T07:39:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -18,6 +18,9 @@ import {
     getTimeFromStructure,
 } from './utils';
 
+export const MIN_TIME = new Date(2000, 0, 0, 0, 0, 0);
+export const MAX_TIME = new Date(2000, 0, 0, 23, 59, 59);
path: packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.tsx
user: login: neretin-trike
body: может по классике [1970](https://en.wikipedia.org/wiki/Unix_time)?  
created_at: 2025-04-24T14:09:23Z
author_association: COLLABORATOR
diff_hunk: @@ -48,14 +52,30 @@ export const TimePicker = ({
     hasLabel = false,
     ...rest
 }: TimePickerProps) => {
-    const normalizeValues = useMemo(() => getNormalizeValues(value, min, max, step), [value]);
+    const minTime = !min || !max ? MIN_TIME : min;
+    const maxTime = !min || !max ? MAX_TIME : max;
+
+    const dateDayDiff = Math.abs((maxTime.getTime() - minTime.getTime()) / (1000 * 3600 * 24));
path: packages/plasma-ui/src/components/Pickers/TimePicker/TimePicker.tsx
user: login: neretin-trike
body: 1000 * 3600 * 24 = 86_400_000 и можно сразу в константу занести
created_at: 2025-04-24T14:10:08Z
author_association: COLLABORATOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-21T14:01:28Z
body: Theme Builder app deployed!

https://plasma.sberdevices.ru/pr/plasma-theme-builder-pr-1932/
<!-- Sticky Pull Request CommentTheme Builder -->
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-21T14:20:24Z
body: Documentation preview deployed!

website: https://plasma.sberdevices.ru/pr/pr-1932/
ui storybook: https://plasma.sberdevices.ru/pr/pr-1932/ui-storybook/
<!-- Sticky Pull Request CommentLinks -->
author_association: CONTRIBUTOR