diff --git a/app/login.tsx b/app/login.tsx index 46144069..bf5aa4fd 100644 --- a/app/login.tsx +++ b/app/login.tsx @@ -277,20 +277,19 @@ const Login: React.FC = () => { /> {/* Password */} - - setCredentials({ ...credentials, password: text }) - } - onSubmitEditing={handleLogin} - placeholder={t("login.password_placeholder")} - className='mb-4' - showPassword={showPassword} - onShowPasswordChange={setShowPassword} - topPosition='4' - testID='tv-password-input' - accessibilityLabel={t("login.password_placeholder")} - /> + + + setCredentials({ ...credentials, password: text }) + } + placeholder={t("login.password_placeholder")} + showPassword={showPassword} + onShowPasswordChange={setShowPassword} + topPosition='4' + layout='tv' + /> + @@ -403,20 +402,22 @@ const Login: React.FC = () => { textContentType='oneTimeCode' clearButtonMode='while-editing' maxLength={500} + extraClassName='mb-4' /> - - setCredentials({ ...credentials, password: text }) - } - placeholder={t("login.password_placeholder")} - showPassword={showPassword} - onShowPasswordChange={setShowPassword} - topPosition='3.5' - testID='mobile-password-input' - accessibilityLabel={t("login.password_placeholder")} - /> + + + setCredentials({ ...credentials, password: text }) + } + placeholder={t("login.password_placeholder")} + showPassword={showPassword} + onShowPasswordChange={setShowPassword} + topPosition='10' + layout='mobile' + /> + void; - onSubmitEditing?: () => void; placeholder: string; - className?: string; - testID?: string; - accessibilityLabel?: string; - maxLength?: number; - showPassword?: boolean; - onShowPasswordChange?: (show: boolean) => void; - topPosition?: "3.5" | "4"; - editable?: boolean; - autoComplete?: - | "password" - | "username" - | "name" - | "email" - | "tel" - | "url" - | "off"; - autoCorrect?: boolean; - iconColor?: string; -} + showPassword: boolean; + onShowPasswordChange: (show: boolean) => void; + topPosition?: string; + layout?: "tv" | "mobile"; +}; -export const PasswordInput: React.FC = ({ - value = "", - onChangeText, - onSubmitEditing, - placeholder, - className = "", - testID, - accessibilityLabel, - maxLength = 500, - showPassword: controlledShowPassword, - onShowPasswordChange, - topPosition = "3.5", - editable = true, - autoComplete, - autoCorrect, - iconColor = "white", -}) => { - const { t } = useTranslation(); - const [internalShowPassword, setInternalShowPassword] = useState(false); +type PasswordVisibilityUncontrolled = { + value?: string; + onChangeText: (text: string) => void; + placeholder: string; + showPassword?: never; + onShowPasswordChange?: never; + topPosition?: string; + layout?: "tv" | "mobile"; +}; - // Use controlled state if provided, otherwise use internal state - const showPassword = controlledShowPassword ?? internalShowPassword; - const setShowPassword = onShowPasswordChange ?? setInternalShowPassword; +type PasswordInputProps = + | PasswordVisibilityControlled + | PasswordVisibilityUncontrolled; - // Construct Tailwind class from validated topPosition - const topClass = `top-${topPosition}`; +export const PasswordInput: React.FC = (props) => { + const { + value = "", + onChangeText, + placeholder, + topPosition = "3.5", + layout = "mobile", + } = props; + + // Type guard to check if we're in controlled mode + const isControlled = + "showPassword" in props && "onShowPasswordChange" in props; + + // For controlled mode, use the provided props + // For uncontrolled mode, use internal state (but we need to handle this differently) + const showPassword = isControlled + ? (props as PasswordVisibilityControlled).showPassword + : false; + + const handleTogglePassword = () => { + if (isControlled) { + (props as PasswordVisibilityControlled).onShowPasswordChange( + !showPassword, + ); + } + // For uncontrolled mode, we could add internal state handling here if needed + }; + + // Generate top position with pixel precision + const getTopStyle = () => { + // Use pixel values directly + const positionInPx = parseFloat(topPosition); + return { top: positionInPx }; + }; return ( - + <> setShowPassword(!showPassword)} - className={`absolute right-3 ${topClass} p-1`} - accessible={true} - accessibilityRole='button' - accessibilityLabel={ - showPassword - ? t("accessibility.hide_password") - : t("accessibility.show_password") - } - accessibilityHint={t("accessibility.toggle_password_visibility")} - accessibilityState={{ selected: showPassword }} - hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} - testID={testID ? `${testID}-toggle` : undefined} + onPress={handleTogglePassword} + className={`absolute right-3 p-1 ${ + layout === "tv" ? "h-10 justify-center" : "" + }`} + style={getTopStyle()} > - + ); }; diff --git a/components/common/Input.tsx b/components/common/Input.tsx index 89fb8463..7af2e0bf 100644 --- a/components/common/Input.tsx +++ b/components/common/Input.tsx @@ -20,7 +20,7 @@ export function Input(props: InputProps) { { {t("home.settings.plugins.jellyseerr.password")} - + + +