@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.
- package/cjs/components/MaskedInput/ColorableInputElement/ColorableInputElement.js +4 -24
- package/cjs/components/MaskedInput/ColorableInputElement/ColorableInputElement.js.map +1 -1
- package/cjs/components/MaskedInput/ColorableInputElement/ColorableInputElement.styles.js +1 -1
- package/cjs/components/MaskedInput/ColorableInputElement/ColorableInputElement.styles.js.map +1 -1
- package/cjs/components/MaskedInput/MaskedInput.d.ts +3 -3
- package/cjs/components/MaskedInput/MaskedInput.js +9 -8
- package/cjs/components/MaskedInput/MaskedInput.js.map +1 -1
- package/cjs/components/MaskedInput/MaskedInput.md +57 -90
- package/components/MaskedInput/ColorableInputElement/ColorableInputElement/ColorableInputElement.js +5 -29
- package/components/MaskedInput/ColorableInputElement/ColorableInputElement/ColorableInputElement.js.map +1 -1
- package/components/MaskedInput/ColorableInputElement/ColorableInputElement.styles/ColorableInputElement.styles.js +1 -1
- package/components/MaskedInput/ColorableInputElement/ColorableInputElement.styles/ColorableInputElement.styles.js.map +1 -1
- package/components/MaskedInput/MaskedInput/MaskedInput.js +10 -7
- package/components/MaskedInput/MaskedInput/MaskedInput.js.map +1 -1
- package/components/MaskedInput/MaskedInput.d.ts +3 -3
- package/components/MaskedInput/MaskedInput.md +57 -90
- package/package.json +2 -2
|
@@ -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)(
|
|
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,
|
|
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":"wdAAA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA,uE;;;;;;;AAOA;AACA;AACA;AACA;;AAEO,IAAMA,qBAAqB,GAAG;AACnC,uBADmC;AAEnC,SAASA,qBAAT,CAA+BC,KAA/B,EAAkEC,GAAlE,EAAmG;AACjG,MAAMC,QAAQ,GAAG,mBAAgC,IAAhC,CAAjB;AACA,MAAMC,OAAO,GAAG,mBAA+B,IAA/B,CAAhB;AACA,MAAMC,OAAO,GAAG,mBAAO,KAAP,CAAhB;AACA,MAAMC,UAAU,GAAGC,eAAMC,MAAN,EAAnB;AACA,MAAMC,KAAK,GAAG,uBAAWC,0BAAX,CAAd;AACA,MAAMC,kBAAkB,GAAG,wBAAY,qBAASC,SAAT,CAAZ,EAAiC,EAAjC,CAA3B;AACA,kBAA4B,qBAAS,IAAT,CAA5B,CAAOC,MAAP,gBAAeC,SAAf;;AAEA,MAAQC,QAAR,GAA2Ed,KAA3E,CAAQc,QAAR,CAAkBC,OAAlB,GAA2Ef,KAA3E,CAAkBe,OAAlB,CAA2BC,OAA3B,GAA2EhB,KAA3E,CAA2BgB,OAA3B,CAAoCC,MAApC,GAA2EjB,KAA3E,CAAoCiB,MAApC,CAA4CC,WAA5C,GAA2ElB,KAA3E,CAA4CkB,WAA5C,CAA4DC,UAA5D,+CAA2EnB,KAA3E;;AAEA;AACEC,EAAAA,GADF;AAEE,sBAAO;AACLmB,MAAAA,KAAK,EAAElB,QAAQ,CAACmB,OADX;AAELC,MAAAA,WAAW,EAAE,+BAAMpB,QAAQ,CAACmB,OAAf,EAFR,EAAP,EAFF;;AAME,IANF;;;AASA,wBAAUE,YAAV,EAAwB,EAAxB;;AAEA,wBAAU,YAAM;AACdC,IAAAA,UAAU,CAACxB,KAAD,CAAV;AACAuB,IAAAA,YAAY;AACb,GAHD,EAGG,CAACX,MAAD,EAASM,WAAT,EAAsBlB,KAAK,CAACyB,KAA5B,EAAmCzB,KAAK,CAAC0B,YAAzC,EAAuD1B,KAAK,CAAC2B,QAA7D,EAAuEvB,OAAO,CAACiB,OAA/E,CAHH;;AAKA,wBAAU,YAAM;AACd,QAAInB,QAAQ,CAACmB,OAAb,EAAsB;AACpBhB,MAAAA,UAAU,CAACgB,OAAX,GAAqBO,gBAAgB,CAAC1B,QAAQ,CAACmB,OAAV,CAArC;AACD;AACF,GAJD;;AAMA;AACE;AACGf,mBAAMuB,YAAN,CAAmBf,QAAnB;AACIK,IAAAA,UADJ;AAECJ,MAAAA,OAAO,EAAEe,WAFV;AAGCd,MAAAA,OAAO,EAAEe,WAHV;AAICd,MAAAA,MAAM,EAAEe,UAJT;AAKC9B,MAAAA,QAAQ,EAARA,QALD;AAMC+B,MAAAA,SAAS,EAAE,iBAAGjC,KAAK,CAACiC,SAAT,EAAoBrB,MAAM,IAAIsB,qCAAcd,KAA5C,CANZ,IADH;;AASGR,IAAAA,MAAM,iBAAI,uCAAM,KAAK,EAAE,EAAEuB,UAAU,EAAE,QAAd,EAAwBC,QAAQ,EAAE,UAAlC,EAA8CC,UAAU,EAAE,KAA1D,EAAb,EAAgF,GAAG,EAAElC,OAArF,GATb,CADF;;;;AAcA,WAAS2B,WAAT,CAAqBQ,CAArB,EAA6D;AAC3D,QAAMC,QAAQ,GAAG,uBAACrC,QAAQ,CAACmB,OAAV,sCAAC,kBAAkBmB,aAAnB,aAAC,sBAAiCC,aAAjC,CAA+C,oBAA/C,CAAD,CAAjB;AACA5B,IAAAA,SAAS,CAAC0B,QAAD,CAAT;;AAEAf,IAAAA,UAAU,CAACxB,KAAD,CAAV;;AAEAe,IAAAA,OAAO,QAAP,YAAAA,OAAO,CAAGuB,CAAH,CAAP;AACD;;AAED,WAASP,WAAT,CAAqBO,CAArB,EAA4D;AAC1DI,IAAAA,UAAU,CAACnB,YAAD,CAAV;;AAEAnB,IAAAA,OAAO,CAACiB,OAAR,GAAkB,IAAlB;;AAEAL,IAAAA,OAAO,QAAP,YAAAA,OAAO,CAAGsB,CAAH,CAAP;AACD;;AAED,WAASN,UAAT,CAAoBM,CAApB,EAA2D;AACzDf,IAAAA,YAAY;;AAEZnB,IAAAA,OAAO,CAACiB,OAAR,GAAkB,KAAlB;;AAEAJ,IAAAA,MAAM,QAAN,YAAAA,MAAM,CAAGqB,CAAH,CAAN;AACD;;AAED,WAASf,YAAT,GAAwB;AACtBmB,IAAAA,UAAU,CAAC,YAAM;AACf7B,MAAAA,SAAS,CAAC,wBAACX,QAAQ,CAACmB,OAAV,sCAAC,mBAAkBmB,aAAnB,aAAC,sBAAiCC,aAAjC,CAA+C,oBAA/C,CAAD,CAAD,CAAT;AACD,KAFS,CAAV;AAGD;;AAED,WAASjB,UAAT,CAAoBxB,KAApB,EAAuD;AACrD,QAAIY,MAAJ,EAAY;AACVF,MAAAA,kBAAkB,CAACV,KAAD,CAAlB;AACD,KAFD,MAEO;AACLU,MAAAA,kBAAkB,CAACiC,MAAnB;AACAzC,MAAAA,QAAQ,CAACmB,OAAT,KAAqBnB,QAAQ,CAACmB,OAAT,CAAiBuB,KAAjB,CAAuBC,eAAvB,GAAyC,EAA9D;AACA,4BAAA3C,QAAQ,CAACmB,OAAT,wCAAkByB,SAAlB,CAA4BC,MAA5B,CAAmCb,qCAAcd,KAAjD;AACD;AACF;;AAED,WAAST,SAAT,CAAmBqC,MAAnB,EAAwE,qCAArDA,MAAqD,cAArDA,MAAqD,GAAPhD,KAAO;AACtE,QAAI,CAACG,OAAO,CAACkB,OAAT,IAAoB,CAACnB,QAAQ,CAACmB,OAA9B,IAAyC,CAAChB,UAAU,CAACgB,OAArD,IAAgE,CAAC,6BAAU4B,0BAAV,CAArE,EAA8F;AAC5F;AACD;;AAED,0BAAA/C,QAAQ,CAACmB,OAAT,wCAAkByB,SAAlB,CAA4BI,GAA5B,CAAgChB,qCAAcd,KAA9C;;AAEA,QAAI+B,MAAM,GAAGhD,OAAO,CAACkB,OAAR,CAAgB+B,UAA7B;AACA,QAAIC,iBAAiB,cAAGF,MAAH,qBAAG,QAAQG,cAAR,CAAuB,MAAvB,CAAxB;;AAEA,QAAI,CAACD,iBAAL,EAAwB;AACtBF,MAAAA,MAAM,GAAGhD,OAAO,CAACkB,OAAR,CAAgBkC,YAAhB,CAA6B,EAAEC,IAAI,EAAE,MAAR,EAA7B,CAAT;;AAEAH,MAAAA,iBAAiB,GAAGJ,2BAAaQ,QAAb,CAAsBC,aAAtB,CAAoC,MAApC,CAApB;AACAL,MAAAA,iBAAiB,CAACM,YAAlB,CAA+B,IAA/B,EAAqC,MAArC;;AAEAR,MAAAA,MAAM,CAACS,WAAP,CAAmBP,iBAAnB;AACD;;AAED,QAAMT,KAAK,GAAGvC,UAAU,CAACgB,OAAzB;;AAEAgC,IAAAA,iBAAiB,CAACQ,WAAlB,GAAgC3D,QAAQ,CAACmB,OAAT,CAAiByC,YAAjB,CAA8B,kBAA9B,KAAqD,EAArF;;AAEA,QAAMC,SAAS,GAAG7D,QAAQ,CAACmB,OAAT,CAAiB2C,qBAAjB,EAAlB;AACA,QAAMC,UAAU,GAAG9D,OAAO,CAACkB,OAAR,CAAgB2C,qBAAhB,EAAnB;;AAEA,QAAME,SAAS,GAAGD,UAAU,CAACE,KAAX,IAAoBJ,SAAS,CAACI,KAAV,GAAkB,GAAtC,CAAlB;AACA,QAAMC,MAAM,GAAGxB,KAAK,CAACyB,SAAN,KAAoB,QAApB,GAA+B,GAA/B,GAAqC,EAApD;;AAEA,QAAIC,eAAe,GAAG9D,KAAK,CAAC+D,cAA5B;AACA,QAAIC,SAAS,GAAGhE,KAAK,CAACiE,qBAAtB;AACA,QAAIzB,MAAM,CAACrB,QAAX,EAAqB;AACnB2C,MAAAA,eAAe,GAAG9D,KAAK,CAACkE,sBAAxB;AACAF,MAAAA,SAAS,GAAGhE,KAAK,CAACkE,sBAAlB;AACD;AACD,QAAI1B,MAAM,CAAC9B,WAAX,EAAwB;AACtBsD,MAAAA,SAAS,GAAGpE,OAAO,CAACiB,OAAR,GAAkBmD,SAAlB,GAA8B,aAA1C;AACD;;AAEDtE,IAAAA,QAAQ,CAACmB,OAAT,CAAiBuB,KAAjB,CAAuBC,eAAvB;;AAEMuB,IAAAA,MAFN;AAGME,IAAAA,eAHN,SAGyBJ,SAHzB;AAIMM,IAAAA,SAJN,SAImBN,SAJnB;;AAMD;AACF,CAxIkC,CAA9B,C","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
|
|
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);
|
package/cjs/components/MaskedInput/ColorableInputElement/ColorableInputElement.styles.js.map
CHANGED
|
@@ -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
|
|
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
|
|
25
|
+
* @default 'focus'
|
|
26
26
|
*/
|
|
27
|
-
|
|
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", "
|
|
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,
|
|
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:
|
|
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: !
|
|
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) &&
|
|
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
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
<
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/>
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
91
|
+
mask: mask.replace(/0/g, '{\\0}'),
|
|
125
92
|
placeholderChar: props.maskChar || '_',
|
|
126
|
-
definitions:
|
|
127
|
-
eager:
|
|
128
|
-
overwrite:
|
|
129
|
-
lazy:
|
|
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
|
-
|
|
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
|
-
|
|
117
|
+
showMask="always"
|
|
151
118
|
value={value}
|
|
152
119
|
onValueChange={setValue}
|
|
153
120
|
/>
|
|
154
121
|
</>
|
|
155
122
|
```
|
|
156
123
|
|
|
157
|
-
|
|
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
|
-
|
|
169
|
-
|
|
137
|
+
showMask="never"
|
|
138
|
+
placeholder="ИНН"
|
|
139
|
+
rightIcon={<Checkbox checked={complete} style={{ pointerEvents: 'none' }} />}
|
|
140
|
+
onValueChange={setValue}
|
|
170
141
|
imaskProps={{
|
|
171
|
-
onAccept: (
|
|
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
|
-
|
|
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
|
-
|
|
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: (
|
|
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
|
-
|
|
174
|
+
#### `imaskProps.blocks`
|
|
208
175
|
|
|
209
|
-
Пример маски
|
|
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
|
-
|
|
196
|
+
showMask="always"
|
|
230
197
|
/>
|
|
231
198
|
```
|
package/components/MaskedInput/ColorableInputElement/ColorableInputElement/ColorableInputElement.js
CHANGED
|
@@ -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(
|
|
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,
|
|
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
|
|
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
|
|
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", "
|
|
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
|
-
|
|
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:
|
|
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: !
|
|
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
|
-
|
|
157
|
+
selectionStart = _e$currentTarget2.selectionStart,
|
|
158
|
+
selectionEnd = _e$currentTarget2.selectionEnd;
|
|
157
159
|
|
|
158
|
-
if (isKeyBackspace(e) &&
|
|
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":"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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":["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
|
|
25
|
+
* @default 'focus'
|
|
26
26
|
*/
|
|
27
|
-
|
|
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
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
<
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/>
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
91
|
+
mask: mask.replace(/0/g, '{\\0}'),
|
|
125
92
|
placeholderChar: props.maskChar || '_',
|
|
126
|
-
definitions:
|
|
127
|
-
eager:
|
|
128
|
-
overwrite:
|
|
129
|
-
lazy:
|
|
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
|
-
|
|
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
|
-
|
|
117
|
+
showMask="always"
|
|
151
118
|
value={value}
|
|
152
119
|
onValueChange={setValue}
|
|
153
120
|
/>
|
|
154
121
|
</>
|
|
155
122
|
```
|
|
156
123
|
|
|
157
|
-
|
|
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
|
-
|
|
169
|
-
|
|
137
|
+
showMask="never"
|
|
138
|
+
placeholder="ИНН"
|
|
139
|
+
rightIcon={<Checkbox checked={complete} style={{ pointerEvents: 'none' }} />}
|
|
140
|
+
onValueChange={setValue}
|
|
170
141
|
imaskProps={{
|
|
171
|
-
onAccept: (
|
|
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
|
-
|
|
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
|
-
|
|
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: (
|
|
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
|
-
|
|
174
|
+
#### `imaskProps.blocks`
|
|
208
175
|
|
|
209
|
-
Пример маски
|
|
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
|
-
|
|
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.
|
|
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:
|
|
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"
|