@hh.ru/magritte-ui-input 5.0.12

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.
Files changed (59) hide show
  1. package/BaseInput.d.ts +4 -0
  2. package/BaseInput.js +125 -0
  3. package/BaseInput.js.map +1 -0
  4. package/DateTimeInput.d.ts +3 -0
  5. package/DateTimeInput.js +41 -0
  6. package/DateTimeInput.js.map +1 -0
  7. package/Input.d.ts +4 -0
  8. package/Input.js +23 -0
  9. package/Input.js.map +1 -0
  10. package/NumberInput.d.ts +3 -0
  11. package/NumberInput.js +29 -0
  12. package/NumberInput.js.map +1 -0
  13. package/PasswordInput.d.ts +3 -0
  14. package/PasswordInput.js +36 -0
  15. package/PasswordInput.js.map +1 -0
  16. package/SearchInput.d.ts +3 -0
  17. package/SearchInput.js +23 -0
  18. package/SearchInput.js.map +1 -0
  19. package/UncontrolledDateTimeInput.d.ts +3 -0
  20. package/UncontrolledDateTimeInput.js +30 -0
  21. package/UncontrolledDateTimeInput.js.map +1 -0
  22. package/UncontrolledInput.d.ts +3 -0
  23. package/UncontrolledInput.js +26 -0
  24. package/UncontrolledInput.js.map +1 -0
  25. package/UncontrolledNumberInput.d.ts +3 -0
  26. package/UncontrolledNumberInput.js +29 -0
  27. package/UncontrolledNumberInput.js.map +1 -0
  28. package/UncontrolledPasswordInput.d.ts +3 -0
  29. package/UncontrolledPasswordInput.js +27 -0
  30. package/UncontrolledPasswordInput.js.map +1 -0
  31. package/UncontrolledSearchInput.d.ts +3 -0
  32. package/UncontrolledSearchInput.js +26 -0
  33. package/UncontrolledSearchInput.js.map +1 -0
  34. package/index.css +445 -0
  35. package/index.d.ts +15 -0
  36. package/index.js +35 -0
  37. package/index.js.map +1 -0
  38. package/index.mock.d.ts +14 -0
  39. package/index.mock.js +38 -0
  40. package/index.mock.js.map +1 -0
  41. package/numberFormatter.d.ts +3 -0
  42. package/numberFormatter.js +52 -0
  43. package/numberFormatter.js.map +1 -0
  44. package/package.json +48 -0
  45. package/types.d.ts +160 -0
  46. package/types.js +3 -0
  47. package/types.js.map +1 -0
  48. package/useDateTimeMask.d.ts +3 -0
  49. package/useDateTimeMask.js +134 -0
  50. package/useDateTimeMask.js.map +1 -0
  51. package/useFocus.d.ts +7 -0
  52. package/useFocus.js +21 -0
  53. package/useFocus.js.map +1 -0
  54. package/useInputAriaProps.d.ts +14 -0
  55. package/useInputAriaProps.js +15 -0
  56. package/useInputAriaProps.js.map +1 -0
  57. package/useUncontrolledInput.d.ts +1 -0
  58. package/useUncontrolledInput.js +14 -0
  59. package/useUncontrolledInput.js.map +1 -0
@@ -0,0 +1,52 @@
1
+ import './index.css';
2
+ import { defaults, format } from '@hh.ru/magritte-common-number-formatter';
3
+
4
+ const calculateDelimiters = (rawText, formatted, groupSeparator) => formatted.split(groupSeparator).length - rawText.trim().split(groupSeparator).length;
5
+ const numberFormatterFactory = (passedParams = {}) => {
6
+ const filteredParams = Object.keys(passedParams).reduce((acc, key) => passedParams[key] === undefined
7
+ ? acc
8
+ : {
9
+ ...acc,
10
+ [key]: passedParams[key],
11
+ }, {});
12
+ const params = { ...defaults, ...filteredParams };
13
+ const ouputFormatParams = {
14
+ groupSeparator: '',
15
+ decimalMark: ['.', ...params.decimalMark],
16
+ allowNegative: params.allowNegative,
17
+ decimalLength: params.decimalLength,
18
+ };
19
+ const decimalDelimitersRegExp = new RegExp(`[${params.decimalMark?.join('')}]`, 'g');
20
+ return (prevValue, value, caretPosition) => {
21
+ const decimalDelimitersCount = value.match(decimalDelimitersRegExp)?.length || 0;
22
+ if (decimalDelimitersCount > 1) {
23
+ const lastChar = prevValue.charAt(value.length - 1);
24
+ const formattedValue = format(prevValue, params) + (params.decimalMark.includes(lastChar) ? lastChar : '');
25
+ const decimalDelimitersPosition = formattedValue.search(decimalDelimitersRegExp);
26
+ return {
27
+ formattedValue,
28
+ outputValue: format(prevValue, ouputFormatParams) + (params.decimalMark.includes(lastChar) ? lastChar : ''),
29
+ caretPosition: decimalDelimitersPosition + 1,
30
+ };
31
+ }
32
+ const lastChar = value.charAt(value.length - 1);
33
+ const prevLastChar = prevValue.charAt(prevValue.length - 1);
34
+ const formattedValue = format(value, params) + (params.decimalMark.includes(lastChar) ? lastChar : '');
35
+ const formattedPrevValue = format(prevValue, params) + (params.decimalMark.includes(prevLastChar) ? prevLastChar : '');
36
+ const outputValue = format(value, ouputFormatParams) + (params.decimalMark.includes(lastChar) ? lastChar : '');
37
+ // разница вы количестве разделителей разрядов между предыдушим и текущим значениями
38
+ const delimitersDelta = calculateDelimiters(formattedPrevValue, formattedValue, params.groupSeparator);
39
+ const prevValueFirstDelimiterPosition = formattedPrevValue.indexOf(params.groupSeparator) + 1;
40
+ // если каретка находится левее первого символа разделителя разрядов, то не применяем сдвиг с учетом
41
+ // разницы в количестве разделителей, т.к. сдвигаются только символы справа от первого разделителя
42
+ const caret = caretPosition < prevValueFirstDelimiterPosition ? caretPosition : caretPosition + delimitersDelta;
43
+ return {
44
+ formattedValue,
45
+ outputValue,
46
+ caretPosition: formattedPrevValue === formattedValue ? Math.max(caret - 1, 0) : caret,
47
+ };
48
+ };
49
+ };
50
+
51
+ export { numberFormatterFactory };
52
+ //# sourceMappingURL=numberFormatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numberFormatter.js","sources":["../src/numberFormatter.ts"],"sourcesContent":["import { format, type FormatParams, defaults } from '@hh.ru/magritte-common-number-formatter';\nimport { InputFormatter } from '@hh.ru/magritte-ui-input/types';\n\nconst calculateDelimiters = (rawText: string, formatted: string, groupSeparator: string): number =>\n formatted.split(groupSeparator).length - rawText.trim().split(groupSeparator).length;\n\nexport const numberFormatterFactory: (params?: FormatParams) => InputFormatter = (passedParams = {}) => {\n const filteredParams = (Object.keys(passedParams) as Array<keyof typeof passedParams>).reduce<FormatParams>(\n (acc, key) =>\n passedParams[key] === undefined\n ? acc\n : {\n ...acc,\n [key]: passedParams[key],\n },\n {}\n );\n const params = { ...defaults, ...filteredParams };\n const ouputFormatParams = {\n groupSeparator: '',\n decimalMark: ['.', ...params.decimalMark],\n allowNegative: params.allowNegative,\n decimalLength: params.decimalLength,\n };\n const decimalDelimitersRegExp = new RegExp(`[${params.decimalMark?.join('')}]`, 'g');\n\n return (prevValue: string, value: string, caretPosition: number) => {\n const decimalDelimitersCount = value.match(decimalDelimitersRegExp)?.length || 0;\n if (decimalDelimitersCount > 1) {\n const lastChar = prevValue.charAt(value.length - 1);\n const formattedValue = format(prevValue, params) + (params.decimalMark.includes(lastChar) ? lastChar : '');\n const decimalDelimitersPosition = formattedValue.search(decimalDelimitersRegExp);\n return {\n formattedValue,\n outputValue:\n format(prevValue, ouputFormatParams) + (params.decimalMark.includes(lastChar) ? lastChar : ''),\n caretPosition: decimalDelimitersPosition + 1,\n };\n }\n const lastChar = value.charAt(value.length - 1);\n const prevLastChar = prevValue.charAt(prevValue.length - 1);\n const formattedValue = format(value, params) + (params.decimalMark.includes(lastChar) ? lastChar : '');\n const formattedPrevValue =\n format(prevValue, params) + (params.decimalMark.includes(prevLastChar) ? prevLastChar : '');\n const outputValue = format(value, ouputFormatParams) + (params.decimalMark.includes(lastChar) ? lastChar : '');\n // разница вы количестве разделителей разрядов между предыдушим и текущим значениями\n const delimitersDelta = calculateDelimiters(formattedPrevValue, formattedValue, params.groupSeparator);\n const prevValueFirstDelimiterPosition = formattedPrevValue.indexOf(params.groupSeparator) + 1;\n // если каретка находится левее первого символа разделителя разрядов, то не применяем сдвиг с учетом\n // разницы в количестве разделителей, т.к. сдвигаются только символы справа от первого разделителя\n const caret = caretPosition < prevValueFirstDelimiterPosition ? caretPosition : caretPosition + delimitersDelta;\n\n return {\n formattedValue,\n outputValue,\n caretPosition: formattedPrevValue === formattedValue ? Math.max(caret - 1, 0) : caret,\n };\n };\n};\n"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@hh.ru/magritte-ui-input",
3
+ "version": "5.0.12",
4
+ "main": "index.js",
5
+ "types": "index.d.ts",
6
+ "sideEffects": [
7
+ "index.css"
8
+ ],
9
+ "scripts": {
10
+ "build": "yarn root:build $(pwd)",
11
+ "build-test-branch": "yarn root:build-test-branch $(pwd)",
12
+ "changelog": "yarn root:changelog $(pwd)",
13
+ "prepack": "yarn root:prepack $(pwd)",
14
+ "postpublish": "yarn root:postpublish $(pwd)",
15
+ "stylelint-test": "yarn root:stylelint-test $(pwd)",
16
+ "eslint-test": "yarn root:eslint-test $(pwd)",
17
+ "ts-config": "yarn root:ts-config $(pwd)",
18
+ "ts-check": "yarn root:ts-check $(pwd)",
19
+ "test": "yarn root:test $(pwd)"
20
+ },
21
+ "peerDependencies": {
22
+ "classnames": ">=2.3.2",
23
+ "react": ">=18.2.0"
24
+ },
25
+ "dependencies": {
26
+ "@hh.ru/magritte-common-focus-visible": "0.1.3",
27
+ "@hh.ru/magritte-common-number-formatter": "1.0.3",
28
+ "@hh.ru/magritte-common-text-selection": "0.1.3",
29
+ "@hh.ru/magritte-common-use-disabled": "1.0.8",
30
+ "@hh.ru/magritte-common-use-multiple-refs": "1.1.2",
31
+ "@hh.ru/magritte-design-tokens": "18.1.1",
32
+ "@hh.ru/magritte-internal-field-hint": "1.2.26",
33
+ "@hh.ru/magritte-ui-action": "4.3.3",
34
+ "@hh.ru/magritte-ui-breakpoint": "4.0.1",
35
+ "@hh.ru/magritte-ui-counter": "4.0.8",
36
+ "@hh.ru/magritte-ui-icon": "7.1.3",
37
+ "@hh.ru/magritte-ui-mock-component": "1.0.10",
38
+ "@hh.ru/magritte-ui-theme-provider": "1.1.21",
39
+ "@hh.ru/magritte-ui-typography": "3.0.8",
40
+ "@maskito/core": "2.3.1",
41
+ "@maskito/kit": "2.3.1",
42
+ "@maskito/react": "2.3.1"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "gitHead": "b660dd64fca3eaad5ec44ea9a73f92bb0d9694aa"
48
+ }
package/types.d.ts ADDED
@@ -0,0 +1,160 @@
1
+ import type { FocusEventHandler, ForwardedRef, MouseEventHandler, ReactNode } from 'react';
2
+ import { type FormatParams } from '@hh.ru/magritte-common-number-formatter';
3
+ import { IconWrapperComponentSize24 } from '@hh.ru/magritte-ui-icon/iconTypes';
4
+ export type InputSize = 'medium' | 'large';
5
+ export interface InputFormatter {
6
+ /**
7
+ * @param prevValue - Значение до изменения
8
+ * @param value - Значение после изменения
9
+ * @param caretPosition - Позиция каретки после изменения
10
+ */
11
+ (prevValue: string, value: string, caretPosition: number): InputFormatterResult;
12
+ }
13
+ export interface InputFormatterResult {
14
+ /** Отформатированное значение предназначенное для отображение */
15
+ formattedValue: string;
16
+ /** Значение которое будет передано в обработчик onChange */
17
+ outputValue: string;
18
+ /** Позиция в которую должна быть установлена каретка после применения изменений */
19
+ caretPosition: number;
20
+ }
21
+ export interface ControlledProps {
22
+ /** Обработчик события изменения */
23
+ onChange: (value: string) => void;
24
+ /** Значение инпута */
25
+ value: string;
26
+ }
27
+ export type UncontrolledProps = Partial<ControlledProps>;
28
+ interface InputBaseProps {
29
+ /** Текст плейсхолдера */
30
+ placeholder?: ReactNode;
31
+ /** Постфикс */
32
+ postfix?: ReactNode;
33
+ /** Обработчик события получения фокуса */
34
+ onFocus?: FocusEventHandler<HTMLInputElement>;
35
+ /** Обработчик события потери фокуса */
36
+ onBlur?: FocusEventHandler<HTMLInputElement>;
37
+ /** Текст подсказки под инпутом */
38
+ description?: ReactNode;
39
+ /** Текст сообщения об ошибке */
40
+ errorMessage?: ReactNode;
41
+ /** Флаг отключения инпута */
42
+ disabled?: boolean;
43
+ /** Признак невалидности */
44
+ invalid?: boolean;
45
+ /** Функция форматтер */
46
+ formatter?: InputFormatter;
47
+ /** data-qa атрибут кнопки инпута */
48
+ buttonDataQa?: string;
49
+ buttonRef?: ForwardedRef<HTMLButtonElement>;
50
+ wrapperRef?: ForwardedRef<HTMLDivElement>;
51
+ /** Ограничение на количество введенных символов */
52
+ maxLength?: number;
53
+ }
54
+ interface LargeInputProps extends InputBaseProps {
55
+ /** Размер инпута */
56
+ size: 'large';
57
+ /** Флаг управляющий режимом отображения поейсхолдера */
58
+ elevatePlaceholder?: boolean;
59
+ }
60
+ export interface MediumInputProps extends InputBaseProps {
61
+ size?: 'medium';
62
+ elevatePlaceholder?: false;
63
+ }
64
+ type OnButtonClickType = MouseEventHandler<HTMLButtonElement>;
65
+ interface InputWithHintProps extends InputBaseProps {
66
+ /** Подсказка к полю ввода */
67
+ hint?: ReactNode;
68
+ /** Флаг показа подсказки при пустом значении инпута */
69
+ showHintAlways?: boolean;
70
+ }
71
+ interface InputWithRightButtonProps extends InputBaseProps {
72
+ /** Флаг управляющий показом кнопки очистки ввода */
73
+ clearable?: never;
74
+ /** Флаг управляющий показом кнопки очистки ввода при фокусе */
75
+ clearableOnFocus?: never;
76
+ /** Иконка кнопки */
77
+ buttonIcon: IconWrapperComponentSize24;
78
+ /** Обработчик события клика по кнопке */
79
+ onButtonClick: OnButtonClickType;
80
+ counter?: never;
81
+ }
82
+ export interface InputWithoutRightButtonProps extends InputBaseProps {
83
+ clearable?: false;
84
+ clearableOnFocus?: false;
85
+ buttonIcon?: never;
86
+ onButtonClick?: never;
87
+ counter?: never;
88
+ }
89
+ interface InputClearableProps extends InputBaseProps {
90
+ clearable: true;
91
+ clearableOnFocus?: never;
92
+ buttonIcon?: never;
93
+ onButtonClick?: OnButtonClickType;
94
+ counter?: never;
95
+ }
96
+ interface InputClearableOnFocusProps extends InputBaseProps {
97
+ clearable?: never;
98
+ clearableOnFocus: true;
99
+ buttonIcon?: never;
100
+ onButtonClick?: OnButtonClickType;
101
+ counter?: never;
102
+ }
103
+ export type InputWithRightButtonClearProps = InputClearableProps | InputClearableOnFocusProps;
104
+ interface InputWithRightCounterProps extends InputBaseProps {
105
+ /** Значение счетчика */
106
+ counter: ReactNode;
107
+ clearable?: never;
108
+ clearableOnFocus?: never;
109
+ buttonIcon?: never;
110
+ onButtonClick?: never;
111
+ }
112
+ interface InputWithInputIconProps extends InputBaseProps {
113
+ inputIcon?: IconWrapperComponentSize24;
114
+ }
115
+ interface InputWithFixedPlaceholderProps extends InputBaseProps {
116
+ /** Фиксированный placeholder: отображается по мере ввода в input и обрезается на длину введённого значения. Обычно применяется для input-ов с маской: дата/время, номер телефона или банковской карты и т.д. */
117
+ fixedPlaceholder?: string;
118
+ }
119
+ type NoButtonInputProps = LargeInputProps | MediumInputProps;
120
+ export type BaseInputProps = NoButtonInputProps & (InputWithRightButtonProps | InputWithoutRightButtonProps | InputWithRightButtonClearProps | InputWithRightCounterProps) & InputWithInputIconProps & InputWithFixedPlaceholderProps & InputWithHintProps & ControlledProps;
121
+ type InputProps = NoButtonInputProps & InputWithHintProps & (InputWithRightButtonProps | InputWithoutRightButtonProps | InputWithRightButtonClearProps);
122
+ export type ControlledInputProps = InputProps & ControlledProps;
123
+ export type UncontrolledInputProps = InputProps & UncontrolledProps;
124
+ type PasswordInputProps = NoButtonInputProps & InputWithHintProps & {
125
+ type?: never;
126
+ clearable?: never;
127
+ };
128
+ export type ControlledPasswordInputProps = PasswordInputProps & ControlledProps;
129
+ export type UncontrolledPasswordInputProps = PasswordInputProps & UncontrolledProps;
130
+ type NumberInputProps = InputProps & {
131
+ formatter?: never;
132
+ } & FormatParams;
133
+ export type ControlledNumberInputProps = NumberInputProps & ControlledProps;
134
+ export type UncontrolledNumberInputProps = NumberInputProps & UncontrolledProps;
135
+ export type SearchInputProps = (InputWithoutRightButtonProps | InputClearableProps) & {
136
+ type?: never;
137
+ postfix?: never;
138
+ errorMessage?: never;
139
+ invalid?: never;
140
+ description?: never;
141
+ size?: InputSize;
142
+ elevatePlaceholder?: false;
143
+ };
144
+ export type ControlledSearchInputProps = SearchInputProps & ControlledProps;
145
+ export type UncontrolledSearchInputProps = SearchInputProps & UncontrolledProps;
146
+ export type DateInputMask = 'd' | 'mm.yyyy' | 'dd.mm.yyyy';
147
+ export type TimeInputRounding = 5 | 15 | 30 | 60;
148
+ export type DateTimeInputProps = NoButtonInputProps & {
149
+ /** Формат заполнения даты */
150
+ dateMask?: DateInputMask;
151
+ /** Флаг для включения режима ввода времени */
152
+ timeMask?: boolean;
153
+ /** Шаг для округления введённого времени */
154
+ timeRounding?: TimeInputRounding;
155
+ /** Обработчик события клика по иконке, так же влияет на показ */
156
+ onButtonClick?: OnButtonClickType;
157
+ };
158
+ export type ControlledDateTimeInputProps = DateTimeInputProps & ControlledProps;
159
+ export type UncontrolledDateTimeInputProps = DateTimeInputProps & UncontrolledProps;
160
+ export {};
package/types.js ADDED
@@ -0,0 +1,3 @@
1
+ import './index.css';
2
+
3
+ //# sourceMappingURL=types.js.map
package/types.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import { RefCallback } from 'react';
2
+ import { type TimeInputRounding, type DateInputMask } from './types';
3
+ export declare const useDateTimeMask: (dateMask?: DateInputMask, timeMask?: boolean, timeRounding?: TimeInputRounding) => RefCallback<HTMLElement>;
@@ -0,0 +1,134 @@
1
+ import './index.css';
2
+ import { useMemo } from 'react';
3
+ import { MASKITO_DEFAULT_OPTIONS } from '@maskito/core';
4
+ import { maskitoDateTimeOptionsGenerator, maskitoDateOptionsGenerator, maskitoTimeOptionsGenerator } from '@maskito/kit';
5
+ import { useMaskito } from '@maskito/react';
6
+
7
+ /**
8
+ * Округление времени (в формате 00:00) до ближайшего заданного шага
9
+ *
10
+ * @param dateTime {String} Строка с постфиксом HH:MM, где H - часы, M - минуты
11
+ * @param roundValue {Number} Шаг для округления
12
+ * @returns {String}
13
+ *
14
+ * @example
15
+ * roundTime('20.12.2023 15:19', 15); // '20.12.2023 15:15'
16
+ * @example
17
+ * roundTime('15:31', 60); // '16:00'
18
+ */
19
+ const roundTime = (dateTime, roundValue) => {
20
+ const regexp = /(\d{2}):(\d{2})$/;
21
+ const match = dateTime.match(regexp);
22
+ const time = match?.[0];
23
+ if (time) {
24
+ const [hours, minutes] = time.split(':').map(Number);
25
+ const totalMinutes = hours * 60 + minutes;
26
+ const roundedMinutes = Math.round(totalMinutes / roundValue) * roundValue;
27
+ const roundedHours = Math.floor(roundedMinutes / 60) % 24;
28
+ const formattedHours = String(roundedHours).padStart(2, '0');
29
+ const formattedMinutes = String(roundedMinutes % 60).padStart(2, '0');
30
+ return dateTime.replace(regexp, `${formattedHours}:${formattedMinutes}`);
31
+ }
32
+ return dateTime;
33
+ };
34
+ /** Постпроцессор для округления времени до заданного шага */
35
+ const roundTimePostprocessor = (enabled, rounding) => (state) => enabled && rounding ? { ...state, value: roundTime(state.value, rounding) } : state;
36
+ /** Препроцессор для автоматического добавления разделителей из маски */
37
+ const autoSeparatorsPreprocessor = (mask) => {
38
+ let lastActionIsInsert = false;
39
+ return (state, actionType) => {
40
+ if (actionType === 'insert') {
41
+ lastActionIsInsert = true;
42
+ return state;
43
+ }
44
+ const canAddSeparator = actionType === 'validation' && lastActionIsInsert;
45
+ lastActionIsInsert = false;
46
+ if (canAddSeparator) {
47
+ const { value, selection } = state.elementState;
48
+ const [from, to] = selection;
49
+ let newValue = '';
50
+ const dateArray = value.split('');
51
+ for (let i = 0; i < mask.length; i++) {
52
+ if (i < dateArray.length) {
53
+ newValue += dateArray[i];
54
+ }
55
+ else if (typeof mask[i] === 'string') {
56
+ newValue += mask[i];
57
+ }
58
+ else {
59
+ break;
60
+ }
61
+ }
62
+ const addedCharacters = newValue.length - value.length;
63
+ return {
64
+ ...state,
65
+ elementState: {
66
+ value: newValue,
67
+ selection: [from + addedCharacters, to + addedCharacters],
68
+ },
69
+ };
70
+ }
71
+ return state;
72
+ };
73
+ };
74
+ /** Препроцессор для замены разделителей "., :;/_" на точку */
75
+ const replaceSeparatorsPreprocessor = (state, actionType) => {
76
+ if (actionType === 'insert') {
77
+ return {
78
+ ...state,
79
+ data: state.data
80
+ .replace(/[^0-9., :;/_]/g, '')
81
+ .replace(/[., :;/_]/g, '.')
82
+ .replace(/([^0-9])\1+/g, '$1'),
83
+ };
84
+ }
85
+ return state;
86
+ };
87
+ const useDateTimeMask = (dateMask, timeMask, timeRounding) => {
88
+ const options = useMemo(() => {
89
+ // маска 'd' - исключение, которого нету в maskito api:
90
+ if (dateMask === 'd') {
91
+ return {
92
+ mask: /^([1-9]|1\d|2[0-9]|3[01])$/,
93
+ };
94
+ }
95
+ const dateSeparator = '.';
96
+ const dateMode = dateMask?.replace(/\./g, '/');
97
+ const timeMode = 'HH:MM';
98
+ let options = { ...MASKITO_DEFAULT_OPTIONS };
99
+ if (dateMask && timeMask) {
100
+ options = maskitoDateTimeOptionsGenerator({
101
+ dateMode,
102
+ timeMode,
103
+ dateSeparator,
104
+ });
105
+ }
106
+ else if (dateMask) {
107
+ options = maskitoDateOptionsGenerator({
108
+ mode: dateMode,
109
+ separator: dateSeparator,
110
+ });
111
+ }
112
+ else if (timeMask) {
113
+ options = maskitoTimeOptionsGenerator({
114
+ mode: timeMode,
115
+ });
116
+ }
117
+ return {
118
+ ...options,
119
+ preprocessors: [
120
+ replaceSeparatorsPreprocessor,
121
+ ...(options.preprocessors || []),
122
+ autoSeparatorsPreprocessor(options.mask),
123
+ ],
124
+ postprocessors: [
125
+ ...(options.postprocessors || []),
126
+ roundTimePostprocessor(Boolean(timeRounding && timeMode), timeRounding),
127
+ ],
128
+ };
129
+ }, [dateMask, timeMask, timeRounding]);
130
+ return useMaskito({ options });
131
+ };
132
+
133
+ export { useDateTimeMask };
134
+ //# sourceMappingURL=useDateTimeMask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDateTimeMask.js","sources":["../src/useDateTimeMask.ts"],"sourcesContent":["import { RefCallback, useMemo } from 'react';\nimport { MaskitoOptions, MASKITO_DEFAULT_OPTIONS, MaskitoPreprocessor, MaskitoPostprocessor } from '@maskito/core';\nimport {\n type MaskitoDateMode,\n maskitoDateOptionsGenerator,\n maskitoTimeOptionsGenerator,\n maskitoDateTimeOptionsGenerator,\n} from '@maskito/kit';\nimport { useMaskito } from '@maskito/react';\n\nimport { type TimeInputRounding, type DateInputMask } from '@hh.ru/magritte-ui-input/types';\n\n/**\n * Округление времени (в формате 00:00) до ближайшего заданного шага\n *\n * @param dateTime {String} Строка с постфиксом HH:MM, где H - часы, M - минуты\n * @param roundValue {Number} Шаг для округления\n * @returns {String}\n *\n * @example\n * roundTime('20.12.2023 15:19', 15); // '20.12.2023 15:15'\n * @example\n * roundTime('15:31', 60); // '16:00'\n */\nconst roundTime = (dateTime: string, roundValue: TimeInputRounding): string => {\n const regexp = /(\\d{2}):(\\d{2})$/;\n const match = dateTime.match(regexp);\n const time = match?.[0];\n\n if (time) {\n const [hours, minutes] = time.split(':').map(Number);\n const totalMinutes = hours * 60 + minutes;\n const roundedMinutes = Math.round(totalMinutes / roundValue) * roundValue;\n const roundedHours = Math.floor(roundedMinutes / 60) % 24;\n const formattedHours = String(roundedHours).padStart(2, '0');\n const formattedMinutes = String(roundedMinutes % 60).padStart(2, '0');\n return dateTime.replace(regexp, `${formattedHours}:${formattedMinutes}`);\n }\n\n return dateTime;\n};\n\n/** Постпроцессор для округления времени до заданного шага */\nconst roundTimePostprocessor =\n (enabled: boolean, rounding?: TimeInputRounding): MaskitoPostprocessor =>\n (state) =>\n enabled && rounding ? { ...state, value: roundTime(state.value, rounding) } : state;\n\n/** Препроцессор для автоматического добавления разделителей из маски */\nconst autoSeparatorsPreprocessor = (mask: Array<RegExp | string>): MaskitoPreprocessor => {\n let lastActionIsInsert = false;\n\n return (state, actionType) => {\n if (actionType === 'insert') {\n lastActionIsInsert = true;\n return state;\n }\n\n const canAddSeparator = actionType === 'validation' && lastActionIsInsert;\n lastActionIsInsert = false;\n\n if (canAddSeparator) {\n const { value, selection } = state.elementState;\n const [from, to] = selection;\n let newValue = '';\n const dateArray = value.split('');\n\n for (let i = 0; i < mask.length; i++) {\n if (i < dateArray.length) {\n newValue += dateArray[i];\n } else if (typeof mask[i] === 'string') {\n newValue += mask[i];\n } else {\n break;\n }\n }\n\n const addedCharacters = newValue.length - value.length;\n\n return {\n ...state,\n elementState: {\n value: newValue,\n selection: [from + addedCharacters, to + addedCharacters],\n },\n };\n }\n\n return state;\n };\n};\n\n/** Препроцессор для замены разделителей \"., :;/_\" на точку */\nconst replaceSeparatorsPreprocessor: MaskitoPreprocessor = (state, actionType) => {\n if (actionType === 'insert') {\n return {\n ...state,\n data: state.data\n .replace(/[^0-9., :;/_]/g, '')\n .replace(/[., :;/_]/g, '.')\n .replace(/([^0-9])\\1+/g, '$1'),\n };\n }\n return state;\n};\n\nexport const useDateTimeMask = (\n dateMask?: DateInputMask,\n timeMask?: boolean,\n timeRounding?: TimeInputRounding\n): RefCallback<HTMLElement> => {\n const options = useMemo<MaskitoOptions>(() => {\n // маска 'd' - исключение, которого нету в maskito api:\n if (dateMask === 'd') {\n return {\n mask: /^([1-9]|1\\d|2[0-9]|3[01])$/,\n };\n }\n\n const dateSeparator = '.';\n const dateMode = dateMask?.replace(/\\./g, '/') as MaskitoDateMode;\n const timeMode = 'HH:MM';\n let options: MaskitoOptions = { ...MASKITO_DEFAULT_OPTIONS };\n\n if (dateMask && timeMask) {\n options = maskitoDateTimeOptionsGenerator({\n dateMode,\n timeMode,\n dateSeparator,\n });\n } else if (dateMask) {\n options = maskitoDateOptionsGenerator({\n mode: dateMode,\n separator: dateSeparator,\n });\n } else if (timeMask) {\n options = maskitoTimeOptionsGenerator({\n mode: timeMode,\n });\n }\n\n return {\n ...options,\n preprocessors: [\n replaceSeparatorsPreprocessor,\n ...(options.preprocessors || []),\n autoSeparatorsPreprocessor(options.mask as Array<RegExp | string>),\n ],\n postprocessors: [\n ...(options.postprocessors || []),\n roundTimePostprocessor(Boolean(timeRounding && timeMode), timeRounding),\n ],\n };\n }, [dateMask, timeMask, timeRounding]);\n\n return useMaskito({ options });\n};\n"],"names":[],"mappings":"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"}
package/useFocus.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { FocusEventHandler, ChangeEventHandler } from 'react';
2
+ export declare const useFocus: <T extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement>(onChange: (value: string) => void, onFocus: FocusEventHandler<T> | undefined, onBlur: FocusEventHandler<T> | undefined) => {
3
+ changeHandler: ChangeEventHandler<T>;
4
+ focusHandler: FocusEventHandler<T>;
5
+ blurHandler: FocusEventHandler<T>;
6
+ isFocused: boolean;
7
+ };
package/useFocus.js ADDED
@@ -0,0 +1,21 @@
1
+ import './index.css';
2
+ import { useState, useCallback } from 'react';
3
+
4
+ const useFocus = (onChange, onFocus, onBlur) => {
5
+ const [isFocused, setFocused] = useState(false);
6
+ const changeHandler = useCallback((event) => {
7
+ onChange(event.target.value);
8
+ }, [onChange]);
9
+ const focusHandler = useCallback((event) => {
10
+ setFocused(true);
11
+ onFocus?.(event);
12
+ }, [setFocused, onFocus]);
13
+ const blurHandler = useCallback((event) => {
14
+ setFocused(false);
15
+ onBlur?.(event);
16
+ }, [setFocused, onBlur]);
17
+ return { changeHandler, focusHandler, blurHandler, isFocused };
18
+ };
19
+
20
+ export { useFocus };
21
+ //# sourceMappingURL=useFocus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFocus.js","sources":["../src/useFocus.ts"],"sourcesContent":["import { useCallback, useState, FocusEventHandler, ChangeEventHandler } from 'react';\n\nexport const useFocus = <T extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement>(\n onChange: (value: string) => void,\n onFocus: FocusEventHandler<T> | undefined,\n onBlur: FocusEventHandler<T> | undefined\n): {\n changeHandler: ChangeEventHandler<T>;\n focusHandler: FocusEventHandler<T>;\n blurHandler: FocusEventHandler<T>;\n isFocused: boolean;\n} => {\n const [isFocused, setFocused] = useState(false);\n\n const changeHandler = useCallback<ChangeEventHandler<T>>(\n (event) => {\n onChange(event.target.value);\n },\n [onChange]\n );\n\n const focusHandler = useCallback<FocusEventHandler<T>>(\n (event) => {\n setFocused(true);\n onFocus?.(event);\n },\n [setFocused, onFocus]\n );\n\n const blurHandler = useCallback<FocusEventHandler<T>>(\n (event) => {\n setFocused(false);\n onBlur?.(event);\n },\n [setFocused, onBlur]\n );\n\n return { changeHandler, focusHandler, blurHandler, isFocused };\n};\n"],"names":[],"mappings":";;AAEa,MAAA,QAAQ,GAAG,CACpB,QAAiC,EACjC,OAAyC,EACzC,MAAwC,KAMxC;IACA,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;AAEhD,IAAA,MAAM,aAAa,GAAG,WAAW,CAC7B,CAAC,KAAK,KAAI;AACN,QAAA,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACjC,KAAC,EACD,CAAC,QAAQ,CAAC,CACb,CAAC;AAEF,IAAA,MAAM,YAAY,GAAG,WAAW,CAC5B,CAAC,KAAK,KAAI;QACN,UAAU,CAAC,IAAI,CAAC,CAAC;AACjB,QAAA,OAAO,GAAG,KAAK,CAAC,CAAC;AACrB,KAAC,EACD,CAAC,UAAU,EAAE,OAAO,CAAC,CACxB,CAAC;AAEF,IAAA,MAAM,WAAW,GAAG,WAAW,CAC3B,CAAC,KAAK,KAAI;QACN,UAAU,CAAC,KAAK,CAAC,CAAC;AAClB,QAAA,MAAM,GAAG,KAAK,CAAC,CAAC;AACpB,KAAC,EACD,CAAC,UAAU,EAAE,MAAM,CAAC,CACvB,CAAC;IAEF,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;AACnE;;;;"}
@@ -0,0 +1,14 @@
1
+ export interface InputAriaHookProps {
2
+ invalid?: boolean;
3
+ hasPlaceholder?: boolean;
4
+ hasDescription?: boolean;
5
+ descriptionId: string;
6
+ labelId: string;
7
+ }
8
+ interface AriaProps {
9
+ 'aria-labelledby'?: string;
10
+ 'aria-describedby'?: string;
11
+ 'aria-invalid'?: boolean;
12
+ }
13
+ export declare const useInputAriaProps: ({ invalid, hasPlaceholder, hasDescription, descriptionId, labelId, }: InputAriaHookProps) => AriaProps;
14
+ export {};
@@ -0,0 +1,15 @@
1
+ import './index.css';
2
+ const useInputAriaProps = ({ invalid, hasPlaceholder, hasDescription, descriptionId, labelId, }) => {
3
+ const ariaProps = {};
4
+ invalid && (ariaProps['aria-invalid'] = !!invalid);
5
+ if (hasPlaceholder) {
6
+ ariaProps['aria-labelledby'] = `input-label-${labelId}`;
7
+ }
8
+ if (hasDescription) {
9
+ ariaProps['aria-describedby'] = `input-description-${descriptionId}`;
10
+ }
11
+ return ariaProps;
12
+ };
13
+
14
+ export { useInputAriaProps };
15
+ //# sourceMappingURL=useInputAriaProps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInputAriaProps.js","sources":["../src/useInputAriaProps.ts"],"sourcesContent":["export interface InputAriaHookProps {\n invalid?: boolean;\n hasPlaceholder?: boolean;\n hasDescription?: boolean;\n descriptionId: string;\n labelId: string;\n}\n\ninterface AriaProps {\n 'aria-labelledby'?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: boolean;\n}\n\nexport const useInputAriaProps = ({\n invalid,\n hasPlaceholder,\n hasDescription,\n descriptionId,\n labelId,\n}: InputAriaHookProps): AriaProps => {\n const ariaProps: AriaProps = {};\n invalid && (ariaProps['aria-invalid'] = !!invalid);\n if (hasPlaceholder) {\n ariaProps['aria-labelledby'] = `input-label-${labelId}`;\n }\n if (hasDescription) {\n ariaProps['aria-describedby'] = `input-description-${descriptionId}`;\n }\n return ariaProps;\n};\n"],"names":[],"mappings":"AAca,MAAA,iBAAiB,GAAG,CAAC,EAC9B,OAAO,EACP,cAAc,EACd,cAAc,EACd,aAAa,EACb,OAAO,GACU,KAAe;IAChC,MAAM,SAAS,GAAc,EAAE,CAAC;IAChC,OAAO,KAAK,SAAS,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;AACnD,IAAA,IAAI,cAAc,EAAE;AAChB,QAAA,SAAS,CAAC,iBAAiB,CAAC,GAAG,CAAe,YAAA,EAAA,OAAO,EAAE,CAAC;AAC3D,KAAA;AACD,IAAA,IAAI,cAAc,EAAE;AAChB,QAAA,SAAS,CAAC,kBAAkB,CAAC,GAAG,CAAqB,kBAAA,EAAA,aAAa,EAAE,CAAC;AACxE,KAAA;AACD,IAAA,OAAO,SAAS,CAAC;AACrB;;;;"}
@@ -0,0 +1 @@
1
+ export declare const useUncontrolledInput: (initialValue?: string, changeHandler?: ((value: string) => void) | undefined) => [string, (value: string) => void];
@@ -0,0 +1,14 @@
1
+ import './index.css';
2
+ import { useState, useCallback } from 'react';
3
+
4
+ const useUncontrolledInput = (initialValue, changeHandler) => {
5
+ const [value, setValue] = useState(initialValue || '');
6
+ const onChange = useCallback((newValue) => {
7
+ setValue(newValue);
8
+ changeHandler?.(newValue);
9
+ }, [changeHandler, setValue]);
10
+ return [value, onChange];
11
+ };
12
+
13
+ export { useUncontrolledInput };
14
+ //# sourceMappingURL=useUncontrolledInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useUncontrolledInput.js","sources":["../src/useUncontrolledInput.ts"],"sourcesContent":["import { useState, useCallback } from 'react';\n\nexport const useUncontrolledInput = (\n initialValue?: string,\n changeHandler?: (value: string) => void\n): [string, (value: string) => void] => {\n const [value, setValue] = useState(initialValue || '');\n\n const onChange = useCallback(\n (newValue: string) => {\n setValue(newValue);\n changeHandler?.(newValue);\n },\n [changeHandler, setValue]\n );\n\n return [value, onChange];\n};\n"],"names":[],"mappings":";;MAEa,oBAAoB,GAAG,CAChC,YAAqB,EACrB,aAAuC,KACJ;AACnC,IAAA,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;AAEvD,IAAA,MAAM,QAAQ,GAAG,WAAW,CACxB,CAAC,QAAgB,KAAI;QACjB,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACnB,QAAA,aAAa,GAAG,QAAQ,CAAC,CAAC;AAC9B,KAAC,EACD,CAAC,aAAa,EAAE,QAAQ,CAAC,CAC5B,CAAC;AAEF,IAAA,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC7B;;;;"}