@skbkontur/react-ui 4.25.1-MaskedInput-2nd.5 → 4.25.1-MaskedInput-2nd.6

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.
@@ -7,19 +7,13 @@ var _ThemeContext = require("../../../lib/theming/ThemeContext");
7
7
  var _forwardRefAndName = require("../../../lib/forwardRefAndName");
8
8
  var _Emotion = require("../../../lib/theming/Emotion");
9
9
 
10
- var _ColorableInputElement = require("./ColorableInputElement.styles");var _excluded = ["children", "onInput", "onFocus", "onBlur"];
10
+ var _ColorableInputElement = require("./ColorableInputElement.styles");var _excluded = ["children", "onInput", "onFocus", "onBlur", "showOnFocus"];
11
11
 
12
12
 
13
13
 
14
14
 
15
15
 
16
16
 
17
- var dictionary = new Map();
18
- var paintText = function paintText(entries) {
19
- entries.forEach(function (entry) {var _dictionary$get;return (_dictionary$get = dictionary.get(entry.target)) == null ? void 0 : _dictionary$get();});
20
- };
21
- var resizeObserver = _globalObject.globalObject.ResizeObserver ? new _globalObject.globalObject.ResizeObserver((0, _lodash.default)(paintText)) : null;
22
-
23
17
  // Возможно придётся включить.
24
18
  // Иногда, на тяжёлых страницах, текст рендерится итеративно.
25
19
  // Из-за этого могут оставаться артефакты при покраске компонента, которые пропадут только после фокуса.
@@ -36,7 +30,7 @@ function ColorableInputElement(props, ref) {
36
30
  var debouncedPaintText = (0, _react.useCallback)((0, _lodash.default)(paintText), []);
37
31
  var _useState = (0, _react.useState)(true),active = _useState[0],setActive = _useState[1];
38
32
 
39
- var children = props.children,onInput = props.onInput,onFocus = props.onFocus,onBlur = props.onBlur,inputProps = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
33
+ var children = props.children,onInput = props.onInput,onFocus = props.onFocus,onBlur = props.onBlur,showOnFocus = props.showOnFocus,inputProps = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
40
34
 
41
35
  (0, _react.useImperativeHandle)(
42
36
  ref,
@@ -47,26 +41,12 @@ function ColorableInputElement(props, ref) {
47
41
  []);
48
42
 
49
43
 
50
- (0, _react.useEffect)(function () {
51
- updateActive();
52
-
53
- if (inputRef.current) {
54
- dictionary.set(inputRef.current, debouncedPaintText);
55
- resizeObserver == null ? void 0 : resizeObserver.observe(inputRef.current);
56
- }
57
-
58
- return function () {
59
- if (inputRef.current) {
60
- dictionary.delete(inputRef.current);
61
- resizeObserver == null ? void 0 : resizeObserver.unobserve(inputRef.current);
62
- }
63
- };
64
- }, []);
44
+ (0, _react.useEffect)(updateActive, []);
65
45
 
66
46
  (0, _react.useEffect)(function () {
67
47
  activation(props);
68
48
  updateActive();
69
- }, [active, props.showOnFocus, props.value, props.defaultValue, props.disabled, focused.current]);
49
+ }, [active, showOnFocus, props.value, props.defaultValue, props.disabled, focused.current]);
70
50
 
71
51
  (0, _react.useEffect)(function () {
72
52
  if (inputRef.current) {
@@ -1 +1 @@
1
- {"version":3,"sources":["ColorableInputElement.tsx"],"names":["dictionary","Map","paintText","entries","forEach","entry","get","target","resizeObserver","globalObject","ResizeObserver","ColorableInputElement","props","ref","inputRef","spanRef","focused","inputStyle","React","useRef","theme","ThemeContext","debouncedPaintText","active","setActive","children","onInput","onFocus","onBlur","inputProps","input","current","getRootNode","updateActive","set","observe","delete","unobserve","activation","showOnFocus","value","defaultValue","disabled","getComputedStyle","cloneElement","handleInput","handleFocus","handleBlur","className","globalClasses","visibility","position","whiteSpace","e","isActive","parentElement","querySelector","setTimeout","cancel","style","backgroundImage","classList","remove","_props","add","shadow","shadowRoot","typedValueElement","getElementById","attachShadow","mode","document","createElement","setAttribute","appendChild","textContent","getAttribute","inputRect","getBoundingClientRect","filledRect","threshold","width","degree","fontStyle","typedValueColor","inputTextColor","maskColor","inputPlaceholderColor","inputTextColorDisabled"],"mappings":"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","sourcesContent":["import React, { ForwardedRef, useContext, useEffect, useImperativeHandle, useRef, useCallback, useState } from 'react';\nimport { globalObject, isBrowser } from '@skbkontur/global-object';\nimport debounce from 'lodash.debounce';\n\nimport { ThemeContext } from '../../../lib/theming/ThemeContext';\nimport { InputElement, InputElementProps } from '../../Input';\nimport { forwardRefAndName } from '../../../lib/forwardRefAndName';\nimport { cx } from '../../../lib/theming/Emotion';\n\nimport { globalClasses } from './ColorableInputElement.styles';\n\nexport type ColorableInputElementProps = InputElementProps & {\n showOnFocus?: boolean;\n children: React.ReactElement;\n};\n\nconst dictionary = new Map<Element, () => void>();\nconst paintText: ResizeObserverCallback = (entries) => {\n entries.forEach((entry) => dictionary.get(entry.target)?.());\n};\nconst resizeObserver = globalObject.ResizeObserver ? new globalObject.ResizeObserver(debounce(paintText)) : null;\n\n// Возможно придётся включить.\n// Иногда, на тяжёлых страницах, текст рендерится итеративно.\n// Из-за этого могут оставаться артефакты при покраске компонента, которые пропадут только после фокуса.\n// setInterval(() => window.requestAnimationFrame(() => dictionary.forEach((paint) => paint())), 1000);\n\nexport const ColorableInputElement = forwardRefAndName(\n 'ColorableInputElement',\n function ColorableInputElement(props: ColorableInputElementProps, ref: ForwardedRef<InputElement>) {\n const inputRef = useRef<HTMLInputElement | null>(null);\n const spanRef = useRef<HTMLSpanElement | null>(null);\n const focused = useRef(false);\n const inputStyle = React.useRef<CSSStyleDeclaration>();\n const theme = useContext(ThemeContext);\n const debouncedPaintText = useCallback(debounce(paintText), []);\n const [active, setActive] = useState(true);\n\n const { children, onInput, onFocus, onBlur, ...inputProps } = props;\n\n useImperativeHandle(\n ref,\n () => ({\n input: inputRef.current,\n getRootNode: () => inputRef.current,\n }),\n [],\n );\n\n useEffect(() => {\n updateActive();\n\n if (inputRef.current) {\n dictionary.set(inputRef.current, debouncedPaintText);\n resizeObserver?.observe(inputRef.current);\n }\n\n return () => {\n if (inputRef.current) {\n dictionary.delete(inputRef.current);\n resizeObserver?.unobserve(inputRef.current);\n }\n };\n }, []);\n\n useEffect(() => {\n activation(props);\n updateActive();\n }, [active, props.showOnFocus, props.value, props.defaultValue, props.disabled, focused.current]);\n\n useEffect(() => {\n if (inputRef.current) {\n inputStyle.current = getComputedStyle(inputRef.current);\n }\n });\n\n return (\n <>\n {React.cloneElement(children, {\n ...inputProps,\n onInput: handleInput,\n onFocus: handleFocus,\n onBlur: handleBlur,\n inputRef,\n className: cx(props.className, active && globalClasses.input),\n })}\n {active && <span style={{ visibility: 'hidden', position: 'absolute', whiteSpace: 'pre' }} ref={spanRef} />}\n </>\n );\n\n function handleInput(e: React.ChangeEvent<HTMLInputElement>) {\n const isActive = !inputRef.current?.parentElement?.querySelector(':placeholder-shown');\n setActive(isActive);\n\n activation(props);\n\n onInput?.(e);\n }\n\n function handleFocus(e: React.FocusEvent<HTMLInputElement>) {\n setTimeout(updateActive);\n\n focused.current = true;\n\n onFocus?.(e);\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n updateActive();\n\n focused.current = false;\n\n onBlur?.(e);\n }\n\n function updateActive() {\n setTimeout(() => {\n setActive(!inputRef.current?.parentElement?.querySelector(':placeholder-shown'));\n });\n }\n\n function activation(props: ColorableInputElementProps) {\n if (active) {\n debouncedPaintText(props);\n } else {\n debouncedPaintText.cancel();\n inputRef.current && (inputRef.current.style.backgroundImage = '');\n inputRef.current?.classList.remove(globalClasses.input);\n }\n }\n\n function paintText(_props: Partial<ColorableInputElementProps> = props) {\n if (!spanRef.current || !inputRef.current || !inputStyle.current || !isBrowser(globalObject)) {\n return;\n }\n\n inputRef.current?.classList.add(globalClasses.input);\n\n let shadow = spanRef.current.shadowRoot;\n let typedValueElement = shadow?.getElementById('span');\n\n if (!typedValueElement) {\n shadow = spanRef.current.attachShadow({ mode: 'open' });\n\n typedValueElement = globalObject.document.createElement('span');\n typedValueElement.setAttribute('id', 'span');\n\n shadow.appendChild(typedValueElement);\n }\n\n const style = inputStyle.current;\n\n typedValueElement.textContent = inputRef.current.getAttribute('data-typed-value') || '';\n\n const inputRect = inputRef.current.getBoundingClientRect();\n const filledRect = spanRef.current.getBoundingClientRect();\n\n const threshold = filledRect.width / (inputRect.width / 100);\n const degree = style.fontStyle === 'italic' ? 100 : 90;\n\n let typedValueColor = theme.inputTextColor;\n let maskColor = theme.inputPlaceholderColor;\n if (_props.disabled) {\n typedValueColor = theme.inputTextColorDisabled;\n maskColor = theme.inputTextColorDisabled;\n }\n if (_props.showOnFocus) {\n maskColor = focused.current ? maskColor : 'transparent';\n }\n\n inputRef.current.style.backgroundImage = `\n linear-gradient(\n ${degree}deg,\n ${typedValueColor} ${threshold}%,\n ${maskColor} ${threshold}%\n )`;\n }\n },\n);\n"]}
1
+ {"version":3,"sources":["ColorableInputElement.tsx"],"names":["ColorableInputElement","props","ref","inputRef","spanRef","focused","inputStyle","React","useRef","theme","ThemeContext","debouncedPaintText","paintText","active","setActive","children","onInput","onFocus","onBlur","showOnFocus","inputProps","input","current","getRootNode","updateActive","activation","value","defaultValue","disabled","getComputedStyle","cloneElement","handleInput","handleFocus","handleBlur","className","globalClasses","visibility","position","whiteSpace","e","isActive","parentElement","querySelector","setTimeout","cancel","style","backgroundImage","classList","remove","_props","globalObject","add","shadow","shadowRoot","typedValueElement","getElementById","attachShadow","mode","document","createElement","setAttribute","appendChild","textContent","getAttribute","inputRect","getBoundingClientRect","filledRect","threshold","width","degree","fontStyle","typedValueColor","inputTextColor","maskColor","inputPlaceholderColor","inputTextColorDisabled"],"mappings":"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","sourcesContent":["import React, { ForwardedRef, useContext, useEffect, useImperativeHandle, useRef, useCallback, useState } from 'react';\nimport { globalObject, isBrowser } from '@skbkontur/global-object';\nimport debounce from 'lodash.debounce';\n\nimport { ThemeContext } from '../../../lib/theming/ThemeContext';\nimport { InputElement, InputElementProps } from '../../Input';\nimport { forwardRefAndName } from '../../../lib/forwardRefAndName';\nimport { cx } from '../../../lib/theming/Emotion';\n\nimport { globalClasses } from './ColorableInputElement.styles';\n\nexport type ColorableInputElementProps = InputElementProps & {\n showOnFocus?: boolean;\n children: React.ReactElement;\n};\n\n// Возможно придётся включить.\n// Иногда, на тяжёлых страницах, текст рендерится итеративно.\n// Из-за этого могут оставаться артефакты при покраске компонента, которые пропадут только после фокуса.\n// setInterval(() => window.requestAnimationFrame(() => dictionary.forEach((paint) => paint())), 1000);\n\nexport const ColorableInputElement = forwardRefAndName(\n 'ColorableInputElement',\n function ColorableInputElement(props: ColorableInputElementProps, ref: ForwardedRef<InputElement>) {\n const inputRef = useRef<HTMLInputElement | null>(null);\n const spanRef = useRef<HTMLSpanElement | null>(null);\n const focused = useRef(false);\n const inputStyle = React.useRef<CSSStyleDeclaration>();\n const theme = useContext(ThemeContext);\n const debouncedPaintText = useCallback(debounce(paintText), []);\n const [active, setActive] = useState(true);\n\n const { children, onInput, onFocus, onBlur, showOnFocus, ...inputProps } = props;\n\n useImperativeHandle(\n ref,\n () => ({\n input: inputRef.current,\n getRootNode: () => inputRef.current,\n }),\n [],\n );\n\n useEffect(updateActive, []);\n\n useEffect(() => {\n activation(props);\n updateActive();\n }, [active, showOnFocus, props.value, props.defaultValue, props.disabled, focused.current]);\n\n useEffect(() => {\n if (inputRef.current) {\n inputStyle.current = getComputedStyle(inputRef.current);\n }\n });\n\n return (\n <>\n {React.cloneElement(children, {\n ...inputProps,\n onInput: handleInput,\n onFocus: handleFocus,\n onBlur: handleBlur,\n inputRef,\n className: cx(props.className, active && globalClasses.input),\n })}\n {active && <span style={{ visibility: 'hidden', position: 'absolute', whiteSpace: 'pre' }} ref={spanRef} />}\n </>\n );\n\n function handleInput(e: React.ChangeEvent<HTMLInputElement>) {\n const isActive = !inputRef.current?.parentElement?.querySelector(':placeholder-shown');\n setActive(isActive);\n\n activation(props);\n\n onInput?.(e);\n }\n\n function handleFocus(e: React.FocusEvent<HTMLInputElement>) {\n setTimeout(updateActive);\n\n focused.current = true;\n\n onFocus?.(e);\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n updateActive();\n\n focused.current = false;\n\n onBlur?.(e);\n }\n\n function updateActive() {\n setTimeout(() => {\n setActive(!inputRef.current?.parentElement?.querySelector(':placeholder-shown'));\n });\n }\n\n function activation(props: ColorableInputElementProps) {\n if (active) {\n debouncedPaintText(props);\n } else {\n debouncedPaintText.cancel();\n inputRef.current && (inputRef.current.style.backgroundImage = '');\n inputRef.current?.classList.remove(globalClasses.input);\n }\n }\n\n function paintText(_props: Partial<ColorableInputElementProps> = props) {\n if (!spanRef.current || !inputRef.current || !inputStyle.current || !isBrowser(globalObject)) {\n return;\n }\n\n inputRef.current?.classList.add(globalClasses.input);\n\n let shadow = spanRef.current.shadowRoot;\n let typedValueElement = shadow?.getElementById('span');\n\n if (!typedValueElement) {\n shadow = spanRef.current.attachShadow({ mode: 'open' });\n\n typedValueElement = globalObject.document.createElement('span');\n typedValueElement.setAttribute('id', 'span');\n\n shadow.appendChild(typedValueElement);\n }\n\n const style = inputStyle.current;\n\n typedValueElement.textContent = inputRef.current.getAttribute('data-typed-value') || '';\n\n const inputRect = inputRef.current.getBoundingClientRect();\n const filledRect = spanRef.current.getBoundingClientRect();\n\n const threshold = filledRect.width / (inputRect.width / 100);\n const degree = style.fontStyle === 'italic' ? 100 : 90;\n\n let typedValueColor = theme.inputTextColor;\n let maskColor = theme.inputPlaceholderColor;\n if (_props.disabled) {\n typedValueColor = theme.inputTextColorDisabled;\n maskColor = theme.inputTextColorDisabled;\n }\n if (_props.showOnFocus) {\n maskColor = focused.current ? maskColor : 'transparent';\n }\n\n inputRef.current.style.backgroundImage = `\n linear-gradient(\n ${degree}deg,\n ${typedValueColor} ${threshold}%,\n ${maskColor} ${threshold}%\n )`;\n }\n },\n);\n"]}
@@ -4,5 +4,5 @@ var globalClasses = (0, _Emotion.prefix)('colorable')({
4
4
  input: 'input' });exports.globalClasses = globalClasses;
5
5
 
6
6
 
7
- (0, _Emotion.injectGlobal)(_templateObject || (_templateObject = (0, _taggedTemplateLiteralLoose2.default)(["\n input.", " {\n display: inline-block;\n background-color: transparent;\n background-size: 100%;\n background-repeat: repeat;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n\n transition: background-color 1s;\n }\n"])),
7
+ (0, _Emotion.injectGlobal)(_templateObject || (_templateObject = (0, _taggedTemplateLiteralLoose2.default)(["\n input.", " {\n display: inline-block;\n background-color: transparent;\n background-size: 100%;\n background-repeat: repeat;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n"])),
8
8
  globalClasses.input);
@@ -1 +1 @@
1
- {"version":3,"sources":["ColorableInputElement.styles.ts"],"names":["globalClasses","input"],"mappings":"2RAAA,uD;;AAEO,IAAMA,aAAa,GAAG,qBAAO,WAAP,EAAoB;AAC/CC,EAAAA,KAAK,EAAE,OADwC,EAApB,CAAtB,C;;;AAIP;AACUD,aAAa,CAACC,KADxB","sourcesContent":["import { injectGlobal, prefix } from '../../../lib/theming/Emotion';\n\nexport const globalClasses = prefix('colorable')({\n input: 'input',\n});\n\ninjectGlobal`\n input.${globalClasses.input} {\n display: inline-block;\n background-color: transparent;\n background-size: 100%;\n background-repeat: repeat;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n\n transition: background-color 1s;\n }\n`;\n"]}
1
+ {"version":3,"sources":["ColorableInputElement.styles.ts"],"names":["globalClasses","input"],"mappings":"2RAAA,uD;;AAEO,IAAMA,aAAa,GAAG,qBAAO,WAAP,EAAoB;AAC/CC,EAAAA,KAAK,EAAE,OADwC,EAApB,CAAtB,C;;;AAIP;AACUD,aAAa,CAACC,KADxB","sourcesContent":["import { injectGlobal, prefix } from '../../../lib/theming/Emotion';\n\nexport const globalClasses = prefix('colorable')({\n input: 'input',\n});\n\ninjectGlobal`\n input.${globalClasses.input} {\n display: inline-block;\n background-color: transparent;\n background-size: 100%;\n background-repeat: repeat;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n`;\n"]}
@@ -19,12 +19,12 @@ export interface MaskedProps {
19
19
  */
20
20
  formatChars?: Record<string, string>;
21
21
  /**
22
- * Всегда показывать символы маски
22
+ * Показывать символы маски
23
23
  *
24
24
  * @see См. `imaskProps.lazy`
25
- * @default false
25
+ * @default 'focus'
26
26
  */
27
- alwaysShowMask?: boolean;
27
+ showMask?: 'always' | 'focus' | 'never';
28
28
  /**
29
29
  * Обработчик неправильного ввода.
30
30
  * Вторым агрументом будет передан метод вспыхивания акцентным цветом.
@@ -11,7 +11,7 @@ var _identifiers = require("../../lib/events/keyboard/identifiers");
11
11
  var _MaskedInput = require("./MaskedInput.styles");
12
12
  var _MaskedInput2 = require("./MaskedInput.helpers");
13
13
  var _ColorableInputElement = require("./ColorableInputElement");
14
- var _FixedIMaskInput = require("./FixedIMaskInput");var _excluded = ["onAccept"],_excluded2 = ["mask", "maskChar", "formatChars", "alwaysShowMask", "imaskProps", "onValueChange", "onUnexpectedInput", "onChange", "element", "className"];
14
+ var _FixedIMaskInput = require("./FixedIMaskInput");var _excluded = ["onAccept"],_excluded2 = ["mask", "maskChar", "formatChars", "showMask", "imaskProps", "onValueChange", "onUnexpectedInput", "onChange", "element", "className"];
15
15
 
16
16
 
17
17
 
@@ -82,7 +82,7 @@ function MaskedInput(props, ref) {
82
82
 
83
83
 
84
84
 
85
- 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),onValueChange = props.onValueChange,onUnexpectedInput = props.onUnexpectedInput,onChange = props.onChange,element = props.element,className = props.className,inputProps = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded2);
85
+ props.mask,maskChar = props.maskChar,formatChars = props.formatChars,_props$showMask = props.showMask,showMask = _props$showMask === void 0 ? 'focus' : _props$showMask,_props$imaskProps = props.imaskProps;_props$imaskProps = _props$imaskProps === void 0 ? {} : _props$imaskProps;var onAccept = _props$imaskProps.onAccept,customIMaskProps = (0, _objectWithoutPropertiesLoose2.default)(_props$imaskProps, _excluded),onValueChange = props.onValueChange,onUnexpectedInput = props.onUnexpectedInput,onChange = props.onChange,element = props.element,className = props.className,inputProps = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded2);
86
86
 
87
87
  var inputRef = (0, _react.useRef)(null);
88
88
 
@@ -122,7 +122,7 @@ function MaskedInput(props, ref) {
122
122
  onKeyDown: handleKeyDown,
123
123
  className: (0, _Emotion.cx)(_MaskedInput.globalClasses.root, _UiFont.uiFontGlobalClasses.root, className),
124
124
  element: /*#__PURE__*/
125
- _react.default.createElement(_ColorableInputElement.ColorableInputElement, { showOnFocus: !alwaysShowMask }, /*#__PURE__*/
125
+ _react.default.createElement(_ColorableInputElement.ColorableInputElement, { showOnFocus: false }, /*#__PURE__*/
126
126
  _react.default.createElement(_FixedIMaskInput.FixedIMaskInput, (0, _extends2.default)({}, imaskProps, { onAccept: handleAccept }))) })));
127
127
 
128
128
 
@@ -130,6 +130,8 @@ function MaskedInput(props, ref) {
130
130
 
131
131
 
132
132
  function getCompatibleIMaskProps() {
133
+ var showMaskPlaceholder = showMask === 'always' || showMask === 'focus' && focused;
134
+
133
135
  return (0, _extends2.default)({
134
136
  mask: mask.replace(/0/g, '{\\0}'),
135
137
  placeholderChar: (0, _MaskedInput2.getMaskChar)(maskChar),
@@ -137,7 +139,7 @@ function MaskedInput(props, ref) {
137
139
  // FIXME: Должно быть eager=true, но в imask ломается удаление по delete
138
140
  eager: 'append',
139
141
  overwrite: 'shift',
140
- lazy: !alwaysShowMask && (props.disabled || !focused) },
142
+ lazy: !showMaskPlaceholder },
141
143
  customIMaskProps);
142
144
 
143
145
  }
@@ -195,18 +197,17 @@ function MaskedInput(props, ref) {
195
197
  }
196
198
 
197
199
  function handleKeyDown(e) {
198
- var _e$currentTarget2 = e.currentTarget,value = _e$currentTarget2.value,selectionStart = _e$currentTarget2.selectionStart;
199
-
200
- prevSelectionStart.current = selectionStart;
200
+ var _e$currentTarget2 = e.currentTarget,value = _e$currentTarget2.value,selectionStart = _e$currentTarget2.selectionStart,selectionEnd = _e$currentTarget2.selectionEnd;
201
201
 
202
202
  if (
203
- (0, _identifiers.isKeyBackspace)(e) && prevSelectionStart.current === 0 ||
203
+ (0, _identifiers.isKeyBackspace)(e) && selectionStart === 0 && selectionEnd === 0 ||
204
204
  (0, _identifiers.isKeyDelete)(e) && prevSelectionStart.current === value.length)
205
205
  {
206
206
  // Случаи, когда нажатие клавиш не тригерит `onInput`
207
207
  handleUnexpectedInput(value);
208
208
  prevValue.current = e.currentTarget.value;
209
209
  }
210
+ prevSelectionStart.current = selectionStart;
210
211
 
211
212
  props.onKeyDown == null ? void 0 : props.onKeyDown(e);
212
213
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["MaskedInput.tsx"],"names":["MaskedInput","props","ref","mask","maskChar","formatChars","alwaysShowMask","imaskProps","onAccept","customIMaskProps","onValueChange","onUnexpectedInput","onChange","element","className","inputProps","inputRef","focused","setFocused","prevValue","value","String","defaultValue","prevSelectionStart","current","Object","assign","selectAll","delaySelectAll","input","selectionStart","getCompatibleIMaskProps","handleFocus","handleBlur","handleInput","handleKeyDown","globalClasses","root","uiFontGlobalClasses","handleAccept","replace","placeholderChar","definitions","eager","overwrite","lazy","disabled","args","e","currentTarget","handleUnexpectedInput","onInput","onFocus","selectAllOnFocus","blink","bind","undefined","onBlur","length","onKeyDown"],"mappings":"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","sourcesContent":["import React, { Ref, useImperativeHandle, useRef, useState, useEffect } from 'react';\nimport { IMaskInputProps } from 'react-imask';\n\nimport { Nullable } from '../../typings/utility-types';\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 } from '../../lib/events/keyboard/identifiers';\n\nimport { globalClasses } from './MaskedInput.styles';\nimport { getDefinitions, getMaskChar } from './MaskedInput.helpers';\nimport { ColorableInputElement } from './ColorableInputElement';\nimport { FixedIMaskInput } from './FixedIMaskInput';\n\nexport interface MaskedProps {\n /** Паттерн маски */\n mask: string;\n /**\n * Символ маски\n *\n * @see См. `imaskProps.placeholderChar`\n * @default _\n */\n maskChar?: Nullable<string>;\n /**\n * Словарь символов-регулярок для маски\n *\n * @see См. `imaskProps.definitions`\n * @default { '9': '[0-9]', 'a': '[A-Za-z]', '*': '[A-Za-z0-9]' }\n */\n formatChars?: Record<string, string>;\n /**\n * Всегда показывать символы маски\n *\n * @see См. `imaskProps.lazy`\n * @default false\n */\n alwaysShowMask?: boolean;\n /**\n * Обработчик неправильного ввода.\n * Вторым агрументом будет передан метод вспыхивания акцентным цветом.\n *\n * Если обработчик не задан, то инпут вспыхивает по-умолчанию.\n *\n * @param value значение инпута.\n * @param blink вспыхнуть акцентным цвтетом.\n */\n onUnexpectedInput?: (value: string, blink: () => void) => void;\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 MaskedInputProps\n extends MaskedProps,\n Omit<InputProps, 'mask' | 'maxLength' | 'type' | 'alwaysShowMask' | 'onUnexpectedInput'> {\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 onValueChange,\n onUnexpectedInput,\n onChange,\n element,\n className,\n ...inputProps\n } = props;\n\n const inputRef = useRef<Input>(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 useImperativeHandle(\n ref,\n () =>\n inputRef.current &&\n Object.assign(inputRef.current, {\n selectAll: inputRef.current.delaySelectAll,\n }),\n [],\n );\n\n useEffect(() => {\n // Для корректной работы onUnexpectedInput надо знать предыдущий value,\n // но imask при монтировании не вызывает onAccept, если value невалиден или laze=false.\n // Поэтому актуальный value при монтировании надо получать вручную\n if (inputRef.current?.input) {\n prevValue.current = inputRef.current.input.value;\n prevSelectionStart.current = inputRef.current.input.selectionStart;\n }\n }, []);\n\n const imaskProps = getCompatibleIMaskProps();\n\n return (\n <Input\n ref={inputRef}\n {...inputProps}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onInput={handleInput}\n onKeyDown={handleKeyDown}\n className={cx(globalClasses.root, uiFontGlobalClasses.root, className)}\n element={\n <ColorableInputElement showOnFocus={!alwaysShowMask}>\n <FixedIMaskInput {...imaskProps} onAccept={handleAccept} />\n </ColorableInputElement>\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 // FIXME: Должно быть eager=true, но в imask ломается удаление по delete\n eager: 'append',\n overwrite: 'shift',\n lazy: !alwaysShowMask && (props.disabled || !focused),\n ...customIMaskProps,\n } as IMaskInputProps<HTMLInputElement>;\n }\n\n function handleAccept(...args: Parameters<Required<IMaskInputProps<HTMLInputElement>>['onAccept']>) {\n const [value, , e] = args;\n\n // Метод onAccept может вызываться при монтировании, если не задан проп defaultValue.\n // Но нативный input никогда не вызывает onChange при монтировании.\n // Наше событие onValueChange в Input вывается в тех же случаях, что и нативный onChange,\n // поэтому чтобы сохранить консинстентность будем ориентироваться на наличие аргумента e.\n // Он содержит нативное событие, вызвавшее изменение.\n e && onValueChange?.(value);\n !e && (prevValue.current = value);\n\n onAccept?.(...args);\n }\n\n /**\n * Отслеживаем неожиданные нажатия\n * handleAccept не вызывается когда значение с маской не меняется\n * Сначала вызывается handleAccept, затем handleInput\n */\n function handleInput(e: React.ChangeEvent<HTMLInputElement>) {\n const { value, selectionStart } = e.currentTarget;\n\n // При вводе неожиданных символов или удалении каретка может перепрыгивать фиксированные символы.\n // Такие случаи не расцениваем как неожиданный ввод, т.к. пользователь может намеренно их вводить.\n if (prevValue.current === value && selectionStart === prevSelectionStart.current) {\n handleUnexpectedInput(value);\n }\n prevValue.current = value;\n prevSelectionStart.current = selectionStart;\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: string) {\n const blink = inputRef.current?.blink.bind(inputRef.current) || (() => undefined);\n onUnexpectedInput ? onUnexpectedInput(value, blink) : blink();\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n setFocused(false);\n props.onBlur?.(e);\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n const { value, selectionStart } = e.currentTarget;\n\n prevSelectionStart.current = selectionStart;\n\n if (\n (isKeyBackspace(e) && prevSelectionStart.current === 0) ||\n (isKeyDelete(e) && prevSelectionStart.current === value.length)\n ) {\n // Случаи, когда нажатие клавиш не тригерит `onInput`\n handleUnexpectedInput(value);\n prevValue.current = e.currentTarget.value;\n }\n\n props.onKeyDown?.(e);\n }\n },\n);\n"]}
1
+ {"version":3,"sources":["MaskedInput.tsx"],"names":["MaskedInput","props","ref","mask","maskChar","formatChars","showMask","imaskProps","onAccept","customIMaskProps","onValueChange","onUnexpectedInput","onChange","element","className","inputProps","inputRef","focused","setFocused","prevValue","value","String","defaultValue","prevSelectionStart","current","Object","assign","selectAll","delaySelectAll","input","selectionStart","getCompatibleIMaskProps","handleFocus","handleBlur","handleInput","handleKeyDown","globalClasses","root","uiFontGlobalClasses","handleAccept","showMaskPlaceholder","replace","placeholderChar","definitions","eager","overwrite","lazy","args","e","currentTarget","handleUnexpectedInput","onInput","onFocus","selectAllOnFocus","blink","bind","undefined","onBlur","selectionEnd","length","onKeyDown"],"mappings":"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","sourcesContent":["import React, { Ref, useImperativeHandle, useRef, useState, useEffect } from 'react';\nimport { IMaskInputProps } from 'react-imask';\n\nimport { Nullable } from '../../typings/utility-types';\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 } from '../../lib/events/keyboard/identifiers';\n\nimport { globalClasses } from './MaskedInput.styles';\nimport { getDefinitions, getMaskChar } from './MaskedInput.helpers';\nimport { ColorableInputElement } from './ColorableInputElement';\nimport { FixedIMaskInput } from './FixedIMaskInput';\n\nexport interface MaskedProps {\n /** Паттерн маски */\n mask: string;\n /**\n * Символ маски\n *\n * @see См. `imaskProps.placeholderChar`\n * @default _\n */\n maskChar?: Nullable<string>;\n /**\n * Словарь символов-регулярок для маски\n *\n * @see См. `imaskProps.definitions`\n * @default { '9': '[0-9]', 'a': '[A-Za-z]', '*': '[A-Za-z0-9]' }\n */\n formatChars?: Record<string, string>;\n /**\n * Показывать символы маски\n *\n * @see См. `imaskProps.lazy`\n * @default 'focus'\n */\n showMask?: 'always' | 'focus' | 'never';\n /**\n * Обработчик неправильного ввода.\n * Вторым агрументом будет передан метод вспыхивания акцентным цветом.\n *\n * Если обработчик не задан, то инпут вспыхивает по-умолчанию.\n *\n * @param value значение инпута.\n * @param blink вспыхнуть акцентным цвтетом.\n */\n onUnexpectedInput?: (value: string, blink: () => void) => void;\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 MaskedInputProps\n extends MaskedProps,\n Omit<InputProps, 'mask' | 'maxLength' | 'type' | 'alwaysShowMask' | 'onUnexpectedInput'> {\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 showMask = 'focus',\n imaskProps: { onAccept, ...customIMaskProps } = {},\n onValueChange,\n onUnexpectedInput,\n onChange,\n element,\n className,\n ...inputProps\n } = props;\n\n const inputRef = useRef<Input>(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 useImperativeHandle(\n ref,\n () =>\n inputRef.current &&\n Object.assign(inputRef.current, {\n selectAll: inputRef.current.delaySelectAll,\n }),\n [],\n );\n\n useEffect(() => {\n // Для корректной работы onUnexpectedInput надо знать предыдущий value,\n // но imask при монтировании не вызывает onAccept, если value невалиден или laze=false.\n // Поэтому актуальный value при монтировании надо получать вручную\n if (inputRef.current?.input) {\n prevValue.current = inputRef.current.input.value;\n prevSelectionStart.current = inputRef.current.input.selectionStart;\n }\n }, []);\n\n const imaskProps = getCompatibleIMaskProps();\n\n return (\n <Input\n ref={inputRef}\n {...inputProps}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onInput={handleInput}\n onKeyDown={handleKeyDown}\n className={cx(globalClasses.root, uiFontGlobalClasses.root, className)}\n element={\n <ColorableInputElement showOnFocus={false}>\n <FixedIMaskInput {...imaskProps} onAccept={handleAccept} />\n </ColorableInputElement>\n }\n />\n );\n\n function getCompatibleIMaskProps(): IMaskInputProps<HTMLInputElement> {\n const showMaskPlaceholder = showMask === 'always' || (showMask === 'focus' && focused);\n\n return {\n mask: mask.replace(/0/g, '{\\\\0}') as any,\n placeholderChar: getMaskChar(maskChar),\n definitions: getDefinitions(formatChars),\n // FIXME: Должно быть eager=true, но в imask ломается удаление по delete\n eager: 'append',\n overwrite: 'shift',\n lazy: !showMaskPlaceholder,\n ...customIMaskProps,\n } as IMaskInputProps<HTMLInputElement>;\n }\n\n function handleAccept(...args: Parameters<Required<IMaskInputProps<HTMLInputElement>>['onAccept']>) {\n const [value, , e] = args;\n\n // Метод onAccept может вызываться при монтировании, если не задан проп defaultValue.\n // Но нативный input никогда не вызывает onChange при монтировании.\n // Наше событие onValueChange в Input вывается в тех же случаях, что и нативный onChange,\n // поэтому чтобы сохранить консинстентность будем ориентироваться на наличие аргумента e.\n // Он содержит нативное событие, вызвавшее изменение.\n e && onValueChange?.(value);\n !e && (prevValue.current = value);\n\n onAccept?.(...args);\n }\n\n /**\n * Отслеживаем неожиданные нажатия\n * handleAccept не вызывается когда значение с маской не меняется\n * Сначала вызывается handleAccept, затем handleInput\n */\n function handleInput(e: React.ChangeEvent<HTMLInputElement>) {\n const { value, selectionStart } = e.currentTarget;\n\n // При вводе неожиданных символов или удалении каретка может перепрыгивать фиксированные символы.\n // Такие случаи не расцениваем как неожиданный ввод, т.к. пользователь может намеренно их вводить.\n if (prevValue.current === value && selectionStart === prevSelectionStart.current) {\n handleUnexpectedInput(value);\n }\n prevValue.current = value;\n prevSelectionStart.current = selectionStart;\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: string) {\n const blink = inputRef.current?.blink.bind(inputRef.current) || (() => undefined);\n onUnexpectedInput ? onUnexpectedInput(value, blink) : blink();\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n setFocused(false);\n props.onBlur?.(e);\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n const { value, selectionStart, selectionEnd } = e.currentTarget;\n\n if (\n (isKeyBackspace(e) && selectionStart === 0 && selectionEnd === 0) ||\n (isKeyDelete(e) && prevSelectionStart.current === value.length)\n ) {\n // Случаи, когда нажатие клавиш не тригерит `onInput`\n handleUnexpectedInput(value);\n prevValue.current = e.currentTarget.value;\n }\n prevSelectionStart.current = selectionStart;\n\n props.onKeyDown?.(e);\n }\n },\n);\n"]}
@@ -1,73 +1,50 @@
1
1
  #### `mask`
2
2
 
3
- Маска телефона
3
+ Паттерн ввода. Пример с номером телефона.
4
4
 
5
5
  ```jsx harmony
6
- import { Input, Checkbox } from '@skbkontur/react-ui';
7
-
8
- const [value, setValue] = React.useState('123');
9
- const [alwaysShowMask, setAlwaysShowMask] = React.useState(false);
10
-
11
- const listeners = {
12
- ...[
13
- 'onKeyPress',
14
- 'onKeyDown',
15
- 'onFocus',
16
- 'onBlur',
17
- 'onInput',
18
- 'onChange',
19
- 'onCut',
20
- ].reduce((list, item) => ({ ...list, [item]: (e) => console.log(item, e) }), {})
21
- };
6
+ const [value, setValue] = React.useState('');
22
7
 
23
- listeners.onValueChange = (v) => {
24
- console.log('onValue', v);
25
- setValue(v);
26
- };
27
- listeners.onUnexpectedInput = (v, blink) => {
28
- console.log('onUnexpectedInput', v);
29
- blink();
30
- };
8
+ <MaskedInput
9
+ mask="+7 (999) 999-99-99"
10
+ placeholder="Номер телефона"
11
+ value={value}
12
+ onValueChange={setValue}
13
+ />
14
+ ```
15
+
16
+ #### `showMask`
31
17
 
18
+ Способ отображения маски.
19
+
20
+ ```jsx harmony
32
21
  <>
33
- <Checkbox checked={alwaysShowMask} onValueChange={setAlwaysShowMask} />
34
- <MaskedInput
35
- mask="9-9-9-9"
36
- // placeholder="123"
37
- alwaysShowMask={alwaysShowMask}
38
- // alwaysShowMask
39
- // defaultValue="321"
40
- // {...listeners}
41
- />
42
- <MaskedInput
43
- mask="+7 999-999-99-99"
44
- alwaysShowMask={alwaysShowMask}
45
- //value={value}
46
- {...listeners}
47
- />
48
- <Input
49
- mask="+7 999-999-99-99"
50
- alwaysShowMask
51
- value={value}
52
- {...listeners}
53
- />
54
- <Input
55
- value={value}
56
- {...listeners}
57
- />
22
+ <code>always</code>
23
+ <br />
24
+ <MaskedInput mask="+7 (999) 999-99-99" showMask="always" placeholder="Номер телефона" />
25
+ <br />
26
+ <br />
27
+ <code>focus</code>
28
+ <br />
29
+ <MaskedInput mask="+7 (999) 999-99-99" showMask="focus" placeholder="Номер телефона" />
30
+ <br />
31
+ <br />
32
+ <code>never</code>
33
+ <br />
34
+ <MaskedInput mask="+7 (999) 999-99-99" showMask="never" placeholder="Номер телефона" />
58
35
  </>
59
36
  ```
60
37
 
61
38
  #### `maskChar`
62
39
 
63
- может изменить символ значения с маской
40
+ Символом маски может быть любой символ.
64
41
 
65
42
  ```jsx harmony
66
43
  <MaskedInput
67
44
  mask="9999 9999 9999 9999"
68
45
  maskChar="X"
69
46
  placeholder="Номер карты"
70
- alwaysShowMask
47
+ showMask="always"
71
48
  />
72
49
  ```
73
50
 
@@ -82,7 +59,7 @@ const [value, setValue] = React.useState('');
82
59
 
83
60
  <MaskedInput
84
61
  mask="Hh:Mm:Ss"
85
- alwaysShowMask
62
+ showMask="always"
86
63
  formatChars={{
87
64
  H: '[0-2]',
88
65
  h: value.startsWith('2') ? '[0-3]' : '[0-9]',
@@ -96,16 +73,6 @@ const [value, setValue] = React.useState('');
96
73
  />
97
74
  ```
98
75
 
99
- #### `alwaysShowMask`
100
-
101
- Показывает маску всегда. Placeholder в этом случае игнорируется. Логика немного отличается от старой реализации, из-за
102
- специфики iMask. Раньше маска обязательно появлялась при фокусе, но теперь чтобы маску было видно надо явно задать этот
103
- проп.
104
-
105
- ```jsx harmony
106
- <MaskedInput mask="+7 (999) 999-99-99" alwaysShowMask placeholder="Номер телефона" />
107
- ```
108
-
109
76
  #### `imaskProps`*
110
77
 
111
78
  Переопределяет пропы iMask.
@@ -121,18 +88,18 @@ const [value, setValue] = React.useState('');
121
88
  Конвертация пропов выглядит примерно так:
122
89
 
123
90
  ```typescript static
124
- mask: mask.replace(/0/g, '{\\0}'),
91
+ mask: mask.replace(/0/g, '{\\0}'),
125
92
  placeholderChar: props.maskChar || '_',
126
- definitions: props.formatChars || { '9': /[0-9]/, a: /[A-Za-z]/, '*': /[A-Za-z0-9]/ },
127
- eager: true,
128
- overwrite: 'shift',
129
- lazy: !alwaysShowMask,
93
+ definitions: props.formatChars || { '9': /[0-9]/, a: /[A-Za-z]/, '*': /[A-Za-z0-9]/ },
94
+ eager: 'append',
95
+ overwrite: 'shift',
96
+ lazy: !(showMask === 'always' || (showMask === 'focus' && focused)),
130
97
  ...props.imaskProps,
131
98
  ```
132
99
 
133
100
  ---
134
101
 
135
- ##### `imaskProps.unmask`
102
+ #### `imaskProps.unmask`
136
103
 
137
104
  Можно сразу получать value без фиксированных символов маски
138
105
 
@@ -147,66 +114,66 @@ const [value, setValue] = React.useState('');
147
114
  imaskProps={{
148
115
  unmask: true
149
116
  }}
150
- alwaysShowMask
117
+ showMask="always"
151
118
  value={value}
152
119
  onValueChange={setValue}
153
120
  />
154
121
  </>
155
122
  ```
156
123
 
157
- ##### `imaskProps.mask []`
124
+ #### `imaskProps.mask []`
158
125
 
159
- Опциональные части маски
126
+ Опциональные части маски.
160
127
 
161
128
  ```jsx harmony
129
+ import { Checkbox } from '@skbkontur/react-ui';
130
+
162
131
  const [value, setValue] = React.useState('');
163
132
  const [complete, setComplete] = React.useState(false);
164
133
 
165
134
 
166
135
  <MaskedInput
167
136
  mask="99-999999[99]-99"
168
- alwaysShowMask
169
- rightIcon={complete ? '✅' : '⬜'}
137
+ showMask="never"
138
+ placeholder="ИНН"
139
+ rightIcon={<Checkbox checked={complete} style={{ pointerEvents: 'none' }} />}
140
+ onValueChange={setValue}
170
141
  imaskProps={{
171
- onAccept: (v, imask) => {
172
- setValue(v);
173
- setComplete(imask.masked.isComplete);
174
- }
142
+ onAccept: (_, imask) => setComplete(imask.masked.isComplete)
175
143
  }}
176
144
  />
177
145
  ```
178
146
 
179
- ##### `imaskProps.mask {}`
147
+ #### `imaskProps.mask {}`
180
148
 
181
149
  Фиксированные части маски, которые попадут в `value` при `unmask = true`. Любой невалидный символ (например`пробел`)
182
- переведёт каретку за фиксированный символ.
150
+ перекинет каретку за фиксированный символ.
183
151
 
184
152
  ```jsx harmony
153
+ import { Checkbox } from '@skbkontur/react-ui';
154
+
185
155
  const [value, setValue] = React.useState('');
186
156
  const [complete, setComplete] = React.useState(false);
187
157
 
188
-
189
158
  <>
190
159
  <span>unmask value: {value}</span>
191
160
  <br />
192
161
  <MaskedInput
193
162
  mask="aa[aaaaaaaaaaaaaaaaa]{@}aa[aaaaaaaaaaaaaaaaa]{\.}aa[aaaa]"
194
- alwaysShowMask
195
- rightIcon={complete ? '✅' : ''}
163
+ showMask="always"
164
+ rightIcon={<Checkbox checked={complete} style={{ pointerEvents: 'none' }} />}
165
+ onValueChange={setValue}
196
166
  imaskProps={{
197
167
  unmask: true,
198
- onAccept: (v, imask) => {
199
- setValue(v);
200
- setComplete(imask.masked.isComplete);
201
- }
168
+ onAccept: (_, imask) => setComplete(imask.masked.isComplete)
202
169
  }}
203
170
  />
204
171
  </>
205
172
  ```
206
173
 
207
- ##### `imaskProps.blocks`
174
+ #### `imaskProps.blocks`
208
175
 
209
- Пример маски времени. Нажмите цифру `6`, чтобы сработало автозаполнение.
176
+ Пример маски времени с автозаполнением.
210
177
 
211
178
  ```jsx harmony
212
179
  import IMask from 'imask';
@@ -226,6 +193,6 @@ const block = {
226
193
  SS: { ...block, to: 59, },
227
194
  }
228
195
  }}
229
- alwaysShowMask
196
+ showMask="always"
230
197
  />
231
198
  ```
@@ -1,24 +1,13 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3
- var _excluded = ["children", "onInput", "onFocus", "onBlur"];
3
+ var _excluded = ["children", "onInput", "onFocus", "onBlur", "showOnFocus"];
4
4
  import React, { useContext, useEffect, useImperativeHandle, useRef, useCallback, useState } from 'react';
5
5
  import { globalObject, isBrowser } from '@skbkontur/global-object';
6
6
  import debounce from 'lodash.debounce';
7
7
  import { ThemeContext } from "../../../../lib/theming/ThemeContext";
8
8
  import { forwardRefAndName } from "../../../../lib/forwardRefAndName";
9
9
  import { cx } from "../../../../lib/theming/Emotion";
10
- import { globalClasses } from "../ColorableInputElement.styles";
11
- var dictionary = new Map();
12
-
13
- var paintText = function paintText(entries) {
14
- entries.forEach(function (entry) {
15
- var _dictionary$get;
16
-
17
- return (_dictionary$get = dictionary.get(entry.target)) == null ? void 0 : _dictionary$get();
18
- });
19
- };
20
-
21
- var resizeObserver = globalObject.ResizeObserver ? new globalObject.ResizeObserver(debounce(paintText)) : null; // Возможно придётся включить.
10
+ import { globalClasses } from "../ColorableInputElement.styles"; // Возможно придётся включить.
22
11
  // Иногда, на тяжёлых страницах, текст рендерится итеративно.
23
12
  // Из-за этого могут оставаться артефакты при покраске компонента, которые пропадут только после фокуса.
24
13
  // setInterval(() => window.requestAnimationFrame(() => dictionary.forEach((paint) => paint())), 1000);
@@ -39,6 +28,7 @@ export var ColorableInputElement = forwardRefAndName('ColorableInputElement', fu
39
28
  onInput = props.onInput,
40
29
  onFocus = props.onFocus,
41
30
  onBlur = props.onBlur,
31
+ showOnFocus = props.showOnFocus,
42
32
  inputProps = _objectWithoutPropertiesLoose(props, _excluded);
43
33
 
44
34
  useImperativeHandle(ref, function () {
@@ -49,25 +39,11 @@ export var ColorableInputElement = forwardRefAndName('ColorableInputElement', fu
49
39
  }
50
40
  };
51
41
  }, []);
52
- useEffect(function () {
53
- updateActive();
54
-
55
- if (inputRef.current) {
56
- dictionary.set(inputRef.current, debouncedPaintText);
57
- resizeObserver == null ? void 0 : resizeObserver.observe(inputRef.current);
58
- }
59
-
60
- return function () {
61
- if (inputRef.current) {
62
- dictionary["delete"](inputRef.current);
63
- resizeObserver == null ? void 0 : resizeObserver.unobserve(inputRef.current);
64
- }
65
- };
66
- }, []);
42
+ useEffect(updateActive, []);
67
43
  useEffect(function () {
68
44
  activation(props);
69
45
  updateActive();
70
- }, [active, props.showOnFocus, props.value, props.defaultValue, props.disabled, focused.current]);
46
+ }, [active, showOnFocus, props.value, props.defaultValue, props.disabled, focused.current]);
71
47
  useEffect(function () {
72
48
  if (inputRef.current) {
73
49
  inputStyle.current = getComputedStyle(inputRef.current);
@@ -1 +1 @@
1
- {"version":3,"sources":["ColorableInputElement.tsx"],"names":["React","useContext","useEffect","useImperativeHandle","useRef","useCallback","useState","globalObject","isBrowser","debounce","ThemeContext","forwardRefAndName","cx","globalClasses","dictionary","Map","paintText","entries","forEach","entry","get","target","resizeObserver","ResizeObserver","ColorableInputElement","props","ref","inputRef","spanRef","focused","inputStyle","theme","debouncedPaintText","active","setActive","children","onInput","onFocus","onBlur","inputProps","input","current","getRootNode","updateActive","set","observe","unobserve","activation","showOnFocus","value","defaultValue","disabled","getComputedStyle","cloneElement","handleInput","handleFocus","handleBlur","className","visibility","position","whiteSpace","e","isActive","parentElement","querySelector","setTimeout","cancel","style","backgroundImage","classList","remove","_props","add","shadow","shadowRoot","typedValueElement","getElementById","attachShadow","mode","document","createElement","setAttribute","appendChild","textContent","getAttribute","inputRect","getBoundingClientRect","filledRect","threshold","width","degree","fontStyle","typedValueColor","inputTextColor","maskColor","inputPlaceholderColor","inputTextColorDisabled"],"mappings":"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","sourcesContent":["import React, { ForwardedRef, useContext, useEffect, useImperativeHandle, useRef, useCallback, useState } from 'react';\nimport { globalObject, isBrowser } from '@skbkontur/global-object';\nimport debounce from 'lodash.debounce';\n\nimport { ThemeContext } from '../../../lib/theming/ThemeContext';\nimport { InputElement, InputElementProps } from '../../Input';\nimport { forwardRefAndName } from '../../../lib/forwardRefAndName';\nimport { cx } from '../../../lib/theming/Emotion';\n\nimport { globalClasses } from './ColorableInputElement.styles';\n\nexport type ColorableInputElementProps = InputElementProps & {\n showOnFocus?: boolean;\n children: React.ReactElement;\n};\n\nconst dictionary = new Map<Element, () => void>();\nconst paintText: ResizeObserverCallback = (entries) => {\n entries.forEach((entry) => dictionary.get(entry.target)?.());\n};\nconst resizeObserver = globalObject.ResizeObserver ? new globalObject.ResizeObserver(debounce(paintText)) : null;\n\n// Возможно придётся включить.\n// Иногда, на тяжёлых страницах, текст рендерится итеративно.\n// Из-за этого могут оставаться артефакты при покраске компонента, которые пропадут только после фокуса.\n// setInterval(() => window.requestAnimationFrame(() => dictionary.forEach((paint) => paint())), 1000);\n\nexport const ColorableInputElement = forwardRefAndName(\n 'ColorableInputElement',\n function ColorableInputElement(props: ColorableInputElementProps, ref: ForwardedRef<InputElement>) {\n const inputRef = useRef<HTMLInputElement | null>(null);\n const spanRef = useRef<HTMLSpanElement | null>(null);\n const focused = useRef(false);\n const inputStyle = React.useRef<CSSStyleDeclaration>();\n const theme = useContext(ThemeContext);\n const debouncedPaintText = useCallback(debounce(paintText), []);\n const [active, setActive] = useState(true);\n\n const { children, onInput, onFocus, onBlur, ...inputProps } = props;\n\n useImperativeHandle(\n ref,\n () => ({\n input: inputRef.current,\n getRootNode: () => inputRef.current,\n }),\n [],\n );\n\n useEffect(() => {\n updateActive();\n\n if (inputRef.current) {\n dictionary.set(inputRef.current, debouncedPaintText);\n resizeObserver?.observe(inputRef.current);\n }\n\n return () => {\n if (inputRef.current) {\n dictionary.delete(inputRef.current);\n resizeObserver?.unobserve(inputRef.current);\n }\n };\n }, []);\n\n useEffect(() => {\n activation(props);\n updateActive();\n }, [active, props.showOnFocus, props.value, props.defaultValue, props.disabled, focused.current]);\n\n useEffect(() => {\n if (inputRef.current) {\n inputStyle.current = getComputedStyle(inputRef.current);\n }\n });\n\n return (\n <>\n {React.cloneElement(children, {\n ...inputProps,\n onInput: handleInput,\n onFocus: handleFocus,\n onBlur: handleBlur,\n inputRef,\n className: cx(props.className, active && globalClasses.input),\n })}\n {active && <span style={{ visibility: 'hidden', position: 'absolute', whiteSpace: 'pre' }} ref={spanRef} />}\n </>\n );\n\n function handleInput(e: React.ChangeEvent<HTMLInputElement>) {\n const isActive = !inputRef.current?.parentElement?.querySelector(':placeholder-shown');\n setActive(isActive);\n\n activation(props);\n\n onInput?.(e);\n }\n\n function handleFocus(e: React.FocusEvent<HTMLInputElement>) {\n setTimeout(updateActive);\n\n focused.current = true;\n\n onFocus?.(e);\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n updateActive();\n\n focused.current = false;\n\n onBlur?.(e);\n }\n\n function updateActive() {\n setTimeout(() => {\n setActive(!inputRef.current?.parentElement?.querySelector(':placeholder-shown'));\n });\n }\n\n function activation(props: ColorableInputElementProps) {\n if (active) {\n debouncedPaintText(props);\n } else {\n debouncedPaintText.cancel();\n inputRef.current && (inputRef.current.style.backgroundImage = '');\n inputRef.current?.classList.remove(globalClasses.input);\n }\n }\n\n function paintText(_props: Partial<ColorableInputElementProps> = props) {\n if (!spanRef.current || !inputRef.current || !inputStyle.current || !isBrowser(globalObject)) {\n return;\n }\n\n inputRef.current?.classList.add(globalClasses.input);\n\n let shadow = spanRef.current.shadowRoot;\n let typedValueElement = shadow?.getElementById('span');\n\n if (!typedValueElement) {\n shadow = spanRef.current.attachShadow({ mode: 'open' });\n\n typedValueElement = globalObject.document.createElement('span');\n typedValueElement.setAttribute('id', 'span');\n\n shadow.appendChild(typedValueElement);\n }\n\n const style = inputStyle.current;\n\n typedValueElement.textContent = inputRef.current.getAttribute('data-typed-value') || '';\n\n const inputRect = inputRef.current.getBoundingClientRect();\n const filledRect = spanRef.current.getBoundingClientRect();\n\n const threshold = filledRect.width / (inputRect.width / 100);\n const degree = style.fontStyle === 'italic' ? 100 : 90;\n\n let typedValueColor = theme.inputTextColor;\n let maskColor = theme.inputPlaceholderColor;\n if (_props.disabled) {\n typedValueColor = theme.inputTextColorDisabled;\n maskColor = theme.inputTextColorDisabled;\n }\n if (_props.showOnFocus) {\n maskColor = focused.current ? maskColor : 'transparent';\n }\n\n inputRef.current.style.backgroundImage = `\n linear-gradient(\n ${degree}deg,\n ${typedValueColor} ${threshold}%,\n ${maskColor} ${threshold}%\n )`;\n }\n },\n);\n"]}
1
+ {"version":3,"sources":["ColorableInputElement.tsx"],"names":["React","useContext","useEffect","useImperativeHandle","useRef","useCallback","useState","globalObject","isBrowser","debounce","ThemeContext","forwardRefAndName","cx","globalClasses","ColorableInputElement","props","ref","inputRef","spanRef","focused","inputStyle","theme","debouncedPaintText","paintText","active","setActive","children","onInput","onFocus","onBlur","showOnFocus","inputProps","input","current","getRootNode","updateActive","activation","value","defaultValue","disabled","getComputedStyle","cloneElement","handleInput","handleFocus","handleBlur","className","visibility","position","whiteSpace","e","isActive","parentElement","querySelector","setTimeout","cancel","style","backgroundImage","classList","remove","_props","add","shadow","shadowRoot","typedValueElement","getElementById","attachShadow","mode","document","createElement","setAttribute","appendChild","textContent","getAttribute","inputRect","getBoundingClientRect","filledRect","threshold","width","degree","fontStyle","typedValueColor","inputTextColor","maskColor","inputPlaceholderColor","inputTextColorDisabled"],"mappings":"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","sourcesContent":["import React, { ForwardedRef, useContext, useEffect, useImperativeHandle, useRef, useCallback, useState } from 'react';\nimport { globalObject, isBrowser } from '@skbkontur/global-object';\nimport debounce from 'lodash.debounce';\n\nimport { ThemeContext } from '../../../lib/theming/ThemeContext';\nimport { InputElement, InputElementProps } from '../../Input';\nimport { forwardRefAndName } from '../../../lib/forwardRefAndName';\nimport { cx } from '../../../lib/theming/Emotion';\n\nimport { globalClasses } from './ColorableInputElement.styles';\n\nexport type ColorableInputElementProps = InputElementProps & {\n showOnFocus?: boolean;\n children: React.ReactElement;\n};\n\n// Возможно придётся включить.\n// Иногда, на тяжёлых страницах, текст рендерится итеративно.\n// Из-за этого могут оставаться артефакты при покраске компонента, которые пропадут только после фокуса.\n// setInterval(() => window.requestAnimationFrame(() => dictionary.forEach((paint) => paint())), 1000);\n\nexport const ColorableInputElement = forwardRefAndName(\n 'ColorableInputElement',\n function ColorableInputElement(props: ColorableInputElementProps, ref: ForwardedRef<InputElement>) {\n const inputRef = useRef<HTMLInputElement | null>(null);\n const spanRef = useRef<HTMLSpanElement | null>(null);\n const focused = useRef(false);\n const inputStyle = React.useRef<CSSStyleDeclaration>();\n const theme = useContext(ThemeContext);\n const debouncedPaintText = useCallback(debounce(paintText), []);\n const [active, setActive] = useState(true);\n\n const { children, onInput, onFocus, onBlur, showOnFocus, ...inputProps } = props;\n\n useImperativeHandle(\n ref,\n () => ({\n input: inputRef.current,\n getRootNode: () => inputRef.current,\n }),\n [],\n );\n\n useEffect(updateActive, []);\n\n useEffect(() => {\n activation(props);\n updateActive();\n }, [active, showOnFocus, props.value, props.defaultValue, props.disabled, focused.current]);\n\n useEffect(() => {\n if (inputRef.current) {\n inputStyle.current = getComputedStyle(inputRef.current);\n }\n });\n\n return (\n <>\n {React.cloneElement(children, {\n ...inputProps,\n onInput: handleInput,\n onFocus: handleFocus,\n onBlur: handleBlur,\n inputRef,\n className: cx(props.className, active && globalClasses.input),\n })}\n {active && <span style={{ visibility: 'hidden', position: 'absolute', whiteSpace: 'pre' }} ref={spanRef} />}\n </>\n );\n\n function handleInput(e: React.ChangeEvent<HTMLInputElement>) {\n const isActive = !inputRef.current?.parentElement?.querySelector(':placeholder-shown');\n setActive(isActive);\n\n activation(props);\n\n onInput?.(e);\n }\n\n function handleFocus(e: React.FocusEvent<HTMLInputElement>) {\n setTimeout(updateActive);\n\n focused.current = true;\n\n onFocus?.(e);\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n updateActive();\n\n focused.current = false;\n\n onBlur?.(e);\n }\n\n function updateActive() {\n setTimeout(() => {\n setActive(!inputRef.current?.parentElement?.querySelector(':placeholder-shown'));\n });\n }\n\n function activation(props: ColorableInputElementProps) {\n if (active) {\n debouncedPaintText(props);\n } else {\n debouncedPaintText.cancel();\n inputRef.current && (inputRef.current.style.backgroundImage = '');\n inputRef.current?.classList.remove(globalClasses.input);\n }\n }\n\n function paintText(_props: Partial<ColorableInputElementProps> = props) {\n if (!spanRef.current || !inputRef.current || !inputStyle.current || !isBrowser(globalObject)) {\n return;\n }\n\n inputRef.current?.classList.add(globalClasses.input);\n\n let shadow = spanRef.current.shadowRoot;\n let typedValueElement = shadow?.getElementById('span');\n\n if (!typedValueElement) {\n shadow = spanRef.current.attachShadow({ mode: 'open' });\n\n typedValueElement = globalObject.document.createElement('span');\n typedValueElement.setAttribute('id', 'span');\n\n shadow.appendChild(typedValueElement);\n }\n\n const style = inputStyle.current;\n\n typedValueElement.textContent = inputRef.current.getAttribute('data-typed-value') || '';\n\n const inputRect = inputRef.current.getBoundingClientRect();\n const filledRect = spanRef.current.getBoundingClientRect();\n\n const threshold = filledRect.width / (inputRect.width / 100);\n const degree = style.fontStyle === 'italic' ? 100 : 90;\n\n let typedValueColor = theme.inputTextColor;\n let maskColor = theme.inputPlaceholderColor;\n if (_props.disabled) {\n typedValueColor = theme.inputTextColorDisabled;\n maskColor = theme.inputTextColorDisabled;\n }\n if (_props.showOnFocus) {\n maskColor = focused.current ? maskColor : 'transparent';\n }\n\n inputRef.current.style.backgroundImage = `\n linear-gradient(\n ${degree}deg,\n ${typedValueColor} ${threshold}%,\n ${maskColor} ${threshold}%\n )`;\n }\n },\n);\n"]}
@@ -6,4 +6,4 @@ import { injectGlobal, prefix } from "../../../../lib/theming/Emotion";
6
6
  export var globalClasses = prefix('colorable')({
7
7
  input: 'input'
8
8
  });
9
- injectGlobal(_templateObject || (_templateObject = _taggedTemplateLiteralLoose(["\n input.", " {\n display: inline-block;\n background-color: transparent;\n background-size: 100%;\n background-repeat: repeat;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n\n transition: background-color 1s;\n }\n"])), globalClasses.input);
9
+ injectGlobal(_templateObject || (_templateObject = _taggedTemplateLiteralLoose(["\n input.", " {\n display: inline-block;\n background-color: transparent;\n background-size: 100%;\n background-repeat: repeat;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n"])), globalClasses.input);
@@ -1 +1 @@
1
- {"version":3,"sources":["ColorableInputElement.styles.ts"],"names":["injectGlobal","prefix","globalClasses","input"],"mappings":"oHAAA,SAASA,YAAT,EAAuBC,MAAvB,QAAqC,8BAArC;;AAEA,OAAO,IAAMC,aAAa,GAAGD,MAAM,CAAC,WAAD,CAAN,CAAoB;AAC/CE,EAAAA,KAAK,EAAE,OADwC,EAApB,CAAtB;;;AAIPH,YAAY;AACFE,aAAa,CAACC,KADZ,CAAZ","sourcesContent":["import { injectGlobal, prefix } from '../../../lib/theming/Emotion';\n\nexport const globalClasses = prefix('colorable')({\n input: 'input',\n});\n\ninjectGlobal`\n input.${globalClasses.input} {\n display: inline-block;\n background-color: transparent;\n background-size: 100%;\n background-repeat: repeat;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n\n transition: background-color 1s;\n }\n`;\n"]}
1
+ {"version":3,"sources":["ColorableInputElement.styles.ts"],"names":["injectGlobal","prefix","globalClasses","input"],"mappings":"oHAAA,SAASA,YAAT,EAAuBC,MAAvB,QAAqC,8BAArC;;AAEA,OAAO,IAAMC,aAAa,GAAGD,MAAM,CAAC,WAAD,CAAN,CAAoB;AAC/CE,EAAAA,KAAK,EAAE,OADwC,EAApB,CAAtB;;;AAIPH,YAAY;AACFE,aAAa,CAACC,KADZ,CAAZ","sourcesContent":["import { injectGlobal, prefix } from '../../../lib/theming/Emotion';\n\nexport const globalClasses = prefix('colorable')({\n input: 'input',\n});\n\ninjectGlobal`\n input.${globalClasses.input} {\n display: inline-block;\n background-color: transparent;\n background-size: 100%;\n background-repeat: repeat;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n`;\n"]}
@@ -1,7 +1,7 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3
3
  var _excluded = ["onAccept"],
4
- _excluded2 = ["mask", "maskChar", "formatChars", "alwaysShowMask", "imaskProps", "onValueChange", "onUnexpectedInput", "onChange", "element", "className"];
4
+ _excluded2 = ["mask", "maskChar", "formatChars", "showMask", "imaskProps", "onValueChange", "onUnexpectedInput", "onChange", "element", "className"];
5
5
  import React, { useImperativeHandle, useRef, useState, useEffect } from 'react';
6
6
  import { forwardRefAndName } from "../../../lib/forwardRefAndName";
7
7
  import { cx } from "../../../lib/theming/Emotion";
@@ -21,7 +21,8 @@ export var MaskedInput = forwardRefAndName('MaskedInput', function MaskedInput(p
21
21
  var mask = props.mask,
22
22
  maskChar = props.maskChar,
23
23
  formatChars = props.formatChars,
24
- alwaysShowMask = props.alwaysShowMask,
24
+ _props$showMask = props.showMask,
25
+ showMask = _props$showMask === void 0 ? 'focus' : _props$showMask,
25
26
  _props$imaskProps = props.imaskProps;
26
27
  _props$imaskProps = _props$imaskProps === void 0 ? {} : _props$imaskProps;
27
28
 
@@ -68,13 +69,14 @@ export var MaskedInput = forwardRefAndName('MaskedInput', function MaskedInput(p
68
69
  onKeyDown: handleKeyDown,
69
70
  className: cx(globalClasses.root, uiFontGlobalClasses.root, className),
70
71
  element: /*#__PURE__*/React.createElement(ColorableInputElement, {
71
- showOnFocus: !alwaysShowMask
72
+ showOnFocus: false
72
73
  }, /*#__PURE__*/React.createElement(FixedIMaskInput, _extends({}, imaskProps, {
73
74
  onAccept: handleAccept
74
75
  })))
75
76
  }));
76
77
 
77
78
  function getCompatibleIMaskProps() {
79
+ var showMaskPlaceholder = showMask === 'always' || showMask === 'focus' && focused;
78
80
  return _extends({
79
81
  mask: mask.replace(/0/g, '{\\0}'),
80
82
  placeholderChar: getMaskChar(maskChar),
@@ -82,7 +84,7 @@ export var MaskedInput = forwardRefAndName('MaskedInput', function MaskedInput(p
82
84
  // FIXME: Должно быть eager=true, но в imask ломается удаление по delete
83
85
  eager: 'append',
84
86
  overwrite: 'shift',
85
- lazy: !alwaysShowMask && (props.disabled || !focused)
87
+ lazy: !showMaskPlaceholder
86
88
  }, customIMaskProps);
87
89
  }
88
90
 
@@ -152,15 +154,16 @@ export var MaskedInput = forwardRefAndName('MaskedInput', function MaskedInput(p
152
154
  function handleKeyDown(e) {
153
155
  var _e$currentTarget2 = e.currentTarget,
154
156
  value = _e$currentTarget2.value,
155
- selectionStart = _e$currentTarget2.selectionStart;
156
- prevSelectionStart.current = selectionStart;
157
+ selectionStart = _e$currentTarget2.selectionStart,
158
+ selectionEnd = _e$currentTarget2.selectionEnd;
157
159
 
158
- if (isKeyBackspace(e) && prevSelectionStart.current === 0 || isKeyDelete(e) && prevSelectionStart.current === value.length) {
160
+ if (isKeyBackspace(e) && selectionStart === 0 && selectionEnd === 0 || isKeyDelete(e) && prevSelectionStart.current === value.length) {
159
161
  // Случаи, когда нажатие клавиш не тригерит `onInput`
160
162
  handleUnexpectedInput(value);
161
163
  prevValue.current = e.currentTarget.value;
162
164
  }
163
165
 
166
+ prevSelectionStart.current = selectionStart;
164
167
  props.onKeyDown == null ? void 0 : props.onKeyDown(e);
165
168
  }
166
169
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["MaskedInput.tsx"],"names":["React","useImperativeHandle","useRef","useState","useEffect","forwardRefAndName","cx","uiFontGlobalClasses","Input","isKeyBackspace","isKeyDelete","globalClasses","getDefinitions","getMaskChar","ColorableInputElement","FixedIMaskInput","MaskedInput","props","ref","mask","maskChar","formatChars","alwaysShowMask","imaskProps","onAccept","customIMaskProps","onValueChange","onUnexpectedInput","onChange","element","className","inputProps","inputRef","focused","setFocused","prevValue","value","String","defaultValue","prevSelectionStart","current","Object","assign","selectAll","delaySelectAll","input","selectionStart","getCompatibleIMaskProps","handleFocus","handleBlur","handleInput","handleKeyDown","root","handleAccept","replace","placeholderChar","definitions","eager","overwrite","lazy","disabled","args","e","currentTarget","handleUnexpectedInput","onInput","onFocus","selectAllOnFocus","blink","bind","undefined","onBlur","length","onKeyDown"],"mappings":"sVAAA,OAAOA,KAAP,IAAqBC,mBAArB,EAA0CC,MAA1C,EAAkDC,QAAlD,EAA4DC,SAA5D,QAA6E,OAA7E;;;;AAIA,SAASC,iBAAT,QAAkC,6BAAlC;AACA,SAASC,EAAT,QAAmB,2BAAnB;AACA,SAASC,mBAAT,QAAoC,yBAApC;AACA,SAASC,KAAT,QAA6C,UAA7C;AACA,SAASC,cAAT,EAAyBC,WAAzB,QAA4C,uCAA5C;;AAEA,SAASC,aAAT,QAA8B,sBAA9B;AACA,SAASC,cAAT,EAAyBC,WAAzB,QAA4C,uBAA5C;AACA,SAASC,qBAAT,QAAsC,yBAAtC;AACA,SAASC,eAAT,QAAgC,mBAAhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA;AACA;AACA;AACA;AACA,OAAO,IAAMC,WAAW,GAAGX,iBAAiB;AAC1C,aAD0C;AAE1C,SAASW,WAAT,CAAqBC,KAArB,EAA8CC,GAA9C,EAAsE;AACpE;AACEC,EAAAA,IADF;;;;;;;;;;;AAYIF,EAAAA,KAZJ,CACEE,IADF,CAEEC,QAFF,GAYIH,KAZJ,CAEEG,QAFF,CAGEC,WAHF,GAYIJ,KAZJ,CAGEI,WAHF,CAIEC,cAJF,GAYIL,KAZJ,CAIEK,cAJF,qBAYIL,KAZJ,CAKEM,UALF,oDAKkD,EALlD,yBAKgBC,QALhB,qBAKgBA,QALhB,CAK6BC,gBAL7B,+DAMEC,aANF,GAYIT,KAZJ,CAMES,aANF,CAOEC,iBAPF,GAYIV,KAZJ,CAOEU,iBAPF,CAQEC,QARF,GAYIX,KAZJ,CAQEW,QARF,CASEC,OATF,GAYIZ,KAZJ,CASEY,OATF,CAUEC,SAVF,GAYIb,KAZJ,CAUEa,SAVF,CAWKC,UAXL,iCAYId,KAZJ;;AAcA,MAAMe,QAAQ,GAAG9B,MAAM,CAAQ,IAAR,CAAvB;;AAEA,kBAA8BC,QAAQ,CAAC,KAAD,CAAtC,CAAO8B,OAAP,gBAAgBC,UAAhB;AACA,MAAMC,SAAS,GAAGjC,MAAM,CAASe,KAAK,CAACmB,KAAN,IAAeC,MAAM,CAACpB,KAAK,CAACqB,YAAP,CAArB,IAA6C,EAAtD,CAAxB;AACA,MAAMC,kBAAkB,GAAGrC,MAAM,CAAgB,IAAhB,CAAjC;;AAEAD,EAAAA,mBAAmB;AACjBiB,EAAAA,GADiB;AAEjB;AACEc,MAAAA,QAAQ,CAACQ,OAAT;AACAC,MAAAA,MAAM,CAACC,MAAP,CAAcV,QAAQ,CAACQ,OAAvB,EAAgC;AAC9BG,QAAAA,SAAS,EAAEX,QAAQ,CAACQ,OAAT,CAAiBI,cADE,EAAhC,CAFF,GAFiB;;AAOjB,IAPiB,CAAnB;;;AAUAxC,EAAAA,SAAS,CAAC,YAAM;AACd;AACA;AACA;AACA,6BAAI4B,QAAQ,CAACQ,OAAb,aAAI,kBAAkBK,KAAtB,EAA6B;AAC3BV,MAAAA,SAAS,CAACK,OAAV,GAAoBR,QAAQ,CAACQ,OAAT,CAAiBK,KAAjB,CAAuBT,KAA3C;AACAG,MAAAA,kBAAkB,CAACC,OAAnB,GAA6BR,QAAQ,CAACQ,OAAT,CAAiBK,KAAjB,CAAuBC,cAApD;AACD;AACF,GARQ,EAQN,EARM,CAAT;;AAUA,MAAMvB,UAAU,GAAGwB,uBAAuB,EAA1C;;AAEA;AACE,wBAAC,KAAD;AACE,MAAA,GAAG,EAAEf,QADP;AAEMD,IAAAA,UAFN;AAGE,MAAA,OAAO,EAAEiB,WAHX;AAIE,MAAA,MAAM,EAAEC,UAJV;AAKE,MAAA,OAAO,EAAEC,WALX;AAME,MAAA,SAAS,EAAEC,aANb;AAOE,MAAA,SAAS,EAAE7C,EAAE,CAACK,aAAa,CAACyC,IAAf,EAAqB7C,mBAAmB,CAAC6C,IAAzC,EAA+CtB,SAA/C,CAPf;AAQE,MAAA,OAAO;AACL,0BAAC,qBAAD,IAAuB,WAAW,EAAE,CAACR,cAArC;AACE,0BAAC,eAAD,eAAqBC,UAArB,IAAiC,QAAQ,EAAE8B,YAA3C,IADF,CATJ,IADF;;;;;;AAiBA,WAASN,uBAAT,GAAsE;AACpE;AACE5B,MAAAA,IAAI,EAAEA,IAAI,CAACmC,OAAL,CAAa,IAAb,EAAmB,OAAnB,CADR;AAEEC,MAAAA,eAAe,EAAE1C,WAAW,CAACO,QAAD,CAF9B;AAGEoC,MAAAA,WAAW,EAAE5C,cAAc,CAACS,WAAD,CAH7B;AAIE;AACAoC,MAAAA,KAAK,EAAE,QALT;AAMEC,MAAAA,SAAS,EAAE,OANb;AAOEC,MAAAA,IAAI,EAAE,CAACrC,cAAD,KAAoBL,KAAK,CAAC2C,QAAN,IAAkB,CAAC3B,OAAvC,CAPR;AAQKR,IAAAA,gBARL;;AAUD;;AAED,WAAS4B,YAAT,GAAoG,mCAA3EQ,IAA2E,oDAA3EA,IAA2E;AAClG,QAAOzB,KAAP,GAAqByB,IAArB,IAAgBC,CAAhB,GAAqBD,IAArB;;AAEA;AACA;AACA;AACA;AACA;AACAC,IAAAA,CAAC,KAAIpC,aAAJ,oBAAIA,aAAa,CAAGU,KAAH,CAAjB,CAAD;AACA,KAAC0B,CAAD,KAAO3B,SAAS,CAACK,OAAV,GAAoBJ,KAA3B;;AAEAZ,IAAAA,QAAQ,QAAR,YAAAA,QAAQ,MAAR,SAAcqC,IAAd;AACD;;AAED;AACJ;AACA;AACA;AACA;AACI,WAASX,WAAT,CAAqBY,CAArB,EAA6D;AAC3D,2BAAkCA,CAAC,CAACC,aAApC,CAAQ3B,KAAR,oBAAQA,KAAR,CAAeU,cAAf,oBAAeA,cAAf;;AAEA;AACA;AACA,QAAIX,SAAS,CAACK,OAAV,KAAsBJ,KAAtB,IAA+BU,cAAc,KAAKP,kBAAkB,CAACC,OAAzE,EAAkF;AAChFwB,MAAAA,qBAAqB,CAAC5B,KAAD,CAArB;AACD;AACDD,IAAAA,SAAS,CAACK,OAAV,GAAoBJ,KAApB;AACAG,IAAAA,kBAAkB,CAACC,OAAnB,GAA6BM,cAA7B;;AAEA7B,IAAAA,KAAK,CAACgD,OAAN,oBAAAhD,KAAK,CAACgD,OAAN,CAAgBH,CAAhB;AACD;;AAED,WAASd,WAAT,CAAqBc,CAArB,EAA4D;AAC1D5B,IAAAA,UAAU,CAAC,IAAD,CAAV;AACAjB,IAAAA,KAAK,CAACiD,OAAN,oBAAAjD,KAAK,CAACiD,OAAN,CAAgBJ,CAAhB;;AAEA;AACA;AACA7C,IAAAA,KAAK,CAACkD,gBAAN,2BAA0BnC,QAAQ,CAACQ,OAAnC,qBAA0B,mBAAkBI,cAAlB,EAA1B;AACD;;AAED,WAASoB,qBAAT,CAA+B5B,KAA/B,EAA8C;AAC5C,QAAMgC,KAAK,GAAG,uBAAApC,QAAQ,CAACQ,OAAT,wCAAkB4B,KAAlB,CAAwBC,IAAxB,CAA6BrC,QAAQ,CAACQ,OAAtC,MAAmD,oBAAM8B,SAAN,EAAjE;AACA3C,IAAAA,iBAAiB,GAAGA,iBAAiB,CAACS,KAAD,EAAQgC,KAAR,CAApB,GAAqCA,KAAK,EAA3D;AACD;;AAED,WAASnB,UAAT,CAAoBa,CAApB,EAA2D;AACzD5B,IAAAA,UAAU,CAAC,KAAD,CAAV;AACAjB,IAAAA,KAAK,CAACsD,MAAN,oBAAAtD,KAAK,CAACsD,MAAN,CAAeT,CAAf;AACD;;AAED,WAASX,aAAT,CAAuBW,CAAvB,EAAiE;AAC/D,4BAAkCA,CAAC,CAACC,aAApC,CAAQ3B,KAAR,qBAAQA,KAAR,CAAeU,cAAf,qBAAeA,cAAf;;AAEAP,IAAAA,kBAAkB,CAACC,OAAnB,GAA6BM,cAA7B;;AAEA;AACGrC,IAAAA,cAAc,CAACqD,CAAD,CAAd,IAAqBvB,kBAAkB,CAACC,OAAnB,KAA+B,CAArD;AACC9B,IAAAA,WAAW,CAACoD,CAAD,CAAX,IAAkBvB,kBAAkB,CAACC,OAAnB,KAA+BJ,KAAK,CAACoC,MAF1D;AAGE;AACA;AACAR,MAAAA,qBAAqB,CAAC5B,KAAD,CAArB;AACAD,MAAAA,SAAS,CAACK,OAAV,GAAoBsB,CAAC,CAACC,aAAF,CAAgB3B,KAApC;AACD;;AAEDnB,IAAAA,KAAK,CAACwD,SAAN,oBAAAxD,KAAK,CAACwD,SAAN,CAAkBX,CAAlB;AACD;AACF,CA/IyC,CAArC","sourcesContent":["import React, { Ref, useImperativeHandle, useRef, useState, useEffect } from 'react';\nimport { IMaskInputProps } from 'react-imask';\n\nimport { Nullable } from '../../typings/utility-types';\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 } from '../../lib/events/keyboard/identifiers';\n\nimport { globalClasses } from './MaskedInput.styles';\nimport { getDefinitions, getMaskChar } from './MaskedInput.helpers';\nimport { ColorableInputElement } from './ColorableInputElement';\nimport { FixedIMaskInput } from './FixedIMaskInput';\n\nexport interface MaskedProps {\n /** Паттерн маски */\n mask: string;\n /**\n * Символ маски\n *\n * @see См. `imaskProps.placeholderChar`\n * @default _\n */\n maskChar?: Nullable<string>;\n /**\n * Словарь символов-регулярок для маски\n *\n * @see См. `imaskProps.definitions`\n * @default { '9': '[0-9]', 'a': '[A-Za-z]', '*': '[A-Za-z0-9]' }\n */\n formatChars?: Record<string, string>;\n /**\n * Всегда показывать символы маски\n *\n * @see См. `imaskProps.lazy`\n * @default false\n */\n alwaysShowMask?: boolean;\n /**\n * Обработчик неправильного ввода.\n * Вторым агрументом будет передан метод вспыхивания акцентным цветом.\n *\n * Если обработчик не задан, то инпут вспыхивает по-умолчанию.\n *\n * @param value значение инпута.\n * @param blink вспыхнуть акцентным цвтетом.\n */\n onUnexpectedInput?: (value: string, blink: () => void) => void;\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 MaskedInputProps\n extends MaskedProps,\n Omit<InputProps, 'mask' | 'maxLength' | 'type' | 'alwaysShowMask' | 'onUnexpectedInput'> {\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 onValueChange,\n onUnexpectedInput,\n onChange,\n element,\n className,\n ...inputProps\n } = props;\n\n const inputRef = useRef<Input>(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 useImperativeHandle(\n ref,\n () =>\n inputRef.current &&\n Object.assign(inputRef.current, {\n selectAll: inputRef.current.delaySelectAll,\n }),\n [],\n );\n\n useEffect(() => {\n // Для корректной работы onUnexpectedInput надо знать предыдущий value,\n // но imask при монтировании не вызывает onAccept, если value невалиден или laze=false.\n // Поэтому актуальный value при монтировании надо получать вручную\n if (inputRef.current?.input) {\n prevValue.current = inputRef.current.input.value;\n prevSelectionStart.current = inputRef.current.input.selectionStart;\n }\n }, []);\n\n const imaskProps = getCompatibleIMaskProps();\n\n return (\n <Input\n ref={inputRef}\n {...inputProps}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onInput={handleInput}\n onKeyDown={handleKeyDown}\n className={cx(globalClasses.root, uiFontGlobalClasses.root, className)}\n element={\n <ColorableInputElement showOnFocus={!alwaysShowMask}>\n <FixedIMaskInput {...imaskProps} onAccept={handleAccept} />\n </ColorableInputElement>\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 // FIXME: Должно быть eager=true, но в imask ломается удаление по delete\n eager: 'append',\n overwrite: 'shift',\n lazy: !alwaysShowMask && (props.disabled || !focused),\n ...customIMaskProps,\n } as IMaskInputProps<HTMLInputElement>;\n }\n\n function handleAccept(...args: Parameters<Required<IMaskInputProps<HTMLInputElement>>['onAccept']>) {\n const [value, , e] = args;\n\n // Метод onAccept может вызываться при монтировании, если не задан проп defaultValue.\n // Но нативный input никогда не вызывает onChange при монтировании.\n // Наше событие onValueChange в Input вывается в тех же случаях, что и нативный onChange,\n // поэтому чтобы сохранить консинстентность будем ориентироваться на наличие аргумента e.\n // Он содержит нативное событие, вызвавшее изменение.\n e && onValueChange?.(value);\n !e && (prevValue.current = value);\n\n onAccept?.(...args);\n }\n\n /**\n * Отслеживаем неожиданные нажатия\n * handleAccept не вызывается когда значение с маской не меняется\n * Сначала вызывается handleAccept, затем handleInput\n */\n function handleInput(e: React.ChangeEvent<HTMLInputElement>) {\n const { value, selectionStart } = e.currentTarget;\n\n // При вводе неожиданных символов или удалении каретка может перепрыгивать фиксированные символы.\n // Такие случаи не расцениваем как неожиданный ввод, т.к. пользователь может намеренно их вводить.\n if (prevValue.current === value && selectionStart === prevSelectionStart.current) {\n handleUnexpectedInput(value);\n }\n prevValue.current = value;\n prevSelectionStart.current = selectionStart;\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: string) {\n const blink = inputRef.current?.blink.bind(inputRef.current) || (() => undefined);\n onUnexpectedInput ? onUnexpectedInput(value, blink) : blink();\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n setFocused(false);\n props.onBlur?.(e);\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n const { value, selectionStart } = e.currentTarget;\n\n prevSelectionStart.current = selectionStart;\n\n if (\n (isKeyBackspace(e) && prevSelectionStart.current === 0) ||\n (isKeyDelete(e) && prevSelectionStart.current === value.length)\n ) {\n // Случаи, когда нажатие клавиш не тригерит `onInput`\n handleUnexpectedInput(value);\n prevValue.current = e.currentTarget.value;\n }\n\n props.onKeyDown?.(e);\n }\n },\n);\n"]}
1
+ {"version":3,"sources":["MaskedInput.tsx"],"names":["React","useImperativeHandle","useRef","useState","useEffect","forwardRefAndName","cx","uiFontGlobalClasses","Input","isKeyBackspace","isKeyDelete","globalClasses","getDefinitions","getMaskChar","ColorableInputElement","FixedIMaskInput","MaskedInput","props","ref","mask","maskChar","formatChars","showMask","imaskProps","onAccept","customIMaskProps","onValueChange","onUnexpectedInput","onChange","element","className","inputProps","inputRef","focused","setFocused","prevValue","value","String","defaultValue","prevSelectionStart","current","Object","assign","selectAll","delaySelectAll","input","selectionStart","getCompatibleIMaskProps","handleFocus","handleBlur","handleInput","handleKeyDown","root","handleAccept","showMaskPlaceholder","replace","placeholderChar","definitions","eager","overwrite","lazy","args","e","currentTarget","handleUnexpectedInput","onInput","onFocus","selectAllOnFocus","blink","bind","undefined","onBlur","selectionEnd","length","onKeyDown"],"mappings":"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","sourcesContent":["import React, { Ref, useImperativeHandle, useRef, useState, useEffect } from 'react';\nimport { IMaskInputProps } from 'react-imask';\n\nimport { Nullable } from '../../typings/utility-types';\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 } from '../../lib/events/keyboard/identifiers';\n\nimport { globalClasses } from './MaskedInput.styles';\nimport { getDefinitions, getMaskChar } from './MaskedInput.helpers';\nimport { ColorableInputElement } from './ColorableInputElement';\nimport { FixedIMaskInput } from './FixedIMaskInput';\n\nexport interface MaskedProps {\n /** Паттерн маски */\n mask: string;\n /**\n * Символ маски\n *\n * @see См. `imaskProps.placeholderChar`\n * @default _\n */\n maskChar?: Nullable<string>;\n /**\n * Словарь символов-регулярок для маски\n *\n * @see См. `imaskProps.definitions`\n * @default { '9': '[0-9]', 'a': '[A-Za-z]', '*': '[A-Za-z0-9]' }\n */\n formatChars?: Record<string, string>;\n /**\n * Показывать символы маски\n *\n * @see См. `imaskProps.lazy`\n * @default 'focus'\n */\n showMask?: 'always' | 'focus' | 'never';\n /**\n * Обработчик неправильного ввода.\n * Вторым агрументом будет передан метод вспыхивания акцентным цветом.\n *\n * Если обработчик не задан, то инпут вспыхивает по-умолчанию.\n *\n * @param value значение инпута.\n * @param blink вспыхнуть акцентным цвтетом.\n */\n onUnexpectedInput?: (value: string, blink: () => void) => void;\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 MaskedInputProps\n extends MaskedProps,\n Omit<InputProps, 'mask' | 'maxLength' | 'type' | 'alwaysShowMask' | 'onUnexpectedInput'> {\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 showMask = 'focus',\n imaskProps: { onAccept, ...customIMaskProps } = {},\n onValueChange,\n onUnexpectedInput,\n onChange,\n element,\n className,\n ...inputProps\n } = props;\n\n const inputRef = useRef<Input>(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 useImperativeHandle(\n ref,\n () =>\n inputRef.current &&\n Object.assign(inputRef.current, {\n selectAll: inputRef.current.delaySelectAll,\n }),\n [],\n );\n\n useEffect(() => {\n // Для корректной работы onUnexpectedInput надо знать предыдущий value,\n // но imask при монтировании не вызывает onAccept, если value невалиден или laze=false.\n // Поэтому актуальный value при монтировании надо получать вручную\n if (inputRef.current?.input) {\n prevValue.current = inputRef.current.input.value;\n prevSelectionStart.current = inputRef.current.input.selectionStart;\n }\n }, []);\n\n const imaskProps = getCompatibleIMaskProps();\n\n return (\n <Input\n ref={inputRef}\n {...inputProps}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onInput={handleInput}\n onKeyDown={handleKeyDown}\n className={cx(globalClasses.root, uiFontGlobalClasses.root, className)}\n element={\n <ColorableInputElement showOnFocus={false}>\n <FixedIMaskInput {...imaskProps} onAccept={handleAccept} />\n </ColorableInputElement>\n }\n />\n );\n\n function getCompatibleIMaskProps(): IMaskInputProps<HTMLInputElement> {\n const showMaskPlaceholder = showMask === 'always' || (showMask === 'focus' && focused);\n\n return {\n mask: mask.replace(/0/g, '{\\\\0}') as any,\n placeholderChar: getMaskChar(maskChar),\n definitions: getDefinitions(formatChars),\n // FIXME: Должно быть eager=true, но в imask ломается удаление по delete\n eager: 'append',\n overwrite: 'shift',\n lazy: !showMaskPlaceholder,\n ...customIMaskProps,\n } as IMaskInputProps<HTMLInputElement>;\n }\n\n function handleAccept(...args: Parameters<Required<IMaskInputProps<HTMLInputElement>>['onAccept']>) {\n const [value, , e] = args;\n\n // Метод onAccept может вызываться при монтировании, если не задан проп defaultValue.\n // Но нативный input никогда не вызывает onChange при монтировании.\n // Наше событие onValueChange в Input вывается в тех же случаях, что и нативный onChange,\n // поэтому чтобы сохранить консинстентность будем ориентироваться на наличие аргумента e.\n // Он содержит нативное событие, вызвавшее изменение.\n e && onValueChange?.(value);\n !e && (prevValue.current = value);\n\n onAccept?.(...args);\n }\n\n /**\n * Отслеживаем неожиданные нажатия\n * handleAccept не вызывается когда значение с маской не меняется\n * Сначала вызывается handleAccept, затем handleInput\n */\n function handleInput(e: React.ChangeEvent<HTMLInputElement>) {\n const { value, selectionStart } = e.currentTarget;\n\n // При вводе неожиданных символов или удалении каретка может перепрыгивать фиксированные символы.\n // Такие случаи не расцениваем как неожиданный ввод, т.к. пользователь может намеренно их вводить.\n if (prevValue.current === value && selectionStart === prevSelectionStart.current) {\n handleUnexpectedInput(value);\n }\n prevValue.current = value;\n prevSelectionStart.current = selectionStart;\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: string) {\n const blink = inputRef.current?.blink.bind(inputRef.current) || (() => undefined);\n onUnexpectedInput ? onUnexpectedInput(value, blink) : blink();\n }\n\n function handleBlur(e: React.FocusEvent<HTMLInputElement>) {\n setFocused(false);\n props.onBlur?.(e);\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n const { value, selectionStart, selectionEnd } = e.currentTarget;\n\n if (\n (isKeyBackspace(e) && selectionStart === 0 && selectionEnd === 0) ||\n (isKeyDelete(e) && prevSelectionStart.current === value.length)\n ) {\n // Случаи, когда нажатие клавиш не тригерит `onInput`\n handleUnexpectedInput(value);\n prevValue.current = e.currentTarget.value;\n }\n prevSelectionStart.current = selectionStart;\n\n props.onKeyDown?.(e);\n }\n },\n);\n"]}
@@ -19,12 +19,12 @@ export interface MaskedProps {
19
19
  */
20
20
  formatChars?: Record<string, string>;
21
21
  /**
22
- * Всегда показывать символы маски
22
+ * Показывать символы маски
23
23
  *
24
24
  * @see См. `imaskProps.lazy`
25
- * @default false
25
+ * @default 'focus'
26
26
  */
27
- alwaysShowMask?: boolean;
27
+ showMask?: 'always' | 'focus' | 'never';
28
28
  /**
29
29
  * Обработчик неправильного ввода.
30
30
  * Вторым агрументом будет передан метод вспыхивания акцентным цветом.
@@ -1,73 +1,50 @@
1
1
  #### `mask`
2
2
 
3
- Маска телефона
3
+ Паттерн ввода. Пример с номером телефона.
4
4
 
5
5
  ```jsx harmony
6
- import { Input, Checkbox } from '@skbkontur/react-ui';
7
-
8
- const [value, setValue] = React.useState('123');
9
- const [alwaysShowMask, setAlwaysShowMask] = React.useState(false);
10
-
11
- const listeners = {
12
- ...[
13
- 'onKeyPress',
14
- 'onKeyDown',
15
- 'onFocus',
16
- 'onBlur',
17
- 'onInput',
18
- 'onChange',
19
- 'onCut',
20
- ].reduce((list, item) => ({ ...list, [item]: (e) => console.log(item, e) }), {})
21
- };
6
+ const [value, setValue] = React.useState('');
22
7
 
23
- listeners.onValueChange = (v) => {
24
- console.log('onValue', v);
25
- setValue(v);
26
- };
27
- listeners.onUnexpectedInput = (v, blink) => {
28
- console.log('onUnexpectedInput', v);
29
- blink();
30
- };
8
+ <MaskedInput
9
+ mask="+7 (999) 999-99-99"
10
+ placeholder="Номер телефона"
11
+ value={value}
12
+ onValueChange={setValue}
13
+ />
14
+ ```
15
+
16
+ #### `showMask`
31
17
 
18
+ Способ отображения маски.
19
+
20
+ ```jsx harmony
32
21
  <>
33
- <Checkbox checked={alwaysShowMask} onValueChange={setAlwaysShowMask} />
34
- <MaskedInput
35
- mask="9-9-9-9"
36
- // placeholder="123"
37
- alwaysShowMask={alwaysShowMask}
38
- // alwaysShowMask
39
- // defaultValue="321"
40
- // {...listeners}
41
- />
42
- <MaskedInput
43
- mask="+7 999-999-99-99"
44
- alwaysShowMask={alwaysShowMask}
45
- //value={value}
46
- {...listeners}
47
- />
48
- <Input
49
- mask="+7 999-999-99-99"
50
- alwaysShowMask
51
- value={value}
52
- {...listeners}
53
- />
54
- <Input
55
- value={value}
56
- {...listeners}
57
- />
22
+ <code>always</code>
23
+ <br />
24
+ <MaskedInput mask="+7 (999) 999-99-99" showMask="always" placeholder="Номер телефона" />
25
+ <br />
26
+ <br />
27
+ <code>focus</code>
28
+ <br />
29
+ <MaskedInput mask="+7 (999) 999-99-99" showMask="focus" placeholder="Номер телефона" />
30
+ <br />
31
+ <br />
32
+ <code>never</code>
33
+ <br />
34
+ <MaskedInput mask="+7 (999) 999-99-99" showMask="never" placeholder="Номер телефона" />
58
35
  </>
59
36
  ```
60
37
 
61
38
  #### `maskChar`
62
39
 
63
- может изменить символ значения с маской
40
+ Символом маски может быть любой символ.
64
41
 
65
42
  ```jsx harmony
66
43
  <MaskedInput
67
44
  mask="9999 9999 9999 9999"
68
45
  maskChar="X"
69
46
  placeholder="Номер карты"
70
- alwaysShowMask
47
+ showMask="always"
71
48
  />
72
49
  ```
73
50
 
@@ -82,7 +59,7 @@ const [value, setValue] = React.useState('');
82
59
 
83
60
  <MaskedInput
84
61
  mask="Hh:Mm:Ss"
85
- alwaysShowMask
62
+ showMask="always"
86
63
  formatChars={{
87
64
  H: '[0-2]',
88
65
  h: value.startsWith('2') ? '[0-3]' : '[0-9]',
@@ -96,16 +73,6 @@ const [value, setValue] = React.useState('');
96
73
  />
97
74
  ```
98
75
 
99
- #### `alwaysShowMask`
100
-
101
- Показывает маску всегда. Placeholder в этом случае игнорируется. Логика немного отличается от старой реализации, из-за
102
- специфики iMask. Раньше маска обязательно появлялась при фокусе, но теперь чтобы маску было видно надо явно задать этот
103
- проп.
104
-
105
- ```jsx harmony
106
- <MaskedInput mask="+7 (999) 999-99-99" alwaysShowMask placeholder="Номер телефона" />
107
- ```
108
-
109
76
  #### `imaskProps`*
110
77
 
111
78
  Переопределяет пропы iMask.
@@ -121,18 +88,18 @@ const [value, setValue] = React.useState('');
121
88
  Конвертация пропов выглядит примерно так:
122
89
 
123
90
  ```typescript static
124
- mask: mask.replace(/0/g, '{\\0}'),
91
+ mask: mask.replace(/0/g, '{\\0}'),
125
92
  placeholderChar: props.maskChar || '_',
126
- definitions: props.formatChars || { '9': /[0-9]/, a: /[A-Za-z]/, '*': /[A-Za-z0-9]/ },
127
- eager: true,
128
- overwrite: 'shift',
129
- lazy: !alwaysShowMask,
93
+ definitions: props.formatChars || { '9': /[0-9]/, a: /[A-Za-z]/, '*': /[A-Za-z0-9]/ },
94
+ eager: 'append',
95
+ overwrite: 'shift',
96
+ lazy: !(showMask === 'always' || (showMask === 'focus' && focused)),
130
97
  ...props.imaskProps,
131
98
  ```
132
99
 
133
100
  ---
134
101
 
135
- ##### `imaskProps.unmask`
102
+ #### `imaskProps.unmask`
136
103
 
137
104
  Можно сразу получать value без фиксированных символов маски
138
105
 
@@ -147,66 +114,66 @@ const [value, setValue] = React.useState('');
147
114
  imaskProps={{
148
115
  unmask: true
149
116
  }}
150
- alwaysShowMask
117
+ showMask="always"
151
118
  value={value}
152
119
  onValueChange={setValue}
153
120
  />
154
121
  </>
155
122
  ```
156
123
 
157
- ##### `imaskProps.mask []`
124
+ #### `imaskProps.mask []`
158
125
 
159
- Опциональные части маски
126
+ Опциональные части маски.
160
127
 
161
128
  ```jsx harmony
129
+ import { Checkbox } from '@skbkontur/react-ui';
130
+
162
131
  const [value, setValue] = React.useState('');
163
132
  const [complete, setComplete] = React.useState(false);
164
133
 
165
134
 
166
135
  <MaskedInput
167
136
  mask="99-999999[99]-99"
168
- alwaysShowMask
169
- rightIcon={complete ? '✅' : '⬜'}
137
+ showMask="never"
138
+ placeholder="ИНН"
139
+ rightIcon={<Checkbox checked={complete} style={{ pointerEvents: 'none' }} />}
140
+ onValueChange={setValue}
170
141
  imaskProps={{
171
- onAccept: (v, imask) => {
172
- setValue(v);
173
- setComplete(imask.masked.isComplete);
174
- }
142
+ onAccept: (_, imask) => setComplete(imask.masked.isComplete)
175
143
  }}
176
144
  />
177
145
  ```
178
146
 
179
- ##### `imaskProps.mask {}`
147
+ #### `imaskProps.mask {}`
180
148
 
181
149
  Фиксированные части маски, которые попадут в `value` при `unmask = true`. Любой невалидный символ (например`пробел`)
182
- переведёт каретку за фиксированный символ.
150
+ перекинет каретку за фиксированный символ.
183
151
 
184
152
  ```jsx harmony
153
+ import { Checkbox } from '@skbkontur/react-ui';
154
+
185
155
  const [value, setValue] = React.useState('');
186
156
  const [complete, setComplete] = React.useState(false);
187
157
 
188
-
189
158
  <>
190
159
  <span>unmask value: {value}</span>
191
160
  <br />
192
161
  <MaskedInput
193
162
  mask="aa[aaaaaaaaaaaaaaaaa]{@}aa[aaaaaaaaaaaaaaaaa]{\.}aa[aaaa]"
194
- alwaysShowMask
195
- rightIcon={complete ? '✅' : ''}
163
+ showMask="always"
164
+ rightIcon={<Checkbox checked={complete} style={{ pointerEvents: 'none' }} />}
165
+ onValueChange={setValue}
196
166
  imaskProps={{
197
167
  unmask: true,
198
- onAccept: (v, imask) => {
199
- setValue(v);
200
- setComplete(imask.masked.isComplete);
201
- }
168
+ onAccept: (_, imask) => setComplete(imask.masked.isComplete)
202
169
  }}
203
170
  />
204
171
  </>
205
172
  ```
206
173
 
207
- ##### `imaskProps.blocks`
174
+ #### `imaskProps.blocks`
208
175
 
209
- Пример маски времени. Нажмите цифру `6`, чтобы сработало автозаполнение.
176
+ Пример маски времени с автозаполнением.
210
177
 
211
178
  ```jsx harmony
212
179
  import IMask from 'imask';
@@ -226,6 +193,6 @@ const block = {
226
193
  SS: { ...block, to: 59, },
227
194
  }
228
195
  }}
229
- alwaysShowMask
196
+ showMask="always"
230
197
  />
231
198
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skbkontur/react-ui",
3
- "version": "4.25.1-MaskedInput-2nd.5",
3
+ "version": "4.25.1-MaskedInput-2nd.6",
4
4
  "description": "UI Components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "index.js",
@@ -40,7 +40,7 @@
40
40
  "fix:prettier": "yarn prettier --write .",
41
41
  "test": "jest --detectOpenHandles",
42
42
  "test:watch": "yarn test --watch",
43
- "creevey": "wait-on -t 300000 http-get://localhost:6060/ && cross-env BABEL_ENV=cjs creevey -c .creevey/config.js",
43
+ "creevey": "wait-on -t 300000 http-get://localhost:6061/ && cross-env BABEL_ENV=cjs creevey -c .creevey/config.js",
44
44
  "creevey:update": "cross-env BABEL_ENV=cjs creevey -c .creevey/config.js --update",
45
45
  "creevey:ui": "yarn creevey --ui",
46
46
  "report:eslint": "yarn eslint -f eslint-html-reporter/reporter.js -o reports/eslint/index.html"