@elliemae/ds-form-helpers-mask-hooks 3.35.0 → 3.36.0-next.1
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/dist/cjs/hooks/useNumberMask.js +12 -24
- package/dist/cjs/hooks/useNumberMask.js.map +1 -1
- package/dist/cjs/hooks/usePhoneMask.js +4 -8
- package/dist/cjs/hooks/usePhoneMask.js.map +1 -1
- package/dist/cjs/hooks/useRegExpMask.js +7 -14
- package/dist/cjs/hooks/useRegExpMask.js.map +1 -1
- package/dist/cjs/hooks/useSSNMask.js +3 -6
- package/dist/cjs/hooks/useSSNMask.js.map +1 -1
- package/dist/cjs/hooks/useZipCodeMask.js +3 -6
- package/dist/cjs/hooks/useZipCodeMask.js.map +1 -1
- package/dist/cjs/utils/addSpecialCharacters.js +2 -4
- package/dist/cjs/utils/addSpecialCharacters.js.map +1 -1
- package/dist/cjs/utils/getPartialMaskedPos.js +1 -2
- package/dist/cjs/utils/getPartialMaskedPos.js.map +1 -1
- package/dist/esm/hooks/useNumberMask.js +12 -24
- package/dist/esm/hooks/useNumberMask.js.map +1 -1
- package/dist/esm/hooks/usePhoneMask.js +4 -8
- package/dist/esm/hooks/usePhoneMask.js.map +1 -1
- package/dist/esm/hooks/useRegExpMask.js +7 -14
- package/dist/esm/hooks/useRegExpMask.js.map +1 -1
- package/dist/esm/hooks/useSSNMask.js +3 -6
- package/dist/esm/hooks/useSSNMask.js.map +1 -1
- package/dist/esm/hooks/useZipCodeMask.js +3 -6
- package/dist/esm/hooks/useZipCodeMask.js.map +1 -1
- package/dist/esm/utils/addSpecialCharacters.js +2 -4
- package/dist/esm/utils/addSpecialCharacters.js.map +1 -1
- package/dist/esm/utils/getPartialMaskedPos.js +1 -2
- package/dist/esm/utils/getPartialMaskedPos.js.map +1 -1
- package/package.json +6 -6
|
@@ -55,12 +55,10 @@ const conformValue = (rawValue, cursorPos, lastKeyCode, opts) => {
|
|
|
55
55
|
let finalPrefix = [prefix?.length, 0].includes(rawValue.indexOf("-")) && allowNegative ? "-" : "";
|
|
56
56
|
let maskedValue = String(rawValue).split("").filter((char, idx) => {
|
|
57
57
|
const validChar = char >= "0" && char <= "9" || char === "." && dotIdx === -1 && decimalPlaces;
|
|
58
|
-
if (char === "." && validChar)
|
|
59
|
-
dotIdx = idx;
|
|
58
|
+
if (char === "." && validChar) dotIdx = idx;
|
|
60
59
|
return validChar;
|
|
61
60
|
});
|
|
62
|
-
if (prefix && maskedValue.length)
|
|
63
|
-
finalPrefix += prefix;
|
|
61
|
+
if (prefix && maskedValue.length) finalPrefix += prefix;
|
|
64
62
|
while (maskedValue.length >= 2 && maskedValue[0] === "0" && maskedValue[1] !== ".") {
|
|
65
63
|
maskedValue = maskedValue.splice(1);
|
|
66
64
|
}
|
|
@@ -85,15 +83,11 @@ const conformValue = (rawValue, cursorPos, lastKeyCode, opts) => {
|
|
|
85
83
|
finalPrefix = "";
|
|
86
84
|
}
|
|
87
85
|
let maskedPos = 0;
|
|
88
|
-
if (maskedValue[maskedPos] === "0" && cursorPos === 1 + prefix.length)
|
|
89
|
-
|
|
90
|
-
if (zeroWasAdded)
|
|
91
|
-
maskedPos += 1;
|
|
86
|
+
if (maskedValue[maskedPos] === "0" && cursorPos === 1 + prefix.length) maskedPos += 1;
|
|
87
|
+
if (zeroWasAdded) maskedPos += 1;
|
|
92
88
|
for (let i = 0; i < cursorPos; i += 1) {
|
|
93
|
-
if (maskedValue[maskedPos] === THOUSANDSSEPARATOR)
|
|
94
|
-
|
|
95
|
-
if (maskedValue[maskedPos] === rawValue[i])
|
|
96
|
-
maskedPos += 1;
|
|
89
|
+
if (maskedValue[maskedPos] === THOUSANDSSEPARATOR) maskedPos += 1;
|
|
90
|
+
if (maskedValue[maskedPos] === rawValue[i]) maskedPos += 1;
|
|
97
91
|
}
|
|
98
92
|
maskedPos += finalPrefix.length;
|
|
99
93
|
const finalSuffix = maskedValue.length ? suffix : "";
|
|
@@ -118,8 +112,7 @@ const useNumberMask = (props) => {
|
|
|
118
112
|
const maskedValue = e.target.value;
|
|
119
113
|
const { decimalRequired = true, decimalPlaces = 2, suffix = "", prefix = "", min = -Infinity } = opts;
|
|
120
114
|
const value = Number(e.target.value.replace(/[,`${prefix}${suffix}`]/g, ""));
|
|
121
|
-
if (value < min)
|
|
122
|
-
valueSetter(`${prefix}${min.toString()}${suffix}`);
|
|
115
|
+
if (value < min) valueSetter(`${prefix}${min.toString()}${suffix}`);
|
|
123
116
|
const dotIdx = maskedValue.indexOf(".");
|
|
124
117
|
const minusIndex = maskedValue.indexOf("-");
|
|
125
118
|
const suffixIndex = suffix.length ? maskedValue.indexOf(suffix) : -1;
|
|
@@ -137,16 +130,14 @@ const useNumberMask = (props) => {
|
|
|
137
130
|
} else if (maskedValue.length - 1 === minusIndex) {
|
|
138
131
|
valueSetter(maskedValue.replace("-", ""));
|
|
139
132
|
}
|
|
140
|
-
if (userOnBlur)
|
|
141
|
-
userOnBlur(e);
|
|
133
|
+
if (userOnBlur) userOnBlur(e);
|
|
142
134
|
},
|
|
143
135
|
[userOnBlur, valueSetter, opts]
|
|
144
136
|
);
|
|
145
137
|
const onKeyDown = (0, import_react.useCallback)(
|
|
146
138
|
(e) => {
|
|
147
139
|
lastKeyCode.current = e.code;
|
|
148
|
-
if (userOnKeyDown)
|
|
149
|
-
userOnKeyDown(e);
|
|
140
|
+
if (userOnKeyDown) userOnKeyDown(e);
|
|
150
141
|
},
|
|
151
142
|
[userOnKeyDown]
|
|
152
143
|
);
|
|
@@ -160,15 +151,12 @@ const useNumberMask = (props) => {
|
|
|
160
151
|
);
|
|
161
152
|
const { max = Infinity, prefix = "", suffix = "" } = opts;
|
|
162
153
|
const value = Number(e.target.value.replace(/[,`${prefix}${suffix}`]/g, ""));
|
|
163
|
-
if (value > max)
|
|
164
|
-
return;
|
|
154
|
+
if (value > max) return;
|
|
165
155
|
valueSetter((prevMask) => {
|
|
166
|
-
if (mask === prevMask)
|
|
167
|
-
setKey((key) => key + 1);
|
|
156
|
+
if (mask === prevMask) setKey((key) => key + 1);
|
|
168
157
|
return mask;
|
|
169
158
|
});
|
|
170
|
-
if (userOnChange)
|
|
171
|
-
userOnChange(e, mask);
|
|
159
|
+
if (userOnChange) userOnChange(e, mask);
|
|
172
160
|
scheduleAfterRender(() => (0, import_utils.setCursorPosition)(e.target, cursorPos));
|
|
173
161
|
},
|
|
174
162
|
[valueSetter, scheduleAfterRender, userOnChange, opts]
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/hooks/useNumberMask.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
4
|
"sourcesContent": ["/* eslint-disable max-params */\n/* eslint-disable max-statements */\n/* eslint-disable complexity */\nimport type React from 'react';\nimport { useCallback, useRef, useState } from 'react';\nimport {\n describe,\n PropTypes,\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useCallbackAfterRender } from '@elliemae/ds-utilities';\nimport { setCursorPosition } from '../utils/index.js';\nimport { useNumberMaskDefaultProps, useNumberMaskPropTypes, type UseNumberMaskT } from '../react-desc-prop-types.js';\nimport { useNumberMaskName } from '../DSMaskDefinitions.js';\n\nconst addThousandsSeparator = (n: string, separator: string) => n.replace(/\\B(?=(\\d{3})+(?!\\d))/g, separator);\n\nconst conformValue = (\n rawValue: string,\n cursorPos: number,\n lastKeyCode: string,\n opts: Omit<UseNumberMaskT.Props, 'valueSetter'>,\n): [string, number] => {\n const {\n includeThousandsSeparator = true,\n allowNegative = false,\n prefix = '',\n suffix = '',\n decimalPlaces = 2,\n decimalRequired = false,\n } = opts;\n const THOUSANDSSEPARATOR = ',';\n\n let dotIdx = -1;\n // allow minus sign before and after the preffix\n let finalPrefix = [prefix?.length, 0].includes(rawValue.indexOf('-')) && allowNegative ? '-' : '';\n\n let maskedValue = String(rawValue)\n .split('')\n .filter((char, idx) => {\n // we take only the first dot\n const validChar = (char >= '0' && char <= '9') || (char === '.' && dotIdx === -1 && decimalPlaces);\n if (char === '.' && validChar) dotIdx = idx;\n return validChar;\n });\n\n if (prefix && maskedValue.length) finalPrefix += prefix;\n\n // REMOVE FOLLOWING ZEROS IN INTEGER PART AFTER LEADER ZERO NUMBER\n while (maskedValue.length >= 2 && maskedValue[0] === '0' && maskedValue[1] !== '.') {\n maskedValue = maskedValue.splice(1);\n }\n dotIdx = maskedValue.findIndex((char) => char === '.');\n\n let integer = maskedValue.slice(0, dotIdx !== -1 ? dotIdx : maskedValue.length);\n const decimal = maskedValue.slice(dotIdx, dotIdx + decimalPlaces + 1);\n // ADDING THOUSANDS SEPARATOR\n if (includeThousandsSeparator) {\n integer = addThousandsSeparator(integer.join(''), THOUSANDSSEPARATOR).split('');\n }\n\n let zeroWasAdded = false;\n\n // MERGIN INT AND DECIMAL IF NECCESSARY\n if (dotIdx !== -1 && !(lastKeyCode === 'Backspace' && decimal.length === 1)) {\n if (integer.length) {\n maskedValue = [...integer, ...decimal];\n } else {\n // if theres no integer add a zero to the left of the dot to cover .23 => 0.23 case\n maskedValue = ['0', ...decimal];\n zeroWasAdded = true;\n }\n } else {\n // If decimal is required we add a dot after integer if exists\n maskedValue = decimalRequired && integer.length ? [...integer, '.'] : integer;\n }\n\n // remove orphans prefix for example \"-$\"\n if (lastKeyCode === 'Backspace' && maskedValue.length === 0) {\n finalPrefix = '';\n }\n\n // SET REAL CURSOR POSITION AFTER ADDING DOT and COMMAS SEPARATORS\n let maskedPos = 0;\n\n // 0 leading case we move the cursor to continue typing\n if (maskedValue[maskedPos] === '0' && cursorPos === 1 + prefix.length) maskedPos += 1;\n\n if (zeroWasAdded) maskedPos += 1;\n\n for (let i = 0; i < cursorPos; i += 1) {\n if (maskedValue[maskedPos] === THOUSANDSSEPARATOR) maskedPos += 1;\n if (maskedValue[maskedPos] === rawValue[i]) maskedPos += 1;\n }\n\n maskedPos += finalPrefix.length;\n\n const finalSuffix = maskedValue.length ? suffix : '';\n\n const maskedValueString = finalPrefix + maskedValue.join('') + finalSuffix;\n return [maskedValueString, maskedPos];\n};\n\nexport const useNumberMask: ((args: UseNumberMaskT.Props) => UseNumberMaskT.OutputT) & { displayName: string } = (\n props,\n) => {\n const propsWithDefault = useMemoMergePropsWithDefault<UseNumberMaskT.InternalProps>(props, useNumberMaskDefaultProps);\n useValidateTypescriptPropTypes(propsWithDefault, useNumberMaskPropTypes, useNumberMaskName);\n\n const {\n valueSetter,\n onChange: userOnChange,\n onKeyDown: userOnKeyDown,\n onBlur: userOnBlur,\n ...opts\n } = propsWithDefault;\n\n const lastKeyCode = useRef('Unidentified');\n\n const scheduleAfterRender = useCallbackAfterRender(true);\n\n // Some times, the value of the mask is not gonna change (user types invalid char for example)\n // This makes the input to go from \"correct\" -> \"incorrect\" -> \"correct\"\n // But since the input is controlled, the input does not re-render\n // This makes the input go mumbo-jumbo and places the cursor in the end, because we kinda changed the value async\n // Solution for this is to trigger a re-render, we do this with a set state call in the on change event\n const [, setKey] = useState(0);\n\n const onBlur: React.FocusEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const maskedValue = e.target.value;\n\n const { decimalRequired = true, decimalPlaces = 2, suffix = '', prefix = '', min = -Infinity } = opts;\n const value = Number(e.target.value.replace(/[,`${prefix}${suffix}`]/g, ''));\n if (value < min) valueSetter(`${prefix}${min.toString()}${suffix}`);\n\n const dotIdx = maskedValue.indexOf('.');\n const minusIndex = maskedValue.indexOf('-');\n\n const suffixIndex = suffix.length ? maskedValue.indexOf(suffix) : -1;\n\n if (decimalRequired) {\n if (dotIdx > -1) {\n const decimal = maskedValue.slice(dotIdx + 1, suffix.length ? -suffix.length : maskedValue.length);\n\n let zerosRest = '';\n while (decimal.length + zerosRest.length !== decimalPlaces) {\n zerosRest += '0';\n }\n\n valueSetter((suffix.length ? maskedValue.slice(0, suffixIndex) : maskedValue) + zerosRest + suffix);\n }\n } else if (maskedValue.length - suffix.length - 1 === dotIdx) {\n // removing orphans dots\n valueSetter(maskedValue.replace('.', ''));\n } else if (maskedValue.length - 1 === minusIndex) {\n // removing orphans minus\n valueSetter(maskedValue.replace('-', ''));\n }\n if (userOnBlur) userOnBlur(e);\n },\n [userOnBlur, valueSetter, opts],\n );\n\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n lastKeyCode.current = e.code;\n if (userOnKeyDown) userOnKeyDown(e);\n },\n [userOnKeyDown],\n );\n\n const onChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const [mask, cursorPos] = conformValue(\n e.target.value,\n e.target.selectionEnd ?? 0,\n lastKeyCode.current,\n opts as UseNumberMaskT.Props,\n );\n\n // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\n const { max = Infinity, prefix = '', suffix = '' } = opts;\n const value = Number(e.target.value.replace(/[,`${prefix}${suffix}`]/g, ''));\n if (value > max) return;\n\n valueSetter((prevMask) => {\n // Here we need to update the key\n if (mask === prevMask) setKey((key) => key + 1);\n\n return mask;\n });\n if (userOnChange) userOnChange(e, mask);\n scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));\n },\n [valueSetter, scheduleAfterRender, userOnChange, opts],\n );\n\n return {\n onKeyDown,\n onChange,\n onBlur,\n };\n};\n\nexport const getNumberMaskedValue = (value: string, opts: Omit<UseNumberMaskT.Props, 'valueSetter'>) => {\n const [maskedValue] = conformValue(value, value.length - 1, '', opts);\n return maskedValue;\n};\n\nuseNumberMask.displayName = useNumberMaskName;\nexport const UseNumberMaskWithSchema = describe(useNumberMask);\nUseNumberMaskWithSchema.propTypes = useNumberMaskPropTypes;\nUseNumberMaskWithSchema.returnType = {\n onKeyDown: PropTypes.func.description('On key down event for input').isRequired,\n onChange: PropTypes.func.description('On change event for input').isRequired,\n onBlur: PropTypes.func.description('On blur event for input').isRequired,\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADIvB,mBAA8C;AAC9C,8BAKO;AACP,0BAAuC;AACvC,mBAAkC;AAClC,mCAAuF;AACvF,+BAAkC;AAElC,MAAM,wBAAwB,CAAC,GAAW,cAAsB,EAAE,QAAQ,yBAAyB,SAAS;AAE5G,MAAM,eAAe,CACnB,UACA,WACA,aACA,SACqB;AACrB,QAAM;AAAA,IACJ,4BAA4B;AAAA,IAC5B,gBAAgB;AAAA,IAChB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,EACpB,IAAI;AACJ,QAAM,qBAAqB;AAE3B,MAAI,SAAS;AAEb,MAAI,cAAc,CAAC,QAAQ,QAAQ,CAAC,EAAE,SAAS,SAAS,QAAQ,GAAG,CAAC,KAAK,gBAAgB,MAAM;AAE/F,MAAI,cAAc,OAAO,QAAQ,EAC9B,MAAM,EAAE,EACR,OAAO,CAAC,MAAM,QAAQ;AAErB,UAAM,YAAa,QAAQ,OAAO,QAAQ,OAAS,SAAS,OAAO,WAAW,MAAM;AACpF,QAAI,SAAS,OAAO
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -59,8 +59,7 @@ const conformValue = (rawValue, cursorPos, lastKeyCode, opts) => {
|
|
|
59
59
|
}
|
|
60
60
|
return char >= "0" && char <= "9";
|
|
61
61
|
});
|
|
62
|
-
while (maskedValue.length && maskedValue[0] === "0")
|
|
63
|
-
maskedValue.splice(0, 1);
|
|
62
|
+
while (maskedValue.length && maskedValue[0] === "0") maskedValue.splice(0, 1);
|
|
64
63
|
maskedValue = maskedValue.slice(0, 10);
|
|
65
64
|
const maskedPos = (0, import_utils.getPartialMaskedPos)(rawValue, maskedValue, cursorPos);
|
|
66
65
|
return (0, import_utils.addSpecialCharacters)(
|
|
@@ -80,8 +79,7 @@ const usePhoneMask = (props) => {
|
|
|
80
79
|
const onKeyDown = (0, import_react.useCallback)(
|
|
81
80
|
(e) => {
|
|
82
81
|
lastKeyCode.current = e.code;
|
|
83
|
-
if (userOnKeyDown)
|
|
84
|
-
userOnKeyDown(e);
|
|
82
|
+
if (userOnKeyDown) userOnKeyDown(e);
|
|
85
83
|
},
|
|
86
84
|
[userOnKeyDown]
|
|
87
85
|
);
|
|
@@ -89,12 +87,10 @@ const usePhoneMask = (props) => {
|
|
|
89
87
|
(e) => {
|
|
90
88
|
const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current, opts);
|
|
91
89
|
valueSetter((prevMask) => {
|
|
92
|
-
if (mask === prevMask)
|
|
93
|
-
setKey((key) => key + 1);
|
|
90
|
+
if (mask === prevMask) setKey((key) => key + 1);
|
|
94
91
|
return mask;
|
|
95
92
|
});
|
|
96
|
-
if (userOnChange)
|
|
97
|
-
userOnChange(e, mask);
|
|
93
|
+
if (userOnChange) userOnChange(e, mask);
|
|
98
94
|
scheduleAfterRender(() => (0, import_utils.setCursorPosition)(e.target, cursorPos));
|
|
99
95
|
},
|
|
100
96
|
[valueSetter, scheduleAfterRender, opts, userOnChange]
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/hooks/usePhoneMask.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
4
|
"sourcesContent": ["/* eslint-disable max-params */\nimport type React from 'react';\nimport { useCallback, useRef, useState } from 'react';\nimport {\n describe,\n PropTypes,\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useCallbackAfterRender } from '@elliemae/ds-utilities';\nimport { addSpecialCharacters, getPartialMaskedPos, setCursorPosition } from '../utils/index.js';\nimport { usePhoneMaskDefaultProps, usePhoneMaskPropTypes, type UsePhoneMaskT } from '../react-desc-prop-types.js';\nimport { usePhoneMaskName } from '../DSMaskDefinitions.js';\n\nconst phoneSpecialChars: [string, number][] = [\n ['(', 0],\n [') ', 4],\n [' - ', 9],\n];\n\nconst internationalPhoneSpecialChars: [string, number][] = [\n ['+1 (', 0],\n [') ', 7],\n [' - ', 12],\n];\n\nconst conformValue = (\n rawValue: string,\n cursorPos: number,\n lastKeyCode: string,\n opts: Omit<UsePhoneMaskT.Props, 'valueSetter'>,\n) => {\n const characters = String(rawValue).split('');\n // Work with digits only\n const { isInternational = false } = opts;\n let maskedValue = characters.filter((char, idx, array) => {\n if (isInternational && idx === 1 && char === '1' && array[0] === '+') {\n return false;\n }\n return char >= '0' && char <= '9';\n });\n // We can't have zeros at the start of the array\n while (maskedValue.length && maskedValue[0] === '0') maskedValue.splice(0, 1);\n\n // We only consider first 10 digits\n maskedValue = maskedValue.slice(0, 10);\n\n const maskedPos = getPartialMaskedPos(rawValue, maskedValue, cursorPos);\n\n return addSpecialCharacters(\n maskedValue,\n isInternational ? internationalPhoneSpecialChars : phoneSpecialChars,\n maskedPos,\n lastKeyCode,\n );\n};\n\nexport const usePhoneMask: ((args: UsePhoneMaskT.Props) => UsePhoneMaskT.OutputT) & { displayName: string } = (\n props,\n) => {\n const propsWithDefault = useMemoMergePropsWithDefault<UsePhoneMaskT.InternalProps>(props, usePhoneMaskDefaultProps);\n useValidateTypescriptPropTypes(propsWithDefault, usePhoneMaskPropTypes, usePhoneMaskName);\n const { valueSetter, onChange: userOnChange, onKeyDown: userOnKeyDown, ...opts } = propsWithDefault;\n\n const lastKeyCode = useRef('Unidentified');\n\n const scheduleAfterRender = useCallbackAfterRender(true);\n\n // Some times, the value of the mask is not gonna change (user types invalid char for example)\n // This makes the input to go from \"correct\" -> \"incorrect\" -> \"correct\"\n // But since the input is controlled, the input does not re-render\n // This makes the input go mumbo-jumbo and places the cursor in the end, because we kinda changed the value async\n // Solution for this is to trigger a re-render, we do this with a set state call in the on change event\n const [, setKey] = useState(0);\n\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n lastKeyCode.current = e.code;\n if (userOnKeyDown) userOnKeyDown(e);\n },\n [userOnKeyDown],\n );\n\n const onChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current, opts);\n\n valueSetter((prevMask) => {\n // Here we need to update the key\n if (mask === prevMask) setKey((key) => key + 1);\n return mask;\n });\n\n if (userOnChange) userOnChange(e, mask);\n\n scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));\n },\n [valueSetter, scheduleAfterRender, opts, userOnChange],\n );\n\n return {\n onKeyDown,\n onChange,\n };\n};\n\nexport const getPhoneMaskedValue = (value: string, opts?: Omit<UsePhoneMaskT.Props, 'valueSetter'>) => {\n const [maskedValue] = conformValue(value, value.length - 1, '', opts || {});\n return maskedValue;\n};\n\nusePhoneMask.displayName = usePhoneMaskName;\nexport const UsePhoneMaskWithSchema = describe(usePhoneMask);\nUsePhoneMaskWithSchema.propTypes = usePhoneMaskPropTypes;\nUsePhoneMaskWithSchema.returnType = {\n onKeyDown: PropTypes.func.description('On key down event for input').isRequired,\n onChange: PropTypes.func.description('On change event for input').isRequired,\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADEvB,mBAA8C;AAC9C,8BAKO;AACP,0BAAuC;AACvC,mBAA6E;AAC7E,mCAAoF;AACpF,+BAAiC;AAEjC,MAAM,oBAAwC;AAAA,EAC5C,CAAC,KAAK,CAAC;AAAA,EACP,CAAC,MAAM,CAAC;AAAA,EACR,CAAC,OAAO,CAAC;AACX;AAEA,MAAM,iCAAqD;AAAA,EACzD,CAAC,QAAQ,CAAC;AAAA,EACV,CAAC,MAAM,CAAC;AAAA,EACR,CAAC,OAAO,EAAE;AACZ;AAEA,MAAM,eAAe,CACnB,UACA,WACA,aACA,SACG;AACH,QAAM,aAAa,OAAO,QAAQ,EAAE,MAAM,EAAE;AAE5C,QAAM,EAAE,kBAAkB,MAAM,IAAI;AACpC,MAAI,cAAc,WAAW,OAAO,CAAC,MAAM,KAAK,UAAU;AACxD,QAAI,mBAAmB,QAAQ,KAAK,SAAS,OAAO,MAAM,CAAC,MAAM,KAAK;AACpE,aAAO;AAAA,IACT;AACA,WAAO,QAAQ,OAAO,QAAQ;AAAA,EAChC,CAAC;AAED,SAAO,YAAY,UAAU,YAAY,CAAC,MAAM
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADEvB,mBAA8C;AAC9C,8BAKO;AACP,0BAAuC;AACvC,mBAA6E;AAC7E,mCAAoF;AACpF,+BAAiC;AAEjC,MAAM,oBAAwC;AAAA,EAC5C,CAAC,KAAK,CAAC;AAAA,EACP,CAAC,MAAM,CAAC;AAAA,EACR,CAAC,OAAO,CAAC;AACX;AAEA,MAAM,iCAAqD;AAAA,EACzD,CAAC,QAAQ,CAAC;AAAA,EACV,CAAC,MAAM,CAAC;AAAA,EACR,CAAC,OAAO,EAAE;AACZ;AAEA,MAAM,eAAe,CACnB,UACA,WACA,aACA,SACG;AACH,QAAM,aAAa,OAAO,QAAQ,EAAE,MAAM,EAAE;AAE5C,QAAM,EAAE,kBAAkB,MAAM,IAAI;AACpC,MAAI,cAAc,WAAW,OAAO,CAAC,MAAM,KAAK,UAAU;AACxD,QAAI,mBAAmB,QAAQ,KAAK,SAAS,OAAO,MAAM,CAAC,MAAM,KAAK;AACpE,aAAO;AAAA,IACT;AACA,WAAO,QAAQ,OAAO,QAAQ;AAAA,EAChC,CAAC;AAED,SAAO,YAAY,UAAU,YAAY,CAAC,MAAM,IAAK,aAAY,OAAO,GAAG,CAAC;AAG5E,gBAAc,YAAY,MAAM,GAAG,EAAE;AAErC,QAAM,gBAAY,kCAAoB,UAAU,aAAa,SAAS;AAEtE,aAAO;AAAA,IACL;AAAA,IACA,kBAAkB,iCAAiC;AAAA,IACnD;AAAA,IACA;AAAA,EACF;AACF;AAEO,MAAM,eAAiG,CAC5G,UACG;AACH,QAAM,uBAAmB,sDAA0D,OAAO,qDAAwB;AAClH,8DAA+B,kBAAkB,oDAAuB,yCAAgB;AACxF,QAAM,EAAE,aAAa,UAAU,cAAc,WAAW,eAAe,GAAG,KAAK,IAAI;AAEnF,QAAM,kBAAc,qBAAO,cAAc;AAEzC,QAAM,0BAAsB,4CAAuB,IAAI;AAOvD,QAAM,CAAC,EAAE,MAAM,QAAI,uBAAS,CAAC;AAE7B,QAAM,gBAA0D;AAAA,IAC9D,CAAC,MAAM;AACL,kBAAY,UAAU,EAAE;AACxB,UAAI,cAAe,eAAc,CAAC;AAAA,IACpC;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,QAAM,eAAuD;AAAA,IAC3D,CAAC,MAAM;AACL,YAAM,CAAC,MAAM,SAAS,IAAI,aAAa,EAAE,OAAO,OAAO,EAAE,OAAO,gBAAgB,GAAG,YAAY,SAAS,IAAI;AAE5G,kBAAY,CAAC,aAAa;AAExB,YAAI,SAAS,SAAU,QAAO,CAAC,QAAQ,MAAM,CAAC;AAC9C,eAAO;AAAA,MACT,CAAC;AAED,UAAI,aAAc,cAAa,GAAG,IAAI;AAEtC,0BAAoB,UAAM,gCAAkB,EAAE,QAAQ,SAAS,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,aAAa,qBAAqB,MAAM,YAAY;AAAA,EACvD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEO,MAAM,sBAAsB,CAAC,OAAe,SAAoD;AACrG,QAAM,CAAC,WAAW,IAAI,aAAa,OAAO,MAAM,SAAS,GAAG,IAAI,QAAQ,CAAC,CAAC;AAC1E,SAAO;AACT;AAEA,aAAa,cAAc;AACpB,MAAM,6BAAyB,kCAAS,YAAY;AAC3D,uBAAuB,YAAY;AACnC,uBAAuB,aAAa;AAAA,EAClC,WAAW,kCAAU,KAAK,YAAY,6BAA6B,EAAE;AAAA,EACrE,UAAU,kCAAU,KAAK,YAAY,2BAA2B,EAAE;AACpE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -70,13 +70,11 @@ const conformValue = (rawValue, cursorPos, lastKeyCode, regExp, filledMask) => {
|
|
|
70
70
|
}
|
|
71
71
|
} else {
|
|
72
72
|
specialChars.push([flatRegExp[i], i]);
|
|
73
|
-
if (rawValueArray[i + offSet] === flatRegExp[i])
|
|
74
|
-
charsFound += 1;
|
|
73
|
+
if (rawValueArray[i + offSet] === flatRegExp[i]) charsFound += 1;
|
|
75
74
|
specialCharsLeft += flatRegExp[i];
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
|
-
if (!fullRegExpMatched)
|
|
79
|
-
specialCharsLeft = "";
|
|
77
|
+
if (!fullRegExpMatched) specialCharsLeft = "";
|
|
80
78
|
const maskedPos = (0, import_utils.getPartialMaskedPos)(rawValue, maskedValue, cursorPos);
|
|
81
79
|
const [maskWithSpecialsChars, finalMaskedPos] = (0, import_utils.addSpecialCharacters)(
|
|
82
80
|
maskedValue,
|
|
@@ -104,8 +102,7 @@ const useRegExpMask = (props) => {
|
|
|
104
102
|
const onKeyDown = (0, import_react.useCallback)(
|
|
105
103
|
(e) => {
|
|
106
104
|
lastKeyCode.current = e.code;
|
|
107
|
-
if (userOnKeyDown)
|
|
108
|
-
userOnKeyDown(e);
|
|
105
|
+
if (userOnKeyDown) userOnKeyDown(e);
|
|
109
106
|
},
|
|
110
107
|
[userOnKeyDown]
|
|
111
108
|
);
|
|
@@ -119,12 +116,10 @@ const useRegExpMask = (props) => {
|
|
|
119
116
|
filledMask
|
|
120
117
|
);
|
|
121
118
|
valueSetter((prevMask) => {
|
|
122
|
-
if (mask === prevMask)
|
|
123
|
-
setKey((key) => key + 1);
|
|
119
|
+
if (mask === prevMask) setKey((key) => key + 1);
|
|
124
120
|
return mask;
|
|
125
121
|
});
|
|
126
|
-
if (userOnChange)
|
|
127
|
-
userOnChange(e, mask);
|
|
122
|
+
if (userOnChange) userOnChange(e, mask);
|
|
128
123
|
scheduleAfterRender(() => (0, import_utils.setCursorPosition)(e.target, cursorPos));
|
|
129
124
|
},
|
|
130
125
|
[regExp, filledMask, valueSetter, userOnChange, scheduleAfterRender]
|
|
@@ -135,11 +130,9 @@ const useRegExpMask = (props) => {
|
|
|
135
130
|
const maskedValue = e.target.value.split("");
|
|
136
131
|
const flatRegExp = (0, import_utils.flatStringArray)(regExp);
|
|
137
132
|
const firstUnderscoreIdx = maskedValue.findIndex((char, idx) => char === "_" && flatRegExp[idx] !== "_");
|
|
138
|
-
if (firstUnderscoreIdx > -1)
|
|
139
|
-
valueSetter(maskedValue.slice(0, firstUnderscoreIdx).join(""));
|
|
133
|
+
if (firstUnderscoreIdx > -1) valueSetter(maskedValue.slice(0, firstUnderscoreIdx).join(""));
|
|
140
134
|
}
|
|
141
|
-
if (userOnBlur)
|
|
142
|
-
userOnBlur(e);
|
|
135
|
+
if (userOnBlur) userOnBlur(e);
|
|
143
136
|
},
|
|
144
137
|
[filledMask, userOnBlur, regExp, valueSetter]
|
|
145
138
|
);
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/hooks/useRegExpMask.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
4
|
"sourcesContent": ["/* eslint-disable max-depth */\n/* eslint-disable max-statements */\n/* eslint-disable max-params */\nimport type React from 'react';\nimport { useCallback, useRef, useState } from 'react';\nimport {\n describe,\n PropTypes,\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useCallbackAfterRender } from '@elliemae/ds-utilities';\nimport { addSpecialCharacters, getPartialMaskedPos, setCursorPosition, flatStringArray } from '../utils/index.js';\nimport { useRegExpMaskDefaultProps, useRegExpMaskPropTypes, type UseRegExpMaskT } from '../react-desc-prop-types.js';\nimport { useRegExpMaskName } from '../DSMaskDefinitions.js';\n\nconst isRegExp = (item: RegExp | string): item is RegExp => typeof item === 'object';\n\nconst conformValue = (\n rawValue: string,\n cursorPos: number,\n lastKeyCode: string,\n regExp: string[],\n filledMask: boolean,\n) => {\n const specialChars: [string, number][] = [];\n const flatRegExp = flatStringArray(regExp);\n const rawValueArray = String(rawValue).split('');\n let offSet = 0;\n let charsFound = 0;\n let specialCharsLeft = '';\n let fullRegExpMatched = false;\n const maskedValue: string[] = [];\n for (let i = 0; i < flatRegExp.length; i += 1) {\n if (isRegExp(flatRegExp[i])) {\n specialCharsLeft = '';\n fullRegExpMatched = false;\n for (let j = charsFound + offSet; j < rawValueArray.length; j += 1) {\n const match = rawValueArray[j]?.match(flatRegExp[i]);\n if (match) {\n maskedValue.push(match[0]);\n charsFound += 1;\n fullRegExpMatched = true;\n break;\n } else {\n offSet += 1;\n }\n }\n if (filledMask && !fullRegExpMatched) {\n maskedValue.push('_');\n }\n } else {\n specialChars.push([flatRegExp[i], i]);\n if (rawValueArray[i + offSet] === flatRegExp[i]) charsFound += 1;\n specialCharsLeft += flatRegExp[i];\n }\n }\n if (!fullRegExpMatched) specialCharsLeft = '';\n\n const maskedPos = getPartialMaskedPos(rawValue, maskedValue, cursorPos);\n const [maskWithSpecialsChars, finalMaskedPos] = addSpecialCharacters(\n maskedValue,\n specialChars,\n maskedPos,\n lastKeyCode,\n );\n const maskReturn = maskWithSpecialsChars + specialCharsLeft;\n return [maskReturn, finalMaskedPos];\n};\n\nexport const useRegExpMask: ((args: UseRegExpMaskT.Props) => UseRegExpMaskT.OutputT) & { displayName: string } = (\n props,\n) => {\n const propsWithDefault = useMemoMergePropsWithDefault<UseRegExpMaskT.InternalProps>(props, useRegExpMaskDefaultProps);\n useValidateTypescriptPropTypes(propsWithDefault, useRegExpMaskPropTypes, useRegExpMaskName);\n const {\n valueSetter,\n onChange: userOnChange,\n onKeyDown: userOnKeyDown,\n onBlur: userOnBlur,\n regExp,\n filledMask,\n } = propsWithDefault;\n\n const lastKeyCode = useRef('Unidentified');\n\n const scheduleAfterRender = useCallbackAfterRender(true);\n\n // Some times, the value of the mask is not gonna change (user types invalid char for example)\n // This makes the input to go from \"correct\" -> \"incorrect\" -> \"correct\"\n // But since the input is controlled, the input does not re-render\n // This makes the input go mumbo-jumbo and places the cursor in the end, because we kinda changed the value async\n // Solution for this is to trigger a re-render, we do this with a set state call in the on change event\n const [, setKey] = useState(0);\n\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n lastKeyCode.current = e.code;\n if (userOnKeyDown) userOnKeyDown(e);\n },\n [userOnKeyDown],\n );\n\n const onChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const [mask, cursorPos] = conformValue(\n e.target.value,\n e.target.selectionEnd ?? 0,\n lastKeyCode.current,\n regExp,\n filledMask,\n );\n\n valueSetter((prevMask) => {\n // Here we need to update the key\n\n if (mask === prevMask) setKey((key) => key + 1);\n return mask as string;\n });\n\n if (userOnChange) userOnChange(e, mask as string);\n\n scheduleAfterRender(() => setCursorPosition(e.target, cursorPos as number));\n },\n [regExp, filledMask, valueSetter, userOnChange, scheduleAfterRender],\n );\n const onBlur: React.FocusEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n if (filledMask) {\n const maskedValue = e.target.value.split('');\n\n const flatRegExp = flatStringArray(regExp);\n const firstUnderscoreIdx = maskedValue.findIndex((char, idx) => char === '_' && flatRegExp[idx] !== '_');\n if (firstUnderscoreIdx > -1) valueSetter(maskedValue.slice(0, firstUnderscoreIdx).join(''));\n }\n\n if (userOnBlur) userOnBlur(e);\n },\n [filledMask, userOnBlur, regExp, valueSetter],\n );\n\n return {\n onKeyDown,\n onChange,\n onBlur,\n };\n};\n\nexport const getRegExpMaskedValue = (value: string, regExp: string[]) => {\n const [maskedValue] = conformValue(value, value.length - 1, '', regExp, false);\n return maskedValue;\n};\n\nuseRegExpMask.displayName = useRegExpMaskName;\nexport const UseRegExpMaskWithSchema = describe(useRegExpMask);\nUseRegExpMaskWithSchema.propTypes = useRegExpMaskPropTypes;\nUseRegExpMaskWithSchema.returnType = {\n onKeyDown: PropTypes.func.description('On key down event for input').isRequired,\n onChange: PropTypes.func.description('On change event for input').isRequired,\n onBlur: PropTypes.func.description('On blur event for input').isRequired,\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADIvB,mBAA8C;AAC9C,8BAKO;AACP,0BAAuC;AACvC,mBAA8F;AAC9F,mCAAuF;AACvF,+BAAkC;AAElC,MAAM,WAAW,CAAC,SAA0C,OAAO,SAAS;AAE5E,MAAM,eAAe,CACnB,UACA,WACA,aACA,QACA,eACG;AACH,QAAM,eAAmC,CAAC;AAC1C,QAAM,iBAAa,8BAAgB,MAAM;AACzC,QAAM,gBAAgB,OAAO,QAAQ,EAAE,MAAM,EAAE;AAC/C,MAAI,SAAS;AACb,MAAI,aAAa;AACjB,MAAI,mBAAmB;AACvB,MAAI,oBAAoB;AACxB,QAAM,cAAwB,CAAC;AAC/B,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,GAAG;AAC7C,QAAI,SAAS,WAAW,CAAC,CAAC,GAAG;AAC3B,yBAAmB;AACnB,0BAAoB;AACpB,eAAS,IAAI,aAAa,QAAQ,IAAI,cAAc,QAAQ,KAAK,GAAG;AAClE,cAAM,QAAQ,cAAc,CAAC,GAAG,MAAM,WAAW,CAAC,CAAC;AACnD,YAAI,OAAO;AACT,sBAAY,KAAK,MAAM,CAAC,CAAC;AACzB,wBAAc;AACd,8BAAoB;AACpB;AAAA,QACF,OAAO;AACL,oBAAU;AAAA,QACZ;AAAA,MACF;AACA,UAAI,cAAc,CAAC,mBAAmB;AACpC,oBAAY,KAAK,GAAG;AAAA,MACtB;AAAA,IACF,OAAO;AACL,mBAAa,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;AACpC,UAAI,cAAc,IAAI,MAAM,MAAM,WAAW,CAAC
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -60,8 +60,7 @@ const useSSNMask = (props) => {
|
|
|
60
60
|
const onKeyDown = (0, import_react.useCallback)(
|
|
61
61
|
(e) => {
|
|
62
62
|
lastKeyCode.current = e.code;
|
|
63
|
-
if (userOnKeyDown)
|
|
64
|
-
userOnKeyDown(e);
|
|
63
|
+
if (userOnKeyDown) userOnKeyDown(e);
|
|
65
64
|
},
|
|
66
65
|
[userOnKeyDown]
|
|
67
66
|
);
|
|
@@ -69,12 +68,10 @@ const useSSNMask = (props) => {
|
|
|
69
68
|
(e) => {
|
|
70
69
|
const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current);
|
|
71
70
|
valueSetter((prevMask) => {
|
|
72
|
-
if (mask === prevMask)
|
|
73
|
-
setKey((key) => key + 1);
|
|
71
|
+
if (mask === prevMask) setKey((key) => key + 1);
|
|
74
72
|
return mask;
|
|
75
73
|
});
|
|
76
|
-
if (userOnChange)
|
|
77
|
-
userOnChange(e, mask);
|
|
74
|
+
if (userOnChange) userOnChange(e, mask);
|
|
78
75
|
scheduleAfterRender(() => (0, import_utils.setCursorPosition)(e.target, cursorPos));
|
|
79
76
|
},
|
|
80
77
|
[valueSetter, scheduleAfterRender, userOnChange]
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/hooks/useSSNMask.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
4
|
"sourcesContent": ["import type React from 'react';\nimport { useCallback, useRef, useState } from 'react';\nimport {\n describe,\n PropTypes,\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useCallbackAfterRender } from '@elliemae/ds-utilities';\nimport { addSpecialCharacters, getPartialMaskedPos, setCursorPosition } from '../utils/index.js';\nimport { useMaskDefaultProps, useMaskPropTypes, type UseMaskT } from '../react-desc-prop-types.js';\nimport { useSSNMaskName } from '../DSMaskDefinitions.js';\n\nconst ssnSpecialChars: [string, number][] = [\n ['-', 3],\n ['-', 6],\n];\n\nconst conformValue = (rawValue: string, cursorPos: number, lastKeyCode: string) => {\n // Work with digits only\n let maskedValue = String(rawValue)\n .split('')\n .filter((char) => char >= '0' && char <= '9');\n\n // We only consider first 9 digits\n maskedValue = maskedValue.slice(0, 9);\n\n const maskedPos = getPartialMaskedPos(rawValue, maskedValue, cursorPos);\n\n return addSpecialCharacters(maskedValue, ssnSpecialChars, maskedPos, lastKeyCode);\n};\n\nexport const useSSNMask: ((args: UseMaskT.Props) => UseMaskT.OutputT) & { displayName: string } = (props) => {\n const propsWithDefault = useMemoMergePropsWithDefault<UseMaskT.InternalProps>(props, useMaskDefaultProps);\n useValidateTypescriptPropTypes(propsWithDefault, useMaskPropTypes, useSSNMaskName);\n\n const { valueSetter, onChange: userOnChange, onKeyDown: userOnKeyDown } = propsWithDefault;\n\n const lastKeyCode = useRef('Unidentified');\n\n const scheduleAfterRender = useCallbackAfterRender(true);\n\n // Some times, the value of the mask is not gonna change (user types invalid char for example)\n // This makes the input to go from \"correct\" -> \"incorrect\" -> \"correct\"\n // But since the input is controlled, the input does not re-render\n // This makes the input go mumbo-jumbo and places the cursor in the end, because we kinda changed the value async\n // Solution for this is to trigger a re-render, we do this with a set state call in the on change event\n const [, setKey] = useState(0);\n\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n lastKeyCode.current = e.code;\n if (userOnKeyDown) userOnKeyDown(e);\n },\n [userOnKeyDown],\n );\n\n const onChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current);\n valueSetter((prevMask) => {\n // Here we need to update the key\n if (mask === prevMask) setKey((key) => key + 1);\n\n return mask;\n });\n if (userOnChange) userOnChange(e, mask);\n scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));\n },\n [valueSetter, scheduleAfterRender, userOnChange],\n );\n\n return {\n onKeyDown,\n onChange,\n };\n};\n\nexport const getSSNMaskedValue = (value: string) => {\n const [maskedValue] = conformValue(value, value.length - 1, '');\n return maskedValue;\n};\n\nuseSSNMask.displayName = useSSNMaskName;\nexport const UseSSNMaskWithSchema = describe(useSSNMask);\nUseSSNMaskWithSchema.propTypes = useMaskPropTypes;\nUseSSNMaskWithSchema.returnType = {\n onKeyDown: PropTypes.func.description('On key down event for input').isRequired,\n onChange: PropTypes.func.description('On change event for input').isRequired,\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADCvB,mBAA8C;AAC9C,8BAKO;AACP,0BAAuC;AACvC,mBAA6E;AAC7E,mCAAqE;AACrE,+BAA+B;AAE/B,MAAM,kBAAsC;AAAA,EAC1C,CAAC,KAAK,CAAC;AAAA,EACP,CAAC,KAAK,CAAC;AACT;AAEA,MAAM,eAAe,CAAC,UAAkB,WAAmB,gBAAwB;AAEjF,MAAI,cAAc,OAAO,QAAQ,EAC9B,MAAM,EAAE,EACR,OAAO,CAAC,SAAS,QAAQ,OAAO,QAAQ,GAAG;AAG9C,gBAAc,YAAY,MAAM,GAAG,CAAC;AAEpC,QAAM,gBAAY,kCAAoB,UAAU,aAAa,SAAS;AAEtE,aAAO,mCAAqB,aAAa,iBAAiB,WAAW,WAAW;AAClF;AAEO,MAAM,aAAqF,CAAC,UAAU;AAC3G,QAAM,uBAAmB,sDAAqD,OAAO,gDAAmB;AACxG,8DAA+B,kBAAkB,+CAAkB,uCAAc;AAEjF,QAAM,EAAE,aAAa,UAAU,cAAc,WAAW,cAAc,IAAI;AAE1E,QAAM,kBAAc,qBAAO,cAAc;AAEzC,QAAM,0BAAsB,4CAAuB,IAAI;AAOvD,QAAM,CAAC,EAAE,MAAM,QAAI,uBAAS,CAAC;AAE7B,QAAM,gBAA0D;AAAA,IAC9D,CAAC,MAAM;AACL,kBAAY,UAAU,EAAE;AACxB,UAAI
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADCvB,mBAA8C;AAC9C,8BAKO;AACP,0BAAuC;AACvC,mBAA6E;AAC7E,mCAAqE;AACrE,+BAA+B;AAE/B,MAAM,kBAAsC;AAAA,EAC1C,CAAC,KAAK,CAAC;AAAA,EACP,CAAC,KAAK,CAAC;AACT;AAEA,MAAM,eAAe,CAAC,UAAkB,WAAmB,gBAAwB;AAEjF,MAAI,cAAc,OAAO,QAAQ,EAC9B,MAAM,EAAE,EACR,OAAO,CAAC,SAAS,QAAQ,OAAO,QAAQ,GAAG;AAG9C,gBAAc,YAAY,MAAM,GAAG,CAAC;AAEpC,QAAM,gBAAY,kCAAoB,UAAU,aAAa,SAAS;AAEtE,aAAO,mCAAqB,aAAa,iBAAiB,WAAW,WAAW;AAClF;AAEO,MAAM,aAAqF,CAAC,UAAU;AAC3G,QAAM,uBAAmB,sDAAqD,OAAO,gDAAmB;AACxG,8DAA+B,kBAAkB,+CAAkB,uCAAc;AAEjF,QAAM,EAAE,aAAa,UAAU,cAAc,WAAW,cAAc,IAAI;AAE1E,QAAM,kBAAc,qBAAO,cAAc;AAEzC,QAAM,0BAAsB,4CAAuB,IAAI;AAOvD,QAAM,CAAC,EAAE,MAAM,QAAI,uBAAS,CAAC;AAE7B,QAAM,gBAA0D;AAAA,IAC9D,CAAC,MAAM;AACL,kBAAY,UAAU,EAAE;AACxB,UAAI,cAAe,eAAc,CAAC;AAAA,IACpC;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,QAAM,eAAuD;AAAA,IAC3D,CAAC,MAAM;AACL,YAAM,CAAC,MAAM,SAAS,IAAI,aAAa,EAAE,OAAO,OAAO,EAAE,OAAO,gBAAgB,GAAG,YAAY,OAAO;AACtG,kBAAY,CAAC,aAAa;AAExB,YAAI,SAAS,SAAU,QAAO,CAAC,QAAQ,MAAM,CAAC;AAE9C,eAAO;AAAA,MACT,CAAC;AACD,UAAI,aAAc,cAAa,GAAG,IAAI;AACtC,0BAAoB,UAAM,gCAAkB,EAAE,QAAQ,SAAS,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,aAAa,qBAAqB,YAAY;AAAA,EACjD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEO,MAAM,oBAAoB,CAAC,UAAkB;AAClD,QAAM,CAAC,WAAW,IAAI,aAAa,OAAO,MAAM,SAAS,GAAG,EAAE;AAC9D,SAAO;AACT;AAEA,WAAW,cAAc;AAClB,MAAM,2BAAuB,kCAAS,UAAU;AACvD,qBAAqB,YAAY;AACjC,qBAAqB,aAAa;AAAA,EAChC,WAAW,kCAAU,KAAK,YAAY,6BAA6B,EAAE;AAAA,EACrE,UAAU,kCAAU,KAAK,YAAY,2BAA2B,EAAE;AACpE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -57,8 +57,7 @@ const useZipCodeMask = (props) => {
|
|
|
57
57
|
const onKeyDown = (0, import_react.useCallback)(
|
|
58
58
|
(e) => {
|
|
59
59
|
lastKeyCode.current = e.code;
|
|
60
|
-
if (userOnKeyDown)
|
|
61
|
-
userOnKeyDown(e);
|
|
60
|
+
if (userOnKeyDown) userOnKeyDown(e);
|
|
62
61
|
},
|
|
63
62
|
[userOnKeyDown]
|
|
64
63
|
);
|
|
@@ -66,12 +65,10 @@ const useZipCodeMask = (props) => {
|
|
|
66
65
|
(e) => {
|
|
67
66
|
const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current);
|
|
68
67
|
valueSetter((prevMask) => {
|
|
69
|
-
if (mask === prevMask)
|
|
70
|
-
setKey((key) => key + 1);
|
|
68
|
+
if (mask === prevMask) setKey((key) => key + 1);
|
|
71
69
|
return mask;
|
|
72
70
|
});
|
|
73
|
-
if (userOnChange)
|
|
74
|
-
userOnChange(e, mask);
|
|
71
|
+
if (userOnChange) userOnChange(e, mask);
|
|
75
72
|
scheduleAfterRender(() => (0, import_utils.setCursorPosition)(e.target, cursorPos));
|
|
76
73
|
},
|
|
77
74
|
[valueSetter, scheduleAfterRender, userOnChange]
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/hooks/useZipCodeMask.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
4
|
"sourcesContent": ["import type React from 'react';\nimport { useCallback, useRef, useState } from 'react';\nimport {\n describe,\n PropTypes,\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useCallbackAfterRender } from '@elliemae/ds-utilities';\nimport { addSpecialCharacters, getPartialMaskedPos, setCursorPosition } from '../utils/index.js';\nimport { useMaskDefaultProps, useMaskPropTypes, type UseMaskT } from '../react-desc-prop-types.js';\nimport { useZipCodeMaskName } from '../DSMaskDefinitions.js';\n\nconst zipCodeSpecialChars: [string, number][] = [['-', 5]];\n\nconst conformValue = (rawValue: string, cursorPos: number, lastKeyCode: string) => {\n // Work with digits only\n let maskedValue = String(rawValue)\n .split('')\n .filter((char) => char >= '0' && char <= '9');\n\n // We only consider first 9 digits\n maskedValue = maskedValue.slice(0, 9);\n\n const maskedPos = getPartialMaskedPos(rawValue, maskedValue, cursorPos);\n\n return addSpecialCharacters(maskedValue, zipCodeSpecialChars, maskedPos, lastKeyCode);\n};\n\nexport const useZipCodeMask: ((args: UseMaskT.Props) => UseMaskT.OutputT) & { displayName: string } = (props) => {\n const propsWithDefault = useMemoMergePropsWithDefault<UseMaskT.InternalProps>(props, useMaskDefaultProps);\n useValidateTypescriptPropTypes(propsWithDefault, useMaskPropTypes, useZipCodeMaskName);\n const { valueSetter, onChange: userOnChange, onKeyDown: userOnKeyDown } = propsWithDefault;\n\n const lastKeyCode = useRef('Unidentified');\n const scheduleAfterRender = useCallbackAfterRender(true);\n\n // Some times, the value of the mask is not gonna change (user types invalid char for example)\n // This makes the input to go from \"correct\" -> \"incorrect\" -> \"correct\"\n // But since the input is controlled, the input does not re-render\n // This makes the input go mumbo-jumbo and places the cursor in the end, because we kinda changed the value async\n // Solution for this is to trigger a re-render, we do this with a set state call in the on change event\n const [, setKey] = useState(0);\n\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n lastKeyCode.current = e.code;\n if (userOnKeyDown) userOnKeyDown(e);\n },\n [userOnKeyDown],\n );\n\n const onChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current);\n valueSetter((prevMask) => {\n // Here we need to update the key\n if (mask === prevMask) setKey((key) => key + 1);\n\n return mask;\n });\n if (userOnChange) userOnChange(e, mask);\n scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));\n },\n [valueSetter, scheduleAfterRender, userOnChange],\n );\n\n return {\n onKeyDown,\n onChange,\n };\n};\n\nexport const getZipCodeMaskedValue = (value: string) => {\n const [maskedValue] = conformValue(value, value.length - 1, '');\n return maskedValue;\n};\n\nuseZipCodeMask.displayName = useZipCodeMaskName;\nexport const UseZipCodeMaskWithSchema = describe(useZipCodeMask);\nUseZipCodeMaskWithSchema.propTypes = useMaskPropTypes;\nUseZipCodeMaskWithSchema.returnType = {\n onKeyDown: PropTypes.func.description('On key down event for input').isRequired,\n onChange: PropTypes.func.description('On change event for input').isRequired,\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADCvB,mBAA8C;AAC9C,8BAKO;AACP,0BAAuC;AACvC,mBAA6E;AAC7E,mCAAqE;AACrE,+BAAmC;AAEnC,MAAM,sBAA0C,CAAC,CAAC,KAAK,CAAC,CAAC;AAEzD,MAAM,eAAe,CAAC,UAAkB,WAAmB,gBAAwB;AAEjF,MAAI,cAAc,OAAO,QAAQ,EAC9B,MAAM,EAAE,EACR,OAAO,CAAC,SAAS,QAAQ,OAAO,QAAQ,GAAG;AAG9C,gBAAc,YAAY,MAAM,GAAG,CAAC;AAEpC,QAAM,gBAAY,kCAAoB,UAAU,aAAa,SAAS;AAEtE,aAAO,mCAAqB,aAAa,qBAAqB,WAAW,WAAW;AACtF;AAEO,MAAM,iBAAyF,CAAC,UAAU;AAC/G,QAAM,uBAAmB,sDAAqD,OAAO,gDAAmB;AACxG,8DAA+B,kBAAkB,+CAAkB,2CAAkB;AACrF,QAAM,EAAE,aAAa,UAAU,cAAc,WAAW,cAAc,IAAI;AAE1E,QAAM,kBAAc,qBAAO,cAAc;AACzC,QAAM,0BAAsB,4CAAuB,IAAI;AAOvD,QAAM,CAAC,EAAE,MAAM,QAAI,uBAAS,CAAC;AAE7B,QAAM,gBAA0D;AAAA,IAC9D,CAAC,MAAM;AACL,kBAAY,UAAU,EAAE;AACxB,UAAI
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADCvB,mBAA8C;AAC9C,8BAKO;AACP,0BAAuC;AACvC,mBAA6E;AAC7E,mCAAqE;AACrE,+BAAmC;AAEnC,MAAM,sBAA0C,CAAC,CAAC,KAAK,CAAC,CAAC;AAEzD,MAAM,eAAe,CAAC,UAAkB,WAAmB,gBAAwB;AAEjF,MAAI,cAAc,OAAO,QAAQ,EAC9B,MAAM,EAAE,EACR,OAAO,CAAC,SAAS,QAAQ,OAAO,QAAQ,GAAG;AAG9C,gBAAc,YAAY,MAAM,GAAG,CAAC;AAEpC,QAAM,gBAAY,kCAAoB,UAAU,aAAa,SAAS;AAEtE,aAAO,mCAAqB,aAAa,qBAAqB,WAAW,WAAW;AACtF;AAEO,MAAM,iBAAyF,CAAC,UAAU;AAC/G,QAAM,uBAAmB,sDAAqD,OAAO,gDAAmB;AACxG,8DAA+B,kBAAkB,+CAAkB,2CAAkB;AACrF,QAAM,EAAE,aAAa,UAAU,cAAc,WAAW,cAAc,IAAI;AAE1E,QAAM,kBAAc,qBAAO,cAAc;AACzC,QAAM,0BAAsB,4CAAuB,IAAI;AAOvD,QAAM,CAAC,EAAE,MAAM,QAAI,uBAAS,CAAC;AAE7B,QAAM,gBAA0D;AAAA,IAC9D,CAAC,MAAM;AACL,kBAAY,UAAU,EAAE;AACxB,UAAI,cAAe,eAAc,CAAC;AAAA,IACpC;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,QAAM,eAAuD;AAAA,IAC3D,CAAC,MAAM;AACL,YAAM,CAAC,MAAM,SAAS,IAAI,aAAa,EAAE,OAAO,OAAO,EAAE,OAAO,gBAAgB,GAAG,YAAY,OAAO;AACtG,kBAAY,CAAC,aAAa;AAExB,YAAI,SAAS,SAAU,QAAO,CAAC,QAAQ,MAAM,CAAC;AAE9C,eAAO;AAAA,MACT,CAAC;AACD,UAAI,aAAc,cAAa,GAAG,IAAI;AACtC,0BAAoB,UAAM,gCAAkB,EAAE,QAAQ,SAAS,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,aAAa,qBAAqB,YAAY;AAAA,EACjD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEO,MAAM,wBAAwB,CAAC,UAAkB;AACtD,QAAM,CAAC,WAAW,IAAI,aAAa,OAAO,MAAM,SAAS,GAAG,EAAE;AAC9D,SAAO;AACT;AAEA,eAAe,cAAc;AACtB,MAAM,+BAA2B,kCAAS,cAAc;AAC/D,yBAAyB,YAAY;AACrC,yBAAyB,aAAa;AAAA,EACpC,WAAW,kCAAU,KAAK,YAAY,6BAA6B,EAAE;AAAA,EACrE,UAAU,kCAAU,KAAK,YAAY,2BAA2B,EAAE;AACpE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -38,14 +38,12 @@ const addSpecialCharacters = (maskWithoutSpecialChars, specialCharsDescr, masked
|
|
|
38
38
|
specialCharsDescr.forEach(([chars, pos]) => {
|
|
39
39
|
if (finalMask.length > pos) {
|
|
40
40
|
finalMask.splice(pos, 0, ...chars);
|
|
41
|
-
if (finalMaskedPos >= pos)
|
|
42
|
-
finalMaskedPos += chars.length;
|
|
41
|
+
if (finalMaskedPos >= pos) finalMaskedPos += chars.length;
|
|
43
42
|
}
|
|
44
43
|
});
|
|
45
44
|
if (lastKeyCode !== "Backspace" && finalMaskedPos < finalMask.length) {
|
|
46
45
|
specialCharsDescr.forEach(([chars, pos]) => {
|
|
47
|
-
if (finalMaskedPos === pos)
|
|
48
|
-
finalMaskedPos += chars.length;
|
|
46
|
+
if (finalMaskedPos === pos) finalMaskedPos += chars.length;
|
|
49
47
|
});
|
|
50
48
|
} else if (lastKeyCode === "Backspace" && finalMaskedPos) {
|
|
51
49
|
for (let i = specialCharsDescr.length - 1; i >= 0; i -= 1) {
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/utils/addSpecialCharacters.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
4
|
"sourcesContent": ["/* eslint-disable max-params */\n/**\n *\n * @param {string[]} maskWithoutSpecialChars An array of characters with the unfinished mask\n * @param {[string, number][]} specialCharsDescr An array of tuples. Each tuple contains a string and a position (What string to add in a particular position)\n * @param {number} maskedPos Current masked position\n * @param {string} lastKeyCode Last key code of the user\n * @returns {[string, number]} A tuple containing the final mask and the final masked position\n */\nexport const addSpecialCharacters = (\n maskWithoutSpecialChars: string[],\n specialCharsDescr: [string, number][],\n maskedPos: number,\n lastKeyCode: string,\n): [string, number] => {\n const finalMask = maskWithoutSpecialChars;\n let finalMaskedPos = maskedPos;\n\n // We insert the special chars in the respective positions, tweaking the masked pos\n specialCharsDescr.forEach(([chars, pos]) => {\n if (finalMask.length > pos) {\n finalMask.splice(pos, 0, ...chars);\n if (finalMaskedPos >= pos) finalMaskedPos += chars.length;\n }\n });\n\n if (lastKeyCode !== 'Backspace' && finalMaskedPos < finalMask.length) {\n // If not erasing, move the cursor forward if we are in a special chars area\n specialCharsDescr.forEach(([chars, pos]) => {\n if (finalMaskedPos === pos) finalMaskedPos += chars.length;\n });\n } else if (lastKeyCode === 'Backspace' && finalMaskedPos) {\n // If erasing, move the cursor back if we are in a special chars area\n for (let i = specialCharsDescr.length - 1; i >= 0; i -= 1) {\n if (\n specialCharsDescr[i][1] + 1 <= finalMaskedPos &&\n finalMaskedPos <= specialCharsDescr[i][1] + specialCharsDescr[i][0].length\n )\n [, finalMaskedPos] = specialCharsDescr[i];\n }\n }\n\n return [finalMask.join(''), finalMaskedPos];\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADShB,MAAM,uBAAuB,CAClC,yBACA,mBACA,WACA,gBACqB;AACrB,QAAM,YAAY;AAClB,MAAI,iBAAiB;AAGrB,oBAAkB,QAAQ,CAAC,CAAC,OAAO,GAAG,MAAM;AAC1C,QAAI,UAAU,SAAS,KAAK;AAC1B,gBAAU,OAAO,KAAK,GAAG,GAAG,KAAK;AACjC,UAAI,kBAAkB
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADShB,MAAM,uBAAuB,CAClC,yBACA,mBACA,WACA,gBACqB;AACrB,QAAM,YAAY;AAClB,MAAI,iBAAiB;AAGrB,oBAAkB,QAAQ,CAAC,CAAC,OAAO,GAAG,MAAM;AAC1C,QAAI,UAAU,SAAS,KAAK;AAC1B,gBAAU,OAAO,KAAK,GAAG,GAAG,KAAK;AACjC,UAAI,kBAAkB,IAAK,mBAAkB,MAAM;AAAA,IACrD;AAAA,EACF,CAAC;AAED,MAAI,gBAAgB,eAAe,iBAAiB,UAAU,QAAQ;AAEpE,sBAAkB,QAAQ,CAAC,CAAC,OAAO,GAAG,MAAM;AAC1C,UAAI,mBAAmB,IAAK,mBAAkB,MAAM;AAAA,IACtD,CAAC;AAAA,EACH,WAAW,gBAAgB,eAAe,gBAAgB;AAExD,aAAS,IAAI,kBAAkB,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG;AACzD,UACE,kBAAkB,CAAC,EAAE,CAAC,IAAI,KAAK,kBAC/B,kBAAkB,kBAAkB,CAAC,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,CAAC,EAAE;AAEpE,SAAC,EAAE,cAAc,IAAI,kBAAkB,CAAC;AAAA,IAC5C;AAAA,EACF;AAEA,SAAO,CAAC,UAAU,KAAK,EAAE,GAAG,cAAc;AAC5C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -35,8 +35,7 @@ var React = __toESM(require("react"));
|
|
|
35
35
|
const getPartialMaskedPos = (rawValue, maskWithoutSpecialChars, cursorPos) => {
|
|
36
36
|
let maskedPos = 0;
|
|
37
37
|
for (let i = 0; i < cursorPos; i += 1) {
|
|
38
|
-
if (maskWithoutSpecialChars[maskedPos] === rawValue[i])
|
|
39
|
-
maskedPos += 1;
|
|
38
|
+
if (maskWithoutSpecialChars[maskedPos] === rawValue[i]) maskedPos += 1;
|
|
40
39
|
}
|
|
41
40
|
return maskedPos;
|
|
42
41
|
};
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/utils/getPartialMaskedPos.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
4
|
"sourcesContent": ["export const getPartialMaskedPos = (rawValue: string, maskWithoutSpecialChars: string[], cursorPos: number): number => {\n let maskedPos = 0;\n for (let i = 0; i < cursorPos; i += 1) {\n if (maskWithoutSpecialChars[maskedPos] === rawValue[i]) maskedPos += 1;\n }\n return maskedPos;\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAhB,MAAM,sBAAsB,CAAC,UAAkB,yBAAmC,cAA8B;AACrH,MAAI,YAAY;AAChB,WAAS,IAAI,GAAG,IAAI,WAAW,KAAK,GAAG;AACrC,QAAI,wBAAwB,SAAS,MAAM,SAAS,CAAC
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAhB,MAAM,sBAAsB,CAAC,UAAkB,yBAAmC,cAA8B;AACrH,MAAI,YAAY;AAChB,WAAS,IAAI,GAAG,IAAI,WAAW,KAAK,GAAG;AACrC,QAAI,wBAAwB,SAAS,MAAM,SAAS,CAAC,EAAG,cAAa;AAAA,EACvE;AACA,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -25,12 +25,10 @@ const conformValue = (rawValue, cursorPos, lastKeyCode, opts) => {
|
|
|
25
25
|
let finalPrefix = [prefix?.length, 0].includes(rawValue.indexOf("-")) && allowNegative ? "-" : "";
|
|
26
26
|
let maskedValue = String(rawValue).split("").filter((char, idx) => {
|
|
27
27
|
const validChar = char >= "0" && char <= "9" || char === "." && dotIdx === -1 && decimalPlaces;
|
|
28
|
-
if (char === "." && validChar)
|
|
29
|
-
dotIdx = idx;
|
|
28
|
+
if (char === "." && validChar) dotIdx = idx;
|
|
30
29
|
return validChar;
|
|
31
30
|
});
|
|
32
|
-
if (prefix && maskedValue.length)
|
|
33
|
-
finalPrefix += prefix;
|
|
31
|
+
if (prefix && maskedValue.length) finalPrefix += prefix;
|
|
34
32
|
while (maskedValue.length >= 2 && maskedValue[0] === "0" && maskedValue[1] !== ".") {
|
|
35
33
|
maskedValue = maskedValue.splice(1);
|
|
36
34
|
}
|
|
@@ -55,15 +53,11 @@ const conformValue = (rawValue, cursorPos, lastKeyCode, opts) => {
|
|
|
55
53
|
finalPrefix = "";
|
|
56
54
|
}
|
|
57
55
|
let maskedPos = 0;
|
|
58
|
-
if (maskedValue[maskedPos] === "0" && cursorPos === 1 + prefix.length)
|
|
59
|
-
|
|
60
|
-
if (zeroWasAdded)
|
|
61
|
-
maskedPos += 1;
|
|
56
|
+
if (maskedValue[maskedPos] === "0" && cursorPos === 1 + prefix.length) maskedPos += 1;
|
|
57
|
+
if (zeroWasAdded) maskedPos += 1;
|
|
62
58
|
for (let i = 0; i < cursorPos; i += 1) {
|
|
63
|
-
if (maskedValue[maskedPos] === THOUSANDSSEPARATOR)
|
|
64
|
-
|
|
65
|
-
if (maskedValue[maskedPos] === rawValue[i])
|
|
66
|
-
maskedPos += 1;
|
|
59
|
+
if (maskedValue[maskedPos] === THOUSANDSSEPARATOR) maskedPos += 1;
|
|
60
|
+
if (maskedValue[maskedPos] === rawValue[i]) maskedPos += 1;
|
|
67
61
|
}
|
|
68
62
|
maskedPos += finalPrefix.length;
|
|
69
63
|
const finalSuffix = maskedValue.length ? suffix : "";
|
|
@@ -88,8 +82,7 @@ const useNumberMask = (props) => {
|
|
|
88
82
|
const maskedValue = e.target.value;
|
|
89
83
|
const { decimalRequired = true, decimalPlaces = 2, suffix = "", prefix = "", min = -Infinity } = opts;
|
|
90
84
|
const value = Number(e.target.value.replace(/[,`${prefix}${suffix}`]/g, ""));
|
|
91
|
-
if (value < min)
|
|
92
|
-
valueSetter(`${prefix}${min.toString()}${suffix}`);
|
|
85
|
+
if (value < min) valueSetter(`${prefix}${min.toString()}${suffix}`);
|
|
93
86
|
const dotIdx = maskedValue.indexOf(".");
|
|
94
87
|
const minusIndex = maskedValue.indexOf("-");
|
|
95
88
|
const suffixIndex = suffix.length ? maskedValue.indexOf(suffix) : -1;
|
|
@@ -107,16 +100,14 @@ const useNumberMask = (props) => {
|
|
|
107
100
|
} else if (maskedValue.length - 1 === minusIndex) {
|
|
108
101
|
valueSetter(maskedValue.replace("-", ""));
|
|
109
102
|
}
|
|
110
|
-
if (userOnBlur)
|
|
111
|
-
userOnBlur(e);
|
|
103
|
+
if (userOnBlur) userOnBlur(e);
|
|
112
104
|
},
|
|
113
105
|
[userOnBlur, valueSetter, opts]
|
|
114
106
|
);
|
|
115
107
|
const onKeyDown = useCallback(
|
|
116
108
|
(e) => {
|
|
117
109
|
lastKeyCode.current = e.code;
|
|
118
|
-
if (userOnKeyDown)
|
|
119
|
-
userOnKeyDown(e);
|
|
110
|
+
if (userOnKeyDown) userOnKeyDown(e);
|
|
120
111
|
},
|
|
121
112
|
[userOnKeyDown]
|
|
122
113
|
);
|
|
@@ -130,15 +121,12 @@ const useNumberMask = (props) => {
|
|
|
130
121
|
);
|
|
131
122
|
const { max = Infinity, prefix = "", suffix = "" } = opts;
|
|
132
123
|
const value = Number(e.target.value.replace(/[,`${prefix}${suffix}`]/g, ""));
|
|
133
|
-
if (value > max)
|
|
134
|
-
return;
|
|
124
|
+
if (value > max) return;
|
|
135
125
|
valueSetter((prevMask) => {
|
|
136
|
-
if (mask === prevMask)
|
|
137
|
-
setKey((key) => key + 1);
|
|
126
|
+
if (mask === prevMask) setKey((key) => key + 1);
|
|
138
127
|
return mask;
|
|
139
128
|
});
|
|
140
|
-
if (userOnChange)
|
|
141
|
-
userOnChange(e, mask);
|
|
129
|
+
if (userOnChange) userOnChange(e, mask);
|
|
142
130
|
scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));
|
|
143
131
|
},
|
|
144
132
|
[valueSetter, scheduleAfterRender, userOnChange, opts]
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/hooks/useNumberMask.ts"],
|
|
4
4
|
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-params */\n/* eslint-disable max-statements */\n/* eslint-disable complexity */\nimport type React from 'react';\nimport { useCallback, useRef, useState } from 'react';\nimport {\n describe,\n PropTypes,\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useCallbackAfterRender } from '@elliemae/ds-utilities';\nimport { setCursorPosition } from '../utils/index.js';\nimport { useNumberMaskDefaultProps, useNumberMaskPropTypes, type UseNumberMaskT } from '../react-desc-prop-types.js';\nimport { useNumberMaskName } from '../DSMaskDefinitions.js';\n\nconst addThousandsSeparator = (n: string, separator: string) => n.replace(/\\B(?=(\\d{3})+(?!\\d))/g, separator);\n\nconst conformValue = (\n rawValue: string,\n cursorPos: number,\n lastKeyCode: string,\n opts: Omit<UseNumberMaskT.Props, 'valueSetter'>,\n): [string, number] => {\n const {\n includeThousandsSeparator = true,\n allowNegative = false,\n prefix = '',\n suffix = '',\n decimalPlaces = 2,\n decimalRequired = false,\n } = opts;\n const THOUSANDSSEPARATOR = ',';\n\n let dotIdx = -1;\n // allow minus sign before and after the preffix\n let finalPrefix = [prefix?.length, 0].includes(rawValue.indexOf('-')) && allowNegative ? '-' : '';\n\n let maskedValue = String(rawValue)\n .split('')\n .filter((char, idx) => {\n // we take only the first dot\n const validChar = (char >= '0' && char <= '9') || (char === '.' && dotIdx === -1 && decimalPlaces);\n if (char === '.' && validChar) dotIdx = idx;\n return validChar;\n });\n\n if (prefix && maskedValue.length) finalPrefix += prefix;\n\n // REMOVE FOLLOWING ZEROS IN INTEGER PART AFTER LEADER ZERO NUMBER\n while (maskedValue.length >= 2 && maskedValue[0] === '0' && maskedValue[1] !== '.') {\n maskedValue = maskedValue.splice(1);\n }\n dotIdx = maskedValue.findIndex((char) => char === '.');\n\n let integer = maskedValue.slice(0, dotIdx !== -1 ? dotIdx : maskedValue.length);\n const decimal = maskedValue.slice(dotIdx, dotIdx + decimalPlaces + 1);\n // ADDING THOUSANDS SEPARATOR\n if (includeThousandsSeparator) {\n integer = addThousandsSeparator(integer.join(''), THOUSANDSSEPARATOR).split('');\n }\n\n let zeroWasAdded = false;\n\n // MERGIN INT AND DECIMAL IF NECCESSARY\n if (dotIdx !== -1 && !(lastKeyCode === 'Backspace' && decimal.length === 1)) {\n if (integer.length) {\n maskedValue = [...integer, ...decimal];\n } else {\n // if theres no integer add a zero to the left of the dot to cover .23 => 0.23 case\n maskedValue = ['0', ...decimal];\n zeroWasAdded = true;\n }\n } else {\n // If decimal is required we add a dot after integer if exists\n maskedValue = decimalRequired && integer.length ? [...integer, '.'] : integer;\n }\n\n // remove orphans prefix for example \"-$\"\n if (lastKeyCode === 'Backspace' && maskedValue.length === 0) {\n finalPrefix = '';\n }\n\n // SET REAL CURSOR POSITION AFTER ADDING DOT and COMMAS SEPARATORS\n let maskedPos = 0;\n\n // 0 leading case we move the cursor to continue typing\n if (maskedValue[maskedPos] === '0' && cursorPos === 1 + prefix.length) maskedPos += 1;\n\n if (zeroWasAdded) maskedPos += 1;\n\n for (let i = 0; i < cursorPos; i += 1) {\n if (maskedValue[maskedPos] === THOUSANDSSEPARATOR) maskedPos += 1;\n if (maskedValue[maskedPos] === rawValue[i]) maskedPos += 1;\n }\n\n maskedPos += finalPrefix.length;\n\n const finalSuffix = maskedValue.length ? suffix : '';\n\n const maskedValueString = finalPrefix + maskedValue.join('') + finalSuffix;\n return [maskedValueString, maskedPos];\n};\n\nexport const useNumberMask: ((args: UseNumberMaskT.Props) => UseNumberMaskT.OutputT) & { displayName: string } = (\n props,\n) => {\n const propsWithDefault = useMemoMergePropsWithDefault<UseNumberMaskT.InternalProps>(props, useNumberMaskDefaultProps);\n useValidateTypescriptPropTypes(propsWithDefault, useNumberMaskPropTypes, useNumberMaskName);\n\n const {\n valueSetter,\n onChange: userOnChange,\n onKeyDown: userOnKeyDown,\n onBlur: userOnBlur,\n ...opts\n } = propsWithDefault;\n\n const lastKeyCode = useRef('Unidentified');\n\n const scheduleAfterRender = useCallbackAfterRender(true);\n\n // Some times, the value of the mask is not gonna change (user types invalid char for example)\n // This makes the input to go from \"correct\" -> \"incorrect\" -> \"correct\"\n // But since the input is controlled, the input does not re-render\n // This makes the input go mumbo-jumbo and places the cursor in the end, because we kinda changed the value async\n // Solution for this is to trigger a re-render, we do this with a set state call in the on change event\n const [, setKey] = useState(0);\n\n const onBlur: React.FocusEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const maskedValue = e.target.value;\n\n const { decimalRequired = true, decimalPlaces = 2, suffix = '', prefix = '', min = -Infinity } = opts;\n const value = Number(e.target.value.replace(/[,`${prefix}${suffix}`]/g, ''));\n if (value < min) valueSetter(`${prefix}${min.toString()}${suffix}`);\n\n const dotIdx = maskedValue.indexOf('.');\n const minusIndex = maskedValue.indexOf('-');\n\n const suffixIndex = suffix.length ? maskedValue.indexOf(suffix) : -1;\n\n if (decimalRequired) {\n if (dotIdx > -1) {\n const decimal = maskedValue.slice(dotIdx + 1, suffix.length ? -suffix.length : maskedValue.length);\n\n let zerosRest = '';\n while (decimal.length + zerosRest.length !== decimalPlaces) {\n zerosRest += '0';\n }\n\n valueSetter((suffix.length ? maskedValue.slice(0, suffixIndex) : maskedValue) + zerosRest + suffix);\n }\n } else if (maskedValue.length - suffix.length - 1 === dotIdx) {\n // removing orphans dots\n valueSetter(maskedValue.replace('.', ''));\n } else if (maskedValue.length - 1 === minusIndex) {\n // removing orphans minus\n valueSetter(maskedValue.replace('-', ''));\n }\n if (userOnBlur) userOnBlur(e);\n },\n [userOnBlur, valueSetter, opts],\n );\n\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n lastKeyCode.current = e.code;\n if (userOnKeyDown) userOnKeyDown(e);\n },\n [userOnKeyDown],\n );\n\n const onChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const [mask, cursorPos] = conformValue(\n e.target.value,\n e.target.selectionEnd ?? 0,\n lastKeyCode.current,\n opts as UseNumberMaskT.Props,\n );\n\n // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\n const { max = Infinity, prefix = '', suffix = '' } = opts;\n const value = Number(e.target.value.replace(/[,`${prefix}${suffix}`]/g, ''));\n if (value > max) return;\n\n valueSetter((prevMask) => {\n // Here we need to update the key\n if (mask === prevMask) setKey((key) => key + 1);\n\n return mask;\n });\n if (userOnChange) userOnChange(e, mask);\n scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));\n },\n [valueSetter, scheduleAfterRender, userOnChange, opts],\n );\n\n return {\n onKeyDown,\n onChange,\n onBlur,\n };\n};\n\nexport const getNumberMaskedValue = (value: string, opts: Omit<UseNumberMaskT.Props, 'valueSetter'>) => {\n const [maskedValue] = conformValue(value, value.length - 1, '', opts);\n return maskedValue;\n};\n\nuseNumberMask.displayName = useNumberMaskName;\nexport const UseNumberMaskWithSchema = describe(useNumberMask);\nUseNumberMaskWithSchema.propTypes = useNumberMaskPropTypes;\nUseNumberMaskWithSchema.returnType = {\n onKeyDown: PropTypes.func.description('On key down event for input').isRequired,\n onChange: PropTypes.func.description('On change event for input').isRequired,\n onBlur: PropTypes.func.description('On blur event for input').isRequired,\n};\n"],
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACIvB,SAAS,aAAa,QAAQ,gBAAgB;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,8BAA8B;AACvC,SAAS,yBAAyB;AAClC,SAAS,2BAA2B,8BAAmD;AACvF,SAAS,yBAAyB;AAElC,MAAM,wBAAwB,CAAC,GAAW,cAAsB,EAAE,QAAQ,yBAAyB,SAAS;AAE5G,MAAM,eAAe,CACnB,UACA,WACA,aACA,SACqB;AACrB,QAAM;AAAA,IACJ,4BAA4B;AAAA,IAC5B,gBAAgB;AAAA,IAChB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,EACpB,IAAI;AACJ,QAAM,qBAAqB;AAE3B,MAAI,SAAS;AAEb,MAAI,cAAc,CAAC,QAAQ,QAAQ,CAAC,EAAE,SAAS,SAAS,QAAQ,GAAG,CAAC,KAAK,gBAAgB,MAAM;AAE/F,MAAI,cAAc,OAAO,QAAQ,EAC9B,MAAM,EAAE,EACR,OAAO,CAAC,MAAM,QAAQ;AAErB,UAAM,YAAa,QAAQ,OAAO,QAAQ,OAAS,SAAS,OAAO,WAAW,MAAM;AACpF,QAAI,SAAS,OAAO
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -29,8 +29,7 @@ const conformValue = (rawValue, cursorPos, lastKeyCode, opts) => {
|
|
|
29
29
|
}
|
|
30
30
|
return char >= "0" && char <= "9";
|
|
31
31
|
});
|
|
32
|
-
while (maskedValue.length && maskedValue[0] === "0")
|
|
33
|
-
maskedValue.splice(0, 1);
|
|
32
|
+
while (maskedValue.length && maskedValue[0] === "0") maskedValue.splice(0, 1);
|
|
34
33
|
maskedValue = maskedValue.slice(0, 10);
|
|
35
34
|
const maskedPos = getPartialMaskedPos(rawValue, maskedValue, cursorPos);
|
|
36
35
|
return addSpecialCharacters(
|
|
@@ -50,8 +49,7 @@ const usePhoneMask = (props) => {
|
|
|
50
49
|
const onKeyDown = useCallback(
|
|
51
50
|
(e) => {
|
|
52
51
|
lastKeyCode.current = e.code;
|
|
53
|
-
if (userOnKeyDown)
|
|
54
|
-
userOnKeyDown(e);
|
|
52
|
+
if (userOnKeyDown) userOnKeyDown(e);
|
|
55
53
|
},
|
|
56
54
|
[userOnKeyDown]
|
|
57
55
|
);
|
|
@@ -59,12 +57,10 @@ const usePhoneMask = (props) => {
|
|
|
59
57
|
(e) => {
|
|
60
58
|
const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current, opts);
|
|
61
59
|
valueSetter((prevMask) => {
|
|
62
|
-
if (mask === prevMask)
|
|
63
|
-
setKey((key) => key + 1);
|
|
60
|
+
if (mask === prevMask) setKey((key) => key + 1);
|
|
64
61
|
return mask;
|
|
65
62
|
});
|
|
66
|
-
if (userOnChange)
|
|
67
|
-
userOnChange(e, mask);
|
|
63
|
+
if (userOnChange) userOnChange(e, mask);
|
|
68
64
|
scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));
|
|
69
65
|
},
|
|
70
66
|
[valueSetter, scheduleAfterRender, opts, userOnChange]
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/hooks/usePhoneMask.ts"],
|
|
4
4
|
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-params */\nimport type React from 'react';\nimport { useCallback, useRef, useState } from 'react';\nimport {\n describe,\n PropTypes,\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useCallbackAfterRender } from '@elliemae/ds-utilities';\nimport { addSpecialCharacters, getPartialMaskedPos, setCursorPosition } from '../utils/index.js';\nimport { usePhoneMaskDefaultProps, usePhoneMaskPropTypes, type UsePhoneMaskT } from '../react-desc-prop-types.js';\nimport { usePhoneMaskName } from '../DSMaskDefinitions.js';\n\nconst phoneSpecialChars: [string, number][] = [\n ['(', 0],\n [') ', 4],\n [' - ', 9],\n];\n\nconst internationalPhoneSpecialChars: [string, number][] = [\n ['+1 (', 0],\n [') ', 7],\n [' - ', 12],\n];\n\nconst conformValue = (\n rawValue: string,\n cursorPos: number,\n lastKeyCode: string,\n opts: Omit<UsePhoneMaskT.Props, 'valueSetter'>,\n) => {\n const characters = String(rawValue).split('');\n // Work with digits only\n const { isInternational = false } = opts;\n let maskedValue = characters.filter((char, idx, array) => {\n if (isInternational && idx === 1 && char === '1' && array[0] === '+') {\n return false;\n }\n return char >= '0' && char <= '9';\n });\n // We can't have zeros at the start of the array\n while (maskedValue.length && maskedValue[0] === '0') maskedValue.splice(0, 1);\n\n // We only consider first 10 digits\n maskedValue = maskedValue.slice(0, 10);\n\n const maskedPos = getPartialMaskedPos(rawValue, maskedValue, cursorPos);\n\n return addSpecialCharacters(\n maskedValue,\n isInternational ? internationalPhoneSpecialChars : phoneSpecialChars,\n maskedPos,\n lastKeyCode,\n );\n};\n\nexport const usePhoneMask: ((args: UsePhoneMaskT.Props) => UsePhoneMaskT.OutputT) & { displayName: string } = (\n props,\n) => {\n const propsWithDefault = useMemoMergePropsWithDefault<UsePhoneMaskT.InternalProps>(props, usePhoneMaskDefaultProps);\n useValidateTypescriptPropTypes(propsWithDefault, usePhoneMaskPropTypes, usePhoneMaskName);\n const { valueSetter, onChange: userOnChange, onKeyDown: userOnKeyDown, ...opts } = propsWithDefault;\n\n const lastKeyCode = useRef('Unidentified');\n\n const scheduleAfterRender = useCallbackAfterRender(true);\n\n // Some times, the value of the mask is not gonna change (user types invalid char for example)\n // This makes the input to go from \"correct\" -> \"incorrect\" -> \"correct\"\n // But since the input is controlled, the input does not re-render\n // This makes the input go mumbo-jumbo and places the cursor in the end, because we kinda changed the value async\n // Solution for this is to trigger a re-render, we do this with a set state call in the on change event\n const [, setKey] = useState(0);\n\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n lastKeyCode.current = e.code;\n if (userOnKeyDown) userOnKeyDown(e);\n },\n [userOnKeyDown],\n );\n\n const onChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current, opts);\n\n valueSetter((prevMask) => {\n // Here we need to update the key\n if (mask === prevMask) setKey((key) => key + 1);\n return mask;\n });\n\n if (userOnChange) userOnChange(e, mask);\n\n scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));\n },\n [valueSetter, scheduleAfterRender, opts, userOnChange],\n );\n\n return {\n onKeyDown,\n onChange,\n };\n};\n\nexport const getPhoneMaskedValue = (value: string, opts?: Omit<UsePhoneMaskT.Props, 'valueSetter'>) => {\n const [maskedValue] = conformValue(value, value.length - 1, '', opts || {});\n return maskedValue;\n};\n\nusePhoneMask.displayName = usePhoneMaskName;\nexport const UsePhoneMaskWithSchema = describe(usePhoneMask);\nUsePhoneMaskWithSchema.propTypes = usePhoneMaskPropTypes;\nUsePhoneMaskWithSchema.returnType = {\n onKeyDown: PropTypes.func.description('On key down event for input').isRequired,\n onChange: PropTypes.func.description('On change event for input').isRequired,\n};\n"],
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACEvB,SAAS,aAAa,QAAQ,gBAAgB;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,8BAA8B;AACvC,SAAS,sBAAsB,qBAAqB,yBAAyB;AAC7E,SAAS,0BAA0B,6BAAiD;AACpF,SAAS,wBAAwB;AAEjC,MAAM,oBAAwC;AAAA,EAC5C,CAAC,KAAK,CAAC;AAAA,EACP,CAAC,MAAM,CAAC;AAAA,EACR,CAAC,OAAO,CAAC;AACX;AAEA,MAAM,iCAAqD;AAAA,EACzD,CAAC,QAAQ,CAAC;AAAA,EACV,CAAC,MAAM,CAAC;AAAA,EACR,CAAC,OAAO,EAAE;AACZ;AAEA,MAAM,eAAe,CACnB,UACA,WACA,aACA,SACG;AACH,QAAM,aAAa,OAAO,QAAQ,EAAE,MAAM,EAAE;AAE5C,QAAM,EAAE,kBAAkB,MAAM,IAAI;AACpC,MAAI,cAAc,WAAW,OAAO,CAAC,MAAM,KAAK,UAAU;AACxD,QAAI,mBAAmB,QAAQ,KAAK,SAAS,OAAO,MAAM,CAAC,MAAM,KAAK;AACpE,aAAO;AAAA,IACT;AACA,WAAO,QAAQ,OAAO,QAAQ;AAAA,EAChC,CAAC;AAED,SAAO,YAAY,UAAU,YAAY,CAAC,MAAM
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACEvB,SAAS,aAAa,QAAQ,gBAAgB;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,8BAA8B;AACvC,SAAS,sBAAsB,qBAAqB,yBAAyB;AAC7E,SAAS,0BAA0B,6BAAiD;AACpF,SAAS,wBAAwB;AAEjC,MAAM,oBAAwC;AAAA,EAC5C,CAAC,KAAK,CAAC;AAAA,EACP,CAAC,MAAM,CAAC;AAAA,EACR,CAAC,OAAO,CAAC;AACX;AAEA,MAAM,iCAAqD;AAAA,EACzD,CAAC,QAAQ,CAAC;AAAA,EACV,CAAC,MAAM,CAAC;AAAA,EACR,CAAC,OAAO,EAAE;AACZ;AAEA,MAAM,eAAe,CACnB,UACA,WACA,aACA,SACG;AACH,QAAM,aAAa,OAAO,QAAQ,EAAE,MAAM,EAAE;AAE5C,QAAM,EAAE,kBAAkB,MAAM,IAAI;AACpC,MAAI,cAAc,WAAW,OAAO,CAAC,MAAM,KAAK,UAAU;AACxD,QAAI,mBAAmB,QAAQ,KAAK,SAAS,OAAO,MAAM,CAAC,MAAM,KAAK;AACpE,aAAO;AAAA,IACT;AACA,WAAO,QAAQ,OAAO,QAAQ;AAAA,EAChC,CAAC;AAED,SAAO,YAAY,UAAU,YAAY,CAAC,MAAM,IAAK,aAAY,OAAO,GAAG,CAAC;AAG5E,gBAAc,YAAY,MAAM,GAAG,EAAE;AAErC,QAAM,YAAY,oBAAoB,UAAU,aAAa,SAAS;AAEtE,SAAO;AAAA,IACL;AAAA,IACA,kBAAkB,iCAAiC;AAAA,IACnD;AAAA,IACA;AAAA,EACF;AACF;AAEO,MAAM,eAAiG,CAC5G,UACG;AACH,QAAM,mBAAmB,6BAA0D,OAAO,wBAAwB;AAClH,iCAA+B,kBAAkB,uBAAuB,gBAAgB;AACxF,QAAM,EAAE,aAAa,UAAU,cAAc,WAAW,eAAe,GAAG,KAAK,IAAI;AAEnF,QAAM,cAAc,OAAO,cAAc;AAEzC,QAAM,sBAAsB,uBAAuB,IAAI;AAOvD,QAAM,CAAC,EAAE,MAAM,IAAI,SAAS,CAAC;AAE7B,QAAM,YAA0D;AAAA,IAC9D,CAAC,MAAM;AACL,kBAAY,UAAU,EAAE;AACxB,UAAI,cAAe,eAAc,CAAC;AAAA,IACpC;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,QAAM,WAAuD;AAAA,IAC3D,CAAC,MAAM;AACL,YAAM,CAAC,MAAM,SAAS,IAAI,aAAa,EAAE,OAAO,OAAO,EAAE,OAAO,gBAAgB,GAAG,YAAY,SAAS,IAAI;AAE5G,kBAAY,CAAC,aAAa;AAExB,YAAI,SAAS,SAAU,QAAO,CAAC,QAAQ,MAAM,CAAC;AAC9C,eAAO;AAAA,MACT,CAAC;AAED,UAAI,aAAc,cAAa,GAAG,IAAI;AAEtC,0BAAoB,MAAM,kBAAkB,EAAE,QAAQ,SAAS,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,aAAa,qBAAqB,MAAM,YAAY;AAAA,EACvD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEO,MAAM,sBAAsB,CAAC,OAAe,SAAoD;AACrG,QAAM,CAAC,WAAW,IAAI,aAAa,OAAO,MAAM,SAAS,GAAG,IAAI,QAAQ,CAAC,CAAC;AAC1E,SAAO;AACT;AAEA,aAAa,cAAc;AACpB,MAAM,yBAAyB,SAAS,YAAY;AAC3D,uBAAuB,YAAY;AACnC,uBAAuB,aAAa;AAAA,EAClC,WAAW,UAAU,KAAK,YAAY,6BAA6B,EAAE;AAAA,EACrE,UAAU,UAAU,KAAK,YAAY,2BAA2B,EAAE;AACpE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -40,13 +40,11 @@ const conformValue = (rawValue, cursorPos, lastKeyCode, regExp, filledMask) => {
|
|
|
40
40
|
}
|
|
41
41
|
} else {
|
|
42
42
|
specialChars.push([flatRegExp[i], i]);
|
|
43
|
-
if (rawValueArray[i + offSet] === flatRegExp[i])
|
|
44
|
-
charsFound += 1;
|
|
43
|
+
if (rawValueArray[i + offSet] === flatRegExp[i]) charsFound += 1;
|
|
45
44
|
specialCharsLeft += flatRegExp[i];
|
|
46
45
|
}
|
|
47
46
|
}
|
|
48
|
-
if (!fullRegExpMatched)
|
|
49
|
-
specialCharsLeft = "";
|
|
47
|
+
if (!fullRegExpMatched) specialCharsLeft = "";
|
|
50
48
|
const maskedPos = getPartialMaskedPos(rawValue, maskedValue, cursorPos);
|
|
51
49
|
const [maskWithSpecialsChars, finalMaskedPos] = addSpecialCharacters(
|
|
52
50
|
maskedValue,
|
|
@@ -74,8 +72,7 @@ const useRegExpMask = (props) => {
|
|
|
74
72
|
const onKeyDown = useCallback(
|
|
75
73
|
(e) => {
|
|
76
74
|
lastKeyCode.current = e.code;
|
|
77
|
-
if (userOnKeyDown)
|
|
78
|
-
userOnKeyDown(e);
|
|
75
|
+
if (userOnKeyDown) userOnKeyDown(e);
|
|
79
76
|
},
|
|
80
77
|
[userOnKeyDown]
|
|
81
78
|
);
|
|
@@ -89,12 +86,10 @@ const useRegExpMask = (props) => {
|
|
|
89
86
|
filledMask
|
|
90
87
|
);
|
|
91
88
|
valueSetter((prevMask) => {
|
|
92
|
-
if (mask === prevMask)
|
|
93
|
-
setKey((key) => key + 1);
|
|
89
|
+
if (mask === prevMask) setKey((key) => key + 1);
|
|
94
90
|
return mask;
|
|
95
91
|
});
|
|
96
|
-
if (userOnChange)
|
|
97
|
-
userOnChange(e, mask);
|
|
92
|
+
if (userOnChange) userOnChange(e, mask);
|
|
98
93
|
scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));
|
|
99
94
|
},
|
|
100
95
|
[regExp, filledMask, valueSetter, userOnChange, scheduleAfterRender]
|
|
@@ -105,11 +100,9 @@ const useRegExpMask = (props) => {
|
|
|
105
100
|
const maskedValue = e.target.value.split("");
|
|
106
101
|
const flatRegExp = flatStringArray(regExp);
|
|
107
102
|
const firstUnderscoreIdx = maskedValue.findIndex((char, idx) => char === "_" && flatRegExp[idx] !== "_");
|
|
108
|
-
if (firstUnderscoreIdx > -1)
|
|
109
|
-
valueSetter(maskedValue.slice(0, firstUnderscoreIdx).join(""));
|
|
103
|
+
if (firstUnderscoreIdx > -1) valueSetter(maskedValue.slice(0, firstUnderscoreIdx).join(""));
|
|
110
104
|
}
|
|
111
|
-
if (userOnBlur)
|
|
112
|
-
userOnBlur(e);
|
|
105
|
+
if (userOnBlur) userOnBlur(e);
|
|
113
106
|
},
|
|
114
107
|
[filledMask, userOnBlur, regExp, valueSetter]
|
|
115
108
|
);
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/hooks/useRegExpMask.ts"],
|
|
4
4
|
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-depth */\n/* eslint-disable max-statements */\n/* eslint-disable max-params */\nimport type React from 'react';\nimport { useCallback, useRef, useState } from 'react';\nimport {\n describe,\n PropTypes,\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useCallbackAfterRender } from '@elliemae/ds-utilities';\nimport { addSpecialCharacters, getPartialMaskedPos, setCursorPosition, flatStringArray } from '../utils/index.js';\nimport { useRegExpMaskDefaultProps, useRegExpMaskPropTypes, type UseRegExpMaskT } from '../react-desc-prop-types.js';\nimport { useRegExpMaskName } from '../DSMaskDefinitions.js';\n\nconst isRegExp = (item: RegExp | string): item is RegExp => typeof item === 'object';\n\nconst conformValue = (\n rawValue: string,\n cursorPos: number,\n lastKeyCode: string,\n regExp: string[],\n filledMask: boolean,\n) => {\n const specialChars: [string, number][] = [];\n const flatRegExp = flatStringArray(regExp);\n const rawValueArray = String(rawValue).split('');\n let offSet = 0;\n let charsFound = 0;\n let specialCharsLeft = '';\n let fullRegExpMatched = false;\n const maskedValue: string[] = [];\n for (let i = 0; i < flatRegExp.length; i += 1) {\n if (isRegExp(flatRegExp[i])) {\n specialCharsLeft = '';\n fullRegExpMatched = false;\n for (let j = charsFound + offSet; j < rawValueArray.length; j += 1) {\n const match = rawValueArray[j]?.match(flatRegExp[i]);\n if (match) {\n maskedValue.push(match[0]);\n charsFound += 1;\n fullRegExpMatched = true;\n break;\n } else {\n offSet += 1;\n }\n }\n if (filledMask && !fullRegExpMatched) {\n maskedValue.push('_');\n }\n } else {\n specialChars.push([flatRegExp[i], i]);\n if (rawValueArray[i + offSet] === flatRegExp[i]) charsFound += 1;\n specialCharsLeft += flatRegExp[i];\n }\n }\n if (!fullRegExpMatched) specialCharsLeft = '';\n\n const maskedPos = getPartialMaskedPos(rawValue, maskedValue, cursorPos);\n const [maskWithSpecialsChars, finalMaskedPos] = addSpecialCharacters(\n maskedValue,\n specialChars,\n maskedPos,\n lastKeyCode,\n );\n const maskReturn = maskWithSpecialsChars + specialCharsLeft;\n return [maskReturn, finalMaskedPos];\n};\n\nexport const useRegExpMask: ((args: UseRegExpMaskT.Props) => UseRegExpMaskT.OutputT) & { displayName: string } = (\n props,\n) => {\n const propsWithDefault = useMemoMergePropsWithDefault<UseRegExpMaskT.InternalProps>(props, useRegExpMaskDefaultProps);\n useValidateTypescriptPropTypes(propsWithDefault, useRegExpMaskPropTypes, useRegExpMaskName);\n const {\n valueSetter,\n onChange: userOnChange,\n onKeyDown: userOnKeyDown,\n onBlur: userOnBlur,\n regExp,\n filledMask,\n } = propsWithDefault;\n\n const lastKeyCode = useRef('Unidentified');\n\n const scheduleAfterRender = useCallbackAfterRender(true);\n\n // Some times, the value of the mask is not gonna change (user types invalid char for example)\n // This makes the input to go from \"correct\" -> \"incorrect\" -> \"correct\"\n // But since the input is controlled, the input does not re-render\n // This makes the input go mumbo-jumbo and places the cursor in the end, because we kinda changed the value async\n // Solution for this is to trigger a re-render, we do this with a set state call in the on change event\n const [, setKey] = useState(0);\n\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n lastKeyCode.current = e.code;\n if (userOnKeyDown) userOnKeyDown(e);\n },\n [userOnKeyDown],\n );\n\n const onChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const [mask, cursorPos] = conformValue(\n e.target.value,\n e.target.selectionEnd ?? 0,\n lastKeyCode.current,\n regExp,\n filledMask,\n );\n\n valueSetter((prevMask) => {\n // Here we need to update the key\n\n if (mask === prevMask) setKey((key) => key + 1);\n return mask as string;\n });\n\n if (userOnChange) userOnChange(e, mask as string);\n\n scheduleAfterRender(() => setCursorPosition(e.target, cursorPos as number));\n },\n [regExp, filledMask, valueSetter, userOnChange, scheduleAfterRender],\n );\n const onBlur: React.FocusEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n if (filledMask) {\n const maskedValue = e.target.value.split('');\n\n const flatRegExp = flatStringArray(regExp);\n const firstUnderscoreIdx = maskedValue.findIndex((char, idx) => char === '_' && flatRegExp[idx] !== '_');\n if (firstUnderscoreIdx > -1) valueSetter(maskedValue.slice(0, firstUnderscoreIdx).join(''));\n }\n\n if (userOnBlur) userOnBlur(e);\n },\n [filledMask, userOnBlur, regExp, valueSetter],\n );\n\n return {\n onKeyDown,\n onChange,\n onBlur,\n };\n};\n\nexport const getRegExpMaskedValue = (value: string, regExp: string[]) => {\n const [maskedValue] = conformValue(value, value.length - 1, '', regExp, false);\n return maskedValue;\n};\n\nuseRegExpMask.displayName = useRegExpMaskName;\nexport const UseRegExpMaskWithSchema = describe(useRegExpMask);\nUseRegExpMaskWithSchema.propTypes = useRegExpMaskPropTypes;\nUseRegExpMaskWithSchema.returnType = {\n onKeyDown: PropTypes.func.description('On key down event for input').isRequired,\n onChange: PropTypes.func.description('On change event for input').isRequired,\n onBlur: PropTypes.func.description('On blur event for input').isRequired,\n};\n"],
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACIvB,SAAS,aAAa,QAAQ,gBAAgB;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,8BAA8B;AACvC,SAAS,sBAAsB,qBAAqB,mBAAmB,uBAAuB;AAC9F,SAAS,2BAA2B,8BAAmD;AACvF,SAAS,yBAAyB;AAElC,MAAM,WAAW,CAAC,SAA0C,OAAO,SAAS;AAE5E,MAAM,eAAe,CACnB,UACA,WACA,aACA,QACA,eACG;AACH,QAAM,eAAmC,CAAC;AAC1C,QAAM,aAAa,gBAAgB,MAAM;AACzC,QAAM,gBAAgB,OAAO,QAAQ,EAAE,MAAM,EAAE;AAC/C,MAAI,SAAS;AACb,MAAI,aAAa;AACjB,MAAI,mBAAmB;AACvB,MAAI,oBAAoB;AACxB,QAAM,cAAwB,CAAC;AAC/B,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,GAAG;AAC7C,QAAI,SAAS,WAAW,CAAC,CAAC,GAAG;AAC3B,yBAAmB;AACnB,0BAAoB;AACpB,eAAS,IAAI,aAAa,QAAQ,IAAI,cAAc,QAAQ,KAAK,GAAG;AAClE,cAAM,QAAQ,cAAc,CAAC,GAAG,MAAM,WAAW,CAAC,CAAC;AACnD,YAAI,OAAO;AACT,sBAAY,KAAK,MAAM,CAAC,CAAC;AACzB,wBAAc;AACd,8BAAoB;AACpB;AAAA,QACF,OAAO;AACL,oBAAU;AAAA,QACZ;AAAA,MACF;AACA,UAAI,cAAc,CAAC,mBAAmB;AACpC,oBAAY,KAAK,GAAG;AAAA,MACtB;AAAA,IACF,OAAO;AACL,mBAAa,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;AACpC,UAAI,cAAc,IAAI,MAAM,MAAM,WAAW,CAAC
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -30,8 +30,7 @@ const useSSNMask = (props) => {
|
|
|
30
30
|
const onKeyDown = useCallback(
|
|
31
31
|
(e) => {
|
|
32
32
|
lastKeyCode.current = e.code;
|
|
33
|
-
if (userOnKeyDown)
|
|
34
|
-
userOnKeyDown(e);
|
|
33
|
+
if (userOnKeyDown) userOnKeyDown(e);
|
|
35
34
|
},
|
|
36
35
|
[userOnKeyDown]
|
|
37
36
|
);
|
|
@@ -39,12 +38,10 @@ const useSSNMask = (props) => {
|
|
|
39
38
|
(e) => {
|
|
40
39
|
const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current);
|
|
41
40
|
valueSetter((prevMask) => {
|
|
42
|
-
if (mask === prevMask)
|
|
43
|
-
setKey((key) => key + 1);
|
|
41
|
+
if (mask === prevMask) setKey((key) => key + 1);
|
|
44
42
|
return mask;
|
|
45
43
|
});
|
|
46
|
-
if (userOnChange)
|
|
47
|
-
userOnChange(e, mask);
|
|
44
|
+
if (userOnChange) userOnChange(e, mask);
|
|
48
45
|
scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));
|
|
49
46
|
},
|
|
50
47
|
[valueSetter, scheduleAfterRender, userOnChange]
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/hooks/useSSNMask.ts"],
|
|
4
4
|
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import type React from 'react';\nimport { useCallback, useRef, useState } from 'react';\nimport {\n describe,\n PropTypes,\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useCallbackAfterRender } from '@elliemae/ds-utilities';\nimport { addSpecialCharacters, getPartialMaskedPos, setCursorPosition } from '../utils/index.js';\nimport { useMaskDefaultProps, useMaskPropTypes, type UseMaskT } from '../react-desc-prop-types.js';\nimport { useSSNMaskName } from '../DSMaskDefinitions.js';\n\nconst ssnSpecialChars: [string, number][] = [\n ['-', 3],\n ['-', 6],\n];\n\nconst conformValue = (rawValue: string, cursorPos: number, lastKeyCode: string) => {\n // Work with digits only\n let maskedValue = String(rawValue)\n .split('')\n .filter((char) => char >= '0' && char <= '9');\n\n // We only consider first 9 digits\n maskedValue = maskedValue.slice(0, 9);\n\n const maskedPos = getPartialMaskedPos(rawValue, maskedValue, cursorPos);\n\n return addSpecialCharacters(maskedValue, ssnSpecialChars, maskedPos, lastKeyCode);\n};\n\nexport const useSSNMask: ((args: UseMaskT.Props) => UseMaskT.OutputT) & { displayName: string } = (props) => {\n const propsWithDefault = useMemoMergePropsWithDefault<UseMaskT.InternalProps>(props, useMaskDefaultProps);\n useValidateTypescriptPropTypes(propsWithDefault, useMaskPropTypes, useSSNMaskName);\n\n const { valueSetter, onChange: userOnChange, onKeyDown: userOnKeyDown } = propsWithDefault;\n\n const lastKeyCode = useRef('Unidentified');\n\n const scheduleAfterRender = useCallbackAfterRender(true);\n\n // Some times, the value of the mask is not gonna change (user types invalid char for example)\n // This makes the input to go from \"correct\" -> \"incorrect\" -> \"correct\"\n // But since the input is controlled, the input does not re-render\n // This makes the input go mumbo-jumbo and places the cursor in the end, because we kinda changed the value async\n // Solution for this is to trigger a re-render, we do this with a set state call in the on change event\n const [, setKey] = useState(0);\n\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n lastKeyCode.current = e.code;\n if (userOnKeyDown) userOnKeyDown(e);\n },\n [userOnKeyDown],\n );\n\n const onChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current);\n valueSetter((prevMask) => {\n // Here we need to update the key\n if (mask === prevMask) setKey((key) => key + 1);\n\n return mask;\n });\n if (userOnChange) userOnChange(e, mask);\n scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));\n },\n [valueSetter, scheduleAfterRender, userOnChange],\n );\n\n return {\n onKeyDown,\n onChange,\n };\n};\n\nexport const getSSNMaskedValue = (value: string) => {\n const [maskedValue] = conformValue(value, value.length - 1, '');\n return maskedValue;\n};\n\nuseSSNMask.displayName = useSSNMaskName;\nexport const UseSSNMaskWithSchema = describe(useSSNMask);\nUseSSNMaskWithSchema.propTypes = useMaskPropTypes;\nUseSSNMaskWithSchema.returnType = {\n onKeyDown: PropTypes.func.description('On key down event for input').isRequired,\n onChange: PropTypes.func.description('On change event for input').isRequired,\n};\n"],
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACCvB,SAAS,aAAa,QAAQ,gBAAgB;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,8BAA8B;AACvC,SAAS,sBAAsB,qBAAqB,yBAAyB;AAC7E,SAAS,qBAAqB,wBAAuC;AACrE,SAAS,sBAAsB;AAE/B,MAAM,kBAAsC;AAAA,EAC1C,CAAC,KAAK,CAAC;AAAA,EACP,CAAC,KAAK,CAAC;AACT;AAEA,MAAM,eAAe,CAAC,UAAkB,WAAmB,gBAAwB;AAEjF,MAAI,cAAc,OAAO,QAAQ,EAC9B,MAAM,EAAE,EACR,OAAO,CAAC,SAAS,QAAQ,OAAO,QAAQ,GAAG;AAG9C,gBAAc,YAAY,MAAM,GAAG,CAAC;AAEpC,QAAM,YAAY,oBAAoB,UAAU,aAAa,SAAS;AAEtE,SAAO,qBAAqB,aAAa,iBAAiB,WAAW,WAAW;AAClF;AAEO,MAAM,aAAqF,CAAC,UAAU;AAC3G,QAAM,mBAAmB,6BAAqD,OAAO,mBAAmB;AACxG,iCAA+B,kBAAkB,kBAAkB,cAAc;AAEjF,QAAM,EAAE,aAAa,UAAU,cAAc,WAAW,cAAc,IAAI;AAE1E,QAAM,cAAc,OAAO,cAAc;AAEzC,QAAM,sBAAsB,uBAAuB,IAAI;AAOvD,QAAM,CAAC,EAAE,MAAM,IAAI,SAAS,CAAC;AAE7B,QAAM,YAA0D;AAAA,IAC9D,CAAC,MAAM;AACL,kBAAY,UAAU,EAAE;AACxB,UAAI
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACCvB,SAAS,aAAa,QAAQ,gBAAgB;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,8BAA8B;AACvC,SAAS,sBAAsB,qBAAqB,yBAAyB;AAC7E,SAAS,qBAAqB,wBAAuC;AACrE,SAAS,sBAAsB;AAE/B,MAAM,kBAAsC;AAAA,EAC1C,CAAC,KAAK,CAAC;AAAA,EACP,CAAC,KAAK,CAAC;AACT;AAEA,MAAM,eAAe,CAAC,UAAkB,WAAmB,gBAAwB;AAEjF,MAAI,cAAc,OAAO,QAAQ,EAC9B,MAAM,EAAE,EACR,OAAO,CAAC,SAAS,QAAQ,OAAO,QAAQ,GAAG;AAG9C,gBAAc,YAAY,MAAM,GAAG,CAAC;AAEpC,QAAM,YAAY,oBAAoB,UAAU,aAAa,SAAS;AAEtE,SAAO,qBAAqB,aAAa,iBAAiB,WAAW,WAAW;AAClF;AAEO,MAAM,aAAqF,CAAC,UAAU;AAC3G,QAAM,mBAAmB,6BAAqD,OAAO,mBAAmB;AACxG,iCAA+B,kBAAkB,kBAAkB,cAAc;AAEjF,QAAM,EAAE,aAAa,UAAU,cAAc,WAAW,cAAc,IAAI;AAE1E,QAAM,cAAc,OAAO,cAAc;AAEzC,QAAM,sBAAsB,uBAAuB,IAAI;AAOvD,QAAM,CAAC,EAAE,MAAM,IAAI,SAAS,CAAC;AAE7B,QAAM,YAA0D;AAAA,IAC9D,CAAC,MAAM;AACL,kBAAY,UAAU,EAAE;AACxB,UAAI,cAAe,eAAc,CAAC;AAAA,IACpC;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,QAAM,WAAuD;AAAA,IAC3D,CAAC,MAAM;AACL,YAAM,CAAC,MAAM,SAAS,IAAI,aAAa,EAAE,OAAO,OAAO,EAAE,OAAO,gBAAgB,GAAG,YAAY,OAAO;AACtG,kBAAY,CAAC,aAAa;AAExB,YAAI,SAAS,SAAU,QAAO,CAAC,QAAQ,MAAM,CAAC;AAE9C,eAAO;AAAA,MACT,CAAC;AACD,UAAI,aAAc,cAAa,GAAG,IAAI;AACtC,0BAAoB,MAAM,kBAAkB,EAAE,QAAQ,SAAS,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,aAAa,qBAAqB,YAAY;AAAA,EACjD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEO,MAAM,oBAAoB,CAAC,UAAkB;AAClD,QAAM,CAAC,WAAW,IAAI,aAAa,OAAO,MAAM,SAAS,GAAG,EAAE;AAC9D,SAAO;AACT;AAEA,WAAW,cAAc;AAClB,MAAM,uBAAuB,SAAS,UAAU;AACvD,qBAAqB,YAAY;AACjC,qBAAqB,aAAa;AAAA,EAChC,WAAW,UAAU,KAAK,YAAY,6BAA6B,EAAE;AAAA,EACrE,UAAU,UAAU,KAAK,YAAY,2BAA2B,EAAE;AACpE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -27,8 +27,7 @@ const useZipCodeMask = (props) => {
|
|
|
27
27
|
const onKeyDown = useCallback(
|
|
28
28
|
(e) => {
|
|
29
29
|
lastKeyCode.current = e.code;
|
|
30
|
-
if (userOnKeyDown)
|
|
31
|
-
userOnKeyDown(e);
|
|
30
|
+
if (userOnKeyDown) userOnKeyDown(e);
|
|
32
31
|
},
|
|
33
32
|
[userOnKeyDown]
|
|
34
33
|
);
|
|
@@ -36,12 +35,10 @@ const useZipCodeMask = (props) => {
|
|
|
36
35
|
(e) => {
|
|
37
36
|
const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current);
|
|
38
37
|
valueSetter((prevMask) => {
|
|
39
|
-
if (mask === prevMask)
|
|
40
|
-
setKey((key) => key + 1);
|
|
38
|
+
if (mask === prevMask) setKey((key) => key + 1);
|
|
41
39
|
return mask;
|
|
42
40
|
});
|
|
43
|
-
if (userOnChange)
|
|
44
|
-
userOnChange(e, mask);
|
|
41
|
+
if (userOnChange) userOnChange(e, mask);
|
|
45
42
|
scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));
|
|
46
43
|
},
|
|
47
44
|
[valueSetter, scheduleAfterRender, userOnChange]
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/hooks/useZipCodeMask.ts"],
|
|
4
4
|
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import type React from 'react';\nimport { useCallback, useRef, useState } from 'react';\nimport {\n describe,\n PropTypes,\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useCallbackAfterRender } from '@elliemae/ds-utilities';\nimport { addSpecialCharacters, getPartialMaskedPos, setCursorPosition } from '../utils/index.js';\nimport { useMaskDefaultProps, useMaskPropTypes, type UseMaskT } from '../react-desc-prop-types.js';\nimport { useZipCodeMaskName } from '../DSMaskDefinitions.js';\n\nconst zipCodeSpecialChars: [string, number][] = [['-', 5]];\n\nconst conformValue = (rawValue: string, cursorPos: number, lastKeyCode: string) => {\n // Work with digits only\n let maskedValue = String(rawValue)\n .split('')\n .filter((char) => char >= '0' && char <= '9');\n\n // We only consider first 9 digits\n maskedValue = maskedValue.slice(0, 9);\n\n const maskedPos = getPartialMaskedPos(rawValue, maskedValue, cursorPos);\n\n return addSpecialCharacters(maskedValue, zipCodeSpecialChars, maskedPos, lastKeyCode);\n};\n\nexport const useZipCodeMask: ((args: UseMaskT.Props) => UseMaskT.OutputT) & { displayName: string } = (props) => {\n const propsWithDefault = useMemoMergePropsWithDefault<UseMaskT.InternalProps>(props, useMaskDefaultProps);\n useValidateTypescriptPropTypes(propsWithDefault, useMaskPropTypes, useZipCodeMaskName);\n const { valueSetter, onChange: userOnChange, onKeyDown: userOnKeyDown } = propsWithDefault;\n\n const lastKeyCode = useRef('Unidentified');\n const scheduleAfterRender = useCallbackAfterRender(true);\n\n // Some times, the value of the mask is not gonna change (user types invalid char for example)\n // This makes the input to go from \"correct\" -> \"incorrect\" -> \"correct\"\n // But since the input is controlled, the input does not re-render\n // This makes the input go mumbo-jumbo and places the cursor in the end, because we kinda changed the value async\n // Solution for this is to trigger a re-render, we do this with a set state call in the on change event\n const [, setKey] = useState(0);\n\n const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n lastKeyCode.current = e.code;\n if (userOnKeyDown) userOnKeyDown(e);\n },\n [userOnKeyDown],\n );\n\n const onChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n const [mask, cursorPos] = conformValue(e.target.value, e.target.selectionEnd ?? 0, lastKeyCode.current);\n valueSetter((prevMask) => {\n // Here we need to update the key\n if (mask === prevMask) setKey((key) => key + 1);\n\n return mask;\n });\n if (userOnChange) userOnChange(e, mask);\n scheduleAfterRender(() => setCursorPosition(e.target, cursorPos));\n },\n [valueSetter, scheduleAfterRender, userOnChange],\n );\n\n return {\n onKeyDown,\n onChange,\n };\n};\n\nexport const getZipCodeMaskedValue = (value: string) => {\n const [maskedValue] = conformValue(value, value.length - 1, '');\n return maskedValue;\n};\n\nuseZipCodeMask.displayName = useZipCodeMaskName;\nexport const UseZipCodeMaskWithSchema = describe(useZipCodeMask);\nUseZipCodeMaskWithSchema.propTypes = useMaskPropTypes;\nUseZipCodeMaskWithSchema.returnType = {\n onKeyDown: PropTypes.func.description('On key down event for input').isRequired,\n onChange: PropTypes.func.description('On change event for input').isRequired,\n};\n"],
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACCvB,SAAS,aAAa,QAAQ,gBAAgB;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,8BAA8B;AACvC,SAAS,sBAAsB,qBAAqB,yBAAyB;AAC7E,SAAS,qBAAqB,wBAAuC;AACrE,SAAS,0BAA0B;AAEnC,MAAM,sBAA0C,CAAC,CAAC,KAAK,CAAC,CAAC;AAEzD,MAAM,eAAe,CAAC,UAAkB,WAAmB,gBAAwB;AAEjF,MAAI,cAAc,OAAO,QAAQ,EAC9B,MAAM,EAAE,EACR,OAAO,CAAC,SAAS,QAAQ,OAAO,QAAQ,GAAG;AAG9C,gBAAc,YAAY,MAAM,GAAG,CAAC;AAEpC,QAAM,YAAY,oBAAoB,UAAU,aAAa,SAAS;AAEtE,SAAO,qBAAqB,aAAa,qBAAqB,WAAW,WAAW;AACtF;AAEO,MAAM,iBAAyF,CAAC,UAAU;AAC/G,QAAM,mBAAmB,6BAAqD,OAAO,mBAAmB;AACxG,iCAA+B,kBAAkB,kBAAkB,kBAAkB;AACrF,QAAM,EAAE,aAAa,UAAU,cAAc,WAAW,cAAc,IAAI;AAE1E,QAAM,cAAc,OAAO,cAAc;AACzC,QAAM,sBAAsB,uBAAuB,IAAI;AAOvD,QAAM,CAAC,EAAE,MAAM,IAAI,SAAS,CAAC;AAE7B,QAAM,YAA0D;AAAA,IAC9D,CAAC,MAAM;AACL,kBAAY,UAAU,EAAE;AACxB,UAAI
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACCvB,SAAS,aAAa,QAAQ,gBAAgB;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,8BAA8B;AACvC,SAAS,sBAAsB,qBAAqB,yBAAyB;AAC7E,SAAS,qBAAqB,wBAAuC;AACrE,SAAS,0BAA0B;AAEnC,MAAM,sBAA0C,CAAC,CAAC,KAAK,CAAC,CAAC;AAEzD,MAAM,eAAe,CAAC,UAAkB,WAAmB,gBAAwB;AAEjF,MAAI,cAAc,OAAO,QAAQ,EAC9B,MAAM,EAAE,EACR,OAAO,CAAC,SAAS,QAAQ,OAAO,QAAQ,GAAG;AAG9C,gBAAc,YAAY,MAAM,GAAG,CAAC;AAEpC,QAAM,YAAY,oBAAoB,UAAU,aAAa,SAAS;AAEtE,SAAO,qBAAqB,aAAa,qBAAqB,WAAW,WAAW;AACtF;AAEO,MAAM,iBAAyF,CAAC,UAAU;AAC/G,QAAM,mBAAmB,6BAAqD,OAAO,mBAAmB;AACxG,iCAA+B,kBAAkB,kBAAkB,kBAAkB;AACrF,QAAM,EAAE,aAAa,UAAU,cAAc,WAAW,cAAc,IAAI;AAE1E,QAAM,cAAc,OAAO,cAAc;AACzC,QAAM,sBAAsB,uBAAuB,IAAI;AAOvD,QAAM,CAAC,EAAE,MAAM,IAAI,SAAS,CAAC;AAE7B,QAAM,YAA0D;AAAA,IAC9D,CAAC,MAAM;AACL,kBAAY,UAAU,EAAE;AACxB,UAAI,cAAe,eAAc,CAAC;AAAA,IACpC;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,QAAM,WAAuD;AAAA,IAC3D,CAAC,MAAM;AACL,YAAM,CAAC,MAAM,SAAS,IAAI,aAAa,EAAE,OAAO,OAAO,EAAE,OAAO,gBAAgB,GAAG,YAAY,OAAO;AACtG,kBAAY,CAAC,aAAa;AAExB,YAAI,SAAS,SAAU,QAAO,CAAC,QAAQ,MAAM,CAAC;AAE9C,eAAO;AAAA,MACT,CAAC;AACD,UAAI,aAAc,cAAa,GAAG,IAAI;AACtC,0BAAoB,MAAM,kBAAkB,EAAE,QAAQ,SAAS,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,aAAa,qBAAqB,YAAY;AAAA,EACjD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEO,MAAM,wBAAwB,CAAC,UAAkB;AACtD,QAAM,CAAC,WAAW,IAAI,aAAa,OAAO,MAAM,SAAS,GAAG,EAAE;AAC9D,SAAO;AACT;AAEA,eAAe,cAAc;AACtB,MAAM,2BAA2B,SAAS,cAAc;AAC/D,yBAAyB,YAAY;AACrC,yBAAyB,aAAa;AAAA,EACpC,WAAW,UAAU,KAAK,YAAY,6BAA6B,EAAE;AAAA,EACrE,UAAU,UAAU,KAAK,YAAY,2BAA2B,EAAE;AACpE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -5,14 +5,12 @@ const addSpecialCharacters = (maskWithoutSpecialChars, specialCharsDescr, masked
|
|
|
5
5
|
specialCharsDescr.forEach(([chars, pos]) => {
|
|
6
6
|
if (finalMask.length > pos) {
|
|
7
7
|
finalMask.splice(pos, 0, ...chars);
|
|
8
|
-
if (finalMaskedPos >= pos)
|
|
9
|
-
finalMaskedPos += chars.length;
|
|
8
|
+
if (finalMaskedPos >= pos) finalMaskedPos += chars.length;
|
|
10
9
|
}
|
|
11
10
|
});
|
|
12
11
|
if (lastKeyCode !== "Backspace" && finalMaskedPos < finalMask.length) {
|
|
13
12
|
specialCharsDescr.forEach(([chars, pos]) => {
|
|
14
|
-
if (finalMaskedPos === pos)
|
|
15
|
-
finalMaskedPos += chars.length;
|
|
13
|
+
if (finalMaskedPos === pos) finalMaskedPos += chars.length;
|
|
16
14
|
});
|
|
17
15
|
} else if (lastKeyCode === "Backspace" && finalMaskedPos) {
|
|
18
16
|
for (let i = specialCharsDescr.length - 1; i >= 0; i -= 1) {
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/utils/addSpecialCharacters.ts"],
|
|
4
4
|
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-params */\n/**\n *\n * @param {string[]} maskWithoutSpecialChars An array of characters with the unfinished mask\n * @param {[string, number][]} specialCharsDescr An array of tuples. Each tuple contains a string and a position (What string to add in a particular position)\n * @param {number} maskedPos Current masked position\n * @param {string} lastKeyCode Last key code of the user\n * @returns {[string, number]} A tuple containing the final mask and the final masked position\n */\nexport const addSpecialCharacters = (\n maskWithoutSpecialChars: string[],\n specialCharsDescr: [string, number][],\n maskedPos: number,\n lastKeyCode: string,\n): [string, number] => {\n const finalMask = maskWithoutSpecialChars;\n let finalMaskedPos = maskedPos;\n\n // We insert the special chars in the respective positions, tweaking the masked pos\n specialCharsDescr.forEach(([chars, pos]) => {\n if (finalMask.length > pos) {\n finalMask.splice(pos, 0, ...chars);\n if (finalMaskedPos >= pos) finalMaskedPos += chars.length;\n }\n });\n\n if (lastKeyCode !== 'Backspace' && finalMaskedPos < finalMask.length) {\n // If not erasing, move the cursor forward if we are in a special chars area\n specialCharsDescr.forEach(([chars, pos]) => {\n if (finalMaskedPos === pos) finalMaskedPos += chars.length;\n });\n } else if (lastKeyCode === 'Backspace' && finalMaskedPos) {\n // If erasing, move the cursor back if we are in a special chars area\n for (let i = specialCharsDescr.length - 1; i >= 0; i -= 1) {\n if (\n specialCharsDescr[i][1] + 1 <= finalMaskedPos &&\n finalMaskedPos <= specialCharsDescr[i][1] + specialCharsDescr[i][0].length\n )\n [, finalMaskedPos] = specialCharsDescr[i];\n }\n }\n\n return [finalMask.join(''), finalMaskedPos];\n};\n"],
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACShB,MAAM,uBAAuB,CAClC,yBACA,mBACA,WACA,gBACqB;AACrB,QAAM,YAAY;AAClB,MAAI,iBAAiB;AAGrB,oBAAkB,QAAQ,CAAC,CAAC,OAAO,GAAG,MAAM;AAC1C,QAAI,UAAU,SAAS,KAAK;AAC1B,gBAAU,OAAO,KAAK,GAAG,GAAG,KAAK;AACjC,UAAI,kBAAkB
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACShB,MAAM,uBAAuB,CAClC,yBACA,mBACA,WACA,gBACqB;AACrB,QAAM,YAAY;AAClB,MAAI,iBAAiB;AAGrB,oBAAkB,QAAQ,CAAC,CAAC,OAAO,GAAG,MAAM;AAC1C,QAAI,UAAU,SAAS,KAAK;AAC1B,gBAAU,OAAO,KAAK,GAAG,GAAG,KAAK;AACjC,UAAI,kBAAkB,IAAK,mBAAkB,MAAM;AAAA,IACrD;AAAA,EACF,CAAC;AAED,MAAI,gBAAgB,eAAe,iBAAiB,UAAU,QAAQ;AAEpE,sBAAkB,QAAQ,CAAC,CAAC,OAAO,GAAG,MAAM;AAC1C,UAAI,mBAAmB,IAAK,mBAAkB,MAAM;AAAA,IACtD,CAAC;AAAA,EACH,WAAW,gBAAgB,eAAe,gBAAgB;AAExD,aAAS,IAAI,kBAAkB,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG;AACzD,UACE,kBAAkB,CAAC,EAAE,CAAC,IAAI,KAAK,kBAC/B,kBAAkB,kBAAkB,CAAC,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,CAAC,EAAE;AAEpE,SAAC,EAAE,cAAc,IAAI,kBAAkB,CAAC;AAAA,IAC5C;AAAA,EACF;AAEA,SAAO,CAAC,UAAU,KAAK,EAAE,GAAG,cAAc;AAC5C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,8 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
const getPartialMaskedPos = (rawValue, maskWithoutSpecialChars, cursorPos) => {
|
|
3
3
|
let maskedPos = 0;
|
|
4
4
|
for (let i = 0; i < cursorPos; i += 1) {
|
|
5
|
-
if (maskWithoutSpecialChars[maskedPos] === rawValue[i])
|
|
6
|
-
maskedPos += 1;
|
|
5
|
+
if (maskWithoutSpecialChars[maskedPos] === rawValue[i]) maskedPos += 1;
|
|
7
6
|
}
|
|
8
7
|
return maskedPos;
|
|
9
8
|
};
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/utils/getPartialMaskedPos.ts"],
|
|
4
4
|
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "export const getPartialMaskedPos = (rawValue: string, maskWithoutSpecialChars: string[], cursorPos: number): number => {\n let maskedPos = 0;\n for (let i = 0; i < cursorPos; i += 1) {\n if (maskWithoutSpecialChars[maskedPos] === rawValue[i]) maskedPos += 1;\n }\n return maskedPos;\n};\n"],
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACAhB,MAAM,sBAAsB,CAAC,UAAkB,yBAAmC,cAA8B;AACrH,MAAI,YAAY;AAChB,WAAS,IAAI,GAAG,IAAI,WAAW,KAAK,GAAG;AACrC,QAAI,wBAAwB,SAAS,MAAM,SAAS,CAAC
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACAhB,MAAM,sBAAsB,CAAC,UAAkB,yBAAmC,cAA8B;AACrH,MAAI,YAAY;AAChB,WAAS,IAAI,GAAG,IAAI,WAAW,KAAK,GAAG;AACrC,QAAI,wBAAwB,SAAS,MAAM,SAAS,CAAC,EAAG,cAAa;AAAA,EACvE;AACA,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliemae/ds-form-helpers-mask-hooks",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.36.0-next.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "ICE MT - Dimsum - Controlled Form Helpers - Text Masks Hooks",
|
|
6
6
|
"files": [
|
|
@@ -36,17 +36,17 @@
|
|
|
36
36
|
"indent": 4
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@elliemae/ds-props-helpers": "3.
|
|
40
|
-
"@elliemae/ds-system": "3.
|
|
41
|
-
"@elliemae/ds-utilities": "3.
|
|
39
|
+
"@elliemae/ds-props-helpers": "3.36.0-next.1",
|
|
40
|
+
"@elliemae/ds-system": "3.36.0-next.1",
|
|
41
|
+
"@elliemae/ds-utilities": "3.36.0-next.1"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@elliemae/pui-cli": "~9.0.0-next.31",
|
|
45
45
|
"@elliemae/pui-theme": "~2.9.3",
|
|
46
46
|
"styled-components": "~5.3.9",
|
|
47
47
|
"styled-system": "~5.1.5",
|
|
48
|
-
"@elliemae/ds-
|
|
49
|
-
"@elliemae/ds-
|
|
48
|
+
"@elliemae/ds-monorepo-devops": "3.36.0-next.1",
|
|
49
|
+
"@elliemae/ds-form-input-text": "3.36.0-next.1"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"@elliemae/pui-theme": "~2.9.3",
|