Skip to content

Commit

Permalink
Merge pull request #46 from deriv-com/aizad/FEQ-1560/password-input
Browse files Browse the repository at this point in the history
Aizad/FEQ-1560/Password Input Field
  • Loading branch information
shayan-deriv authored Feb 1, 2024
2 parents 63365d8 + 5025c17 commit ab5b850
Show file tree
Hide file tree
Showing 15 changed files with 552 additions and 94 deletions.
23 changes: 23 additions & 0 deletions lib/components/Input/HelperMessage.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
$inactive_color: #999999;
$success_color: #4bb4b3;
$warning_color: #ffad3a;
$error_field: #ec3f3f;

.deriv-helper-message {
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 18px;
&--general {
color: $inactive_color;
}
&--success {
color: $success_color;
}
&--warning {
color: $warning_color;
}
&--error {
color: $error_field;
}
}
16 changes: 9 additions & 7 deletions lib/components/Input/HelperMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import React, { ReactNode } from "react";
import clsx from "clsx";
import { InputVariants } from ".";
import "./Input.scss";
import "./HelperMessage.scss";

export interface HelperMessageProps {
error?: boolean;
message?: ReactNode;
variant?: InputVariants;
disabled?: boolean;
}

const MessageVariant: Record<InputVariants, string> = {
general: "deriv-helper-message__general",
success: "deriv-helper-message__success",
error: "deriv-helper-message__error",
type TMessageVariant = Exclude<InputVariants, "disabled">;
const MessageVariant: Record<TMessageVariant, string> = {
general: "deriv-helper-message--general",
success: "deriv-helper-message--success",
warning: "deriv-helper-message--warning",
error: "deriv-helper-message--error",
};

const HelperMessage = ({
Expand All @@ -25,7 +26,8 @@ const HelperMessage = ({
<p
className={clsx("deriv-helper-message", {
[MessageVariant["general"]]: disabled,
[MessageVariant[error ? "error" : variant]]: !disabled,
[MessageVariant[error ? "error" : (variant as TMessageVariant)]]:
!disabled,
})}
>
{message}
Expand Down
116 changes: 49 additions & 67 deletions lib/components/Input/Input.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,44 @@ $disabled_color: #d6d6d6;
$inactive_color: #999999;
$active_color: #85acb0;
$success_color: #4bb4b3;
$warning_color: #ffad3a;
$error_field: #ec3f3f;
$inactive_color: #999999;
$border: 1px solid;

.deriv-input {
display: inline-block;
display: inline-flex;
position: relative;
border-radius: 4px;
width: 328px;
box-sizing: border-box;
text-align: left;
padding: 10px 16px;
border: $border;

&--general {
border-color: $inactive_color;
&:focus-within {
border-color: $active_color;
}
}
&--error {
border-color: $error_field;
}
&--success {
border-color: $success_color;
}

&--active {
border-color: $active_color;
}

&--field {
&--disabled {
border-color: $disabled_color;
}

&__field {
width: 100%;
padding: 10px 16px;
outline: none;
border-radius: 4px;
width: 328px;
box-sizing: border-box;
outline: none;
text-align: left;
&:disabled {
border: $border $disabled_color;
color: $inactive_color;
}
&::placeholder {
visibility: hidden;
}
Expand All @@ -36,27 +53,9 @@ $border: 1px solid;
height: fit-content;
}
}
&__general {
border: $border $inactive_color;
&:focus {
border: $border $active_color;
}
}
&__error {
border: $border $error_field;
&:focus {
border: $border $error_field;
}
}
&__success {
border: $border $success_color;
&:focus {
border: $border $success_color;
}
}
}

&--label {
&__label {
display: inline-block;
position: absolute;
top: 0;
Expand All @@ -68,61 +67,44 @@ $border: 1px solid;
text-transform: capitalize;
transition: all 0.15s ease-out;
padding: 0;
&__general {
&--general {
color: $inactive_color;
}
&__error {
&--error {
color: $error_field;
}
&__success {
&--success {
color: $success_color;
}
&--active {
color: $active_color;
}

&--disabled {
color: $disabled_color;
}
}

&--helper-message {
&__helper-message {
top: calc(100% + 2px);
position: absolute;
left: 16px;
margin-top: 2px;
line-height: 1;
}

&--right-content {
position: absolute;
right: 16px;
bottom: 25%;
&__right-content {
margin-left: 16px;
}
}

.deriv-input--field__general:disabled + .deriv-input--label,
.deriv-input--field__error:disabled + .deriv-input--label,
.deriv-input--field__success:disabled + .deriv-input--label {
color: $inactive_color;
cursor: not-allowed;
}

.deriv-input--field:focus + .deriv-input--label {
.deriv-input--general .deriv-input__field:focus + .deriv-input__label {
color: $active_color;
}

.deriv-input--field__error:focus + .deriv-input--label {
.deriv-input--error .deriv-input__field:focus + .deriv-input__label {
color: $error_field;
}

.deriv-input--field__success:focus + .deriv-input--label {
.deriv-input--success .deriv-input__field:focus + .deriv-input__label {
color: $success_color;
}

.deriv-helper-message {
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 18px;
&__general {
color: $inactive_color;
}
&__success {
color: $success_color;
}
&__error {
color: $error_field;
}
}
56 changes: 37 additions & 19 deletions lib/components/Input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ import clsx from "clsx";
import HelperMessage from "./HelperMessage";
import "./Input.scss";

export type InputVariants = "general" | "success" | "error";
interface InputProps
export type InputVariants =
| "general"
| "success"
| "error"
| "warning"
| "disabled";
interface InputProps
extends Omit<ComponentProps<"input">, "style" | "placeholder"> {
label?: string;
leftPlaceholder?: ReactNode;
Expand All @@ -15,15 +20,19 @@ export type InputVariants = "general" | "success" | "error";
}

const InputVariant: Record<InputVariants, string> = {
general: "deriv-input--field__general",
success: "deriv-input--field__success",
error: "deriv-input--field__error",
general: "deriv-input--general",
success: "deriv-input--success",
warning: "deriv-input--general",
error: "deriv-input--error",
disabled: "deriv-input--disabled",
};

const LabelVariant: Record<InputVariants, string> = {
general: "deriv-input--label__general",
success: "deriv-input--label__success",
error: "deriv-input--label__error",
general: "deriv-input__label--general",
success: "deriv-input__label--success",
warning: "deriv-input__label--general",
error: "deriv-input__label--error",
disabled: "deriv-input__label--disabled",
};

export const Input = ({
Expand All @@ -39,33 +48,42 @@ export const Input = ({
...rest
}: InputProps) => {
return (
<div className="deriv-input">
<div
className={clsx(
"deriv-input",
className,
InputVariant[error ? "error" : variant],
{
"deriv-input--disabled": disabled,
}
)}
>
{leftPlaceholder && (
<div className="deriv-input--left-content">{leftPlaceholder}</div>
<div className="deriv-input__left-content">{leftPlaceholder}</div>
)}
<input
placeholder={label}
className={clsx(
"deriv-input--field",
className,
InputVariant[error ? "error" : variant]
)}
className="deriv-input__field"
id={id}
disabled={disabled}
{...rest}
/>
<label
className={clsx(
"deriv-input--label",
LabelVariant[error ? "error" : variant]
"deriv-input__label",
LabelVariant[error ? "error" : variant],
{
"deriv-input--label--disabled": disabled,
}
)}
htmlFor={id}
>
{label}
</label>
{rightPlaceholder && (
<div className="deriv-input--right-content">{rightPlaceholder}</div>
<div className="deriv-input__right-content">{rightPlaceholder}</div>
)}
<div className="deriv-input--helper-message">
<div className="deriv-input__helper-message">
{message && (
<HelperMessage
message={message}
Expand Down
61 changes: 61 additions & 0 deletions lib/components/PasswordInput/PasswordConstants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
export type TScore = 0 | 1 | 2 | 3 | 4;

export type passwordKeys =
| "common"
| "commonNames"
| "dates"
| "extendedRepeat"
| "keyPattern"
| "namesByThemselves"
| "pwned"
| "recentYears"
| "sequences"
| "similarToCommon"
| "simpleRepeat"
| "straightRow"
| "topHundred"
| "topTen"
| "userInputs"
| "wordByItself";

export const passwordRegex = {
hasLowerCase: /[a-z]/,
hasNumber: /\d/,
hasSymbol: /\W/,
hasUpperCase: /[A-Z]/,
isLengthValid: /^.{8,25}$/,
isPasswordValid: /^(?=.*[a-z])(?=.*\d)(?=.*[A-Z])[!-~]{8,25}$/,
};

export const passwordValues = {
longPassword: 12,
maxLength: 25,
minLength: 8,
};

export const passwordErrorMessage = {
invalidLength: "You should enter 8-25 characters.",
missingCharacter:
"Password should have lower and uppercase English letters with numbers.",
PasswordError: "That password is incorrect. Please try again.",
};

export const warningMessages: Record<passwordKeys, string> = {
common: "This is a very common password.",
commonNames: "Common names and surnames are easy to guess.",
dates: "Dates are easy to guess.",
extendedRepeat:
'Repeated character patterns like "abcabcabc" are easy to guess.',
keyPattern: "Short keyboard patterns are easy to guess.",
namesByThemselves: "Single names or surnames are easy to guess.",
pwned: "Your password was exposed by a data breach on the Internet.",
recentYears: "Recent years are easy to guess.",
sequences: 'Common character sequences like "abc" are easy to guess.',
similarToCommon: "This is similar to a commonly used password.",
simpleRepeat: 'Repeated characters like "aaa" are easy to guess.',
straightRow: "Straight rows of keys on your keyboard are easy to guess.",
topHundred: "This is a frequently used password.",
topTen: "This is a heavily used password.",
userInputs: "There should not be any personal or page related data.",
wordByItself: "Single words are easy to guess.",
};
Loading

0 comments on commit ab5b850

Please sign in to comment.