@skbkontur/react-ui 6.1.7-1c902.0 → 6.1.7-4c72d.0
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/components/MenuItem/MenuItem.d.ts +1 -1
- package/components/MenuItem/MenuItem.js +0 -1
- package/components/MenuItem/MenuItem.js.map +1 -1
- package/components/MenuItem/MenuItem.styles.d.ts +0 -1
- package/components/MenuItem/MenuItem.styles.js +7 -10
- package/components/MenuItem/MenuItem.styles.js.map +1 -1
- package/components/TimePicker/TimePicker.d.ts +44 -25
- package/components/TimePicker/TimePicker.js +373 -191
- package/components/TimePicker/TimePicker.js.map +1 -1
- package/components/TimePicker/TimePicker.styles.d.ts +3 -1
- package/components/TimePicker/TimePicker.styles.js +9 -3
- package/components/TimePicker/TimePicker.styles.js.map +1 -1
- package/components/TimePicker/TimePickerItems.d.ts +5 -1
- package/components/TimePicker/TimePickerItems.js +39 -29
- package/components/TimePicker/TimePickerItems.js.map +1 -1
- package/components/TimePicker/TimePickerMobilePopup.d.ts +5 -2
- package/components/TimePicker/TimePickerMobilePopup.js +4 -4
- package/components/TimePicker/TimePickerMobilePopup.js.map +1 -1
- package/components/TimePicker/TimePickerPopup.d.ts +5 -1
- package/components/TimePicker/TimePickerPopup.js +4 -4
- package/components/TimePicker/TimePickerPopup.js.map +1 -1
- package/components/TimePicker/helpers/TimePicker.constants.d.ts +8 -1
- package/components/TimePicker/helpers/TimePicker.constants.js +8 -7
- package/components/TimePicker/helpers/TimePicker.constants.js.map +1 -1
- package/components/TimePicker/helpers/TimePicker.editing.d.ts +1 -5
- package/components/TimePicker/helpers/TimePicker.editing.js +8 -35
- package/components/TimePicker/helpers/TimePicker.editing.js.map +1 -1
- package/components/TimePicker/helpers/TimePicker.shared.d.ts +20 -22
- package/components/TimePicker/helpers/TimePicker.shared.js +27 -24
- package/components/TimePicker/helpers/TimePicker.shared.js.map +1 -1
- package/components/TimePicker/helpers/TimePicker.value.d.ts +22 -11
- package/components/TimePicker/helpers/TimePicker.value.js +69 -37
- package/components/TimePicker/helpers/TimePicker.value.js.map +1 -1
- package/components/TimePicker/helpers/scrollSelectedItemIntoView.d.ts +2 -0
- package/components/TimePicker/helpers/scrollSelectedItemIntoView.js +2 -0
- package/components/TimePicker/helpers/scrollSelectedItemIntoView.js.map +1 -1
- package/components/TimePicker/helpers/validateTimePicker.js +2 -4
- package/components/TimePicker/helpers/validateTimePicker.js.map +1 -1
- package/components/TimePicker/hooks/useTimePickerDropdown.d.ts +6 -1
- package/components/TimePicker/hooks/useTimePickerDropdown.js +15 -33
- package/components/TimePicker/hooks/useTimePickerDropdown.js.map +1 -1
- package/components/TimePicker/hooks/useTimePickerSource.d.ts +29 -0
- package/components/TimePicker/hooks/useTimePickerSource.js +67 -0
- package/components/TimePicker/hooks/useTimePickerSource.js.map +1 -0
- package/components/TimePicker/hooks/useTimePickerValue.d.ts +15 -4
- package/components/TimePicker/hooks/useTimePickerValue.js +40 -20
- package/components/TimePicker/hooks/useTimePickerValue.js.map +1 -1
- package/components/TimePicker/index.d.ts +3 -1
- package/components/TimePicker/index.js +1 -0
- package/components/TimePicker/index.js.map +1 -1
- package/components/TimePicker/locale/locales/en.js +2 -0
- package/components/TimePicker/locale/locales/en.js.map +1 -1
- package/components/TimePicker/locale/locales/ru.js +2 -0
- package/components/TimePicker/locale/locales/ru.js.map +1 -1
- package/components/TimePicker/locale/types.d.ts +2 -0
- package/components/TimePicker/locale/types.js.map +1 -1
- package/internal/NativeTimeInput/NativeTimeInput.d.ts +4 -0
- package/internal/NativeTimeInput/NativeTimeInput.js +7 -2
- package/internal/NativeTimeInput/NativeTimeInput.js.map +1 -1
- package/internal/NativeTimeInput/NativeTimeInput.utils.d.ts +2 -0
- package/internal/NativeTimeInput/NativeTimeInput.utils.js +4 -8
- package/internal/NativeTimeInput/NativeTimeInput.utils.js.map +1 -1
- package/internal/TimeInput/TimeFragments.d.ts +0 -1
- package/internal/TimeInput/TimeFragments.js +30 -8
- package/internal/TimeInput/TimeFragments.js.map +1 -1
- package/internal/TimeInput/TimeFragments.styles.d.ts +15 -0
- package/internal/TimeInput/TimeFragments.styles.js +39 -9
- package/internal/TimeInput/TimeFragments.styles.js.map +1 -1
- package/internal/TimeInput/TimeInput.d.ts +0 -1
- package/internal/TimeInput/TimeInput.js +0 -1
- package/internal/TimeInput/TimeInput.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
import { isValidElement } from 'react';
|
|
2
|
+
import { isMenuItem } from '../../MenuItem/index.js';
|
|
2
3
|
import { DIGIT_REGEXP, EMPTY_SEGMENT, EMPTY_VALUE, HOURS_MAX_VALUE, MINUTES_AND_SECONDS_MAX_VALUE, NON_DIGIT_REGEXP, TIME_PLACEHOLDER_CHAR, TIME_SEGMENT_LENGTH, TIME_SEGMENTS_BY_FORMAT, TIME_SEPARATOR, ZERO_PAD_CHAR, } from './TimePicker.constants.js';
|
|
4
|
+
var isNotMenuElement = function (item) { return typeof item !== 'function' && !isValidElement(item); };
|
|
3
5
|
/** Проверяет, что элемент источника содержит время, а не является React-элементом. */
|
|
4
6
|
export var isTimeItem = function (item) {
|
|
5
|
-
return
|
|
7
|
+
return isNotMenuElement(item);
|
|
6
8
|
};
|
|
7
9
|
/** Проверяет, что элемент выпадающего списка содержит время, а не является React-элементом. */
|
|
8
|
-
export var isTimeMenuItem = function (item) {
|
|
9
|
-
|
|
10
|
+
export var isTimeMenuItem = function (item) { return isNotMenuElement(item); };
|
|
11
|
+
/**
|
|
12
|
+
* Проверяет, что элемент выпадающего списка — это `MenuItem`, по которому можно ходить с клавиатуры.
|
|
13
|
+
* Заблокированные и невыбираемые пункты в навигации не участвуют, как и элементы-функции:
|
|
14
|
+
* последние отрисовываются как есть, поэтому кликом по ним по-прежнему управляет их собственный `onClick`.
|
|
15
|
+
*/
|
|
16
|
+
export var isNavigableMenuElement = function (item) {
|
|
17
|
+
if (typeof item === 'function' || !isValidElement(item) || !isMenuItem(item)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
var _a = item.props, disabled = _a.disabled, isNotSelectable = _a.isNotSelectable;
|
|
21
|
+
return !disabled && !isNotSelectable;
|
|
22
|
+
};
|
|
23
|
+
/** Проверяет, что на элементе выпадающего списка может стоять выделение с клавиатуры. */
|
|
24
|
+
export var isHighlightableMenuItem = function (item) {
|
|
25
|
+
return isTimeMenuItem(item) ? !item.disabled : isNavigableMenuElement(item);
|
|
10
26
|
};
|
|
11
|
-
/** Возвращает время элемента. */
|
|
12
27
|
export var getTimeItemValue = function (item) { return (typeof item === 'string' ? item : item.value); };
|
|
13
|
-
/** Возвращает подпись элемента. У элемента-строки подписи нет. */
|
|
14
28
|
export var getTimeItemLabel = function (item) { return (typeof item === 'string' ? undefined : item.label); };
|
|
15
|
-
/** Проверяет, заблокирован ли элемент. Элемент-строка заблокированным быть не может. */
|
|
16
29
|
export var isTimeItemDisabled = function (item) { return typeof item !== 'string' && Boolean(item.disabled); };
|
|
17
|
-
/** Проверяет, задан ли элемент объектом. */
|
|
18
30
|
export var isTimeItemObject = function (item) { return typeof item !== 'string'; };
|
|
19
31
|
/**
|
|
20
32
|
* Дефолтное преобразование времени в элемент.
|
|
@@ -23,9 +35,7 @@ export var isTimeItemObject = function (item) { return typeof item !== 'string';
|
|
|
23
35
|
export var timeValueToItem = function (value, asObject) {
|
|
24
36
|
return (asObject ? { value: value } : value);
|
|
25
37
|
};
|
|
26
|
-
/** Возвращает массив сегментов, используемых в заданном формате времени. */
|
|
27
38
|
export var getTimeSegments = function (format) { return TIME_SEGMENTS_BY_FORMAT[format]; };
|
|
28
|
-
/** Возвращает верхнюю границу допустимого значения для конкретного сегмента. */
|
|
29
39
|
export var getTimeSegmentMax = function (segment) {
|
|
30
40
|
return segment === 'hours' ? HOURS_MAX_VALUE : MINUTES_AND_SECONDS_MAX_VALUE;
|
|
31
41
|
};
|
|
@@ -44,27 +54,20 @@ export var sanitizeSegment = function (segment) {
|
|
|
44
54
|
.join('')
|
|
45
55
|
.padEnd(TIME_SEGMENT_LENGTH, TIME_PLACEHOLDER_CHAR);
|
|
46
56
|
};
|
|
47
|
-
|
|
48
|
-
* Нормализует сегмент для committed-значения.
|
|
49
|
-
* Пустой сегмент преобразуется в `00`, а значения выше максимума — к максимуму сегмента.
|
|
50
|
-
*/
|
|
51
|
-
export var normalizeTimeSegment = function (segmentValue, segment) {
|
|
57
|
+
var normalizeSegment = function (segmentValue, segment, emptyResult) {
|
|
52
58
|
var digits = getDigits(segmentValue);
|
|
53
59
|
if (!digits) {
|
|
54
|
-
return
|
|
60
|
+
return emptyResult;
|
|
55
61
|
}
|
|
56
62
|
return String(Math.min(Number(digits), getTimeSegmentMax(segment))).padStart(TIME_SEGMENT_LENGTH, ZERO_PAD_CHAR);
|
|
57
63
|
};
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
/** Нормализует сегмент для committed-значения: пустой сегмент становится `00`. */
|
|
65
|
+
export var normalizeTimeSegment = function (segmentValue, segment) {
|
|
66
|
+
return normalizeSegment(segmentValue, segment, '00');
|
|
67
|
+
};
|
|
68
|
+
/** Нормализует сегмент для режима редактирования: полностью пустой сегмент остается пустым. */
|
|
62
69
|
export var normalizeEditableSegment = function (segmentValue, segment) {
|
|
63
|
-
|
|
64
|
-
if (!digits) {
|
|
65
|
-
return EMPTY_SEGMENT;
|
|
66
|
-
}
|
|
67
|
-
return String(Math.min(Number(digits), getTimeSegmentMax(segment))).padStart(TIME_SEGMENT_LENGTH, ZERO_PAD_CHAR);
|
|
70
|
+
return normalizeSegment(segmentValue, segment, EMPTY_SEGMENT);
|
|
68
71
|
};
|
|
69
72
|
/** Проверяет, что сегмент содержит одну введенную цифру и ожидает вторую. */
|
|
70
73
|
export var hasPendingSingleDigit = function (segmentValue) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimePicker.shared.js","sourceRoot":"","sources":["TimePicker.shared.ts"],"names":[],"mappings":"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","sourcesContent":["import { isValidElement } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\n\nimport {\n DIGIT_REGEXP,\n EMPTY_SEGMENT,\n EMPTY_VALUE,\n HOURS_MAX_VALUE,\n MINUTES_AND_SECONDS_MAX_VALUE,\n NON_DIGIT_REGEXP,\n TIME_PLACEHOLDER_CHAR,\n TIME_SEGMENT_LENGTH,\n TIME_SEGMENTS_BY_FORMAT,\n TIME_SEPARATOR,\n ZERO_PAD_CHAR,\n} from './TimePicker.constants.js';\n\nexport type TimeFormat = 'HH:mm' | 'HH:mm:ss';\nexport type TimeSegment = 'hours' | 'minutes' | 'seconds';\n\nexport interface TimeItem {\n disabled?: boolean;\n value: string;\n label?: ReactNode;\n}\n\n/** Элемент со временем: строка в формате `HH:mm[:ss]` или объект. */\nexport type TimeItemValue = string | TimeItem;\n\n/** Элемент, который можно передать в `source`: элемент со временем или React-элемент. */\nexport type TimePickerExtendedItem<T extends TimeItemValue = TimeItemValue> = T | ReactElement | (() => ReactElement);\n\nexport type TimePickerSource<T extends TimeItemValue = TimeItemValue> =\n | Array<TimePickerExtendedItem<T>>\n | ((query: string) => Array<TimePickerExtendedItem<T>> | Promise<Array<TimePickerExtendedItem<T>>>);\n\n/** Значение поля времени: элемент, строка в формате `HH:mm[:ss]` или пустое значение. */\nexport type TimePickerValue<T extends TimeItemValue = TimeItemValue> = T | string | null;\n\n/** Преобразует введенное пользователем время в элемент. */\nexport type TimePickerValueToItem<T extends TimeItemValue = TimeItemValue> = (value: string) => T;\n\n/** Разобранный элемент выпадающего списка: исходный элемент, его время, подпись и доступность. */\nexport interface TimePickerResolvedItem<T extends TimeItemValue = TimeItemValue> {\n item: T;\n value: string;\n label?: ReactNode;\n disabled: boolean;\n}\n\n/** Элемент выпадающего списка: разобранный элемент со временем или React-элемент. */\nexport type TimePickerMenuItem<T extends TimeItemValue = TimeItemValue> =\n | TimePickerResolvedItem<T>\n | ReactElement\n | (() => ReactElement);\n\n/** Проверяет, что элемент источника содержит время, а не является React-элементом. */\nexport const isTimeItem = <T extends TimeItemValue>(item: TimePickerExtendedItem<T>): item is T => {\n return typeof item === 'string' || (typeof item !== 'function' && !isValidElement(item));\n};\n\n/** Проверяет, что элемент выпадающего списка содержит время, а не является React-элементом. */\nexport const isTimeMenuItem = <T extends TimeItemValue>(\n item: TimePickerMenuItem<T>,\n): item is TimePickerResolvedItem<T> => {\n return typeof item !== 'function' && !isValidElement(item);\n};\n\n/** Возвращает время элемента. */\nexport const getTimeItemValue = (item: TimeItemValue): string => (typeof item === 'string' ? item : item.value);\n\n/** Возвращает подпись элемента. У элемента-строки подписи нет. */\nexport const getTimeItemLabel = (item: TimeItemValue): ReactNode => (typeof item === 'string' ? undefined : item.label);\n\n/** Проверяет, заблокирован ли элемент. Элемент-строка заблокированным быть не может. */\nexport const isTimeItemDisabled = (item: TimeItemValue): boolean => typeof item !== 'string' && Boolean(item.disabled);\n\n/** Проверяет, задан ли элемент объектом. */\nexport const isTimeItemObject = (item: TimeItemValue): item is TimeItem => typeof item !== 'string';\n\n/**\n * Дефолтное преобразование времени в элемент.\n * Компонент повторяет форму элементов источника: строку оставляет строкой, а объекту задает только `value`.\n */\nexport const timeValueToItem = <T extends TimeItemValue>(value: string, asObject: boolean): T =>\n (asObject ? { value } : value) as T;\n\n/**\n * Результат ввода одной цифры в активный сегмент.\n * Содержит следующее display-значение и инструкции для UI по выбору сегмента и необходимости blink.\n */\nexport interface TimeDigitInputResult {\n isFinalPart: boolean;\n isCompletedPart: boolean;\n nextValue: string;\n selectedSegment: TimeSegment;\n shouldBlink: boolean;\n}\n\n/** Возвращает массив сегментов, используемых в заданном формате времени. */\nexport const getTimeSegments = (format: TimeFormat): TimeSegment[] => TIME_SEGMENTS_BY_FORMAT[format];\n\n/** Возвращает верхнюю границу допустимого значения для конкретного сегмента. */\nexport const getTimeSegmentMax = (segment: TimeSegment): number =>\n segment === 'hours' ? HOURS_MAX_VALUE : MINUTES_AND_SECONDS_MAX_VALUE;\n\n/** Извлекает из сегмента только цифры и ограничивает результат длиной сегмента. */\nexport const getDigits = (segment: string): string =>\n segment.replace(NON_DIGIT_REGEXP, EMPTY_VALUE).slice(0, TIME_SEGMENT_LENGTH);\n\n/**\n * Приводит произвольное строковое значение сегмента к display-форме:\n * оставляет только цифры и плейсхолдеры, ограничивает длину и дополняет незаполненные позиции плейсхолдером.\n */\nexport const sanitizeSegment = (segment: string): string =>\n Array.from(segment)\n .filter((char) => DIGIT_REGEXP.test(char) || char === TIME_PLACEHOLDER_CHAR)\n .slice(0, TIME_SEGMENT_LENGTH)\n .join('')\n .padEnd(TIME_SEGMENT_LENGTH, TIME_PLACEHOLDER_CHAR);\n\n/**\n * Нормализует сегмент для committed-значения.\n * Пустой сегмент преобразуется в `00`, а значения выше максимума — к максимуму сегмента.\n */\nexport const normalizeTimeSegment = (segmentValue: string, segment: TimeSegment): string => {\n const digits = getDigits(segmentValue);\n\n if (!digits) {\n return '00';\n }\n\n return String(Math.min(Number(digits), getTimeSegmentMax(segment))).padStart(TIME_SEGMENT_LENGTH, ZERO_PAD_CHAR);\n};\n\n/**\n * Нормализует сегмент для режима редактирования.\n * В отличие от committed-нормализации, полностью пустой сегмент остается пустым.\n */\nexport const normalizeEditableSegment = (segmentValue: string, segment: TimeSegment): string => {\n const digits = getDigits(segmentValue);\n\n if (!digits) {\n return EMPTY_SEGMENT;\n }\n\n return String(Math.min(Number(digits), getTimeSegmentMax(segment))).padStart(TIME_SEGMENT_LENGTH, ZERO_PAD_CHAR);\n};\n\n/** Проверяет, что сегмент содержит одну введенную цифру и ожидает вторую. */\nexport const hasPendingSingleDigit = (segmentValue: string): boolean =>\n new RegExp(`^\\\\d${TIME_PLACEHOLDER_CHAR}$`).test(segmentValue);\n\n/**\n * Разбивает входное значение на display-сегменты текущего формата.\n * Поддерживает committed-значение (`HH:mm[:ss]`) и display-значение с плейсхолдерами\n */\nexport const getDisplaySegments = (value: string, format: TimeFormat): string[] => {\n const segments = getTimeSegments(format);\n const fallback = segments.map(() => EMPTY_SEGMENT);\n\n if (value === EMPTY_VALUE) {\n return fallback;\n }\n\n if (value.includes(TIME_SEPARATOR) || value.includes(TIME_PLACEHOLDER_CHAR)) {\n const sourceParts = value.split(TIME_SEPARATOR);\n return segments.map((_, index) => sanitizeSegment(sourceParts[index] ?? EMPTY_VALUE));\n }\n\n const digits = value.replace(NON_DIGIT_REGEXP, EMPTY_VALUE);\n\n return segments.map((_, index) => {\n const segmentStart = index * TIME_SEGMENT_LENGTH;\n const segmentEnd = segmentStart + TIME_SEGMENT_LENGTH;\n\n return sanitizeSegment(digits.slice(segmentStart, segmentEnd));\n });\n};\n"]}
|
|
1
|
+
{"version":3,"file":"TimePicker.shared.js","sourceRoot":"","sources":["TimePicker.shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAIvC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,WAAW,EACX,eAAe,EACf,6BAA6B,EAC7B,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,aAAa,GACd,MAAM,2BAA2B,CAAC;AA+CnC,IAAM,gBAAgB,GAAG,UAAC,IAAa,IAAc,OAAA,OAAO,IAAI,KAAK,UAAU,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAnD,CAAmD,CAAC;AAEzG,sFAAsF;AACtF,MAAM,CAAC,IAAM,UAAU,GAAG,UAA0B,IAA+B;IACjF,OAAA,gBAAgB,CAAC,IAAI,CAAC;AAAtB,CAAsB,CAAC;AAEzB,+FAA+F;AAC/F,MAAM,CAAC,IAAM,cAAc,GAAG,UAC5B,IAA2B,IACW,OAAA,gBAAgB,CAAC,IAAI,CAAC,EAAtB,CAAsB,CAAC;AAE/D;;;;GAIG;AACH,MAAM,CAAC,IAAM,sBAAsB,GAAG,UACpC,IAA2B;IAE3B,IAAI,OAAO,IAAI,KAAK,UAAU,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7E,OAAO,KAAK,CAAC;IACf,CAAC;IAEK,IAAA,KAAgC,IAAI,CAAC,KAAsB,EAAzD,QAAQ,cAAA,EAAE,eAAe,qBAAgC,CAAC;IAElE,OAAO,CAAC,QAAQ,IAAI,CAAC,eAAe,CAAC;AACvC,CAAC,CAAC;AAEF,yFAAyF;AACzF,MAAM,CAAC,IAAM,uBAAuB,GAAG,UAA0B,IAA2B;IAC1F,OAAA,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC;AAApE,CAAoE,CAAC;AAEvE,MAAM,CAAC,IAAM,gBAAgB,GAAG,UAAC,IAAmB,IAAa,OAAA,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAA9C,CAA8C,CAAC;AAEhH,MAAM,CAAC,IAAM,gBAAgB,GAAG,UAAC,IAAmB,IAAgB,OAAA,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAnD,CAAmD,CAAC;AAExH,MAAM,CAAC,IAAM,kBAAkB,GAAG,UAAC,IAAmB,IAAc,OAAA,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAlD,CAAkD,CAAC;AAEvH,MAAM,CAAC,IAAM,gBAAgB,GAAG,UAAC,IAAmB,IAAuB,OAAA,OAAO,IAAI,KAAK,QAAQ,EAAxB,CAAwB,CAAC;AAEpG;;;GAGG;AACH,MAAM,CAAC,IAAM,eAAe,GAAG,UAA0B,KAAa,EAAE,QAAiB;IACvF,OAAA,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,OAAA,EAAE,CAAC,CAAC,CAAC,KAAK,CAAM;AAAnC,CAAmC,CAAC;AAStC,MAAM,CAAC,IAAM,eAAe,GAAG,UAAC,MAAkB,IAAoB,OAAA,uBAAuB,CAAC,MAAM,CAAC,EAA/B,CAA+B,CAAC;AAEtG,MAAM,CAAC,IAAM,iBAAiB,GAAG,UAAC,OAAoB;IACpD,OAAA,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,6BAA6B;AAArE,CAAqE,CAAC;AAExE,mFAAmF;AACnF,MAAM,CAAC,IAAM,SAAS,GAAG,UAAC,OAAe;IACvC,OAAA,OAAO,CAAC,OAAO,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC;AAA5E,CAA4E,CAAC;AAE/E;;;GAGG;AACH,MAAM,CAAC,IAAM,eAAe,GAAG,UAAC,OAAe;IAC7C,OAAA,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;SAChB,MAAM,CAAC,UAAC,IAAI,IAAK,OAAA,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,qBAAqB,EAAzD,CAAyD,CAAC;SAC3E,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC;SAC7B,IAAI,CAAC,EAAE,CAAC;SACR,MAAM,CAAC,mBAAmB,EAAE,qBAAqB,CAAC;AAJrD,CAIqD,CAAC;AAExD,IAAM,gBAAgB,GAAG,UAAC,YAAoB,EAAE,OAAoB,EAAE,WAAmB;IACvF,IAAM,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC,CAAC;IAEvC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,EAAE,aAAa,CAAC,CAAC;AACnH,CAAC,CAAC;AAEF,kFAAkF;AAClF,MAAM,CAAC,IAAM,oBAAoB,GAAG,UAAC,YAAoB,EAAE,OAAoB;IAC7E,OAAA,gBAAgB,CAAC,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC;AAA7C,CAA6C,CAAC;AAEhD,+FAA+F;AAC/F,MAAM,CAAC,IAAM,wBAAwB,GAAG,UAAC,YAAoB,EAAE,OAAoB;IACjF,OAAA,gBAAgB,CAAC,YAAY,EAAE,OAAO,EAAE,aAAa,CAAC;AAAtD,CAAsD,CAAC;AAEzD,6EAA6E;AAC7E,MAAM,CAAC,IAAM,qBAAqB,GAAG,UAAC,YAAoB;IACxD,OAAA,IAAI,MAAM,CAAC,cAAO,qBAAqB,MAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;AAA9D,CAA8D,CAAC;AAEjE;;;GAGG;AACH,MAAM,CAAC,IAAM,kBAAkB,GAAG,UAAC,KAAa,EAAE,MAAkB;IAClE,IAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACzC,IAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,cAAM,OAAA,aAAa,EAAb,CAAa,CAAC,CAAC;IAEnD,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;QAC1B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QAC5E,IAAM,aAAW,GAAG,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAChD,OAAO,QAAQ,CAAC,GAAG,CAAC,UAAC,CAAC,EAAE,KAAK,YAAK,OAAA,eAAe,CAAC,MAAA,aAAW,CAAC,KAAK,CAAC,mCAAI,WAAW,CAAC,CAAA,EAAA,CAAC,CAAC;IACxF,CAAC;IAED,IAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;IAE5D,OAAO,QAAQ,CAAC,GAAG,CAAC,UAAC,CAAC,EAAE,KAAK;QAC3B,IAAM,YAAY,GAAG,KAAK,GAAG,mBAAmB,CAAC;QACjD,IAAM,UAAU,GAAG,YAAY,GAAG,mBAAmB,CAAC;QAEtD,OAAO,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC","sourcesContent":["import { isValidElement } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\n\nimport type { MenuItemProps } from '../../MenuItem/index.js';\nimport { isMenuItem } from '../../MenuItem/index.js';\nimport {\n DIGIT_REGEXP,\n EMPTY_SEGMENT,\n EMPTY_VALUE,\n HOURS_MAX_VALUE,\n MINUTES_AND_SECONDS_MAX_VALUE,\n NON_DIGIT_REGEXP,\n TIME_PLACEHOLDER_CHAR,\n TIME_SEGMENT_LENGTH,\n TIME_SEGMENTS_BY_FORMAT,\n TIME_SEPARATOR,\n ZERO_PAD_CHAR,\n} from './TimePicker.constants.js';\n\nexport type TimeFormat = 'HH:mm' | 'HH:mm:ss';\nexport type TimeSegment = 'hours' | 'minutes' | 'seconds';\n\nexport interface TimeItem {\n disabled?: boolean;\n value: string;\n label?: ReactNode;\n}\n\n/** Элемент со временем: строка в формате `HH:mm[:ss]` или объект. */\nexport type TimeItemValue = string | TimeItem;\n\n/**\n * React-элемент выпадающего списка: сам элемент или функция, возвращающая его.\n * Параметры типа заданы как `any`, чтобы тип совпадал с тем, что дает инлайн-разметка в `source`:\n * иначе TypeScript не отличает React-элемент от элемента со временем и не выводит тип элемента.\n */\nexport type TimePickerMenuElement = ReactElement<any, any> | (() => ReactElement<any, any>);\n\n/** Элемент, который можно передать в `source`: элемент со временем или React-элемент. */\nexport type TimePickerExtendedItem<T extends TimeItemValue = TimeItemValue> = T | TimePickerMenuElement;\n\nexport type TimePickerSource<T extends TimeItemValue = TimeItemValue> =\n | Array<TimePickerExtendedItem<T>>\n | ((query: string) => Array<TimePickerExtendedItem<T>> | Promise<Array<TimePickerExtendedItem<T>>>);\n\n/** Значение поля времени: элемент, строка в формате `HH:mm[:ss]` или пустое значение. */\nexport type TimePickerValue<T extends TimeItemValue = TimeItemValue> = T | string | null;\n\n/** Преобразует введенное пользователем время в элемент. */\nexport type TimePickerValueToItem<T extends TimeItemValue = TimeItemValue> = (value: string) => T;\n\n/** Разобранный элемент выпадающего списка: исходный элемент, его время, подпись и доступность. */\nexport interface TimePickerResolvedItem<T extends TimeItemValue = TimeItemValue> {\n item: T;\n value: string;\n label?: ReactNode;\n disabled: boolean;\n}\n\n/** Элемент выпадающего списка: разобранный элемент со временем или React-элемент. */\nexport type TimePickerMenuItem<T extends TimeItemValue = TimeItemValue> =\n | TimePickerResolvedItem<T>\n | TimePickerMenuElement;\n\nconst isNotMenuElement = (item: unknown): boolean => typeof item !== 'function' && !isValidElement(item);\n\n/** Проверяет, что элемент источника содержит время, а не является React-элементом. */\nexport const isTimeItem = <T extends TimeItemValue>(item: TimePickerExtendedItem<T>): item is T =>\n isNotMenuElement(item);\n\n/** Проверяет, что элемент выпадающего списка содержит время, а не является React-элементом. */\nexport const isTimeMenuItem = <T extends TimeItemValue>(\n item: TimePickerMenuItem<T>,\n): item is TimePickerResolvedItem<T> => isNotMenuElement(item);\n\n/**\n * Проверяет, что элемент выпадающего списка — это `MenuItem`, по которому можно ходить с клавиатуры.\n * Заблокированные и невыбираемые пункты в навигации не участвуют, как и элементы-функции:\n * последние отрисовываются как есть, поэтому кликом по ним по-прежнему управляет их собственный `onClick`.\n */\nexport const isNavigableMenuElement = <T extends TimeItemValue>(\n item: TimePickerMenuItem<T>,\n): item is ReactElement<MenuItemProps> => {\n if (typeof item === 'function' || !isValidElement(item) || !isMenuItem(item)) {\n return false;\n }\n\n const { disabled, isNotSelectable } = item.props as MenuItemProps;\n\n return !disabled && !isNotSelectable;\n};\n\n/** Проверяет, что на элементе выпадающего списка может стоять выделение с клавиатуры. */\nexport const isHighlightableMenuItem = <T extends TimeItemValue>(item: TimePickerMenuItem<T>): boolean =>\n isTimeMenuItem(item) ? !item.disabled : isNavigableMenuElement(item);\n\nexport const getTimeItemValue = (item: TimeItemValue): string => (typeof item === 'string' ? item : item.value);\n\nexport const getTimeItemLabel = (item: TimeItemValue): ReactNode => (typeof item === 'string' ? undefined : item.label);\n\nexport const isTimeItemDisabled = (item: TimeItemValue): boolean => typeof item !== 'string' && Boolean(item.disabled);\n\nexport const isTimeItemObject = (item: TimeItemValue): item is TimeItem => typeof item !== 'string';\n\n/**\n * Дефолтное преобразование времени в элемент.\n * Компонент повторяет форму элементов источника: строку оставляет строкой, а объекту задает только `value`.\n */\nexport const timeValueToItem = <T extends TimeItemValue>(value: string, asObject: boolean): T =>\n (asObject ? { value } : value) as T;\n\n/** Результат ввода одной цифры: следующее display-значение, сегмент под выделением и признак вспышки. */\nexport interface TimeDigitInputResult {\n nextValue: string;\n selectedSegment: TimeSegment;\n shouldBlink: boolean;\n}\n\nexport const getTimeSegments = (format: TimeFormat): TimeSegment[] => TIME_SEGMENTS_BY_FORMAT[format];\n\nexport const getTimeSegmentMax = (segment: TimeSegment): number =>\n segment === 'hours' ? HOURS_MAX_VALUE : MINUTES_AND_SECONDS_MAX_VALUE;\n\n/** Извлекает из сегмента только цифры и ограничивает результат длиной сегмента. */\nexport const getDigits = (segment: string): string =>\n segment.replace(NON_DIGIT_REGEXP, EMPTY_VALUE).slice(0, TIME_SEGMENT_LENGTH);\n\n/**\n * Приводит произвольное строковое значение сегмента к display-форме:\n * оставляет только цифры и плейсхолдеры, ограничивает длину и дополняет незаполненные позиции плейсхолдером.\n */\nexport const sanitizeSegment = (segment: string): string =>\n Array.from(segment)\n .filter((char) => DIGIT_REGEXP.test(char) || char === TIME_PLACEHOLDER_CHAR)\n .slice(0, TIME_SEGMENT_LENGTH)\n .join('')\n .padEnd(TIME_SEGMENT_LENGTH, TIME_PLACEHOLDER_CHAR);\n\nconst normalizeSegment = (segmentValue: string, segment: TimeSegment, emptyResult: string): string => {\n const digits = getDigits(segmentValue);\n\n if (!digits) {\n return emptyResult;\n }\n\n return String(Math.min(Number(digits), getTimeSegmentMax(segment))).padStart(TIME_SEGMENT_LENGTH, ZERO_PAD_CHAR);\n};\n\n/** Нормализует сегмент для committed-значения: пустой сегмент становится `00`. */\nexport const normalizeTimeSegment = (segmentValue: string, segment: TimeSegment): string =>\n normalizeSegment(segmentValue, segment, '00');\n\n/** Нормализует сегмент для режима редактирования: полностью пустой сегмент остается пустым. */\nexport const normalizeEditableSegment = (segmentValue: string, segment: TimeSegment): string =>\n normalizeSegment(segmentValue, segment, EMPTY_SEGMENT);\n\n/** Проверяет, что сегмент содержит одну введенную цифру и ожидает вторую. */\nexport const hasPendingSingleDigit = (segmentValue: string): boolean =>\n new RegExp(`^\\\\d${TIME_PLACEHOLDER_CHAR}$`).test(segmentValue);\n\n/**\n * Разбивает входное значение на display-сегменты текущего формата.\n * Поддерживает committed-значение (`HH:mm[:ss]`) и display-значение с плейсхолдерами\n */\nexport const getDisplaySegments = (value: string, format: TimeFormat): string[] => {\n const segments = getTimeSegments(format);\n const fallback = segments.map(() => EMPTY_SEGMENT);\n\n if (value === EMPTY_VALUE) {\n return fallback;\n }\n\n if (value.includes(TIME_SEPARATOR) || value.includes(TIME_PLACEHOLDER_CHAR)) {\n const sourceParts = value.split(TIME_SEPARATOR);\n return segments.map((_, index) => sanitizeSegment(sourceParts[index] ?? EMPTY_VALUE));\n }\n\n const digits = value.replace(NON_DIGIT_REGEXP, EMPTY_VALUE);\n\n return segments.map((_, index) => {\n const segmentStart = index * TIME_SEGMENT_LENGTH;\n const segmentEnd = segmentStart + TIME_SEGMENT_LENGTH;\n\n return sanitizeSegment(digits.slice(segmentStart, segmentEnd));\n });\n};\n"]}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { type TimeFormat, type TimeItemValue, type TimePickerExtendedItem, type TimePickerMenuItem, type TimeSegment } from './TimePicker.shared.js';
|
|
2
|
-
/** Проверяет,
|
|
2
|
+
/** Проверяет, что в display-значении нет ни одной введенной цифры. */
|
|
3
3
|
export declare const isTimeDisplayEmpty: (value: string) => boolean;
|
|
4
|
-
/** Приводит значение поля — элемент, строку или пустое значение — к строке времени. */
|
|
5
4
|
export declare const getTimeValueString: (value: TimeItemValue | null | undefined) => string;
|
|
6
5
|
/**
|
|
7
6
|
* Разбирает элементы источника для отрисовки: достает время и подпись,
|
|
@@ -11,12 +10,11 @@ export declare const getTimeValueString: (value: TimeItemValue | null | undefine
|
|
|
11
10
|
*/
|
|
12
11
|
export declare const resolveTimeItems: <T extends TimeItemValue>(items: Array<TimePickerExtendedItem<T>>, format: TimeFormat, minTime?: string, maxTime?: string) => Array<TimePickerMenuItem<T>>;
|
|
13
12
|
/**
|
|
14
|
-
* Оставляет
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* React-элементы не участвуют в сравнении и остаются на своих местах.
|
|
13
|
+
* Оставляет только элементы, которые компонент умеет показать в меню.
|
|
14
|
+
* Пустые значения — результат условного рендера вроде `isVisible && item` или `items.length && item` —
|
|
15
|
+
* молча отбрасываются, а элементы, из которых не получается собрать время, отбрасываются с предупреждением.
|
|
18
16
|
*/
|
|
19
|
-
export declare const
|
|
17
|
+
export declare const sanitizeTimeItems: <T extends TimeItemValue>(items: Array<TimePickerExtendedItem<T>>, format: TimeFormat) => Array<TimePickerExtendedItem<T>>;
|
|
20
18
|
/**
|
|
21
19
|
* Проверяет, выходит ли значение за диапазон `minTime`/`maxTime` после нормализации.
|
|
22
20
|
* Пустое значение не считается выходящим за диапазон. Если `minTime > maxTime`, диапазон трактуется как переходящий через полночь.
|
|
@@ -28,21 +26,34 @@ export declare const isTimeValueOutOfRange: (value: string, format: TimeFormat,
|
|
|
28
26
|
*/
|
|
29
27
|
export declare const normalizeTimeValue: (value: string, format: TimeFormat) => string;
|
|
30
28
|
/**
|
|
31
|
-
* Преобразует display-значение в
|
|
29
|
+
* Преобразует display-значение в промежуточное значение для `onInputValueChange`.
|
|
32
30
|
* Заполненные сегменты дополняются до двух цифр, пропущенные сегменты до последнего заполненного становятся `00`.
|
|
33
31
|
*/
|
|
34
32
|
export declare const serializeTimeValue: (value: string, format: TimeFormat) => string;
|
|
35
|
-
/** Возвращает display-значение с плейсхолдерами из partial или committed value. */
|
|
36
33
|
export declare const getTimeDisplayValue: (value: string, format: TimeFormat) => string;
|
|
34
|
+
/**
|
|
35
|
+
* Возвращает display-значение внешнего `value`.
|
|
36
|
+
* Сегменты, записанные одной цифрой, дополняются нулем, поэтому `9:00` показывается как `09:00` —
|
|
37
|
+
* так же, как компонент показывает время элементов источника.
|
|
38
|
+
* Значение без разделителя остается частично введенным: `1` — это первая цифра часов, а не `01:00`.
|
|
39
|
+
*/
|
|
40
|
+
export declare const getExternalTimeDisplayValue: (value: string, format: TimeFormat) => string;
|
|
37
41
|
/** Заменяет значение выбранного сегмента, сохраняя остальные сегменты display-значения без изменений. */
|
|
38
42
|
export declare const replaceTimeSegment: (value: string, segment: TimeSegment, nextSegmentValue: string, format: TimeFormat) => string;
|
|
43
|
+
/**
|
|
44
|
+
* Проверяет, что вставленное значение похоже на время:
|
|
45
|
+
* это либо сегменты из одной-двух цифр через любой разделитель — `12:30`, `9:5`, `1:23:45`, `12.30`, —
|
|
46
|
+
* либо цифры подряд — `9`, `1230`, `123045`.
|
|
47
|
+
* Строки, из которых время собралось бы случайно — `2026-08-01`, `hello 42`, — временем не считаются.
|
|
48
|
+
*/
|
|
49
|
+
export declare const isTimeLikePastedValue: (value: string) => boolean;
|
|
39
50
|
/**
|
|
40
51
|
* Парсит вставленное пользователем значение и сразу преобразует его в committed-форму.
|
|
52
|
+
* Значение, не похожее на время, отдается как пустое: такую вставку компонент считает некорректным вводом.
|
|
41
53
|
*/
|
|
42
54
|
export declare const parsePastedTimeValue: (value: string, format: TimeFormat) => string;
|
|
43
55
|
/** Возвращает текущее display-значение сегмента или пустой сегмент, если индекс отсутствует. */
|
|
44
56
|
export declare const getTimeSegmentValue: (value: string, segment: TimeSegment, format: TimeFormat) => string;
|
|
45
|
-
/** Возвращает полностью пустое display-значение для выбранной точности времени. */
|
|
46
57
|
export declare const getEmptyDisplayValue: (precision: TimeFormat) => string;
|
|
47
58
|
/**
|
|
48
59
|
* Преобразует display-значение в поисковый запрос для фильтрации элементов.
|
|
@@ -52,7 +63,7 @@ export declare const getEmptyDisplayValue: (precision: TimeFormat) => string;
|
|
|
52
63
|
*/
|
|
53
64
|
export declare const getTimeFilterQuery: (value: string, format: TimeFormat) => string;
|
|
54
65
|
/**
|
|
55
|
-
*
|
|
66
|
+
* Фильтрует элементы по запросу из поля ввода.
|
|
56
67
|
* Сравнивает запрос посегментно: введенные цифры сегмента должны быть префиксом соответствующего сегмента элемента.
|
|
57
68
|
* Пустой запрос возвращает все элементы.
|
|
58
69
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import warning from 'warning';
|
|
2
|
+
import { DIGIT_REGEXP, EMPTY_SEGMENT, EMPTY_VALUE, NON_DIGIT_REGEXP, TIME_LIKE_DIGITS_REGEXP, TIME_LIKE_SEGMENTS_REGEXP, TIME_SEPARATOR, ZERO_PAD_CHAR, } from './TimePicker.constants.js';
|
|
3
|
+
import { getDigits, getDisplaySegments, getTimeSegments, normalizeTimeSegment, sanitizeSegment, getTimeItemLabel, getTimeItemValue, isTimeItemDisabled, isTimeItem, isTimeItemObject, } from './TimePicker.shared.js';
|
|
4
|
+
/** Проверяет, что в display-значении нет ни одной введенной цифры. */
|
|
4
5
|
export var isTimeDisplayEmpty = function (value) { return !DIGIT_REGEXP.test(value); };
|
|
5
|
-
/** Приводит значение поля — элемент, строку или пустое значение — к строке времени. */
|
|
6
6
|
export var getTimeValueString = function (value) {
|
|
7
7
|
if (value === null || value === undefined) {
|
|
8
8
|
return EMPTY_VALUE;
|
|
@@ -30,22 +30,30 @@ export var resolveTimeItems = function (items, format, minTime, maxTime) {
|
|
|
30
30
|
});
|
|
31
31
|
};
|
|
32
32
|
/**
|
|
33
|
-
* Оставляет
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* React-элементы не участвуют в сравнении и остаются на своих местах.
|
|
33
|
+
* Оставляет только элементы, которые компонент умеет показать в меню.
|
|
34
|
+
* Пустые значения — результат условного рендера вроде `isVisible && item` или `items.length && item` —
|
|
35
|
+
* молча отбрасываются, а элементы, из которых не получается собрать время, отбрасываются с предупреждением.
|
|
37
36
|
*/
|
|
38
|
-
export var
|
|
39
|
-
|
|
37
|
+
export var sanitizeTimeItems = function (items, format) {
|
|
38
|
+
if (!Array.isArray(items)) {
|
|
39
|
+
warning(false, '[TimePicker]: the source function is expected to return an array or a Promise of an array.');
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
40
42
|
return items.filter(function (item) {
|
|
43
|
+
if (!item) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
41
46
|
if (!isTimeItem(item)) {
|
|
42
47
|
return true;
|
|
43
48
|
}
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
if (isTimeItemObject(item) && typeof item.value !== 'string') {
|
|
50
|
+
warning(false, '[TimePicker]: a source item is expected to be a time string or an object with a time value.');
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (normalizeTimeValue(getTimeItemValue(item), format) === EMPTY_VALUE) {
|
|
54
|
+
warning(false, "[TimePicker]: the source item value \"".concat(getTimeItemValue(item), "\" is not a time."));
|
|
46
55
|
return false;
|
|
47
56
|
}
|
|
48
|
-
usedValues.add(normalizedValue);
|
|
49
57
|
return true;
|
|
50
58
|
});
|
|
51
59
|
};
|
|
@@ -74,8 +82,9 @@ export var normalizeTimeValue = function (value, format) {
|
|
|
74
82
|
if (isTimeDisplayEmpty(value)) {
|
|
75
83
|
return EMPTY_VALUE;
|
|
76
84
|
}
|
|
85
|
+
var displaySegments = getDisplaySegments(value, format);
|
|
77
86
|
return getTimeSegments(format)
|
|
78
|
-
.map(function (segment, index) { return normalizeTimeSegment(
|
|
87
|
+
.map(function (segment, index) { return normalizeTimeSegment(displaySegments[index], segment); })
|
|
79
88
|
.join(TIME_SEPARATOR);
|
|
80
89
|
};
|
|
81
90
|
var normalizeTimeRangeValue = function (value, format) {
|
|
@@ -86,30 +95,43 @@ var normalizeTimeRangeValue = function (value, format) {
|
|
|
86
95
|
return normalizedValue === EMPTY_VALUE ? undefined : normalizedValue;
|
|
87
96
|
};
|
|
88
97
|
/**
|
|
89
|
-
* Преобразует display-значение в
|
|
98
|
+
* Преобразует display-значение в промежуточное значение для `onInputValueChange`.
|
|
90
99
|
* Заполненные сегменты дополняются до двух цифр, пропущенные сегменты до последнего заполненного становятся `00`.
|
|
91
100
|
*/
|
|
92
101
|
export var serializeTimeValue = function (value, format) {
|
|
93
|
-
var serializedSegments = getDisplaySegments(value, format).map(function (segmentValue) {
|
|
102
|
+
var serializedSegments = takeFilledSegments(getDisplaySegments(value, format).map(function (segmentValue) {
|
|
94
103
|
var digits = getDigits(segmentValue);
|
|
95
|
-
return digits ? digits.padStart(EMPTY_SEGMENT.length,
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
.map(function (segmentValue) { return segmentValue || '00'; })
|
|
104
|
-
.join(TIME_SEPARATOR);
|
|
104
|
+
return digits ? digits.padStart(EMPTY_SEGMENT.length, ZERO_PAD_CHAR) : EMPTY_VALUE;
|
|
105
|
+
}));
|
|
106
|
+
return serializedSegments.map(function (segmentValue) { return segmentValue || '00'; }).join(TIME_SEPARATOR);
|
|
107
|
+
};
|
|
108
|
+
/** Отбрасывает незаполненный хвост сегментов: ведущие пустые сегменты остаются на своих местах. */
|
|
109
|
+
var takeFilledSegments = function (segments) {
|
|
110
|
+
var lastFilledIndex = segments.reduce(function (result, segmentValue, index) { return (segmentValue ? index : result); }, -1);
|
|
111
|
+
return segments.slice(0, lastFilledIndex + 1);
|
|
105
112
|
};
|
|
106
|
-
/** Возвращает display-значение с плейсхолдерами из partial или committed value. */
|
|
107
113
|
export var getTimeDisplayValue = function (value, format) {
|
|
108
114
|
if (value === EMPTY_VALUE) {
|
|
109
115
|
return EMPTY_VALUE;
|
|
110
116
|
}
|
|
111
117
|
return getDisplaySegments(value, format).join(TIME_SEPARATOR);
|
|
112
118
|
};
|
|
119
|
+
/**
|
|
120
|
+
* Возвращает display-значение внешнего `value`.
|
|
121
|
+
* Сегменты, записанные одной цифрой, дополняются нулем, поэтому `9:00` показывается как `09:00` —
|
|
122
|
+
* так же, как компонент показывает время элементов источника.
|
|
123
|
+
* Значение без разделителя остается частично введенным: `1` — это первая цифра часов, а не `01:00`.
|
|
124
|
+
*/
|
|
125
|
+
export var getExternalTimeDisplayValue = function (value, format) {
|
|
126
|
+
if (!value.includes(TIME_SEPARATOR)) {
|
|
127
|
+
return getTimeDisplayValue(value, format);
|
|
128
|
+
}
|
|
129
|
+
var paddedSegments = value.split(TIME_SEPARATOR).map(function (segmentValue) {
|
|
130
|
+
var digits = getDigits(segmentValue);
|
|
131
|
+
return digits ? digits.padStart(EMPTY_SEGMENT.length, ZERO_PAD_CHAR) : EMPTY_VALUE;
|
|
132
|
+
});
|
|
133
|
+
return getTimeDisplayValue(paddedSegments.join(TIME_SEPARATOR), format);
|
|
134
|
+
};
|
|
113
135
|
/** Заменяет значение выбранного сегмента, сохраняя остальные сегменты display-значения без изменений. */
|
|
114
136
|
export var replaceTimeSegment = function (value, segment, nextSegmentValue, format) {
|
|
115
137
|
var segments = getDisplaySegments(value, format);
|
|
@@ -117,14 +139,30 @@ export var replaceTimeSegment = function (value, segment, nextSegmentValue, form
|
|
|
117
139
|
segments[index] = sanitizeSegment(nextSegmentValue);
|
|
118
140
|
return segments.join(TIME_SEPARATOR);
|
|
119
141
|
};
|
|
142
|
+
/**
|
|
143
|
+
* Проверяет, что вставленное значение похоже на время:
|
|
144
|
+
* это либо сегменты из одной-двух цифр через любой разделитель — `12:30`, `9:5`, `1:23:45`, `12.30`, —
|
|
145
|
+
* либо цифры подряд — `9`, `1230`, `123045`.
|
|
146
|
+
* Строки, из которых время собралось бы случайно — `2026-08-01`, `hello 42`, — временем не считаются.
|
|
147
|
+
*/
|
|
148
|
+
export var isTimeLikePastedValue = function (value) {
|
|
149
|
+
var trimmedValue = value.trim();
|
|
150
|
+
return TIME_LIKE_SEGMENTS_REGEXP.test(trimmedValue) || TIME_LIKE_DIGITS_REGEXP.test(trimmedValue);
|
|
151
|
+
};
|
|
120
152
|
/**
|
|
121
153
|
* Парсит вставленное пользователем значение и сразу преобразует его в committed-форму.
|
|
154
|
+
* Значение, не похожее на время, отдается как пустое: такую вставку компонент считает некорректным вводом.
|
|
122
155
|
*/
|
|
123
156
|
export var parsePastedTimeValue = function (value, format) {
|
|
124
|
-
|
|
157
|
+
var trimmedValue = value.trim();
|
|
158
|
+
if (!DIGIT_REGEXP.test(trimmedValue) || !isTimeLikePastedValue(trimmedValue)) {
|
|
125
159
|
return EMPTY_VALUE;
|
|
126
160
|
}
|
|
127
|
-
|
|
161
|
+
// Разделители сегментов приводятся к одному виду, чтобы `9.5` разбирался так же, как `9:5`.
|
|
162
|
+
var normalizedSeparators = TIME_LIKE_SEGMENTS_REGEXP.test(trimmedValue)
|
|
163
|
+
? trimmedValue.split(NON_DIGIT_REGEXP).join(TIME_SEPARATOR)
|
|
164
|
+
: trimmedValue;
|
|
165
|
+
var segments = getDisplaySegments(normalizedSeparators, format);
|
|
128
166
|
return normalizeTimeValue(segments.join(TIME_SEPARATOR), format);
|
|
129
167
|
};
|
|
130
168
|
/** Возвращает текущее display-значение сегмента или пустой сегмент, если индекс отсутствует. */
|
|
@@ -134,7 +172,6 @@ export var getTimeSegmentValue = function (value, segment, format) {
|
|
|
134
172
|
var index = getTimeSegments(format).indexOf(segment);
|
|
135
173
|
return (_a = segments[index]) !== null && _a !== void 0 ? _a : EMPTY_SEGMENT;
|
|
136
174
|
};
|
|
137
|
-
/** Возвращает полностью пустое display-значение для выбранной точности времени. */
|
|
138
175
|
export var getEmptyDisplayValue = function (precision) {
|
|
139
176
|
return getTimeSegments(precision)
|
|
140
177
|
.map(function () { return EMPTY_SEGMENT; })
|
|
@@ -147,15 +184,10 @@ export var getEmptyDisplayValue = function (precision) {
|
|
|
147
184
|
* Это нужно для посегментного сравнения в `filterTimeItems` и передается как есть в пользовательскую `source`.
|
|
148
185
|
*/
|
|
149
186
|
export var getTimeFilterQuery = function (value, format) {
|
|
150
|
-
|
|
151
|
-
var lastFilledIndex = segments.reduce(function (result, segmentValue, index) { return (segmentValue ? index : result); }, -1);
|
|
152
|
-
if (lastFilledIndex < 0) {
|
|
153
|
-
return EMPTY_VALUE;
|
|
154
|
-
}
|
|
155
|
-
return segments.slice(0, lastFilledIndex + 1).join(TIME_SEPARATOR);
|
|
187
|
+
return takeFilledSegments(getDisplaySegments(value, format).map(getDigits)).join(TIME_SEPARATOR);
|
|
156
188
|
};
|
|
157
189
|
/**
|
|
158
|
-
*
|
|
190
|
+
* Фильтрует элементы по запросу из поля ввода.
|
|
159
191
|
* Сравнивает запрос посегментно: введенные цифры сегмента должны быть префиксом соответствующего сегмента элемента.
|
|
160
192
|
* Пустой запрос возвращает все элементы.
|
|
161
193
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimePicker.value.js","sourceRoot":"","sources":["TimePicker.value.ts"],"names":[],"mappings":"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","sourcesContent":["import { DIGIT_REGEXP, EMPTY_SEGMENT, EMPTY_VALUE, TIME_SEPARATOR } from './TimePicker.constants.js';\nimport {\n getDigits,\n getDisplaySegments,\n getTimeSegments,\n normalizeTimeSegment,\n sanitizeSegment,\n getTimeItemLabel,\n getTimeItemValue,\n isTimeItemDisabled,\n type TimeFormat,\n type TimeItemValue,\n type TimePickerExtendedItem,\n type TimePickerMenuItem,\n type TimeSegment,\n isTimeItem,\n} from './TimePicker.shared.js';\n\n/** Проверяет, содержит ли display-значение хотя бы одну введенную цифру. */\nexport const isTimeDisplayEmpty = (value: string): boolean => !DIGIT_REGEXP.test(value);\n\n/** Приводит значение поля — элемент, строку или пустое значение — к строке времени. */\nexport const getTimeValueString = (value: TimeItemValue | null | undefined): string => {\n if (value === null || value === undefined) {\n return EMPTY_VALUE;\n }\n\n return getTimeItemValue(value);\n};\n\n/**\n * Разбирает элементы источника для отрисовки: достает время и подпись,\n * а `disabled` дополняет проверкой диапазона `minTime`/`maxTime`.\n * Исходный элемент сохраняется как есть — именно он уходит в `onValueChange`.\n * React-элементы остаются на своих местах.\n */\nexport const resolveTimeItems = <T extends TimeItemValue>(\n items: Array<TimePickerExtendedItem<T>>,\n format: TimeFormat,\n minTime?: string,\n maxTime?: string,\n): Array<TimePickerMenuItem<T>> =>\n items.map((item) => {\n if (!isTimeItem(item)) {\n return item;\n }\n\n const value = getTimeItemValue(item);\n\n return {\n item,\n value,\n label: getTimeItemLabel(item),\n disabled: isTimeItemDisabled(item) || isTimeValueOutOfRange(value, format, minTime, maxTime),\n };\n });\n\n/**\n * Оставляет в списке только первый элемент для каждого времени.\n * Времена сравниваются после нормализации к текущему формату,\n * поэтому в формате `HH:mm` элементы `12:00` и `12:00:30` считаются одинаковыми.\n * React-элементы не участвуют в сравнении и остаются на своих местах.\n */\nexport const dedupeTimeItems = <T extends TimeItemValue>(\n items: Array<TimePickerExtendedItem<T>>,\n format: TimeFormat,\n): Array<TimePickerExtendedItem<T>> => {\n const usedValues = new Set<string>();\n\n return items.filter((item) => {\n if (!isTimeItem(item)) {\n return true;\n }\n\n const normalizedValue = normalizeTimeValue(getTimeItemValue(item), format);\n\n if (usedValues.has(normalizedValue)) {\n return false;\n }\n\n usedValues.add(normalizedValue);\n\n return true;\n });\n};\n\n/**\n * Проверяет, выходит ли значение за диапазон `minTime`/`maxTime` после нормализации.\n * Пустое значение не считается выходящим за диапазон. Если `minTime > maxTime`, диапазон трактуется как переходящий через полночь.\n */\nexport const isTimeValueOutOfRange = (\n value: string,\n format: TimeFormat,\n minTime?: string,\n maxTime?: string,\n): boolean => {\n const normalizedValue = normalizeTimeValue(value, format);\n\n if (normalizedValue === EMPTY_VALUE) {\n return false;\n }\n\n const normalizedMinTime = normalizeTimeRangeValue(minTime, format);\n const normalizedMaxTime = normalizeTimeRangeValue(maxTime, format);\n\n if (normalizedMinTime && normalizedMaxTime && normalizedMinTime > normalizedMaxTime) {\n return normalizedValue < normalizedMinTime && normalizedValue > normalizedMaxTime;\n }\n\n return (\n (normalizedMinTime !== undefined && normalizedValue < normalizedMinTime) ||\n (normalizedMaxTime !== undefined && normalizedValue > normalizedMaxTime)\n );\n};\n\n/**\n * Нормализует display-значение в committed-форму `HH:mm[:ss]`.\n * Частично заполненные сегменты дополняются и ограничиваются максимумами сегментов.\n */\nexport const normalizeTimeValue = (value: string, format: TimeFormat): string => {\n if (isTimeDisplayEmpty(value)) {\n return EMPTY_VALUE;\n }\n\n return getTimeSegments(format)\n .map((segment, index) => normalizeTimeSegment(getDisplaySegments(value, format)[index], segment))\n .join(TIME_SEPARATOR);\n};\n\nconst normalizeTimeRangeValue = (value: string | undefined, format: TimeFormat): string | undefined => {\n if (!value) {\n return undefined;\n }\n\n const normalizedValue = normalizeTimeValue(value, format);\n\n return normalizedValue === EMPTY_VALUE ? undefined : normalizedValue;\n};\n\n/**\n * Преобразует display-значение в partial raw value для `onValueChange`.\n * Заполненные сегменты дополняются до двух цифр, пропущенные сегменты до последнего заполненного становятся `00`.\n */\nexport const serializeTimeValue = (value: string, format: TimeFormat): string => {\n const serializedSegments = getDisplaySegments(value, format).map((segmentValue) => {\n const digits = getDigits(segmentValue);\n\n return digits ? digits.padStart(EMPTY_SEGMENT.length, '0') : EMPTY_VALUE;\n });\n\n const lastFilledIndex = serializedSegments.reduce(\n (result, segmentValue, index) => (segmentValue ? index : result),\n -1,\n );\n\n if (lastFilledIndex < 0) {\n return EMPTY_VALUE;\n }\n\n return serializedSegments\n .slice(0, lastFilledIndex + 1)\n .map((segmentValue) => segmentValue || '00')\n .join(TIME_SEPARATOR);\n};\n\n/** Возвращает display-значение с плейсхолдерами из partial или committed value. */\nexport const getTimeDisplayValue = (value: string, format: TimeFormat): string => {\n if (value === EMPTY_VALUE) {\n return EMPTY_VALUE;\n }\n\n return getDisplaySegments(value, format).join(TIME_SEPARATOR);\n};\n\n/** Заменяет значение выбранного сегмента, сохраняя остальные сегменты display-значения без изменений. */\nexport const replaceTimeSegment = (\n value: string,\n segment: TimeSegment,\n nextSegmentValue: string,\n format: TimeFormat,\n): string => {\n const segments = getDisplaySegments(value, format);\n const index = getTimeSegments(format).indexOf(segment);\n\n segments[index] = sanitizeSegment(nextSegmentValue);\n\n return segments.join(TIME_SEPARATOR);\n};\n\n/**\n * Парсит вставленное пользователем значение и сразу преобразует его в committed-форму.\n */\nexport const parsePastedTimeValue = (value: string, format: TimeFormat): string => {\n if (!DIGIT_REGEXP.test(value)) {\n return EMPTY_VALUE;\n }\n\n const segments = getDisplaySegments(value, format);\n\n return normalizeTimeValue(segments.join(TIME_SEPARATOR), format);\n};\n\n/** Возвращает текущее display-значение сегмента или пустой сегмент, если индекс отсутствует. */\nexport const getTimeSegmentValue = (value: string, segment: TimeSegment, format: TimeFormat): string => {\n const segments = getDisplaySegments(value, format);\n const index = getTimeSegments(format).indexOf(segment);\n\n return segments[index] ?? EMPTY_SEGMENT;\n};\n\n/** Возвращает полностью пустое display-значение для выбранной точности времени. */\nexport const getEmptyDisplayValue = (precision: TimeFormat): string =>\n getTimeSegments(precision)\n .map(() => EMPTY_SEGMENT)\n .join(TIME_SEPARATOR);\n\n/**\n * Преобразует display-значение в поисковый запрос для фильтрации элементов.\n * Сегменты содержат только введенные цифры, незаполненный хвост отбрасывается: `12:3_` => `12:3`, `1_:__` => `1`.\n * Позиции сегментов сохраняются, поэтому ведущие незаполненные сегменты остаются пустыми: `__:34` => `:34`.\n * Это нужно для посегментного сравнения в `filterTimeItems` и передается как есть в пользовательскую `source`.\n */\nexport const getTimeFilterQuery = (value: string, format: TimeFormat): string => {\n const segments = getDisplaySegments(value, format).map(getDigits);\n\n const lastFilledIndex = segments.reduce((result, segmentValue, index) => (segmentValue ? index : result), -1);\n\n if (lastFilledIndex < 0) {\n return EMPTY_VALUE;\n }\n\n return segments.slice(0, lastFilledIndex + 1).join(TIME_SEPARATOR);\n};\n\n/**\n * Дефолтная функция фильтрации элементов по запросу из поля ввода.\n * Сравнивает запрос посегментно: введенные цифры сегмента должны быть префиксом соответствующего сегмента элемента.\n * Пустой запрос возвращает все элементы.\n */\nexport const filterTimeItems = <T extends TimeItemValue>(\n items: Array<TimePickerExtendedItem<T>>,\n query: string,\n format: TimeFormat,\n): Array<TimePickerExtendedItem<T>> => {\n const querySegments = query.split(TIME_SEPARATOR).map(getDigits);\n\n if (querySegments.every((segmentValue) => !segmentValue)) {\n return items;\n }\n\n return items.filter((item) => {\n if (!isTimeItem(item)) {\n return true;\n }\n\n const itemSegments = getDisplaySegments(normalizeTimeValue(getTimeItemValue(item), format), format);\n\n return querySegments.every(\n (segmentValue, index) => !segmentValue || (itemSegments[index] ?? EMPTY_VALUE).startsWith(segmentValue),\n );\n });\n};\n"]}
|
|
1
|
+
{"version":3,"file":"TimePicker.value.js","sourceRoot":"","sources":["TimePicker.value.ts"],"names":[],"mappings":"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","sourcesContent":["import warning from 'warning';\n\nimport {\n DIGIT_REGEXP,\n EMPTY_SEGMENT,\n EMPTY_VALUE,\n NON_DIGIT_REGEXP,\n TIME_LIKE_DIGITS_REGEXP,\n TIME_LIKE_SEGMENTS_REGEXP,\n TIME_SEPARATOR,\n ZERO_PAD_CHAR,\n} from './TimePicker.constants.js';\nimport {\n getDigits,\n getDisplaySegments,\n getTimeSegments,\n normalizeTimeSegment,\n sanitizeSegment,\n getTimeItemLabel,\n getTimeItemValue,\n isTimeItemDisabled,\n type TimeFormat,\n type TimeItemValue,\n type TimePickerExtendedItem,\n type TimePickerMenuItem,\n type TimeSegment,\n isTimeItem,\n isTimeItemObject,\n} from './TimePicker.shared.js';\n\n/** Проверяет, что в display-значении нет ни одной введенной цифры. */\nexport const isTimeDisplayEmpty = (value: string): boolean => !DIGIT_REGEXP.test(value);\n\nexport const getTimeValueString = (value: TimeItemValue | null | undefined): string => {\n if (value === null || value === undefined) {\n return EMPTY_VALUE;\n }\n\n return getTimeItemValue(value);\n};\n\n/**\n * Разбирает элементы источника для отрисовки: достает время и подпись,\n * а `disabled` дополняет проверкой диапазона `minTime`/`maxTime`.\n * Исходный элемент сохраняется как есть — именно он уходит в `onValueChange`.\n * React-элементы остаются на своих местах.\n */\nexport const resolveTimeItems = <T extends TimeItemValue>(\n items: Array<TimePickerExtendedItem<T>>,\n format: TimeFormat,\n minTime?: string,\n maxTime?: string,\n): Array<TimePickerMenuItem<T>> =>\n items.map((item) => {\n if (!isTimeItem(item)) {\n return item;\n }\n\n const value = getTimeItemValue(item);\n\n return {\n item,\n value,\n label: getTimeItemLabel(item),\n disabled: isTimeItemDisabled(item) || isTimeValueOutOfRange(value, format, minTime, maxTime),\n };\n });\n\n/**\n * Оставляет только элементы, которые компонент умеет показать в меню.\n * Пустые значения — результат условного рендера вроде `isVisible && item` или `items.length && item` —\n * молча отбрасываются, а элементы, из которых не получается собрать время, отбрасываются с предупреждением.\n */\nexport const sanitizeTimeItems = <T extends TimeItemValue>(\n items: Array<TimePickerExtendedItem<T>>,\n format: TimeFormat,\n): Array<TimePickerExtendedItem<T>> => {\n if (!Array.isArray(items)) {\n warning(false, '[TimePicker]: the source function is expected to return an array or a Promise of an array.');\n\n return [];\n }\n\n return items.filter((item) => {\n if (!item) {\n return false;\n }\n\n if (!isTimeItem(item)) {\n return true;\n }\n\n if (isTimeItemObject(item) && typeof item.value !== 'string') {\n warning(false, '[TimePicker]: a source item is expected to be a time string or an object with a time value.');\n\n return false;\n }\n\n if (normalizeTimeValue(getTimeItemValue(item), format) === EMPTY_VALUE) {\n warning(false, `[TimePicker]: the source item value \"${getTimeItemValue(item)}\" is not a time.`);\n\n return false;\n }\n\n return true;\n });\n};\n\n/**\n * Проверяет, выходит ли значение за диапазон `minTime`/`maxTime` после нормализации.\n * Пустое значение не считается выходящим за диапазон. Если `minTime > maxTime`, диапазон трактуется как переходящий через полночь.\n */\nexport const isTimeValueOutOfRange = (\n value: string,\n format: TimeFormat,\n minTime?: string,\n maxTime?: string,\n): boolean => {\n const normalizedValue = normalizeTimeValue(value, format);\n\n if (normalizedValue === EMPTY_VALUE) {\n return false;\n }\n\n const normalizedMinTime = normalizeTimeRangeValue(minTime, format);\n const normalizedMaxTime = normalizeTimeRangeValue(maxTime, format);\n\n if (normalizedMinTime && normalizedMaxTime && normalizedMinTime > normalizedMaxTime) {\n return normalizedValue < normalizedMinTime && normalizedValue > normalizedMaxTime;\n }\n\n return (\n (normalizedMinTime !== undefined && normalizedValue < normalizedMinTime) ||\n (normalizedMaxTime !== undefined && normalizedValue > normalizedMaxTime)\n );\n};\n\n/**\n * Нормализует display-значение в committed-форму `HH:mm[:ss]`.\n * Частично заполненные сегменты дополняются и ограничиваются максимумами сегментов.\n */\nexport const normalizeTimeValue = (value: string, format: TimeFormat): string => {\n if (isTimeDisplayEmpty(value)) {\n return EMPTY_VALUE;\n }\n\n const displaySegments = getDisplaySegments(value, format);\n\n return getTimeSegments(format)\n .map((segment, index) => normalizeTimeSegment(displaySegments[index], segment))\n .join(TIME_SEPARATOR);\n};\n\nconst normalizeTimeRangeValue = (value: string | undefined, format: TimeFormat): string | undefined => {\n if (!value) {\n return undefined;\n }\n\n const normalizedValue = normalizeTimeValue(value, format);\n\n return normalizedValue === EMPTY_VALUE ? undefined : normalizedValue;\n};\n\n/**\n * Преобразует display-значение в промежуточное значение для `onInputValueChange`.\n * Заполненные сегменты дополняются до двух цифр, пропущенные сегменты до последнего заполненного становятся `00`.\n */\nexport const serializeTimeValue = (value: string, format: TimeFormat): string => {\n const serializedSegments = takeFilledSegments(\n getDisplaySegments(value, format).map((segmentValue) => {\n const digits = getDigits(segmentValue);\n\n return digits ? digits.padStart(EMPTY_SEGMENT.length, ZERO_PAD_CHAR) : EMPTY_VALUE;\n }),\n );\n\n return serializedSegments.map((segmentValue) => segmentValue || '00').join(TIME_SEPARATOR);\n};\n\n/** Отбрасывает незаполненный хвост сегментов: ведущие пустые сегменты остаются на своих местах. */\nconst takeFilledSegments = (segments: string[]): string[] => {\n const lastFilledIndex = segments.reduce((result, segmentValue, index) => (segmentValue ? index : result), -1);\n\n return segments.slice(0, lastFilledIndex + 1);\n};\n\nexport const getTimeDisplayValue = (value: string, format: TimeFormat): string => {\n if (value === EMPTY_VALUE) {\n return EMPTY_VALUE;\n }\n\n return getDisplaySegments(value, format).join(TIME_SEPARATOR);\n};\n\n/**\n * Возвращает display-значение внешнего `value`.\n * Сегменты, записанные одной цифрой, дополняются нулем, поэтому `9:00` показывается как `09:00` —\n * так же, как компонент показывает время элементов источника.\n * Значение без разделителя остается частично введенным: `1` — это первая цифра часов, а не `01:00`.\n */\nexport const getExternalTimeDisplayValue = (value: string, format: TimeFormat): string => {\n if (!value.includes(TIME_SEPARATOR)) {\n return getTimeDisplayValue(value, format);\n }\n\n const paddedSegments = value.split(TIME_SEPARATOR).map((segmentValue) => {\n const digits = getDigits(segmentValue);\n\n return digits ? digits.padStart(EMPTY_SEGMENT.length, ZERO_PAD_CHAR) : EMPTY_VALUE;\n });\n\n return getTimeDisplayValue(paddedSegments.join(TIME_SEPARATOR), format);\n};\n\n/** Заменяет значение выбранного сегмента, сохраняя остальные сегменты display-значения без изменений. */\nexport const replaceTimeSegment = (\n value: string,\n segment: TimeSegment,\n nextSegmentValue: string,\n format: TimeFormat,\n): string => {\n const segments = getDisplaySegments(value, format);\n const index = getTimeSegments(format).indexOf(segment);\n\n segments[index] = sanitizeSegment(nextSegmentValue);\n\n return segments.join(TIME_SEPARATOR);\n};\n\n/**\n * Проверяет, что вставленное значение похоже на время:\n * это либо сегменты из одной-двух цифр через любой разделитель — `12:30`, `9:5`, `1:23:45`, `12.30`, —\n * либо цифры подряд — `9`, `1230`, `123045`.\n * Строки, из которых время собралось бы случайно — `2026-08-01`, `hello 42`, — временем не считаются.\n */\nexport const isTimeLikePastedValue = (value: string): boolean => {\n const trimmedValue = value.trim();\n\n return TIME_LIKE_SEGMENTS_REGEXP.test(trimmedValue) || TIME_LIKE_DIGITS_REGEXP.test(trimmedValue);\n};\n\n/**\n * Парсит вставленное пользователем значение и сразу преобразует его в committed-форму.\n * Значение, не похожее на время, отдается как пустое: такую вставку компонент считает некорректным вводом.\n */\nexport const parsePastedTimeValue = (value: string, format: TimeFormat): string => {\n const trimmedValue = value.trim();\n\n if (!DIGIT_REGEXP.test(trimmedValue) || !isTimeLikePastedValue(trimmedValue)) {\n return EMPTY_VALUE;\n }\n\n // Разделители сегментов приводятся к одному виду, чтобы `9.5` разбирался так же, как `9:5`.\n const normalizedSeparators = TIME_LIKE_SEGMENTS_REGEXP.test(trimmedValue)\n ? trimmedValue.split(NON_DIGIT_REGEXP).join(TIME_SEPARATOR)\n : trimmedValue;\n\n const segments = getDisplaySegments(normalizedSeparators, format);\n\n return normalizeTimeValue(segments.join(TIME_SEPARATOR), format);\n};\n\n/** Возвращает текущее display-значение сегмента или пустой сегмент, если индекс отсутствует. */\nexport const getTimeSegmentValue = (value: string, segment: TimeSegment, format: TimeFormat): string => {\n const segments = getDisplaySegments(value, format);\n const index = getTimeSegments(format).indexOf(segment);\n\n return segments[index] ?? EMPTY_SEGMENT;\n};\n\nexport const getEmptyDisplayValue = (precision: TimeFormat): string =>\n getTimeSegments(precision)\n .map(() => EMPTY_SEGMENT)\n .join(TIME_SEPARATOR);\n\n/**\n * Преобразует display-значение в поисковый запрос для фильтрации элементов.\n * Сегменты содержат только введенные цифры, незаполненный хвост отбрасывается: `12:3_` => `12:3`, `1_:__` => `1`.\n * Позиции сегментов сохраняются, поэтому ведущие незаполненные сегменты остаются пустыми: `__:34` => `:34`.\n * Это нужно для посегментного сравнения в `filterTimeItems` и передается как есть в пользовательскую `source`.\n */\nexport const getTimeFilterQuery = (value: string, format: TimeFormat): string =>\n takeFilledSegments(getDisplaySegments(value, format).map(getDigits)).join(TIME_SEPARATOR);\n\n/**\n * Фильтрует элементы по запросу из поля ввода.\n * Сравнивает запрос посегментно: введенные цифры сегмента должны быть префиксом соответствующего сегмента элемента.\n * Пустой запрос возвращает все элементы.\n */\nexport const filterTimeItems = <T extends TimeItemValue>(\n items: Array<TimePickerExtendedItem<T>>,\n query: string,\n format: TimeFormat,\n): Array<TimePickerExtendedItem<T>> => {\n const querySegments = query.split(TIME_SEPARATOR).map(getDigits);\n\n if (querySegments.every((segmentValue) => !segmentValue)) {\n return items;\n }\n\n return items.filter((item) => {\n if (!isTimeItem(item)) {\n return true;\n }\n\n const itemSegments = getDisplaySegments(normalizeTimeValue(getTimeItemValue(item), format), format);\n\n return querySegments.every(\n (segmentValue, index) => !segmentValue || (itemSegments[index] ?? EMPTY_VALUE).startsWith(segmentValue),\n );\n });\n};\n"]}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Прокручивает ближайший scrollable-контейнер так, чтобы выбранный элемент оказался ближе к центру viewport контейнера.
|
|
3
|
+
* Отличается от библиотечной `scrollYCenterIntoNearestScrollable` тем, что смещение считается от текущего `scrollTop`:
|
|
4
|
+
* центр — это дельта относительно контейнера, поэтому библиотечная версия верна только для непрокрученного меню.
|
|
3
5
|
*/
|
|
4
6
|
export declare const scrollSelectedItemIntoView: (element: HTMLElement) => void;
|
|
@@ -2,6 +2,8 @@ import { findNearestScrollableParent } from '../../../lib/dom/scrollYCenterIntoN
|
|
|
2
2
|
import { getOwnerGlobalObject, isBrowser } from '../../../lib/globalObject.js';
|
|
3
3
|
/**
|
|
4
4
|
* Прокручивает ближайший scrollable-контейнер так, чтобы выбранный элемент оказался ближе к центру viewport контейнера.
|
|
5
|
+
* Отличается от библиотечной `scrollYCenterIntoNearestScrollable` тем, что смещение считается от текущего `scrollTop`:
|
|
6
|
+
* центр — это дельта относительно контейнера, поэтому библиотечная версия верна только для непрокрученного меню.
|
|
5
7
|
*/
|
|
6
8
|
export var scrollSelectedItemIntoView = function (element) {
|
|
7
9
|
var globalObject = getOwnerGlobalObject(element);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scrollSelectedItemIntoView.js","sourceRoot":"","sources":["scrollSelectedItemIntoView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,wDAAwD,CAAC;AACrG,OAAO,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE/E
|
|
1
|
+
{"version":3,"file":"scrollSelectedItemIntoView.js","sourceRoot":"","sources":["scrollSelectedItemIntoView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,wDAAwD,CAAC;AACrG,OAAO,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE/E;;;;GAIG;AACH,MAAM,CAAC,IAAM,0BAA0B,GAAG,UAAC,OAAoB;IAC7D,IAAM,YAAY,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAEnD,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,OAAO;IACT,CAAC;IAED,IAAM,MAAM,GAAG,2BAA2B,CAAC,OAAO,CAAC,CAAC;IAEpD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,IAAM,WAAW,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IACpD,IAAM,UAAU,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAC;IAElD,IAAM,YAAY,GAAG,WAAW,CAAC,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC;IACtD,IAAM,eAAe,GAAG,WAAW,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/D,IAAM,eAAe,GAAG,CAAC,YAAY,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAE7D,IAAI,eAAe,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,SAAS,GAAG,eAAe,EAAE,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC,CAAC","sourcesContent":["import { findNearestScrollableParent } from '../../../lib/dom/scrollYCenterIntoNearestScrollable.js';\nimport { getOwnerGlobalObject, isBrowser } from '../../../lib/globalObject.js';\n\n/**\n * Прокручивает ближайший scrollable-контейнер так, чтобы выбранный элемент оказался ближе к центру viewport контейнера.\n * Отличается от библиотечной `scrollYCenterIntoNearestScrollable` тем, что смещение считается от текущего `scrollTop`:\n * центр — это дельта относительно контейнера, поэтому библиотечная версия верна только для непрокрученного меню.\n */\nexport const scrollSelectedItemIntoView = (element: HTMLElement): void => {\n const globalObject = getOwnerGlobalObject(element);\n\n if (!isBrowser(globalObject)) {\n return;\n }\n\n const parent = findNearestScrollableParent(element);\n\n if (!parent) {\n return;\n }\n\n const elementRect = element.getBoundingClientRect();\n const parentRect = parent.getBoundingClientRect();\n\n const scrollTopPos = elementRect.top - parentRect.top;\n const scrollBottomPos = elementRect.bottom - parentRect.bottom;\n const scrollCenterPos = (scrollTopPos + scrollBottomPos) / 2;\n\n if (scrollCenterPos !== 0) {\n parent.scrollTo({ top: parent.scrollTop + scrollCenterPos });\n }\n};\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getTimeValueString, isTimeValueOutOfRange, normalizeTimeValue } from './TimePicker.value.js';
|
|
2
2
|
export var validateTimePicker = function (value, options) {
|
|
3
3
|
if (options === void 0) { options = {}; }
|
|
4
4
|
var timeValue = getTimeValueString(value);
|
|
@@ -6,9 +6,7 @@ export var validateTimePicker = function (value, options) {
|
|
|
6
6
|
return false;
|
|
7
7
|
}
|
|
8
8
|
var _a = options.format, format = _a === void 0 ? 'HH:mm' : _a, minTime = options.minTime, maxTime = options.maxTime;
|
|
9
|
-
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
9
|
+
// Нормализованное значение уже канонично, поэтому отдельная проверка display-формы не нужна.
|
|
12
10
|
if (normalizeTimeValue(timeValue, format) !== timeValue) {
|
|
13
11
|
return false;
|
|
14
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateTimePicker.js","sourceRoot":"","sources":["validateTimePicker.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"validateTimePicker.js","sourceRoot":"","sources":["validateTimePicker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAQtG,MAAM,CAAC,IAAM,kBAAkB,GAAG,UAChC,KAAkC,EAClC,OAAyC;IAAzC,wBAAA,EAAA,YAAyC;IAEzC,IAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAE5C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,IAAA,KAAuC,OAAO,OAA9B,EAAhB,MAAM,mBAAG,OAAO,KAAA,EAAE,OAAO,GAAc,OAAO,QAArB,EAAE,OAAO,GAAK,OAAO,QAAZ,CAAa;IAEvD,6FAA6F;IAC7F,IAAI,kBAAkB,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,SAAS,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CAAC,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AACrE,CAAC,CAAC","sourcesContent":["import type { Nullable } from '../../../typings/utility-types.js';\nimport type { TimeFormat, TimeItem } from './TimePicker.shared.js';\nimport { getTimeValueString, isTimeValueOutOfRange, normalizeTimeValue } from './TimePicker.value.js';\n\nexport interface TimePickerValidationOptions {\n format?: TimeFormat;\n minTime?: string;\n maxTime?: string;\n}\n\nexport const validateTimePicker = (\n value: Nullable<string | TimeItem>,\n options: TimePickerValidationOptions = {},\n): boolean => {\n const timeValue = getTimeValueString(value);\n\n if (!timeValue) {\n return false;\n }\n\n const { format = 'HH:mm', minTime, maxTime } = options;\n\n // Нормализованное значение уже канонично, поэтому отдельная проверка display-формы не нужна.\n if (normalizeTimeValue(timeValue, format) !== timeValue) {\n return false;\n }\n\n return !isTimeValueOutOfRange(timeValue, format, minTime, maxTime);\n};\n"]}
|
|
@@ -5,9 +5,14 @@ interface UseTimePickerDropdownOptions<T extends TimeItemValue> {
|
|
|
5
5
|
items: Array<TimePickerMenuItem<T>>;
|
|
6
6
|
selectedItemIndex: number | null;
|
|
7
7
|
autoHighlightKey: string | null;
|
|
8
|
+
/**
|
|
9
|
+
* Состоянием открытости владеет компонент: от него зависит запрос элементов,
|
|
10
|
+
* а элементы, в свою очередь, нужны этому хуку для навигации.
|
|
11
|
+
*/
|
|
12
|
+
isDropdownOpened: boolean;
|
|
13
|
+
setIsDropdownOpened(isOpened: boolean): void;
|
|
8
14
|
}
|
|
9
15
|
interface UseTimePickerDropdownResult {
|
|
10
|
-
isDropdownOpened: boolean;
|
|
11
16
|
highlightedItemIndex: number | null;
|
|
12
17
|
openDropdown(): void;
|
|
13
18
|
closeDropdown(): void;
|