/
DnTyr
/
Password-Development
Обзор
Документация
Войти
/
DnTyr
/
Password-Development
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
frontend/src/components/analyzer/PasswordInput.js
120 строк
3 KB
DT
first_commit
03 июн 2026, 10:22
03 июн 2026, 10:22
357cb35
Код
Авторство
О чём код?
import React, { useState, useRef, useLayoutEffect } from "react"; import { useTranslation } from "react-i18next"; import { containsCyrillic } from "../../utils/validators"; import { toastError } from "../../utils/toast"; import { Eye, EyeOff } from 'lucide-react'; function PasswordInput({ value, onChange, onEnter, isLeaked, isSafe, leakCount, onToggleVisibility, }) { const { t } = useTranslation(); const [visible, setVisible] = useState(false); const textareaRef = useRef(null); useLayoutEffect(() => { const node = textareaRef.current; if (!node) return; node.style.height = "auto"; const newHeight = node.scrollHeight; node.style.height = `${newHeight}px`; }, [value, visible]); const handleChange = (e) => { const newValue = e.target.value; if (containsCyrillic(newValue)) { toastError("Кириллица не поддерживается"); return; } onChange(newValue); if (textareaRef.current) { textareaRef.current.style.height = "auto"; textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; } }; return ( <div className="password-analyzer-container"> <div className="input-wrapper input-wrapper--password-toggle"> <label htmlFor="password-analyzer-input" className="sr-only"> {t("Пароль для проверки")} </label> <textarea ref={textareaRef} id="password-analyzer-input" onCopy={(e) => { if (!visible) { e.preventDefault(); } }} className={` ${isLeaked ? "input-leaked" : ""} ${isSafe ? "input-safe" : ""} ${!visible ? "is-masked" : ""} ${ (leakCount === "found_locally" || (typeof leakCount === "number" && leakCount > 0)) && !isLeaked ? "state-leaked" : "" } ${leakCount === "clean" && !isSafe ? "state-safe" : ""} `} name="password" autoComplete="off" spellCheck="false" placeholder={t("Введите пароль...")} value={value} maxLength={128} rows={1} onChange={handleChange} onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); if (e.repeat) return; // игнорируем автоповтор при удержании onEnter?.(); e.target.blur(); // прячем клавиатуру на мобильных } }} /> <button type="button" className="password-visibility-toggle" onClick={() => { const nextVisible = !visible; setVisible(nextVisible); if (nextVisible) { onToggleVisibility?.(); } }} aria-label={visible ? t("Скрыть пароль") : t("Показать пароль")} > {visible ? <EyeOff size={20} /> : <Eye size={20} />} </button> </div> <div className={`char-counter ${value.length >= 128 ? 'char-counter--limit' : ''}`}> {value.length} / 128 </div> </div> ); } export default PasswordInput;