[VPAT-27] chore(security): disable autocomplete on sensitive input fields #8517
Disable autocomplete on authentication and security-related forms to prevent browsers from storing sensitive credentials. This affects sign-in, password reset, account security, and onboarding forms across admin, web, and space apps. Modified components: - Auth forms (email, password, unique code, forgot/reset/set password) - Account security pages - Instance setup and profile onboarding - Shared UI components (auth-input, password-input)
This commit is contained in:
parent
d3c6e5ec94
commit
e9b011896d
20 changed files with 52 additions and 40 deletions
|
|
@ -146,7 +146,7 @@ export function InstanceSignInForm() {
|
||||||
placeholder="name@company.com"
|
placeholder="name@company.com"
|
||||||
value={formData.email}
|
value={formData.email}
|
||||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -165,7 +165,7 @@ export function InstanceSignInForm() {
|
||||||
placeholder="Enter your password"
|
placeholder="Enter your password"
|
||||||
value={formData.password}
|
value={formData.password}
|
||||||
onChange={(e) => handleFormChange("password", e.target.value)}
|
onChange={(e) => handleFormChange("password", e.target.value)}
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
{showPassword ? (
|
{showPassword ? (
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ export function InstanceSetupForm() {
|
||||||
value={formData.email}
|
value={formData.email}
|
||||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||||
hasError={errorData.type && errorData.type === EErrorCodes.INVALID_EMAIL ? true : false}
|
hasError={errorData.type && errorData.type === EErrorCodes.INVALID_EMAIL ? true : false}
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
{errorData.type && errorData.type === EErrorCodes.INVALID_EMAIL && errorData.message && (
|
{errorData.type && errorData.type === EErrorCodes.INVALID_EMAIL && errorData.message && (
|
||||||
<p className="px-1 text-11 text-danger-primary">{errorData.message}</p>
|
<p className="px-1 text-11 text-danger-primary">{errorData.message}</p>
|
||||||
|
|
@ -268,7 +268,7 @@ export function InstanceSetupForm() {
|
||||||
hasError={errorData.type && errorData.type === EErrorCodes.INVALID_PASSWORD ? true : false}
|
hasError={errorData.type && errorData.type === EErrorCodes.INVALID_PASSWORD ? true : false}
|
||||||
onFocus={() => setIsPasswordInputFocused(true)}
|
onFocus={() => setIsPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsPasswordInputFocused(false)}
|
onBlur={() => setIsPasswordInputFocused(false)}
|
||||||
autoComplete="on"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
{showPassword.password ? (
|
{showPassword.password ? (
|
||||||
<button
|
<button
|
||||||
|
|
@ -312,6 +312,7 @@ export function InstanceSetupForm() {
|
||||||
className="w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
className="w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||||
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
{showPassword.retypePassword ? (
|
{showPassword.retypePassword ? (
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ export const AuthEmailForm = observer(function AuthEmailForm(props: TAuthEmailFo
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
placeholder="name@company.com"
|
placeholder="name@company.com"
|
||||||
className={`disable-autofill-style h-10 w-full placeholder:text-placeholder autofill:bg-danger-subtle border-0 focus:bg-none active:bg-transparent`}
|
className={`disable-autofill-style h-10 w-full placeholder:text-placeholder autofill:bg-danger-subtle border-0 focus:bg-none active:bg-transparent`}
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||||
className="disable-autofill-style h-10 w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
className="disable-autofill-style h-10 w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||||
onFocus={() => setIsPasswordInputFocused(true)}
|
onFocus={() => setIsPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsPasswordInputFocused(false)}
|
onBlur={() => setIsPasswordInputFocused(false)}
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
{showPassword?.password ? (
|
{showPassword?.password ? (
|
||||||
|
|
@ -192,6 +192,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||||
className="disable-autofill-style h-10 w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
className="disable-autofill-style h-10 w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||||
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
{showPassword?.retypePassword ? (
|
{showPassword?.retypePassword ? (
|
||||||
<EyeOff
|
<EyeOff
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||||
placeholder="name@company.com"
|
placeholder="name@company.com"
|
||||||
className={`disable-autofill-style h-10 w-full placeholder:text-placeholder border-0`}
|
className={`disable-autofill-style h-10 w-full placeholder:text-placeholder border-0`}
|
||||||
|
autoComplete="off"
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
{uniqueCodeFormData.email.length > 0 && (
|
{uniqueCodeFormData.email.length > 0 && (
|
||||||
|
|
@ -119,6 +120,7 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||||
onChange={(e) => handleFormChange("code", e.target.value)}
|
onChange={(e) => handleFormChange("code", e.target.value)}
|
||||||
placeholder="123456"
|
placeholder="123456"
|
||||||
className="disable-autofill-style h-10 w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
className="disable-autofill-style h-10 w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||||
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<div className="flex w-full items-center justify-between px-1 text-11 pt-1">
|
<div className="flex w-full items-center justify-between px-1 text-11 pt-1">
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ export const AuthEmailForm = observer(function AuthEmailForm(props: TAuthEmailFo
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
placeholder={t("auth.common.email.placeholder")}
|
placeholder={t("auth.common.email.placeholder")}
|
||||||
className={`disable-autofill-style h-10 w-full placeholder:text-placeholder autofill:bg-danger-primary border-0 focus:bg-none active:bg-transparent`}
|
className={`disable-autofill-style h-10 w-full placeholder:text-placeholder autofill:bg-danger-primary border-0 focus:bg-none active:bg-transparent`}
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ export const ForgotPasswordForm = observer(function ForgotPasswordForm() {
|
||||||
hasError={Boolean(errors.email)}
|
hasError={Boolean(errors.email)}
|
||||||
placeholder={t("auth.common.email.placeholder")}
|
placeholder={t("auth.common.email.placeholder")}
|
||||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
disabled={resendTimerCode > 0}
|
disabled={resendTimerCode > 0}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||||
className="disable-autofill-style h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
className="disable-autofill-style h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||||
onFocus={() => setIsPasswordInputFocused(true)}
|
onFocus={() => setIsPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsPasswordInputFocused(false)}
|
onBlur={() => setIsPasswordInputFocused(false)}
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
|
|
@ -250,6 +250,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||||
className="disable-autofill-style h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
className="disable-autofill-style h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||||
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ export const ResetPasswordForm = observer(function ResetPasswordForm() {
|
||||||
//hasError={Boolean(errors.email)}
|
//hasError={Boolean(errors.email)}
|
||||||
placeholder={t("auth.common.email.placeholder")}
|
placeholder={t("auth.common.email.placeholder")}
|
||||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 text-placeholder cursor-not-allowed"
|
className="h-10 w-full border border-strong !bg-surface-1 pr-12 text-placeholder cursor-not-allowed"
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -144,7 +144,7 @@ export const ResetPasswordForm = observer(function ResetPasswordForm() {
|
||||||
minLength={8}
|
minLength={8}
|
||||||
onFocus={() => setIsPasswordInputFocused(true)}
|
onFocus={() => setIsPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsPasswordInputFocused(false)}
|
onBlur={() => setIsPasswordInputFocused(false)}
|
||||||
autoComplete="on"
|
autoComplete="new-password"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
{showPassword.password ? (
|
{showPassword.password ? (
|
||||||
|
|
@ -175,6 +175,7 @@ export const ResetPasswordForm = observer(function ResetPasswordForm() {
|
||||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||||
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
{showPassword.retypePassword ? (
|
{showPassword.retypePassword ? (
|
||||||
<EyeOff
|
<EyeOff
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ export const SetPasswordForm = observer(function SetPasswordForm() {
|
||||||
//hasError={Boolean(errors.email)}
|
//hasError={Boolean(errors.email)}
|
||||||
placeholder={t("auth.common.email.placeholder")}
|
placeholder={t("auth.common.email.placeholder")}
|
||||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 text-placeholder cursor-not-allowed"
|
className="h-10 w-full border border-strong !bg-surface-1 pr-12 text-placeholder cursor-not-allowed"
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -147,7 +147,7 @@ export const SetPasswordForm = observer(function SetPasswordForm() {
|
||||||
minLength={8}
|
minLength={8}
|
||||||
onFocus={() => setIsPasswordInputFocused(true)}
|
onFocus={() => setIsPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsPasswordInputFocused(false)}
|
onBlur={() => setIsPasswordInputFocused(false)}
|
||||||
autoComplete="on"
|
autoComplete="new-password"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
{showPassword.password ? (
|
{showPassword.password ? (
|
||||||
|
|
@ -178,6 +178,7 @@ export const SetPasswordForm = observer(function SetPasswordForm() {
|
||||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||||
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
{showPassword.retypePassword ? (
|
{showPassword.retypePassword ? (
|
||||||
<EyeOff
|
<EyeOff
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||||
placeholder={t("auth.common.email.placeholder")}
|
placeholder={t("auth.common.email.placeholder")}
|
||||||
className="disable-autofill-style h-10 w-full placeholder:text-placeholder border-0"
|
className="disable-autofill-style h-10 w-full placeholder:text-placeholder border-0"
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
{uniqueCodeFormData.email.length > 0 && (
|
{uniqueCodeFormData.email.length > 0 && (
|
||||||
|
|
@ -134,6 +134,7 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||||
onChange={(e) => handleFormChange("code", e.target.value)}
|
onChange={(e) => handleFormChange("code", e.target.value)}
|
||||||
placeholder={t("auth.common.unique_code.placeholder")}
|
placeholder={t("auth.common.unique_code.placeholder")}
|
||||||
className="disable-autofill-style h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
className="disable-autofill-style h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||||
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<div className="flex w-full items-center justify-between px-1 text-11 pt-1">
|
<div className="flex w-full items-center justify-between px-1 text-11 pt-1">
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,7 @@ export const ChangeEmailModal = observer(function ChangeEmailModal(props: Props)
|
||||||
{ "border-danger-strong": errors.email },
|
{ "border-danger-strong": errors.email },
|
||||||
{ "cursor-not-allowed !bg-surface-2": secondStep }
|
{ "cursor-not-allowed !bg-surface-2": secondStep }
|
||||||
)}
|
)}
|
||||||
|
autoComplete="off"
|
||||||
disabled={secondStep}
|
disabled={secondStep}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
@ -187,6 +188,7 @@ export const ChangeEmailModal = observer(function ChangeEmailModal(props: Props)
|
||||||
ref={ref}
|
ref={ref}
|
||||||
placeholder={changeEmailT("form.code.placeholder")}
|
placeholder={changeEmailT("form.code.placeholder")}
|
||||||
className={cn({ "border-danger-strong": errors.code })}
|
className={cn({ "border-danger-strong": errors.code })}
|
||||||
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -392,7 +392,7 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||||
className="w-full border-[0.5px] border-subtle pr-12 placeholder:text-placeholder"
|
className="w-full border-[0.5px] border-subtle pr-12 placeholder:text-placeholder"
|
||||||
onFocus={() => setIsPasswordInputFocused(true)}
|
onFocus={() => setIsPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsPasswordInputFocused(false)}
|
onBlur={() => setIsPasswordInputFocused(false)}
|
||||||
autoComplete="on"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
{showPassword.password ? (
|
{showPassword.password ? (
|
||||||
<EyeOff
|
<EyeOff
|
||||||
|
|
@ -433,6 +433,7 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||||
hasError={Boolean(errors.confirm_password)}
|
hasError={Boolean(errors.confirm_password)}
|
||||||
placeholder={t("auth.common.password.confirm_password.placeholder")}
|
placeholder={t("auth.common.password.confirm_password.placeholder")}
|
||||||
className="w-full border-subtle pr-12 placeholder:text-placeholder"
|
className="w-full border-subtle pr-12 placeholder:text-placeholder"
|
||||||
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
{showPassword.retypePassword ? (
|
{showPassword.retypePassword ? (
|
||||||
<EyeOff
|
<EyeOff
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ export const SecurityProfileSettings = observer(function SecurityProfileSettings
|
||||||
placeholder={t("old_password")}
|
placeholder={t("old_password")}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
hasError={Boolean(errors.old_password)}
|
hasError={Boolean(errors.old_password)}
|
||||||
|
autoComplete="current-password"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -193,6 +194,7 @@ export const SecurityProfileSettings = observer(function SecurityProfileSettings
|
||||||
hasError={Boolean(errors.new_password)}
|
hasError={Boolean(errors.new_password)}
|
||||||
onFocus={() => setIsPasswordInputFocused(true)}
|
onFocus={() => setIsPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsPasswordInputFocused(false)}
|
onBlur={() => setIsPasswordInputFocused(false)}
|
||||||
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -238,6 +240,7 @@ export const SecurityProfileSettings = observer(function SecurityProfileSettings
|
||||||
hasError={Boolean(errors.confirm_password)}
|
hasError={Boolean(errors.confirm_password)}
|
||||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||||
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,7 @@ import React, { useState } from "react";
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
import { AuthInput } from "./auth-input";
|
import { AuthInput } from "./auth-input";
|
||||||
|
|
||||||
export interface AuthConfirmPasswordInputProps extends Omit<
|
export type TAuthConfirmPasswordInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
|
||||||
React.InputHTMLAttributes<HTMLInputElement>,
|
|
||||||
"autoComplete"
|
|
||||||
> {
|
|
||||||
password: string;
|
password: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
|
@ -19,9 +16,8 @@ export interface AuthConfirmPasswordInputProps extends Omit<
|
||||||
containerClassName?: string;
|
containerClassName?: string;
|
||||||
labelClassName?: string;
|
labelClassName?: string;
|
||||||
errorClassName?: string;
|
errorClassName?: string;
|
||||||
autoComplete?: "on" | "off";
|
|
||||||
onPasswordMatchChange?: (matches: boolean) => void;
|
onPasswordMatchChange?: (matches: boolean) => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function AuthConfirmPasswordInput({
|
export function AuthConfirmPasswordInput({
|
||||||
password,
|
password,
|
||||||
|
|
@ -35,7 +31,7 @@ export function AuthConfirmPasswordInput({
|
||||||
onChange,
|
onChange,
|
||||||
onPasswordMatchChange,
|
onPasswordMatchChange,
|
||||||
...props
|
...props
|
||||||
}: AuthConfirmPasswordInputProps) {
|
}: TAuthConfirmPasswordInputProps) {
|
||||||
const [isFocused, setIsFocused] = useState(false);
|
const [isFocused, setIsFocused] = useState(false);
|
||||||
|
|
||||||
const confirmPassword = value as string;
|
const confirmPassword = value as string;
|
||||||
|
|
@ -77,7 +73,7 @@ export function AuthConfirmPasswordInput({
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onFocus={handleFocus}
|
onFocus={handleFocus}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
{confirmPassword && passwordsMatch && <p className="text-13 text-success-primary">Passwords match</p>}
|
{confirmPassword && passwordsMatch && <p className="text-13 text-success-primary">Passwords match</p>}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,12 @@ import React, { useState } from "react";
|
||||||
import { Input } from "../form-fields/input";
|
import { Input } from "../form-fields/input";
|
||||||
import { cn } from "../utils";
|
import { cn } from "../utils";
|
||||||
|
|
||||||
export interface AuthInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "autoComplete"> {
|
export type TAuthInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
|
||||||
label?: string;
|
label?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
showPasswordToggle?: boolean;
|
showPasswordToggle?: boolean;
|
||||||
errorClassName?: string;
|
errorClassName?: string;
|
||||||
autoComplete?: "on" | "off";
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const baseContainerClassName = "flex flex-col gap-1.5";
|
const baseContainerClassName = "flex flex-col gap-1.5";
|
||||||
|
|
||||||
|
|
@ -26,8 +25,9 @@ export function AuthInput({
|
||||||
errorClassName = "",
|
errorClassName = "",
|
||||||
className = "",
|
className = "",
|
||||||
type = "text",
|
type = "text",
|
||||||
|
autoComplete = "off",
|
||||||
...props
|
...props
|
||||||
}: AuthInputProps) {
|
}: TAuthInputProps) {
|
||||||
const { id } = props;
|
const { id } = props;
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const isPasswordType = type === "password";
|
const isPasswordType = type === "password";
|
||||||
|
|
@ -45,6 +45,7 @@ export function AuthInput({
|
||||||
<Input
|
<Input
|
||||||
{...props}
|
{...props}
|
||||||
type={inputType}
|
type={inputType}
|
||||||
|
autoComplete={autoComplete}
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-md disable-autofill-style h-6 w-full placeholder:text-14 placeholder:text-placeholder p-0 border-none",
|
"rounded-md disable-autofill-style h-6 w-full placeholder:text-14 placeholder:text-placeholder p-0 border-none",
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,16 @@ import { cn, getPasswordStrength } from "@plane/utils";
|
||||||
import { PasswordStrengthIndicator } from "../form-fields/password/indicator";
|
import { PasswordStrengthIndicator } from "../form-fields/password/indicator";
|
||||||
import { AuthInput } from "./auth-input";
|
import { AuthInput } from "./auth-input";
|
||||||
|
|
||||||
export interface AuthPasswordInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "autoComplete"> {
|
export type TAuthPasswordInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
|
||||||
label?: string;
|
label?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
showPasswordStrength?: boolean;
|
showPasswordStrength?: boolean;
|
||||||
showPasswordToggle?: boolean;
|
showPasswordToggle?: boolean;
|
||||||
containerClassName?: string;
|
containerClassName?: string;
|
||||||
errorClassName?: string;
|
errorClassName?: string;
|
||||||
autoComplete?: "on" | "off";
|
|
||||||
onPasswordChange?: (password: string) => void;
|
onPasswordChange?: (password: string) => void;
|
||||||
onPasswordStrengthChange?: (strength: E_PASSWORD_STRENGTH) => void;
|
onPasswordStrengthChange?: (strength: E_PASSWORD_STRENGTH) => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function AuthPasswordInput({
|
export function AuthPasswordInput({
|
||||||
label = "Password",
|
label = "Password",
|
||||||
|
|
@ -35,7 +34,7 @@ export function AuthPasswordInput({
|
||||||
onPasswordChange,
|
onPasswordChange,
|
||||||
onPasswordStrengthChange,
|
onPasswordStrengthChange,
|
||||||
...props
|
...props
|
||||||
}: AuthPasswordInputProps) {
|
}: TAuthPasswordInputProps) {
|
||||||
const [isFocused, setIsFocused] = useState(false);
|
const [isFocused, setIsFocused] = useState(false);
|
||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
|
@ -73,7 +72,7 @@ export function AuthPasswordInput({
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onFocus={handleFocus}
|
onFocus={handleFocus}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
autoComplete="on"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
{showPasswordStrength && value && isFocused && (
|
{showPasswordStrength && value && isFocused && (
|
||||||
<PasswordStrengthIndicator password={value as string} showCriteria />
|
<PasswordStrengthIndicator password={value as string} showCriteria />
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ export { AuthConfirmPasswordInput } from "./auth-confirm-password-input";
|
||||||
export { AuthForgotPassword } from "./auth-forgot-password";
|
export { AuthForgotPassword } from "./auth-forgot-password";
|
||||||
|
|
||||||
export type { AuthFormProps, AuthFormData, AuthMode } from "./auth-form";
|
export type { AuthFormProps, AuthFormData, AuthMode } from "./auth-form";
|
||||||
export type { AuthInputProps } from "./auth-input";
|
export type { TAuthInputProps } from "./auth-input";
|
||||||
export type { AuthPasswordInputProps } from "./auth-password-input";
|
export type { TAuthPasswordInputProps } from "./auth-password-input";
|
||||||
export type { AuthConfirmPasswordInputProps } from "./auth-confirm-password-input";
|
export type { TAuthConfirmPasswordInputProps } from "./auth-confirm-password-input";
|
||||||
export type { AuthForgotPasswordProps } from "./auth-forgot-password";
|
export type { AuthForgotPasswordProps } from "./auth-forgot-password";
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement>
|
||||||
inputSize?: "xs" | "sm" | "md";
|
inputSize?: "xs" | "sm" | "md";
|
||||||
hasError?: boolean;
|
hasError?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
autoComplete?: "on" | "off";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Input = React.forwardRef(function Input(props: InputProps, ref: React.ForwardedRef<HTMLInputElement>) {
|
const Input = React.forwardRef(function Input(props: InputProps, ref: React.ForwardedRef<HTMLInputElement>) {
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Eye, EyeClosed } from "lucide-react";
|
import { Eye, EyeClosed } from "lucide-react";
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Tooltip } from "@plane/propel/tooltip";
|
import { Tooltip } from "@plane/propel/tooltip";
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
|
|
||||||
interface PasswordInputProps {
|
type TPasswordInputProps = {
|
||||||
id: string;
|
id: string;
|
||||||
value: string;
|
value: string;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
|
|
@ -17,7 +17,8 @@ interface PasswordInputProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
showToggle?: boolean;
|
showToggle?: boolean;
|
||||||
error?: boolean;
|
error?: boolean;
|
||||||
}
|
autoComplete?: React.HTMLInputAutoCompleteAttribute;
|
||||||
|
};
|
||||||
|
|
||||||
export function PasswordInput({
|
export function PasswordInput({
|
||||||
id,
|
id,
|
||||||
|
|
@ -27,7 +28,8 @@ export function PasswordInput({
|
||||||
className,
|
className,
|
||||||
showToggle = true,
|
showToggle = true,
|
||||||
error = false,
|
error = false,
|
||||||
}: PasswordInputProps) {
|
autoComplete = "off",
|
||||||
|
}: TPasswordInputProps) {
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
|
|
@ -45,6 +47,7 @@ export function PasswordInput({
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
|
autoComplete={autoComplete}
|
||||||
/>
|
/>
|
||||||
{showToggle && (
|
{showToggle && (
|
||||||
<Tooltip tooltipContent={showPassword ? "Hide password" : "Show password"} position="top">
|
<Tooltip tooltipContent={showPassword ? "Hide password" : "Show password"} position="top">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue