Skip to content

Commit 2a3811e

Browse files
committed
Added Molecules PasswordFormField
1 parent 4f4d1ca commit 2a3811e

4 files changed

Lines changed: 145 additions & 0 deletions

File tree

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export { ErrorBanner } from "./molecules/errors/error-banner";
6767

6868
export { CheckboxFormField } from "./molecules/form-fields/checkbox-form-field";
6969
export { InputFormField } from "./molecules/form-fields/input-form-field";
70+
export { PasswordFormField } from "./molecules/form-fields/password-form-field";
7071

7172
// #endregion Molecules
7273

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { text, boolean } from "@storybook/addon-knobs";
2+
import React from "react";
3+
import { PasswordFormField } from "./password-form-field";
4+
5+
export default {
6+
component: PasswordFormField,
7+
title: "Molecules | Forms / Password Form Field",
8+
};
9+
10+
export const passwordFormFieldKnobs = () => (
11+
<PasswordFormField
12+
disabled={boolean("Disabled", false)}
13+
errorMessage={text("Error Message", "")}
14+
label={text("Label", "Password")}
15+
onChange={() => {}}
16+
placeholder={text("Placeholder", "Placeholder...")}
17+
required={boolean("Required", true)}
18+
value={text("Value", "Password")}
19+
isValid={boolean("Valid", true)}
20+
/>
21+
);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from "react";
2+
import { render } from "@testing-library/react";
3+
import { PasswordFormField } from "./password-form-field";
4+
import faker from "faker";
5+
6+
describe("PasswordFormField", () => {
7+
test("when default props, renders input with label", () => {
8+
// Arrange
9+
const expected = faker.random.words();
10+
11+
// Act
12+
const { getByLabelText } = render(
13+
<PasswordFormField label={expected} onChange={() => {}} />
14+
);
15+
16+
// Assert
17+
expect(getByLabelText(expected)).not.toBeNull();
18+
});
19+
});
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import React, { useState } from "react";
2+
import uuid from "uuid";
3+
import { InputProperties } from "../../atoms/interfaces/input-properties";
4+
import { PasswordInput } from "../../atoms/forms/password-input";
5+
6+
// -----------------------------------------------------------------------------------------
7+
// #region Interfaces
8+
// -----------------------------------------------------------------------------------------
9+
10+
export interface PasswordFormFields extends InputProperties {
11+
errorMessage?: string;
12+
13+
/**
14+
* Unique identifier used select the underlying <input> for functional/e2e testing
15+
*/
16+
inputTestId?: string;
17+
18+
label: string;
19+
required?: boolean;
20+
}
21+
22+
// #endregion Interfaces
23+
24+
// -----------------------------------------------------------------------------------------
25+
// #region Component
26+
// -----------------------------------------------------------------------------------------
27+
28+
const PasswordFormField: React.FC<PasswordFormFields> = (
29+
props: PasswordFormFields
30+
) => {
31+
const {
32+
disabled,
33+
errorMessage,
34+
inputTestId,
35+
isValid,
36+
label,
37+
placeholder,
38+
onChange,
39+
required,
40+
value,
41+
} = props;
42+
43+
const fieldId = uuid.v4();
44+
const [isVisible, setIsVisible] = useState<boolean>(false);
45+
const disableShowHide = value == null || value === "" || disabled;
46+
const passwordShowHideLabel = isVisible ? "Hide" : "Show";
47+
48+
const onChangeIsVisible = (
49+
event: React.MouseEvent<Element, MouseEvent>
50+
) => {
51+
event.preventDefault();
52+
53+
setIsVisible(!isVisible);
54+
};
55+
56+
if (disabled && isVisible === true) {
57+
setIsVisible(false);
58+
}
59+
60+
return (
61+
<div className={`c-form-field -password ${isValid ? "" : "-invalid"}`}>
62+
<label htmlFor={fieldId}>
63+
{label}
64+
{required && (
65+
<span className="c-form-field__required">{" *"}</span>
66+
)}
67+
</label>
68+
{// if
69+
!disableShowHide && (
70+
<button
71+
type="button"
72+
aria-label={`${passwordShowHideLabel} Password`}
73+
onClick={(event) => onChangeIsVisible(event)}>
74+
{passwordShowHideLabel}
75+
</button>
76+
)}
77+
<PasswordInput
78+
disabled={disabled}
79+
id={fieldId}
80+
isValid={isValid}
81+
isVisible={isVisible}
82+
onChange={onChange}
83+
placeholder={placeholder}
84+
testId={inputTestId}
85+
value={value}
86+
/>
87+
<div className="c-form-field__bottom">
88+
<div className="c-form-field__bottom__errors">
89+
<label>{errorMessage}</label>
90+
</div>
91+
</div>
92+
</div>
93+
);
94+
};
95+
96+
// #endregion Component
97+
98+
// -----------------------------------------------------------------------------------------
99+
// #region Exports
100+
// -----------------------------------------------------------------------------------------
101+
102+
export { PasswordFormField };
103+
104+
// #endregion Exports

0 commit comments

Comments
 (0)