Add Input component

This commit is contained in:
Stephan
2022-10-07 23:08:38 +02:00
parent 87a3b9daca
commit 3cf541ab8b
5 changed files with 129 additions and 0 deletions
+2
View File
@@ -12,6 +12,7 @@
}, },
"dependencies": { "dependencies": {
"framer-motion": "^7.5.1", "framer-motion": "^7.5.1",
"lodash.uniqueid": "^4.0.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^6.4.1", "react-router-dom": "^6.4.1",
@@ -27,6 +28,7 @@
"@storybook/builder-vite": "^0.2.3", "@storybook/builder-vite": "^0.2.3",
"@storybook/react": "^6.5.12", "@storybook/react": "^6.5.12",
"@storybook/testing-library": "^0.0.13", "@storybook/testing-library": "^0.0.13",
"@types/lodash.uniqueid": "^4.0.7",
"@types/react": "^18.0.17", "@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"@vitejs/plugin-react": "^2.1.0", "@vitejs/plugin-react": "^2.1.0",
+68
View File
@@ -0,0 +1,68 @@
@import "../../styles/colors.scss";
.inputContainer {
background: #f0f0f0;
width: 15rem;
display: flex;
font-size: 1rem;
font-family: sans-serif;
padding: 10px 14px;
border-radius: 100vh;
}
.iconContainer {
display: block;
width: 1.7em;
height: 1.7em;
justify-self: center;
align-self: center;
display: flex;
justify-content: center;
align-items: center;
svg {
width: 100%;
height: 100%;
fill: $unimportant;
}
}
.innerInput {
padding-left: 16px;
width: 100%;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.label {
color: $unimportant;
position: absolute;
left: 16px;
transition: transform 100ms, left 100ms;
}
.input {
width: 100%;
background: none;
outline: none;
border: none;
font-size: inherit;
&:focus ~ .label,
&:not(:placeholder-shown) ~ .label {
left: 100%;
transform: translateX(calc(-100% - 0.5em)) scale(0.8);
}
}
+37
View File
@@ -0,0 +1,37 @@
import React, { useRef, useState } from "react";
import uniqueId from "lodash.uniqueid";
import styles from "./Input.module.scss";
import { ReactComponent } from "../../assets/svgr-custom";
interface InputProps {
value: string;
onChange?: React.HTMLAttributes<HTMLInputElement>["onChange"];
placeholder?: string;
label?: string;
icon?: typeof ReactComponent;
}
const Input: React.FC<InputProps> = ({ value, onChange, placeholder, label, icon: Icon }) => {
const [id] = useState(uniqueId());
const input = useRef<HTMLInputElement>(null);
return (
<div className={styles.inputContainer} onClick={() => input.current?.focus()}>
{Icon && (
<span className={styles.iconContainer}>
<Icon />
</span>
)}
<div className={styles.innerInput}>
<input type="text" id={id} className={styles.input} placeholder={label ? " " : placeholder} ref={input} />
<label htmlFor={id} className={styles.label}>
{label}
</label>
</div>
</div>
);
};
export default Input;
+3
View File
@@ -0,0 +1,3 @@
import Input from "./Input";
export default Input;
+19
View File
@@ -0,0 +1,19 @@
import React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
// @ts-ignore
import { ReactComponent as Icon } from "../assets/search.svg";
import Input from "../components/input";
export default { title: "Input", component: Input } as ComponentMeta<typeof Input>;
const Template: ComponentStory<typeof Input> = (args) => <Input {...args} />;
export const DefaultInput = Template.bind({});
DefaultInput.args = {
value: "test",
icon: Icon,
label: "test",
};