Skip to content

Commit

Permalink
feat(textfield): added Super cool text field ‼️
Browse files Browse the repository at this point in the history
fix #3
  • Loading branch information
hackr-sh committed May 9, 2023
1 parent b6b71c2 commit 49f5438
Show file tree
Hide file tree
Showing 2 changed files with 201 additions and 1 deletion.
169 changes: 168 additions & 1 deletion src/components/TextField.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,170 @@
import React from "react";
import "./css/main.css";
import styled from "styled-components";
import { getThemeValue } from "./ThemeProvider";

export const TextField = () => <input type="text" />;
export type TextFieldProps = React.HTMLAttributes<HTMLInputElement> & {
children: React.ReactNode;
type?: "text" | "password" | "email" | "number";
disabled?: boolean;
placeholder?: string;
regex?: RegExp;
value?: string;
setValue?: (value: string) => void;
error?: string;
success?: string;
info?: string;
divProps?: React.HTMLAttributes<HTMLDivElement>;
variant?: "underlined" | "outlined" | "none";
};

export const TextField = (props: TextFieldProps) => {
const { regex, error, success, info } = props;
const [regexPassed, setRegexPassed] = React.useState(true);
const ref = React.useRef<HTMLInputElement>(null);

React.useEffect(() => {
ref.current?.addEventListener("input", (event: any) => {
const e = event as React.ChangeEvent<HTMLInputElement>;
if (regex && e.target.value) {
setRegexPassed(regex.test(e.target.value ?? ""));
} else {
setRegexPassed(true);
}
});
}, [regex, ref]);

React.useEffect(() => {
if (regex && props.value) {
setRegexPassed(regex.test(props.value ?? ""));
} else {
setRegexPassed(true);
}
}, [regex, props.value]);

return (
<TextFieldContainer {...props.divProps}>
<TextFieldElement
{...props}
error={error ?? !regexPassed ? "" : undefined}
ref={ref}
/>
<HelperText
shown={
(!!error && typeof error === "string" && error.length > 0) ||
(!!success && typeof success === "string" && success.length > 0) ||
(!!info && typeof info === "string" && info.length > 0)
}
error={!!error}
success={!!success}
info={!!info}
>
{error ?? success ?? info ?? ""}
</HelperText>
</TextFieldContainer>
);
};

const TextFieldElement = styled.input<TextFieldProps>`
font-family: "Poppins", sans-serif;
font-size: 1em;
color: ${(props) => props.theme.text ?? getThemeValue("text")};
border: 2px solid ${(props) => props.theme.text ?? getThemeValue("text")};
background-color: ${(props) =>
props.theme.background ?? getThemeValue("background")};
border-radius: 0.375em;
padding: 0.5em 1em;
outline: none;
transition: all 0.2s ease-in-out;
:disabled {
border-color: ${(props) =>
props.theme.disabled ?? getThemeValue("disabled")};
color: ${(props) => props.theme.disabled ?? getThemeValue("disabled")};
cursor: not-allowed;
}
&:hover:not(:disabled) {
border-color: ${(props) =>
props.theme.secondary ?? getThemeValue("secondary")};
}
&:active:not(:disabled),
&:focus:not(:disabled) {
border-color: ${(props) => props.theme.primary ?? getThemeValue("primary")};
}
&:not(:focus):not(:disabled) {
${(props) =>
props.info &&
`
border-color: ${props.theme.info ?? getThemeValue("info")};
color: ${props.theme.info ?? getThemeValue("info")};
::placeholder {
color: ${props.theme.info ?? getThemeValue("info")};
}
`}
${(props) =>
props.success &&
`
border-color: ${props.theme.success ?? getThemeValue("success")};
color: ${props.theme.success ?? getThemeValue("success")};
::placeholder {
color: ${props.theme.success ?? getThemeValue("success")};
}
`}
${(props) =>
props.error &&
`
border-color: ${props.theme.error ?? getThemeValue("error")};
color: ${props.theme.error ?? getThemeValue("error")};
::placeholder {
color: ${props.theme.error ?? getThemeValue("error")};
}
`}
}
${(props) =>
props.variant === "underlined" &&
`
border: none;
border-bottom: 2px solid ${props.theme.text ?? getThemeValue("text")};
border-radius: 0;
padding: 0.25em;
`}
${(props) =>
props.variant === "none" &&
`
border: none;
padding: 0.25em;
`}
`;

const HelperText = styled.p<{
shown: boolean;
error?: boolean;
success?: boolean;
info?: boolean;
}>`
opacity: ${(props) => (props.shown ? 1 : 0)};
font-family: "Poppins", sans-serif;
font-size: 0.75em;
color: ${(props) =>
props.error
? props.theme.error ?? getThemeValue("error")
: props.success
? props.theme.success ?? getThemeValue("success")
: props.info
? props.theme.info ?? getThemeValue("info")
: props.theme.text ?? getThemeValue("text")};
margin: 0.25em 0 0 0.5em;
position: absolute;
bottom: ${(props) => (props.shown ? "-1.5em" : "-0.5em")};
transition: all 0.2s ease-in-out;
`;

const TextFieldContainer = styled.div`
display: flex;
position: relative;
`;
33 changes: 33 additions & 0 deletions src/stories/TextField.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { Meta, StoryObj } from '@storybook/react';

import { TextField } from "../components/TextField";

const meta: Meta<typeof TextField> = {
title: 'Example/TextField',
component: TextField,
tags: ['autodocs'],
parameters: {
controls: { hideNoControlsWarning: true },
},
argTypes: {
placeholder: {
defaultValue: "lorem ipsum",
control: {
type: "text",
},
},
},

};

export default meta;
type Story = StoryObj<typeof meta>;

export const TextStory: Story = {
args: {
type: 'text',
disabled: false,
placeholder: "lorem ipsum",
regex: /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/g,
},
};

0 comments on commit 49f5438

Please sign in to comment.