1
1
import React from "react" ;
2
+ import "./css/main.css" ;
3
+ import styled from "styled-components" ;
4
+ import { getThemeValue } from "./ThemeProvider" ;
2
5
3
- export const TextField = ( ) => < input type = "text" /> ;
6
+ export type TextFieldProps = React . HTMLAttributes < HTMLInputElement > & {
7
+ children : React . ReactNode ;
8
+ type ?: "text" | "password" | "email" | "number" ;
9
+ disabled ?: boolean ;
10
+ placeholder ?: string ;
11
+ regex ?: RegExp ;
12
+ value ?: string ;
13
+ setValue ?: ( value : string ) => void ;
14
+ error ?: string ;
15
+ success ?: string ;
16
+ info ?: string ;
17
+ divProps ?: React . HTMLAttributes < HTMLDivElement > ;
18
+ variant ?: "underlined" | "outlined" | "none" ;
19
+ } ;
20
+
21
+ export const TextField = ( props : TextFieldProps ) => {
22
+ const { regex, error, success, info } = props ;
23
+ const [ regexPassed , setRegexPassed ] = React . useState ( true ) ;
24
+ const ref = React . useRef < HTMLInputElement > ( null ) ;
25
+
26
+ React . useEffect ( ( ) => {
27
+ ref . current ?. addEventListener ( "input" , ( event : any ) => {
28
+ const e = event as React . ChangeEvent < HTMLInputElement > ;
29
+ if ( regex && e . target . value ) {
30
+ setRegexPassed ( regex . test ( e . target . value ?? "" ) ) ;
31
+ } else {
32
+ setRegexPassed ( true ) ;
33
+ }
34
+ } ) ;
35
+ } , [ regex , ref ] ) ;
36
+
37
+ React . useEffect ( ( ) => {
38
+ if ( regex && props . value ) {
39
+ setRegexPassed ( regex . test ( props . value ?? "" ) ) ;
40
+ } else {
41
+ setRegexPassed ( true ) ;
42
+ }
43
+ } , [ regex , props . value ] ) ;
44
+
45
+ return (
46
+ < TextFieldContainer { ...props . divProps } >
47
+ < TextFieldElement
48
+ { ...props }
49
+ error = { error ?? ! regexPassed ? "" : undefined }
50
+ ref = { ref }
51
+ />
52
+ < HelperText
53
+ shown = {
54
+ ( ! ! error && typeof error === "string" && error . length > 0 ) ||
55
+ ( ! ! success && typeof success === "string" && success . length > 0 ) ||
56
+ ( ! ! info && typeof info === "string" && info . length > 0 )
57
+ }
58
+ error = { ! ! error }
59
+ success = { ! ! success }
60
+ info = { ! ! info }
61
+ >
62
+ { error ?? success ?? info ?? "" }
63
+ </ HelperText >
64
+ </ TextFieldContainer >
65
+ ) ;
66
+ } ;
67
+
68
+ const TextFieldElement = styled . input < TextFieldProps > `
69
+ font-family: "Poppins", sans-serif;
70
+ font-size: 1em;
71
+ color: ${ ( props ) => props . theme . text ?? getThemeValue ( "text" ) } ;
72
+ border: 2px solid ${ ( props ) => props . theme . text ?? getThemeValue ( "text" ) } ;
73
+ background-color: ${ ( props ) =>
74
+ props . theme . background ?? getThemeValue ( "background" ) } ;
75
+ border-radius: 0.375em;
76
+ padding: 0.5em 1em;
77
+ outline: none;
78
+ transition: all 0.2s ease-in-out;
79
+
80
+ :disabled {
81
+ border-color: ${ ( props ) =>
82
+ props . theme . disabled ?? getThemeValue ( "disabled" ) } ;
83
+ color: ${ ( props ) => props . theme . disabled ?? getThemeValue ( "disabled" ) } ;
84
+ cursor: not-allowed;
85
+ }
86
+
87
+ &:hover:not(:disabled) {
88
+ border-color: ${ ( props ) =>
89
+ props . theme . secondary ?? getThemeValue ( "secondary" ) } ;
90
+ }
91
+
92
+ &:active:not(:disabled),
93
+ &:focus:not(:disabled) {
94
+ border-color: ${ ( props ) => props . theme . primary ?? getThemeValue ( "primary" ) } ;
95
+ }
96
+
97
+ &:not(:focus):not(:disabled) {
98
+ ${ ( props ) =>
99
+ props . info &&
100
+ `
101
+ border-color: ${ props . theme . info ?? getThemeValue ( "info" ) } ;
102
+ color: ${ props . theme . info ?? getThemeValue ( "info" ) } ;
103
+ ::placeholder {
104
+ color: ${ props . theme . info ?? getThemeValue ( "info" ) } ;
105
+ }
106
+ ` }
107
+ ${ ( props ) =>
108
+ props . success &&
109
+ `
110
+ border-color: ${ props . theme . success ?? getThemeValue ( "success" ) } ;
111
+ color: ${ props . theme . success ?? getThemeValue ( "success" ) } ;
112
+ ::placeholder {
113
+ color: ${ props . theme . success ?? getThemeValue ( "success" ) } ;
114
+ }
115
+ ` }
116
+ ${ ( props ) =>
117
+ props . error &&
118
+ `
119
+ border-color: ${ props . theme . error ?? getThemeValue ( "error" ) } ;
120
+ color: ${ props . theme . error ?? getThemeValue ( "error" ) } ;
121
+ ::placeholder {
122
+ color: ${ props . theme . error ?? getThemeValue ( "error" ) } ;
123
+ }
124
+ ` }
125
+ }
126
+
127
+ ${ ( props ) =>
128
+ props . variant === "underlined" &&
129
+ `
130
+ border: none;
131
+ border-bottom: 2px solid ${ props . theme . text ?? getThemeValue ( "text" ) } ;
132
+ border-radius: 0;
133
+ padding: 0.25em;
134
+ ` }
135
+
136
+ ${ ( props ) =>
137
+ props . variant === "none" &&
138
+ `
139
+ border: none;
140
+ padding: 0.25em;
141
+ ` }
142
+ ` ;
143
+
144
+ const HelperText = styled . p < {
145
+ shown : boolean ;
146
+ error ?: boolean ;
147
+ success ?: boolean ;
148
+ info ?: boolean ;
149
+ } > `
150
+ opacity: ${ ( props ) => ( props . shown ? 1 : 0 ) } ;
151
+ font-family: "Poppins", sans-serif;
152
+ font-size: 0.75em;
153
+ color: ${ ( props ) =>
154
+ props . error
155
+ ? props . theme . error ?? getThemeValue ( "error" )
156
+ : props . success
157
+ ? props . theme . success ?? getThemeValue ( "success" )
158
+ : props . info
159
+ ? props . theme . info ?? getThemeValue ( "info" )
160
+ : props . theme . text ?? getThemeValue ( "text" ) } ;
161
+ margin: 0.25em 0 0 0.5em;
162
+ position: absolute;
163
+ bottom: ${ ( props ) => ( props . shown ? "-1.5em" : "-0.5em" ) } ;
164
+ transition: all 0.2s ease-in-out;
165
+ ` ;
166
+
167
+ const TextFieldContainer = styled . div `
168
+ display: flex;
169
+ position: relative;
170
+ ` ;
0 commit comments