(react) add InputPassword

We had the need to have a built-in password input able to show or
hide the password.

Closes #301
This commit is contained in:
Nathan Vasse
2024-03-13 15:29:18 +01:00
committed by NathanVss
parent c63aff4861
commit a8ec9fb757
8 changed files with 110 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
import { Meta } from "@storybook/react";
import { InputPassword } from ":/components/Forms/Input/InputPassword";
export default {
title: "Components/Forms/Input",
component: InputPassword,
} as Meta<typeof InputPassword>;
export const Password = {
args: {
label: "Your most secret password",
},
};

View File

@@ -0,0 +1,41 @@
import React, { forwardRef } from "react";
import { Input, InputProps } from ":/components/Forms/Input/index";
import { Button } from ":/components/Button";
import { useCunningham } from ":/components/Provider";
export const InputPassword = forwardRef<
HTMLInputElement,
Omit<InputProps, "rightIcon">
>((props: InputProps, ref) => {
const [showPassword, setShowPassword] = React.useState(false);
const { className, ...otherProps } = props;
const customClassName = "c__input--password";
const { t } = useCunningham();
return (
<Input
{...otherProps}
ref={ref}
className={className + " " + customClassName}
type={showPassword ? "text" : "password"}
rightIcon={
showPassword ? (
<Button
onClick={() => setShowPassword(false)}
icon={<span className="material-icons">visibility_off</span>}
color="tertiary-text"
size="small"
aria-label={t("components.forms.input.password.hide_password")}
/>
) : (
<Button
onClick={() => setShowPassword(true)}
icon={<span className="material-icons">visibility</span>}
color="tertiary-text"
size="small"
aria-label={t("components.forms.input.password.show_password")}
/>
)
}
/>
);
});

View File

@@ -133,3 +133,10 @@
}
}
}
.c__input--password {
.c__input__icon-right .material-icons {
font-size: 1.5rem;
}
}

View File

@@ -1,6 +1,7 @@
import { Canvas, Meta, Story, Source, ArgTypes } from '@storybook/blocks';
import { Input } from "./index";
import * as Stories from './index.stories';
import * as InputPasswordStories from './InputPassword.stories';
<Meta of={Stories}/>
@@ -65,6 +66,12 @@ in mind to also define `charCounterMax`.
<Canvas of={Stories.CharCounter} sourceState="shown"/>
## Password
You can also use a built-in password input that includes a button to show or hide the password.
<Canvas of={InputPasswordStories.Password} sourceState="shown"/>
## Controlled / Non Controlled
Like a native input, you can use the Input component in a controlled or non controlled way. You can see the example below

View File

@@ -4,6 +4,8 @@ import userEvent from "@testing-library/user-event";
import { expect } from "vitest";
import { Input, InputOnlyProps } from ":/components/Forms/Input/index";
import { Button } from ":/components/Button";
import { InputPassword } from ":/components/Forms/Input/InputPassword";
import { CunninghamProvider } from ":/components/Provider";
import { FieldProps } from "../Field";
const spyError = vi.spyOn(global.console, "error");
@@ -242,4 +244,32 @@ describe("<Input/>", () => {
document.querySelector(".c__field.my-custom-class"),
).toBeInTheDocument();
});
it("renders with className", async () => {
render(<Input label="First name" className="my-custom-class" />);
expect(
document.querySelector(".c__field.my-custom-class"),
).toBeInTheDocument();
});
it("allows to show/hide password", async () => {
render(
<CunninghamProvider>
<InputPassword label="Password" />
</CunninghamProvider>,
);
const user = userEvent.setup();
const input: HTMLInputElement = screen.getByLabelText("Password");
await user.type(input, "azerty");
expect(input.type).toEqual("password");
let button = screen.getByRole("button", { name: "Show password" });
await user.click(button);
expect(input.type).toEqual("text");
button = screen.getByRole("button", { name: "Hide password" });
await user.click(button);
expect(input.type).toEqual("password");
});
});

View File

@@ -12,6 +12,7 @@ export * from "./components/Forms/DatePicker";
export * from "./components/Forms/Field";
export * from "./components/Forms/FileUploader";
export * from "./components/Forms/Input";
export * from "./components/Forms/Input/InputPassword";
export * from "./components/Forms/Radio";
export * from "./components/Forms/Select";
export * from "./components/Forms/Switch";

View File

@@ -24,6 +24,12 @@
"test": "This is a test: {name}"
},
"forms": {
"input": {
"password": {
"show_password": "Show password",
"hide_password": "Hide password"
}
},
"select": {
"toggle_button_aria_label": "Toggle dropdown",
"clear_button_aria_label": "Clear selection",