Skip to content

Commit

Permalink
chore: improve PasswordInput
Browse files Browse the repository at this point in the history
  • Loading branch information
aizad-deriv committed Feb 1, 2024
1 parent 4585d43 commit 510ea35
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 25 deletions.
49 changes: 24 additions & 25 deletions lib/components/PasswordInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {
ChangeEvent,
ComponentProps,
FocusEvent,
useCallback,
useMemo,
useState,
Expand All @@ -19,6 +20,7 @@ import {
import { EyeIcon, EyeIconSlash } from "./PasswordIcon";
import { PasswordMeter } from "./PasswordMeter";
import "./PasswordInput.scss";
import clsx from "clsx";

export const validatePassword = (password: string) => {
const score = calculateScore(password);
Expand All @@ -40,11 +42,8 @@ export const validatePassword = (password: string) => {

type InputProps = ComponentProps<typeof Input>;

interface PasswordInputProps
extends Pick<
InputProps,
"value" | "onChange" | "label" | "id" | "autoComplete"
> {
interface PasswordInputProps extends Omit<InputProps, "variant"> {
wrapperClassName?: string;
hidePasswordMeter?: boolean;
hint?: string;
}
Expand All @@ -58,50 +57,49 @@ const PasswordVariant: Record<TScore, InputProps["variant"]> = {
};

export const PasswordInput = ({
autoComplete,
id,
label,
value,
onChange,
hint,
hidePasswordMeter,
wrapperClassName,
...rest
}: PasswordInputProps) => {
const [isTouched, setIsTouched] = useState(false);
const [showPassword, setShowPassword] = useState(false);

const { errorMessage, score } = useMemo(
() => validatePassword(value as string),
[value]
() => validatePassword(rest.value as string),
[rest.value]
);

const handleChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
onChange?.(e);
rest.onChange?.(e);
if (!isTouched) {
setIsTouched(true);
}
},
[isTouched, onChange]
[isTouched, rest.onChange]
);

const handleBlur = useCallback(() => {
if (!isTouched) {
setIsTouched(true);
}
}, [isTouched]);
const handleBlur = useCallback(
(e: FocusEvent<HTMLInputElement>) => {
if (!isTouched) {
setIsTouched(true);
}
rest.onBlur?.(e);
},
[isTouched]
);

return (
<div className="deriv-password">
<div className={clsx("deriv-password", wrapperClassName)}>
<Input
autoComplete={autoComplete}
id={id}
label={label}
type={showPassword ? "text" : "password"}
value={value}
message={isTouched ? errorMessage : "" || hint}
onChange={handleChange}
onBlur={handleBlur}
variant={isTouched ? PasswordVariant[score as TScore] : "general"}
variant={
isTouched || rest.value ? PasswordVariant[score as TScore] : "general"
}
rightPlaceholder={
<button
className="deriv-password__icon"
Expand All @@ -110,6 +108,7 @@ export const PasswordInput = ({
{showPassword ? <EyeIcon /> : <EyeIconSlash />}
</button>
}
{...rest}
/>
{!hidePasswordMeter && <PasswordMeter score={score as TScore} />}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { StoryObj, Meta } from "@storybook/react";
import { PasswordInput } from "../../lib/main";
import { useState } from "react";

const meta = {
title: "Components/PasswordInput",
Expand All @@ -26,6 +27,11 @@ const meta = {
disable: true,
},
},
value: {
control: {
disable: true,
},
},
onChange: {
control: {
disable: true,
Expand All @@ -50,4 +56,15 @@ export const Default: Story = {
onChange: () => {},
hidePasswordMeter: false,
},
render: (args) => {
const [value, setValue] = useState("");

return (
<PasswordInput
{...args}
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
},
};

0 comments on commit 510ea35

Please sign in to comment.