add react-input-mask
This commit is contained in:
Generated
+46
-2
@@ -1,13 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "no-copy-frontend",
|
"name": "no-copy-frontend",
|
||||||
"version": "0.9.0",
|
"version": "0.10.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "no-copy-frontend",
|
"name": "no-copy-frontend",
|
||||||
"version": "0.9.0",
|
"version": "0.10.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@react-input/mask": "^2.0.4",
|
||||||
"@tailwindcss/postcss": "^4.1.17",
|
"@tailwindcss/postcss": "^4.1.17",
|
||||||
"@tanstack/match-sorter-utils": "^8.19.4",
|
"@tanstack/match-sorter-utils": "^8.19.4",
|
||||||
"@tanstack/react-query": "^5.90.11",
|
"@tanstack/react-query": "^5.90.11",
|
||||||
@@ -1652,6 +1653,49 @@
|
|||||||
"node": ">=0.10"
|
"node": ">=0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-input/core": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-input/core/-/core-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-xLLBueYFbant9308uv3cIJQz5NYSixeGspjP3Nt6jogRHTcHYMRmlVFUuSzQiP8Z8/5BdnPkudRSsN0/AJ1fbw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/react-input"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": ">=16.8",
|
||||||
|
"react": ">=16.8 || ^19.0.0-rc",
|
||||||
|
"react-dom": ">=16.8 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-input/mask": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-input/mask/-/mask-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-NOielvQSBOlGLVuEcxtkjaGneC0GJFXjC7KOF99ed9H9XSDruWnQirjht5uSbWqLeeiOup0VD2YjM+6FH+aWBg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-input/core": "^2.0.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/react-input"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": ">=16.8",
|
||||||
|
"react": ">=16.8 || ^19.0.0-rc",
|
||||||
|
"react-dom": ">=16.8 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@reduxjs/toolkit": {
|
"node_modules/@reduxjs/toolkit": {
|
||||||
"version": "2.11.1",
|
"version": "2.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.1.tgz",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"lint": "eslint"
|
"lint": "eslint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@react-input/mask": "^2.0.4",
|
||||||
"@tailwindcss/postcss": "^4.1.17",
|
"@tailwindcss/postcss": "^4.1.17",
|
||||||
"@tanstack/match-sorter-utils": "^8.19.4",
|
"@tanstack/match-sorter-utils": "^8.19.4",
|
||||||
"@tanstack/react-query": "^5.90.11",
|
"@tanstack/react-query": "^5.90.11",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState, ChangeEvent, useEffect, useRef, KeyboardEvent } from 'react';
|
import { useState, ChangeEvent } from 'react';
|
||||||
|
import { InputMask } from '@react-input/mask';
|
||||||
import styles from '@/app/styles/module/login.module.scss';
|
import styles from '@/app/styles/module/login.module.scss';
|
||||||
|
|
||||||
interface PhoneInputProps {
|
interface PhoneInputProps {
|
||||||
@@ -10,104 +11,21 @@ interface PhoneInputProps {
|
|||||||
|
|
||||||
export default function PhoneInput({ phoneState, validateHandler }: PhoneInputProps) {
|
export default function PhoneInput({ phoneState, validateHandler }: PhoneInputProps) {
|
||||||
const [phone, setPhone] = useState(phoneState ? phoneState : '');
|
const [phone, setPhone] = useState(phoneState ? phoneState : '');
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
|
||||||
|
|
||||||
const formatPhoneNumber = (value: string, isBackspace: boolean): string => {
|
|
||||||
if (value === '+') {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const digitsOnly = value.replace(/\D/g, '');
|
|
||||||
|
|
||||||
if (!digitsOnly) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
const limitedDigits = digitsOnly.slice(0, 11);
|
|
||||||
const countryCode = 7;
|
|
||||||
const phoneNumber = limitedDigits.startsWith('7')
|
|
||||||
? limitedDigits.slice(1)
|
|
||||||
: limitedDigits;
|
|
||||||
|
|
||||||
let formatted = `+${countryCode}`;
|
|
||||||
|
|
||||||
if (phoneNumber.length > 0) {
|
|
||||||
formatted += ` (${phoneNumber.slice(0, 3)}`;
|
|
||||||
}
|
|
||||||
if (phoneNumber.length >= 3) {
|
|
||||||
formatted += `) ${phoneNumber.slice(3, 6)}`;
|
|
||||||
}
|
|
||||||
if (phoneNumber.length >= 6) {
|
|
||||||
formatted += `-${phoneNumber.slice(6, 8)}`;
|
|
||||||
}
|
|
||||||
if (phoneNumber.length >= 8) {
|
|
||||||
formatted += `-${phoneNumber.slice(8, 10)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBackspace) {
|
|
||||||
const lastChar = formatted[formatted.length - 1];
|
|
||||||
const specialChars = ['-', '(', ')', ' '];
|
|
||||||
|
|
||||||
if (specialChars.includes(lastChar)) {
|
|
||||||
if (lastChar === ' ' && formatted[formatted.length - 2] === ')') {
|
|
||||||
return formatted.slice(0, -2);
|
|
||||||
}
|
|
||||||
return formatted.slice(0, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return formatted;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChange = (e: ChangeEvent<HTMLInputElement>): void => {
|
|
||||||
const input = e.target.value;
|
|
||||||
const nativeEvent = e.nativeEvent as InputEvent;
|
|
||||||
const isBackspace = nativeEvent.inputType === 'deleteContentBackward';
|
|
||||||
const formatted = formatPhoneNumber(input, isBackspace);
|
|
||||||
setPhone(formatted);
|
|
||||||
};
|
|
||||||
|
|
||||||
const range = useRef<{
|
|
||||||
start: number | null,
|
|
||||||
key: string;
|
|
||||||
} | null>(null);
|
|
||||||
|
|
||||||
const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>): void => {
|
|
||||||
const input = e.currentTarget;
|
|
||||||
range.current = {
|
|
||||||
start: input.selectionStart,
|
|
||||||
key: e.key
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log('use');
|
|
||||||
if (range.current?.key === 'Backspace' && inputRef.current) {
|
|
||||||
const startPos = range.current.start ?? 0;
|
|
||||||
const newPosition = Math.max(0, startPos - 1);
|
|
||||||
inputRef.current.setSelectionRange(newPosition, newPosition);
|
|
||||||
} else if (range.current?.key === 'Delete' && inputRef.current) {
|
|
||||||
inputRef.current.setSelectionRange(range.current.start, range.current.start);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [phone]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<InputMask
|
||||||
type="phone"
|
type="phone"
|
||||||
id="phone"
|
id="phone"
|
||||||
name="phone"
|
name="phone"
|
||||||
ref={inputRef}
|
|
||||||
className={`${styles['form-input']}`}
|
className={`${styles['form-input']}`}
|
||||||
placeholder="+7 (999) 123-45-67"
|
mask="+7 (___) ___-__-__"
|
||||||
|
replacement={{ _: /\d/ }}
|
||||||
value={phone}
|
value={phone}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
handleChange(e);
|
setPhone(e.target.value);
|
||||||
validateHandler(e);
|
validateHandler(e);
|
||||||
}}
|
}}
|
||||||
onKeyDown={(e) => {
|
placeholder="+7 (999) 123-45-67"
|
||||||
handleKeyDown(e);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user