@skbkontur/react-ui 4.25.0 → 4.25.1-MaskedInput-fix.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.
Files changed (73) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE +21 -21
  3. package/cjs/components/Gapped/Gapped.md +43 -43
  4. package/cjs/components/Input/Input.d.ts +3 -2
  5. package/cjs/components/Input/Input.js +7 -4
  6. package/cjs/components/Input/Input.js.map +1 -1
  7. package/cjs/components/MaskedInput/MaskedInput.d.ts +22 -4
  8. package/cjs/components/MaskedInput/MaskedInput.helpers.d.ts +10 -0
  9. package/cjs/components/MaskedInput/MaskedInput.helpers.js +30 -0
  10. package/cjs/components/MaskedInput/MaskedInput.helpers.js.map +1 -0
  11. package/cjs/components/MaskedInput/MaskedInput.js +190 -20
  12. package/cjs/components/MaskedInput/MaskedInput.js.map +1 -1
  13. package/cjs/components/MaskedInput/MaskedInput.md +173 -9
  14. package/cjs/components/MaskedInput/MaskedInput.styles.d.ts +3 -0
  15. package/cjs/components/MaskedInput/MaskedInput.styles.js +4 -0
  16. package/cjs/components/MaskedInput/MaskedInput.styles.js.map +1 -0
  17. package/cjs/components/RadioGroup/RadioGroup.md +43 -43
  18. package/cjs/index.d.ts +3 -0
  19. package/cjs/index.js +3 -0
  20. package/cjs/index.js.map +1 -1
  21. package/cjs/internal/MaskedInputElement/MaskedInputElement.d.ts +6 -9
  22. package/cjs/internal/MaskedInputElement/MaskedInputElement.js +99 -129
  23. package/cjs/internal/MaskedInputElement/MaskedInputElement.js.map +1 -1
  24. package/cjs/internal/MaskedInputElement/MaskedInputElement.styles.d.ts +2 -3
  25. package/cjs/internal/MaskedInputElement/MaskedInputElement.styles.js +7 -17
  26. package/cjs/internal/MaskedInputElement/MaskedInputElement.styles.js.map +1 -1
  27. package/cjs/internal/ThemeShowcase/ThemeShowcase.md +13 -13
  28. package/cjs/lib/styles/HoldSelectionColor.js +1 -1
  29. package/cjs/lib/styles/HoldSelectionColor.js.map +1 -1
  30. package/cjs/lib/styles/UiFont.d.ts +4 -0
  31. package/cjs/lib/styles/UiFont.js +39 -0
  32. package/cjs/lib/styles/UiFont.js.map +1 -0
  33. package/components/Gapped/Gapped.md +43 -43
  34. package/components/Input/Input/Input.js +8 -4
  35. package/components/Input/Input/Input.js.map +1 -1
  36. package/components/Input/Input.d.ts +3 -2
  37. package/components/MaskedInput/MaskedInput/MaskedInput.js +171 -22
  38. package/components/MaskedInput/MaskedInput/MaskedInput.js.map +1 -1
  39. package/components/MaskedInput/MaskedInput.d.ts +22 -4
  40. package/components/MaskedInput/MaskedInput.helpers/MaskedInput.helpers.js +27 -0
  41. package/components/MaskedInput/MaskedInput.helpers/MaskedInput.helpers.js.map +1 -0
  42. package/components/MaskedInput/MaskedInput.helpers/package.json +6 -0
  43. package/components/MaskedInput/MaskedInput.helpers.d.ts +10 -0
  44. package/components/MaskedInput/MaskedInput.md +173 -9
  45. package/components/MaskedInput/MaskedInput.styles/MaskedInput.styles.js +4 -0
  46. package/components/MaskedInput/MaskedInput.styles/MaskedInput.styles.js.map +1 -0
  47. package/components/MaskedInput/MaskedInput.styles/package.json +6 -0
  48. package/components/MaskedInput/MaskedInput.styles.d.ts +3 -0
  49. package/components/RadioGroup/RadioGroup.md +43 -43
  50. package/index.d.ts +3 -0
  51. package/index.js +3 -0
  52. package/index.js.map +1 -1
  53. package/internal/MaskedInputElement/MaskedInputElement/MaskedInputElement.js +105 -161
  54. package/internal/MaskedInputElement/MaskedInputElement/MaskedInputElement.js.map +1 -1
  55. package/internal/MaskedInputElement/MaskedInputElement.d.ts +6 -9
  56. package/internal/MaskedInputElement/MaskedInputElement.styles/MaskedInputElement.styles.js +5 -8
  57. package/internal/MaskedInputElement/MaskedInputElement.styles/MaskedInputElement.styles.js.map +1 -1
  58. package/internal/MaskedInputElement/MaskedInputElement.styles.d.ts +2 -3
  59. package/internal/ThemeShowcase/ThemeShowcase.md +13 -13
  60. package/lib/styles/HoldSelectionColor/HoldSelectionColor.js +1 -1
  61. package/lib/styles/HoldSelectionColor/HoldSelectionColor.js.map +1 -1
  62. package/lib/styles/UiFont/UiFont.js +30 -0
  63. package/lib/styles/UiFont/UiFont.js.map +1 -0
  64. package/lib/styles/UiFont/package.json +6 -0
  65. package/lib/styles/UiFont.d.ts +4 -0
  66. package/package.json +2 -5
  67. package/cjs/internal/MaskedInputElement/MaskedInputElement.helpers.d.ts +0 -16
  68. package/cjs/internal/MaskedInputElement/MaskedInputElement.helpers.js +0 -52
  69. package/cjs/internal/MaskedInputElement/MaskedInputElement.helpers.js.map +0 -1
  70. package/internal/MaskedInputElement/MaskedInputElement.helpers/MaskedInputElement.helpers.js +0 -43
  71. package/internal/MaskedInputElement/MaskedInputElement.helpers/MaskedInputElement.helpers.js.map +0 -1
  72. package/internal/MaskedInputElement/MaskedInputElement.helpers/package.json +0 -6
  73. package/internal/MaskedInputElement/MaskedInputElement.helpers.d.ts +0 -16
@@ -1,9 +1,38 @@
1
1
  "use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;exports.__esModule = true;exports.MaskedInput = void 0;var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));var _react = _interopRequireWildcard(require("react"));
2
2
 
3
- var _Input = require("../Input");
3
+ var _reactImask = require("react-imask");
4
+ var _globalObject = require("@skbkontur/global-object");
5
+
4
6
 
5
7
  var _MaskedInputElement = require("../../internal/MaskedInputElement");
6
- var _forwardRefAndName = require("../../lib/forwardRefAndName");var _excluded = ["mask", "maskChar", "formatChars", "alwaysShowMask", "placeholder"];
8
+ var _forwardRefAndName = require("../../lib/forwardRefAndName");
9
+ var _Emotion = require("../../lib/theming/Emotion");
10
+ var _UiFont = require("../../lib/styles/UiFont");
11
+ var _Input = require("../Input");
12
+ var _identifiers = require("../../lib/events/keyboard/identifiers");
13
+ var _isInstanceOf = require("../../lib/isInstanceOf");
14
+
15
+ var _MaskedInput = require("./MaskedInput.styles");
16
+ var _MaskedInput2 = require("./MaskedInput.helpers");var _excluded = ["onAccept"],_excluded2 = ["mask", "maskChar", "formatChars", "alwaysShowMask", "imaskProps", "placeholder", "onValueChange", "onUnexpectedInput", "onKeyDownCapture", "onChange", "element"];
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
7
36
 
8
37
 
9
38
 
@@ -32,47 +61,188 @@ var _forwardRefAndName = require("../../lib/forwardRefAndName");var _excluded =
32
61
  var MaskedInput = (0, _forwardRefAndName.forwardRefAndName)(
33
62
  'MaskedInput',
34
63
  function MaskedInput(props, ref) {
35
- var mask = props.mask,maskChar = props.maskChar,formatChars = props.formatChars,alwaysShowMask = props.alwaysShowMask,placeholder = props.placeholder,inputProps = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
64
+ var
65
+ mask =
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+ props.mask,maskChar = props.maskChar,formatChars = props.formatChars,alwaysShowMask = props.alwaysShowMask,_props$imaskProps = props.imaskProps;_props$imaskProps = _props$imaskProps === void 0 ? {} : _props$imaskProps;var onAccept = _props$imaskProps.onAccept,customIMaskProps = (0, _objectWithoutPropertiesLoose2.default)(_props$imaskProps, _excluded),placeholder = props.placeholder,onValueChange = props.onValueChange,onUnexpectedInput = props.onUnexpectedInput,onKeyDownCapture = props.onKeyDownCapture,onChange = props.onChange,element = props.element,inputProps = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded2);
78
+
79
+ var inputRef = (0, _react.useRef)(null);
80
+ var imaskRef = (0, _react.useRef)(null);
81
+
36
82
  var _useState = (0, _react.useState)(false),focused = _useState[0],setFocused = _useState[1];
83
+ var prevValue = (0, _react.useRef)(props.value || String(props.defaultValue) || '');
84
+ var prevSelectionStart = (0, _react.useRef)(null);
85
+
37
86
  var showPlaceholder = !(alwaysShowMask || focused);
38
- var innerRef = (0, _react.useRef)(null);
39
87
 
40
- (0, _react.useImperativeHandle)(ref, function () {return innerRef.current;});
88
+ (0, _react.useImperativeHandle)(
89
+ ref,
90
+ function () {return (
91
+ inputRef.current &&
92
+ Object.assign(inputRef.current, {
93
+ selectAll: inputRef.current.delaySelectAll }));},
94
+
95
+ []);
96
+
97
+
98
+ (0, _react.useEffect)(function () {var _inputRef$current;
99
+ /**
100
+ * Для корректной работы `onUnexpectedInput` надо знать предыдущий `value`,
101
+ * но `imask` при монтировании не вызывает `onAccept`, если `value` невалиден или `laze=false`
102
+ * Поэтому актуальный `value` при монтировании надо получать вручную
103
+ */
104
+ if ((_inputRef$current = inputRef.current) != null && _inputRef$current.input) {
105
+ prevValue.current = inputRef.current.input.value;
106
+ prevSelectionStart.current = inputRef.current.input.selectionStart;
107
+ }
108
+ }, []);
109
+
110
+ // useEffect(() => {
111
+ // inputRef.current &&
112
+ // (inputRef.current.selectAll = () => {
113
+ // setTimeout(() => {
114
+ // inputRef.current?.setSelectionRange(0, 999);
115
+ // });
116
+ // });
117
+ // }, []);
118
+
119
+ var imaskProps = getCompatibleIMaskProps();
41
120
 
42
121
  return /*#__PURE__*/(
43
122
  _react.default.createElement(_Input.Input, (0, _extends2.default)({
44
- ref: innerRef },
123
+ ref: inputRef },
45
124
  inputProps, {
46
125
  placeholder: showPlaceholder ? placeholder : undefined,
47
126
  onFocus: handleFocus,
48
127
  onBlur: handleBlur,
128
+ onInput: handleInput,
129
+ onMouseUp: handleSelect,
130
+ onKeyDownCapture: handleKeyDownCapture,
131
+ className: (0, _Emotion.cx)(_MaskedInput.globalClasses.root, _UiFont.uiFontGlobalClasses.root),
132
+ "data-tid": _MaskedInputElement.MaskedInputElementDataTids.root,
49
133
  element: /*#__PURE__*/
50
- _react.default.createElement(_MaskedInputElement.MaskedInputElement, {
51
- mask: mask,
52
- maskChar: maskChar,
53
- formatChars: formatChars,
54
- alwaysShowMask: alwaysShowMask,
55
- onUnexpectedInput: handleUnexpectedInput }) })));
134
+ _react.default.createElement(_MaskedInputElement.MaskedInputElement, { maskChars: getMaskChars(imaskProps) }, /*#__PURE__*/
135
+ _react.default.createElement(_reactImask.IMaskInput, (0, _extends2.default)({ ref: imaskRef }, imaskProps, { onAccept: handleAccept }))) })));
56
136
 
57
137
 
58
138
 
59
139
 
60
140
 
61
- function handleUnexpectedInput(value) {
62
- if (props.onUnexpectedInput) {
63
- props.onUnexpectedInput(value);
64
- } else if (innerRef.current) {
65
- innerRef.current.blink();
141
+ function handleSelect(e) {var _inputRef$current2;
142
+ if (
143
+ (0, _isInstanceOf.isInstanceOf)(e.target, _globalObject.globalObject.HTMLInputElement) &&
144
+ e.target === ((_inputRef$current2 = inputRef.current) == null ? void 0 : _inputRef$current2.input) &&
145
+ e.target.closest('.react-ui-masked-input-root'))
146
+ {var _imaskRef$current;
147
+ var nearest = (_imaskRef$current = imaskRef.current) == null ? void 0 : _imaskRef$current.maskRef.masked.nearestInputPos(e.target.value.length, 'LEFT');
148
+ if (
149
+ typeof e.target.selectionStart === 'number' &&
150
+ typeof nearest === 'number' &&
151
+ e.target.selectionStart >= nearest)
152
+ {
153
+ e.target.selectionStart = nearest;
154
+ e.target.selectionEnd = nearest;
155
+ }
66
156
  }
67
157
  }
68
158
 
69
- function handleFocus(e) {
159
+ function getCompatibleIMaskProps() {
160
+ return (0, _extends2.default)({
161
+ mask: mask.replace(/0/g, '{\\0}'),
162
+ placeholderChar: (0, _MaskedInput2.getMaskChar)(maskChar),
163
+ definitions: (0, _MaskedInput2.getDefinitions)(formatChars),
164
+ eager: true,
165
+ overwrite: 'shift',
166
+ lazy: alwaysShowMask === null ? true : !(alwaysShowMask || focused) },
167
+ customIMaskProps);
168
+
169
+ }
170
+
171
+ function getMaskChars(imaskProps) {
172
+ var imaskPropsFix = imaskProps;
173
+ var maskChars = [imaskPropsFix.placeholderChar];
174
+ if (imaskPropsFix.blocks) {
175
+ Object.values(imaskPropsFix.blocks).forEach(
176
+ function (_ref) {var placeholderChar = _ref.placeholderChar;return placeholderChar && maskChars.push(placeholderChar);});
177
+
178
+ }
179
+
180
+ return maskChars;
181
+ }
182
+
183
+ function handleAccept() {for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {args[_key] = arguments[_key];}
184
+ var value = args[0],e = args[2];
185
+
186
+ onAccept == null ? void 0 : onAccept.apply(void 0, args);
187
+
188
+ /**
189
+ * Метод `onAccept` может вызываться при монтировании, если не задан проп `defaultValue`.
190
+ * Но нативный `input` никогда не вызывает `onChange` при монтировании.
191
+ * Наше событие `onValueChange` в `Input` вывается в тех же случаях, что и нативный `onChange`,
192
+ * поэтому чтобы сохранить консинстентность будем ориентироваться на наличие аргумента `e`.
193
+ * Он содержит нативное событие, вызвавшее изменение.
194
+ * Если его нет, значит `imask` вызывал `onAccept` по некой собственной логике.
195
+ */
196
+ e && (onValueChange == null ? void 0 : onValueChange(value));
197
+ }
198
+
199
+ /**
200
+ * Отслеживаем неожиданные нажатия
201
+ * handleAccept не вызывается когда значение с маской не меняется
202
+ * Сначала вызывается handleAccept, затем handleInput
203
+ */
204
+ function handleInput(e) {
205
+ if (prevValue.current === e.target.value && prevSelectionStart.current === e.target.selectionStart) {
206
+ handleUnexpectedInput(e.target.value);
207
+ }
208
+
209
+ prevValue.current = e.target.value;
210
+
211
+ props.onInput == null ? void 0 : props.onInput(e);
212
+ }
213
+
214
+ function handleFocus(e) {var _inputRef$current3;
70
215
  setFocused(true);
71
- props.onFocus && props.onFocus(e);
216
+ props.onFocus == null ? void 0 : props.onFocus(e);
217
+
218
+ // если `value` из пропов отличается от `value`, которое получит `input` после обработки,
219
+ // то `imask` будет ставить курсор за последним валидным символом.
220
+ props.selectAllOnFocus && ((_inputRef$current3 = inputRef.current) == null ? void 0 : _inputRef$current3.delaySelectAll());
221
+ }
222
+
223
+ function handleUnexpectedInput(value) {if (value === void 0) {value = '';}
224
+ if (onUnexpectedInput) {
225
+ onUnexpectedInput(value);
226
+ } else if (inputRef.current) {
227
+ inputRef.current.blink();
228
+ }
72
229
  }
73
230
 
74
231
  function handleBlur(e) {
75
232
  setFocused(false);
76
- props.onBlur && props.onBlur(e);
233
+ props.onBlur == null ? void 0 : props.onBlur(e);
234
+ }
235
+
236
+ function handleKeyDownCapture(e) {
237
+ var isDeleteKey = (0, _identifiers.someKeys)(_identifiers.isKeyBackspace, _identifiers.isKeyDelete)(e);
238
+
239
+ prevSelectionStart.current = e.currentTarget.selectionStart;
240
+
241
+ if (!e.currentTarget.value && isDeleteKey && !e.repeat) {
242
+ handleUnexpectedInput(e.currentTarget.value);
243
+ prevValue.current = e.currentTarget.value;
244
+ }
245
+
246
+ onKeyDownCapture == null ? void 0 : onKeyDownCapture(e);
77
247
  }
78
248
  });exports.MaskedInput = MaskedInput;
@@ -1 +1 @@
1
- {"version":3,"sources":["MaskedInput.tsx"],"names":["MaskedInput","props","ref","mask","maskChar","formatChars","alwaysShowMask","placeholder","inputProps","focused","setFocused","showPlaceholder","innerRef","current","undefined","handleFocus","handleBlur","handleUnexpectedInput","value","onUnexpectedInput","blink","e","onFocus","onBlur"],"mappings":"8cAAA;;AAEA;;AAEA;AACA,gE;;;;;;;;;;;;;;;;;;;;;;AAsBA;AACA;AACA;AACA;AACO,IAAMA,WAAW,GAAG;AACzB,aADyB;AAEzB,SAASA,WAAT,CAAqBC,KAArB,EAA8CC,GAA9C,EAAsE;AACpE,MAAQC,IAAR,GAAoFF,KAApF,CAAQE,IAAR,CAAcC,QAAd,GAAoFH,KAApF,CAAcG,QAAd,CAAwBC,WAAxB,GAAoFJ,KAApF,CAAwBI,WAAxB,CAAqCC,cAArC,GAAoFL,KAApF,CAAqCK,cAArC,CAAqDC,WAArD,GAAoFN,KAApF,CAAqDM,WAArD,CAAqEC,UAArE,+CAAoFP,KAApF;AACA,kBAA8B,qBAAS,KAAT,CAA9B,CAAOQ,OAAP,gBAAgBC,UAAhB;AACA,MAAMC,eAAe,GAAG,EAAEL,cAAc,IAAIG,OAApB,CAAxB;AACA,MAAMG,QAAQ,GAAG,mBAAc,IAAd,CAAjB;;AAEA,kCAAoBV,GAApB,EAAyB,oBAAMU,QAAQ,CAACC,OAAf,EAAzB;;AAEA;AACE,iCAAC,YAAD;AACE,MAAA,GAAG,EAAED,QADP;AAEMJ,IAAAA,UAFN;AAGE,MAAA,WAAW,EAAEG,eAAe,GAAGJ,WAAH,GAAiBO,SAH/C;AAIE,MAAA,OAAO,EAAEC,WAJX;AAKE,MAAA,MAAM,EAAEC,UALV;AAME,MAAA,OAAO;AACL,mCAAC,sCAAD;AACE,QAAA,IAAI,EAAEb,IADR;AAEE,QAAA,QAAQ,EAAEC,QAFZ;AAGE,QAAA,WAAW,EAAEC,WAHf;AAIE,QAAA,cAAc,EAAEC,cAJlB;AAKE,QAAA,iBAAiB,EAAEW,qBALrB,GAPJ,IADF;;;;;;AAmBA,WAASA,qBAAT,CAA+BC,KAA/B,EAA8C;AAC5C,QAAIjB,KAAK,CAACkB,iBAAV,EAA6B;AAC3BlB,MAAAA,KAAK,CAACkB,iBAAN,CAAwBD,KAAxB;AACD,KAFD,MAEO,IAAIN,QAAQ,CAACC,OAAb,EAAsB;AAC3BD,MAAAA,QAAQ,CAACC,OAAT,CAAiBO,KAAjB;AACD;AACF;;AAED,WAASL,WAAT,CAAqBM,CAArB,EAA4D;AAC1DX,IAAAA,UAAU,CAAC,IAAD,CAAV;AACAT,IAAAA,KAAK,CAACqB,OAAN,IAAiBrB,KAAK,CAACqB,OAAN,CAAcD,CAAd,CAAjB;AACD;;AAED,WAASL,UAAT,CAAoBK,CAApB,EAA2D;AACzDX,IAAAA,UAAU,CAAC,KAAD,CAAV;AACAT,IAAAA,KAAK,CAACsB,MAAN,IAAgBtB,KAAK,CAACsB,MAAN,CAAaF,CAAb,CAAhB;AACD;AACF,CA9CwB,CAApB,C","sourcesContent":["import React, { Ref, useImperativeHandle, useRef, useState } from 'react';\n\nimport { Input, InputProps, InputType } from '../Input';\nimport { Nullable } from '../../typings/utility-types';\nimport { MaskedInputElement } from '../../internal/MaskedInputElement';\nimport { forwardRefAndName } from '../../lib/forwardRefAndName';\n\nexport interface MaskedProps {\n /** Паттерн маски */\n mask: string;\n /** Символ маски */\n maskChar?: Nullable<string>;\n /**\n * Словарь символов-регулярок для маски\n * @default { '9': '[0-9]', 'a': '[A-Za-z]', '*': '[A-Za-z0-9]' }\n */\n formatChars?: Record<string, string>;\n /** Показывать символы маски */\n alwaysShowMask?: boolean;\n}\n\nexport type MaskInputType = Exclude<InputType, 'number' | 'date' | 'time' | 'password'>;\n\nexport interface MaskedInputProps extends MaskedProps, Omit<InputProps, 'mask' | 'maxLength' | 'type' | 'element'> {\n type?: MaskInputType;\n}\n\n/**\n * Интерфейс пропсов наследуется от `Input`.\n * Из пропсов `Input` исключены некоторые не применимые к полю с маской пропсы и сокращен список возможных значений в type.\n */\nexport const MaskedInput = forwardRefAndName(\n 'MaskedInput',\n function MaskedInput(props: MaskedInputProps, ref: Ref<Input | null>) {\n const { mask, maskChar, formatChars, alwaysShowMask, placeholder, ...inputProps } = props;\n const [focused, setFocused] = useState(false);\n const showPlaceholder = !(alwaysShowMask || focused);\n const innerRef = useRef<Input>(null);\n\n useImperativeHandle(ref, () => innerRef.current);\n\n return (\n <Input\n ref={innerRef}\n {...inputProps}\n placeholder={showPlaceholder ? placeholder : undefined}\n onFocus={handleFocus}\n onBlur={handleBlur}\n element={\n <MaskedInputElement\n mask={mask}\n maskChar={maskChar}\n formatChars={formatChars}\n alwaysShowMask={alwaysShowMask}\n onUnexpectedInput={handleUnexpectedInput}\n />\n }\n />\n );\n\n function handleUnexpectedInput(value: string) {\n if (props.onUnexpectedInput) {\n props.onUnexpectedInput(value);\n } else if (innerRef.current) {\n innerRef.current.blink();\n }\n }\n\n function handleFocus(e: React.FocusEvent<HTMLInputElement>) {\n setFocused(true);\n props.onFocus && props.onFocus(e);\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n setFocused(false);\n props.onBlur && props.onBlur(e);\n }\n },\n);\n"]}
1
+ {"version":3,"sources":["MaskedInput.tsx"],"names":["MaskedInput","props","ref","mask","maskChar","formatChars","alwaysShowMask","imaskProps","onAccept","customIMaskProps","placeholder","onValueChange","onUnexpectedInput","onKeyDownCapture","onChange","element","inputProps","inputRef","imaskRef","focused","setFocused","prevValue","value","String","defaultValue","prevSelectionStart","showPlaceholder","current","Object","assign","selectAll","delaySelectAll","input","selectionStart","getCompatibleIMaskProps","undefined","handleFocus","handleBlur","handleInput","handleSelect","handleKeyDownCapture","globalClasses","root","uiFontGlobalClasses","MaskedInputElementDataTids","getMaskChars","handleAccept","e","target","globalObject","HTMLInputElement","closest","nearest","maskRef","masked","nearestInputPos","length","selectionEnd","replace","placeholderChar","definitions","eager","overwrite","lazy","imaskPropsFix","maskChars","blocks","values","forEach","push","args","handleUnexpectedInput","onInput","onFocus","selectAllOnFocus","blink","onBlur","isDeleteKey","isKeyBackspace","isKeyDelete","currentTarget","repeat"],"mappings":"8cAAA;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,qD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA;AACA;AACA;AACA;AACO,IAAMA,WAAW,GAAG;AACzB,aADyB;AAEzB,SAASA,WAAT,CAAqBC,KAArB,EAA8CC,GAA9C,EAAsE;AACpE;AACEC,EAAAA,IADF;;;;;;;;;;;;AAaIF,EAAAA,KAbJ,CACEE,IADF,CAEEC,QAFF,GAaIH,KAbJ,CAEEG,QAFF,CAGEC,WAHF,GAaIJ,KAbJ,CAGEI,WAHF,CAIEC,cAJF,GAaIL,KAbJ,CAIEK,cAJF,qBAaIL,KAbJ,CAKEM,UALF,oDAKkD,EALlD,yBAKgBC,QALhB,qBAKgBA,QALhB,CAK6BC,gBAL7B,6EAMEC,WANF,GAaIT,KAbJ,CAMES,WANF,CAOEC,aAPF,GAaIV,KAbJ,CAOEU,aAPF,CAQEC,iBARF,GAaIX,KAbJ,CAQEW,iBARF,CASEC,gBATF,GAaIZ,KAbJ,CASEY,gBATF,CAUEC,QAVF,GAaIb,KAbJ,CAUEa,QAVF,CAWEC,OAXF,GAaId,KAbJ,CAWEc,OAXF,CAYKC,UAZL,+CAaIf,KAbJ;;AAeA,MAAMgB,QAAQ,GAAG,mBAAc,IAAd,CAAjB;AACA,MAAMC,QAAQ,GAAG,mBAAqB,IAArB,CAAjB;;AAEA,kBAA8B,qBAAS,KAAT,CAA9B,CAAOC,OAAP,gBAAgBC,UAAhB;AACA,MAAMC,SAAS,GAAG,mBAAepB,KAAK,CAACqB,KAAN,IAAeC,MAAM,CAACtB,KAAK,CAACuB,YAAP,CAArB,IAA6C,EAA5D,CAAlB;AACA,MAAMC,kBAAkB,GAAG,mBAAsB,IAAtB,CAA3B;;AAEA,MAAMC,eAAe,GAAG,EAAEpB,cAAc,IAAIa,OAApB,CAAxB;;AAEA;AACEjB,EAAAA,GADF;AAEE;AACEe,MAAAA,QAAQ,CAACU,OAAT;AACAC,MAAAA,MAAM,CAACC,MAAP,CAAcZ,QAAQ,CAACU,OAAvB,EAAgC;AAC9BG,QAAAA,SAAS,EAAEb,QAAQ,CAACU,OAAT,CAAiBI,cADE,EAAhC,CAFF,GAFF;;AAOE,IAPF;;;AAUA,wBAAU,YAAM;AACd;AACN;AACA;AACA;AACA;AACM,6BAAId,QAAQ,CAACU,OAAb,aAAI,kBAAkBK,KAAtB,EAA6B;AAC3BX,MAAAA,SAAS,CAACM,OAAV,GAAoBV,QAAQ,CAACU,OAAT,CAAiBK,KAAjB,CAAuBV,KAA3C;AACAG,MAAAA,kBAAkB,CAACE,OAAnB,GAA6BV,QAAQ,CAACU,OAAT,CAAiBK,KAAjB,CAAuBC,cAApD;AACD;AACF,GAVD,EAUG,EAVH;;AAYA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,MAAM1B,UAAU,GAAG2B,uBAAuB,EAA1C;;AAEA;AACE,iCAAC,YAAD;AACE,MAAA,GAAG,EAAEjB,QADP;AAEMD,IAAAA,UAFN;AAGE,MAAA,WAAW,EAAEU,eAAe,GAAGhB,WAAH,GAAiByB,SAH/C;AAIE,MAAA,OAAO,EAAEC,WAJX;AAKE,MAAA,MAAM,EAAEC,UALV;AAME,MAAA,OAAO,EAAEC,WANX;AAOE,MAAA,SAAS,EAAEC,YAPb;AAQE,MAAA,gBAAgB,EAAEC,oBARpB;AASE,MAAA,SAAS,EAAE,iBAAGC,2BAAcC,IAAjB,EAAuBC,4BAAoBD,IAA3C,CATb;AAUE,kBAAUE,+CAA2BF,IAVvC;AAWE,MAAA,OAAO;AACL,mCAAC,sCAAD,IAAoB,SAAS,EAAEG,YAAY,CAACtC,UAAD,CAA3C;AACE,mCAAC,sBAAD,2BAAY,GAAG,EAAEW,QAAjB,IAA+BX,UAA/B,IAA2C,QAAQ,EAAEuC,YAArD,IADF,CAZJ,IADF;;;;;;AAoBA,WAASP,YAAT,CAAsBQ,CAAtB,EAA6D;AAC3D;AACE,oCAAaA,CAAC,CAACC,MAAf,EAAuBC,2BAAaC,gBAApC;AACAH,IAAAA,CAAC,CAACC,MAAF,4BAAa/B,QAAQ,CAACU,OAAtB,qBAAa,mBAAkBK,KAA/B,CADA;AAEAe,IAAAA,CAAC,CAACC,MAAF,CAASG,OAAT,CAAiB,6BAAjB,CAHF;AAIE;AACA,UAAMC,OAAO,wBAAGlC,QAAQ,CAACS,OAAZ,qBAAG,kBAAkB0B,OAAlB,CAA0BC,MAA1B,CAAiCC,eAAjC,CAAiDR,CAAC,CAACC,MAAF,CAAS1B,KAAT,CAAekC,MAAhE,EAAwE,MAAxE,CAAhB;AACA;AACE,aAAOT,CAAC,CAACC,MAAF,CAASf,cAAhB,KAAmC,QAAnC;AACA,aAAOmB,OAAP,KAAmB,QADnB;AAEAL,MAAAA,CAAC,CAACC,MAAF,CAASf,cAAT,IAA2BmB,OAH7B;AAIE;AACAL,QAAAA,CAAC,CAACC,MAAF,CAASf,cAAT,GAA0BmB,OAA1B;AACAL,QAAAA,CAAC,CAACC,MAAF,CAASS,YAAT,GAAwBL,OAAxB;AACD;AACF;AACF;;AAED,WAASlB,uBAAT,GAAsE;AACpE;AACE/B,MAAAA,IAAI,EAAEA,IAAI,CAACuD,OAAL,CAAa,IAAb,EAAmB,OAAnB,CADR;AAEEC,MAAAA,eAAe,EAAE,+BAAYvD,QAAZ,CAFnB;AAGEwD,MAAAA,WAAW,EAAE,kCAAevD,WAAf,CAHf;AAIEwD,MAAAA,KAAK,EAAE,IAJT;AAKEC,MAAAA,SAAS,EAAE,OALb;AAMEC,MAAAA,IAAI,EAAEzD,cAAc,KAAK,IAAnB,GAA0B,IAA1B,GAAiC,EAAEA,cAAc,IAAIa,OAApB,CANzC;AAOKV,IAAAA,gBAPL;;AASD;;AAED,WAASoC,YAAT,CAAsBtC,UAAtB,EAA+E;AAC7E,QAAMyD,aAAa,GAAGzD,UAAtB;AACA,QAAM0D,SAAS,GAAG,CAACD,aAAa,CAACL,eAAf,CAAlB;AACA,QAAIK,aAAa,CAACE,MAAlB,EAA0B;AACvBtC,MAAAA,MAAM,CAACuC,MAAP,CAAcH,aAAa,CAACE,MAA5B,CAAD,CAA6EE,OAA7E;AACE,2BAAGT,eAAH,QAAGA,eAAH,QAAyBA,eAAe,IAAIM,SAAS,CAACI,IAAV,CAAeV,eAAf,CAA5C,EADF;;AAGD;;AAED,WAAOM,SAAP;AACD;;AAED,WAASnB,YAAT,GAAoG,mCAA3EwB,IAA2E,oDAA3EA,IAA2E;AAClG,QAAOhD,KAAP,GAAqBgD,IAArB,IAAgBvB,CAAhB,GAAqBuB,IAArB;;AAEA9D,IAAAA,QAAQ,QAAR,YAAAA,QAAQ,MAAR,SAAc8D,IAAd;;AAEA;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACMvB,IAAAA,CAAC,KAAIpC,aAAJ,oBAAIA,aAAa,CAAGW,KAAH,CAAjB,CAAD;AACD;;AAED;AACJ;AACA;AACA;AACA;AACI,WAASgB,WAAT,CAAqBS,CAArB,EAA6D;AAC3D,QAAI1B,SAAS,CAACM,OAAV,KAAsBoB,CAAC,CAACC,MAAF,CAAS1B,KAA/B,IAAwCG,kBAAkB,CAACE,OAAnB,KAA+BoB,CAAC,CAACC,MAAF,CAASf,cAApF,EAAoG;AAClGsC,MAAAA,qBAAqB,CAACxB,CAAC,CAACC,MAAF,CAAS1B,KAAV,CAArB;AACD;;AAEDD,IAAAA,SAAS,CAACM,OAAV,GAAoBoB,CAAC,CAACC,MAAF,CAAS1B,KAA7B;;AAEArB,IAAAA,KAAK,CAACuE,OAAN,oBAAAvE,KAAK,CAACuE,OAAN,CAAgBzB,CAAhB;AACD;;AAED,WAASX,WAAT,CAAqBW,CAArB,EAA4D;AAC1D3B,IAAAA,UAAU,CAAC,IAAD,CAAV;AACAnB,IAAAA,KAAK,CAACwE,OAAN,oBAAAxE,KAAK,CAACwE,OAAN,CAAgB1B,CAAhB;;AAEA;AACA;AACA9C,IAAAA,KAAK,CAACyE,gBAAN,2BAA0BzD,QAAQ,CAACU,OAAnC,qBAA0B,mBAAkBI,cAAlB,EAA1B;AACD;;AAED,WAASwC,qBAAT,CAA+BjD,KAA/B,EAA2C,KAAZA,KAAY,cAAZA,KAAY,GAAJ,EAAI;AACzC,QAAIV,iBAAJ,EAAuB;AACrBA,MAAAA,iBAAiB,CAACU,KAAD,CAAjB;AACD,KAFD,MAEO,IAAIL,QAAQ,CAACU,OAAb,EAAsB;AAC3BV,MAAAA,QAAQ,CAACU,OAAT,CAAiBgD,KAAjB;AACD;AACF;;AAED,WAAStC,UAAT,CAAoBU,CAApB,EAA2D;AACzD3B,IAAAA,UAAU,CAAC,KAAD,CAAV;AACAnB,IAAAA,KAAK,CAAC2E,MAAN,oBAAA3E,KAAK,CAAC2E,MAAN,CAAe7B,CAAf;AACD;;AAED,WAASP,oBAAT,CAA8BO,CAA9B,EAAwE;AACtE,QAAM8B,WAAW,GAAG,2BAASC,2BAAT,EAAyBC,wBAAzB,EAAsChC,CAAtC,CAApB;;AAEAtB,IAAAA,kBAAkB,CAACE,OAAnB,GAA6BoB,CAAC,CAACiC,aAAF,CAAgB/C,cAA7C;;AAEA,QAAI,CAACc,CAAC,CAACiC,aAAF,CAAgB1D,KAAjB,IAA0BuD,WAA1B,IAAyC,CAAC9B,CAAC,CAACkC,MAAhD,EAAwD;AACtDV,MAAAA,qBAAqB,CAACxB,CAAC,CAACiC,aAAF,CAAgB1D,KAAjB,CAArB;AACAD,MAAAA,SAAS,CAACM,OAAV,GAAoBoB,CAAC,CAACiC,aAAF,CAAgB1D,KAApC;AACD;;AAEDT,IAAAA,gBAAgB,QAAhB,YAAAA,gBAAgB,CAAGkC,CAAH,CAAhB;AACD;AACF,CA3LwB,CAApB,C","sourcesContent":["import React, { Ref, useImperativeHandle, useRef, useState, useEffect } from 'react';\nimport { InputMask, MaskedPatternOptions, MaskedPattern } from 'imask';\nimport { IMaskInput, IMaskInputProps } from 'react-imask';\nimport { globalObject } from '@skbkontur/global-object';\n\nimport { Nullable } from '../../typings/utility-types';\nimport { MaskedInputElement, MaskedInputElementDataTids } from '../../internal/MaskedInputElement';\nimport { forwardRefAndName } from '../../lib/forwardRefAndName';\nimport { cx } from '../../lib/theming/Emotion';\nimport { uiFontGlobalClasses } from '../../lib/styles/UiFont';\nimport { Input, InputProps, InputType } from '../Input';\nimport { isKeyBackspace, isKeyDelete, someKeys } from '../../lib/events/keyboard/identifiers';\nimport { isInstanceOf } from '../../lib/isInstanceOf';\n\nimport { globalClasses } from './MaskedInput.styles';\nimport { getDefinitions, getMaskChar } from './MaskedInput.helpers';\n\nexport interface MaskedProps {\n /** Паттерн маски */\n mask: string;\n /** Символ маски */\n maskChar?: Nullable<string>;\n /**\n * Словарь символов-регулярок для маски\n * @default { '9': '[0-9]', 'a': '[A-Za-z]', '*': '[A-Za-z0-9]' }\n */\n formatChars?: Record<string, string>;\n /**\n * Показывать символы маски\n *\n * null - не показывать\n * true - показывать всегда\n * false - показывать по фокусу\n */\n alwaysShowMask?: boolean | null;\n /**\n * Пропы для компонента `IMaskInput`\n *\n * @see https://imask.js.org/guide.html\n */\n imaskProps?: IMaskInputProps<HTMLInputElement>;\n}\n\nexport type MaskInputType = Exclude<InputType, 'number' | 'date' | 'time' | 'password'>;\n\nexport interface IMaskRefType {\n maskRef: InputMask<MaskedPatternOptions>;\n element: HTMLInputElement;\n}\n\nexport interface MaskedInputProps\n extends MaskedProps,\n Omit<InputProps, 'mask' | 'maxLength' | 'type' | 'alwaysShowMask'> {\n type?: MaskInputType;\n}\n\n/**\n * Интерфейс пропсов наследуется от `Input`.\n * Из пропсов `Input` исключены некоторые не применимые к полю с маской пропсы и сокращен список возможных значений в type.\n */\nexport const MaskedInput = forwardRefAndName(\n 'MaskedInput',\n function MaskedInput(props: MaskedInputProps, ref: Ref<Input | null>) {\n const {\n mask,\n maskChar,\n formatChars,\n alwaysShowMask,\n imaskProps: { onAccept, ...customIMaskProps } = {},\n placeholder,\n onValueChange,\n onUnexpectedInput,\n onKeyDownCapture,\n onChange,\n element,\n ...inputProps\n } = props;\n\n const inputRef = useRef<Input>(null);\n const imaskRef = useRef<IMaskRefType>(null);\n\n const [focused, setFocused] = useState(false);\n const prevValue = useRef<string>(props.value || String(props.defaultValue) || '');\n const prevSelectionStart = useRef<number | null>(null);\n\n const showPlaceholder = !(alwaysShowMask || focused);\n\n useImperativeHandle(\n ref,\n () =>\n inputRef.current &&\n Object.assign(inputRef.current, {\n selectAll: inputRef.current.delaySelectAll,\n }),\n [],\n );\n\n useEffect(() => {\n /**\n * Для корректной работы `onUnexpectedInput` надо знать предыдущий `value`,\n * но `imask` при монтировании не вызывает `onAccept`, если `value` невалиден или `laze=false`\n * Поэтому актуальный `value` при монтировании надо получать вручную\n */\n if (inputRef.current?.input) {\n prevValue.current = inputRef.current.input.value;\n prevSelectionStart.current = inputRef.current.input.selectionStart;\n }\n }, []);\n\n // useEffect(() => {\n // inputRef.current &&\n // (inputRef.current.selectAll = () => {\n // setTimeout(() => {\n // inputRef.current?.setSelectionRange(0, 999);\n // });\n // });\n // }, []);\n\n const imaskProps = getCompatibleIMaskProps();\n\n return (\n <Input\n ref={inputRef}\n {...inputProps}\n placeholder={showPlaceholder ? placeholder : undefined}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onInput={handleInput}\n onMouseUp={handleSelect}\n onKeyDownCapture={handleKeyDownCapture}\n className={cx(globalClasses.root, uiFontGlobalClasses.root)}\n data-tid={MaskedInputElementDataTids.root}\n element={\n <MaskedInputElement maskChars={getMaskChars(imaskProps)}>\n <IMaskInput ref={imaskRef} {...imaskProps} onAccept={handleAccept} />\n </MaskedInputElement>\n }\n />\n );\n\n function handleSelect(e: React.MouseEvent<HTMLInputElement>) {\n if (\n isInstanceOf(e.target, globalObject.HTMLInputElement) &&\n e.target === inputRef.current?.input &&\n e.target.closest('.react-ui-masked-input-root')\n ) {\n const nearest = imaskRef.current?.maskRef.masked.nearestInputPos(e.target.value.length, 'LEFT');\n if (\n typeof e.target.selectionStart === 'number' &&\n typeof nearest === 'number' &&\n e.target.selectionStart >= nearest\n ) {\n e.target.selectionStart = nearest;\n e.target.selectionEnd = nearest;\n }\n }\n }\n\n function getCompatibleIMaskProps(): IMaskInputProps<HTMLInputElement> {\n return {\n mask: mask.replace(/0/g, '{\\\\0}') as any,\n placeholderChar: getMaskChar(maskChar),\n definitions: getDefinitions(formatChars),\n eager: true,\n overwrite: 'shift',\n lazy: alwaysShowMask === null ? true : !(alwaysShowMask || focused),\n ...customIMaskProps,\n } as IMaskInputProps<HTMLInputElement>;\n }\n\n function getMaskChars(imaskProps: IMaskInputProps<HTMLInputElement>): string[] {\n const imaskPropsFix = imaskProps as MaskedPattern;\n const maskChars = [imaskPropsFix.placeholderChar];\n if (imaskPropsFix.blocks) {\n (Object.values(imaskPropsFix.blocks) as Array<{ placeholderChar?: string }>).forEach(\n ({ placeholderChar }) => placeholderChar && maskChars.push(placeholderChar),\n );\n }\n\n return maskChars;\n }\n\n function handleAccept(...args: Parameters<Required<IMaskInputProps<HTMLInputElement>>['onAccept']>) {\n const [value, , e] = args;\n\n onAccept?.(...args);\n\n /**\n * Метод `onAccept` может вызываться при монтировании, если не задан проп `defaultValue`.\n * Но нативный `input` никогда не вызывает `onChange` при монтировании.\n * Наше событие `onValueChange` в `Input` вывается в тех же случаях, что и нативный `onChange`,\n * поэтому чтобы сохранить консинстентность будем ориентироваться на наличие аргумента `e`.\n * Он содержит нативное событие, вызвавшее изменение.\n * Если его нет, значит `imask` вызывал `onAccept` по некой собственной логике.\n */\n e && onValueChange?.(value);\n }\n\n /**\n * Отслеживаем неожиданные нажатия\n * handleAccept не вызывается когда значение с маской не меняется\n * Сначала вызывается handleAccept, затем handleInput\n */\n function handleInput(e: React.ChangeEvent<HTMLInputElement>) {\n if (prevValue.current === e.target.value && prevSelectionStart.current === e.target.selectionStart) {\n handleUnexpectedInput(e.target.value);\n }\n\n prevValue.current = e.target.value;\n\n props.onInput?.(e);\n }\n\n function handleFocus(e: React.FocusEvent<HTMLInputElement>) {\n setFocused(true);\n props.onFocus?.(e);\n\n // если `value` из пропов отличается от `value`, которое получит `input` после обработки,\n // то `imask` будет ставить курсор за последним валидным символом.\n props.selectAllOnFocus && inputRef.current?.delaySelectAll();\n }\n\n function handleUnexpectedInput(value = '') {\n if (onUnexpectedInput) {\n onUnexpectedInput(value);\n } else if (inputRef.current) {\n inputRef.current.blink();\n }\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n setFocused(false);\n props.onBlur?.(e);\n }\n\n function handleKeyDownCapture(e: React.KeyboardEvent<HTMLInputElement>) {\n const isDeleteKey = someKeys(isKeyBackspace, isKeyDelete)(e);\n\n prevSelectionStart.current = e.currentTarget.selectionStart;\n\n if (!e.currentTarget.value && isDeleteKey && !e.repeat) {\n handleUnexpectedInput(e.currentTarget.value);\n prevValue.current = e.currentTarget.value;\n }\n\n onKeyDownCapture?.(e);\n }\n },\n);\n"]}
@@ -1,21 +1,185 @@
1
+ #### `mask`
2
+
3
+ Маска телефона
4
+
5
+ ```jsx harmony
6
+ const [value, setValue] = React.useState('123');
7
+
8
+ <MaskedInput
9
+ mask="+7 999-999-99-99"
10
+ alwaysShowMask
11
+ value={value}
12
+ onValueChange={setValue}
13
+ />
14
+ ```
15
+
16
+ #### `maskChar`
17
+
18
+ может изменить символ значения с маской
19
+
20
+ ```jsx harmony
21
+ <MaskedInput
22
+ mask="9999 9999 9999 9999"
23
+ maskChar="X"
24
+ placeholder="Номер карты"
25
+ alwaysShowMask
26
+ />
27
+ ```
28
+
29
+ #### `formatChars`
30
+
31
+ При необходимости можно настроить собственный словарь.
32
+
33
+ Возможности `imaskProps.blocks` намного шире. Смотрите пример ниже.
34
+
35
+ ```jsx harmony
36
+ const [value, setValue] = React.useState('');
37
+
38
+ <MaskedInput
39
+ mask="Hh:Mm:Ss"
40
+ alwaysShowMask
41
+ formatChars={{
42
+ H: '[0-2]',
43
+ h: value.startsWith('2') ? '[0-3]' : '[0-9]',
44
+ M: '[0-5]',
45
+ m: '[0-9]',
46
+ S: '[0-5]',
47
+ s: '[0-9]',
48
+ }}
49
+ value={value}
50
+ onValueChange={setValue}
51
+ />
52
+ ```
53
+
54
+ #### `alwaysShowMask`
55
+
56
+ Показывает маску всегда. Placeholder в этом случае игнорируется.
57
+ Логика немного отличается от старой реализации, из-за специфики iMask.
58
+ Раньше маска обязательно появлялась при фокусе, но теперь чтобы маску было видно надо явно задать этот проп.
59
+
60
+ ```jsx harmony
61
+ <MaskedInput mask="+7 (999) 999-99-99" alwaysShowMask placeholder="Номер телефона" />
62
+ ```
63
+
64
+ #### `imaskProps`*
65
+
66
+ Переопределяет пропы iMask.
67
+
68
+ ---
69
+
70
+ Контрол используется внутри пакет [iMask](https://imask.js.org/). Пропы `mask`, `maskChar` и `formatChars` прокидываются
71
+ с необходимыми доработками. Также для обратной совместимости со старым поведением добавляется несколько других пропов.
72
+
73
+ Обратите внимание, что в `definitions` попадает **`0: /\d/`**. Это дефолтное поле, которое нельзя удалить. Но в старой
74
+ реализации `0` считался фиксированным символом, из-за чего приходится немного редактировать маску.
75
+
76
+ Конвертация пропов выглядит примерно так:
77
+
78
+ ```typescript static
79
+ mask: mask.replace(/0/g, '{\\0}'),
80
+ placeholderChar: props.maskChar || '_',
81
+ definitions: props.formatChars || { '9': /[0-9]/, a: /[A-Za-z]/, '*': /[A-Za-z0-9]/ },
82
+ eager: true,
83
+ overwrite: 'shift',
84
+ lazy: !alwaysShowMask,
85
+ ...props.imaskProps,
86
+ ```
87
+
88
+ ---
89
+
90
+ ##### `imaskProps.unmask`
91
+
92
+ Можно сразу получать value без фиксированных символов маски
93
+
1
94
  ```jsx harmony
2
- <MaskedInput mask={'+7 999 999-99-99'} placeholder={"Номер телефона"} />
95
+ const [value, setValue] = React.useState('');
96
+
97
+ <>
98
+ <span>unmask value: {value}</span>
99
+ <br />
100
+ <MaskedInput
101
+ mask="+7 (999) 999-99-99"
102
+ imaskProps={{
103
+ unmask: true
104
+ }}
105
+ alwaysShowMask
106
+ value={value}
107
+ onValueChange={setValue}
108
+ />
109
+ </>
3
110
  ```
4
111
 
5
- Можно изменить символ значения с маской
112
+ ##### `imaskProps.mask []`
113
+
114
+ Опциональные части маски
115
+
6
116
  ```jsx harmony
7
- <MaskedInput mask={'9999 9999 9999 9999'} maskChar={'X'} placeholder={"Номер карты"} />
117
+ const [value, setValue] = React.useState('');
118
+ const [complete, setComplete] = React.useState(false);
119
+
120
+
121
+ <MaskedInput
122
+ mask="99-999999[99]-99"
123
+ alwaysShowMask
124
+ rightIcon={complete ? '✅' : '⬜'}
125
+ imaskProps={{
126
+ onAccept: (v, imask) => {
127
+ setValue(v);
128
+ setComplete(imask.masked.isComplete);
129
+ }
130
+ }}
131
+ />
8
132
  ```
9
133
 
10
- **alwaysShowMask** позволяет показывать маску всегда. Placeholder в этом случае игнорируется.
134
+ ##### `imaskProps.mask {}`
135
+
136
+ Фиксированные части маски, которые попадут в `value` при `unmask = true`. Любой невалидный символ (например`пробел`) переведёт каретку за фиксированный символ.
137
+
11
138
  ```jsx harmony
12
- <MaskedInput mask={'9999 9999 9999 9999'} alwaysShowMask maskChar={'X'} placeholder={"Номер карты"} />
139
+ const [value, setValue] = React.useState('');
140
+ const [complete, setComplete] = React.useState(false);
141
+
142
+
143
+ <>
144
+ <span>unmask value: {value}</span>
145
+ <br />
146
+ <MaskedInput
147
+ mask="aa[aaaaaaaaaaaaaaaaa]{@}aa[aaaaaaaaaaaaaaaaa]{\.}aa[aaaa]"
148
+ alwaysShowMask
149
+ rightIcon={complete ? '✅' : '⬜'}
150
+ imaskProps={{
151
+ unmask: true,
152
+ onAccept: (v, imask) => {
153
+ setValue(v);
154
+ setComplete(imask.masked.isComplete);
155
+ }
156
+ }}
157
+ />
158
+ </>
13
159
  ```
14
160
 
15
- Для форматирования по маске используется пакет [iMask](https://imask.js.org/). Используйте особенности пакета принимая всю ответственность на себя.
161
+ ##### `imaskProps.blocks`
16
162
 
17
- `MaskedInput` гарантирует поддержку работы 3 пропов: **mask**, **maskChar**, **alwaysShowMask** с заданными по-умолчанию **formatChars**.
163
+ Пример маски времени. Нажмите цифру `6`, чтобы сработало автозаполнение.
18
164
 
19
- Остальное поведение может меняться в мажорных релизах.
165
+ ```jsx harmony
166
+ import IMask from 'imask';
20
167
 
21
- Например, iMask [позволяет добавлять](https://imask.js.org/guide.html#masked-pattern) в значения без форматирования константы с помощью фигурных скобок. Использовать этот вариант **НЕ РЕКОМЕНДУЕТСЯ**.
168
+ const block = {
169
+ mask: IMask.MaskedRange,
170
+ from: 0,
171
+ autofix: 'pad',
172
+ };
173
+
174
+ <MaskedInput
175
+ mask="HH:MM:SS"
176
+ imaskProps={{
177
+ blocks: {
178
+ HH: { ...block, to: 23, },
179
+ MM: { ...block, to: 59, },
180
+ SS: { ...block, to: 59, },
181
+ }
182
+ }}
183
+ alwaysShowMask
184
+ />
185
+ ```
@@ -0,0 +1,3 @@
1
+ export declare const globalClasses: {
2
+ root: string;
3
+ };
@@ -0,0 +1,4 @@
1
+ "use strict";exports.__esModule = true;exports.globalClasses = void 0;var _Emotion = require("../../lib/theming/Emotion");
2
+
3
+ var globalClasses = (0, _Emotion.prefix)('masked-input')({
4
+ root: 'root' });exports.globalClasses = globalClasses;
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["MaskedInput.styles.ts"],"names":["globalClasses","root"],"mappings":"sEAAA;;AAEO,IAAMA,aAAa,GAAG,qBAAO,cAAP,EAAuB;AAClDC,EAAAA,IAAI,EAAE,MAD4C,EAAvB,CAAtB,C","sourcesContent":["import { prefix } from '../../lib/theming/Emotion';\n\nexport const globalClasses = prefix('masked-input')({\n root: 'root',\n});\n"]}
@@ -1,43 +1,43 @@
1
- ```jsx harmony
2
- import { Gapped, Radio } from '@skbkontur/react-ui';
3
-
4
- let items = ['One', 'Two', 'Three', 'Four'];
5
-
6
- let simpleRadioGroup = (
7
- <div>
8
- <h2>Numbers</h2>
9
- <RadioGroup name="number-simple" items={items} defaultValue="One" />
10
- </div>
11
- );
12
-
13
- let complexRadioGroup = (
14
- <div>
15
- <h2>Numbers</h2>
16
- <RadioGroup name="number-complex" defaultValue="3">
17
- <Gapped gap={40}>
18
- <Gapped vertical gap={0}>
19
- <b>Odd</b>
20
- <Radio value="1">One</Radio>
21
- <Radio value="3">Three</Radio>
22
- <Radio value="5" disabled>
23
- Five
24
- </Radio>
25
- <Radio value="7">Seven</Radio>
26
- </Gapped>
27
- <Gapped vertical gap={0}>
28
- <b>Even</b>
29
- <Radio value="2">Two</Radio>
30
- <Radio value="4">Four</Radio>
31
- <Radio value="6">Six</Radio>
32
- <Radio value="8">Eight</Radio>
33
- </Gapped>
34
- </Gapped>
35
- </RadioGroup>
36
- </div>
37
- );
38
-
39
- <div>
40
- {simpleRadioGroup}
41
- {complexRadioGroup}
42
- </div>;
43
- ```
1
+ ```jsx harmony
2
+ import { Gapped, Radio } from '@skbkontur/react-ui';
3
+
4
+ let items = ['One', 'Two', 'Three', 'Four'];
5
+
6
+ let simpleRadioGroup = (
7
+ <div>
8
+ <h2>Numbers</h2>
9
+ <RadioGroup name="number-simple" items={items} defaultValue="One" />
10
+ </div>
11
+ );
12
+
13
+ let complexRadioGroup = (
14
+ <div>
15
+ <h2>Numbers</h2>
16
+ <RadioGroup name="number-complex" defaultValue="3">
17
+ <Gapped gap={40}>
18
+ <Gapped vertical gap={0}>
19
+ <b>Odd</b>
20
+ <Radio value="1">One</Radio>
21
+ <Radio value="3">Three</Radio>
22
+ <Radio value="5" disabled>
23
+ Five
24
+ </Radio>
25
+ <Radio value="7">Seven</Radio>
26
+ </Gapped>
27
+ <Gapped vertical gap={0}>
28
+ <b>Even</b>
29
+ <Radio value="2">Two</Radio>
30
+ <Radio value="4">Four</Radio>
31
+ <Radio value="6">Six</Radio>
32
+ <Radio value="8">Eight</Radio>
33
+ </Gapped>
34
+ </Gapped>
35
+ </RadioGroup>
36
+ </div>
37
+ );
38
+
39
+ <div>
40
+ {simpleRadioGroup}
41
+ {complexRadioGroup}
42
+ </div>;
43
+ ```
package/cjs/index.d.ts CHANGED
@@ -45,6 +45,7 @@ export * from './components/TokenInput';
45
45
  export * from './components/Tooltip';
46
46
  export * from './components/TooltipMenu';
47
47
  export * from './components/ResponsiveLayout';
48
+ export * from './components/MaskedInput';
48
49
  export * from './lib/featureFlagsContext';
49
50
  export * from './lib/locale';
50
51
  export * from './lib/theming/ThemeContext';
@@ -55,6 +56,8 @@ export * from './lib/theming/themes/DefaultTheme8pxOld';
55
56
  export * from './lib/theming/themes/FlatTheme8pxOld';
56
57
  export * from './lib/theming/themes/Theme2022';
57
58
  export * from './lib/theming/themes/Theme2022Dark';
59
+ export * from './lib/theming/themes/Theme2022Update2024';
60
+ export * from './lib/theming/themes/Theme2022DarkUpdate2024';
58
61
  export * from './lib/types/props';
59
62
  export * from './internal/Popup/types';
60
63
  export * as ColorFunctions from './lib/styles/ColorFunctions';
package/cjs/index.js CHANGED
@@ -45,6 +45,7 @@ var _TokenInput = require("./components/TokenInput");Object.keys(_TokenInput).fo
45
45
  var _Tooltip = require("./components/Tooltip");Object.keys(_Tooltip).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _Tooltip[key]) return;exports[key] = _Tooltip[key];});
46
46
  var _TooltipMenu = require("./components/TooltipMenu");Object.keys(_TooltipMenu).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _TooltipMenu[key]) return;exports[key] = _TooltipMenu[key];});
47
47
  var _ResponsiveLayout = require("./components/ResponsiveLayout");Object.keys(_ResponsiveLayout).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _ResponsiveLayout[key]) return;exports[key] = _ResponsiveLayout[key];});
48
+ var _MaskedInput = require("./components/MaskedInput");Object.keys(_MaskedInput).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _MaskedInput[key]) return;exports[key] = _MaskedInput[key];});
48
49
  var _featureFlagsContext = require("./lib/featureFlagsContext");Object.keys(_featureFlagsContext).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _featureFlagsContext[key]) return;exports[key] = _featureFlagsContext[key];});
49
50
  var _locale = require("./lib/locale");Object.keys(_locale).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _locale[key]) return;exports[key] = _locale[key];});
50
51
  var _ThemeContext = require("./lib/theming/ThemeContext");Object.keys(_ThemeContext).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _ThemeContext[key]) return;exports[key] = _ThemeContext[key];});
@@ -55,5 +56,7 @@ var _DefaultTheme8pxOld = require("./lib/theming/themes/DefaultTheme8pxOld");Obj
55
56
  var _FlatTheme8pxOld = require("./lib/theming/themes/FlatTheme8pxOld");Object.keys(_FlatTheme8pxOld).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _FlatTheme8pxOld[key]) return;exports[key] = _FlatTheme8pxOld[key];});
56
57
  var _Theme = require("./lib/theming/themes/Theme2022");Object.keys(_Theme).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _Theme[key]) return;exports[key] = _Theme[key];});
57
58
  var _Theme2022Dark = require("./lib/theming/themes/Theme2022Dark");Object.keys(_Theme2022Dark).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _Theme2022Dark[key]) return;exports[key] = _Theme2022Dark[key];});
59
+ var _Theme2022Update = require("./lib/theming/themes/Theme2022Update2024");Object.keys(_Theme2022Update).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _Theme2022Update[key]) return;exports[key] = _Theme2022Update[key];});
60
+ var _Theme2022DarkUpdate = require("./lib/theming/themes/Theme2022DarkUpdate2024");Object.keys(_Theme2022DarkUpdate).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _Theme2022DarkUpdate[key]) return;exports[key] = _Theme2022DarkUpdate[key];});
58
61
  var _props = require("./lib/types/props");Object.keys(_props).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _props[key]) return;exports[key] = _props[key];});
59
62
  var _types = require("./internal/Popup/types");Object.keys(_types).forEach(function (key) {if (key === "default" || key === "__esModule") return;if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;if (key in exports && exports[key] === _types[key]) return;exports[key] = _types[key];});var _ColorFunctions = _interopRequireWildcard(require("./lib/styles/ColorFunctions"));exports.ColorFunctions = _ColorFunctions;var _DimensionFunctions = _interopRequireWildcard(require("./lib/styles/DimensionFunctions"));exports.DimensionFunctions = _DimensionFunctions;