Input.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import { Flex, BoxProps } from "reflexbox/styled-components";
  2. import styled, { css, keyframes } from "styled-components";
  3. import { withProp, prop, ifProp } from "styled-tools";
  4. import { FC } from "react";
  5. import { Span } from "./Text";
  6. interface StyledSelectProps extends BoxProps {
  7. autoFocus?: boolean;
  8. name?: string;
  9. id?: string;
  10. type?: string;
  11. value?: string;
  12. required?: boolean;
  13. onChange?: any;
  14. placeholderSize?: number[];
  15. br?: string;
  16. bbw?: string;
  17. }
  18. export const TextInput = styled(Flex).attrs({
  19. as: "input"
  20. })<StyledSelectProps>`
  21. position: relative;
  22. box-sizing: border-box;
  23. letter-spacing: 0.05em;
  24. color: #444;
  25. background-color: white;
  26. box-shadow: 0 10px 35px hsla(200, 15%, 70%, 0.2);
  27. border: none;
  28. border-radius: ${prop("br", "100px")};
  29. border-bottom: 5px solid #f5f5f5;
  30. border-bottom-width: ${prop("bbw", "5px")};
  31. transition: all 0.5s ease-out;
  32. :focus {
  33. outline: none;
  34. box-shadow: 0 20px 35px hsla(200, 15%, 70%, 0.4);
  35. }
  36. ::placeholder {
  37. font-size: ${withProp("placeholderSize", s => s[0] || 14)}px;
  38. letter-spacing: 0.05em;
  39. color: #888;
  40. }
  41. @media screen and (min-width: 64em) {
  42. ::placeholder {
  43. font-size: ${withProp(
  44. "placeholderSize",
  45. s => s[3] || s[2] || s[1] || s[0] || 16
  46. )}px;
  47. }
  48. }
  49. @media screen and (min-width: 52em) {
  50. letter-spacing: 0.1em;
  51. border-bottom-width: ${prop("bbw", "6px")};
  52. ::placeholder {
  53. font-size: ${withProp(
  54. "placeholderSize",
  55. s => s[2] || s[1] || s[0] || 15
  56. )}px;
  57. }
  58. }
  59. @media screen and (min-width: 40em) {
  60. ::placeholder {
  61. font-size: ${withProp("placeholderSize", s => s[1] || s[0] || 15)}px;
  62. }
  63. }
  64. `;
  65. TextInput.defaultProps = {
  66. value: "",
  67. height: [40, 44],
  68. py: 0,
  69. px: [3, 24],
  70. fontSize: [14, 15],
  71. placeholderSize: [13, 14]
  72. };
  73. interface StyledSelectProps extends BoxProps {
  74. name?: string;
  75. id?: string;
  76. type?: string;
  77. value?: string;
  78. required?: boolean;
  79. onChange?: any;
  80. br?: string;
  81. bbw?: string;
  82. }
  83. interface SelectOptions extends StyledSelectProps {
  84. options: Array<{ key: string; value: string | number }>;
  85. }
  86. const StyledSelect: FC<StyledSelectProps> = styled(Flex).attrs({
  87. as: "select"
  88. })<StyledSelectProps>`
  89. position: relative;
  90. box-sizing: border-box;
  91. letter-spacing: 0.05em;
  92. color: #444;
  93. background-color: white;
  94. box-shadow: 0 10px 35px hsla(200, 15%, 70%, 0.2);
  95. border: none;
  96. border-radius: ${prop("br", "100px")};
  97. border-bottom: 5px solid #f5f5f5;
  98. border-bottom-width: ${prop("bbw", "5px")};
  99. transition: all 0.5s ease-out;
  100. appearance: none;
  101. background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 24 24' fill='none' stroke='%235c666b' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  102. background-repeat: no-repeat, repeat;
  103. background-position: right 1.2em top 50%, 0 0;
  104. background-size: 1em auto, 100%;
  105. :focus {
  106. outline: none;
  107. box-shadow: 0 20px 35px hsla(200, 15%, 70%, 0.4);
  108. }
  109. @media screen and (min-width: 52em) {
  110. letter-spacing: 0.1em;
  111. border-bottom-width: ${prop("bbw", "6px")};
  112. }
  113. `;
  114. export const Select: FC<SelectOptions> = ({ options, ...props }) => (
  115. <StyledSelect {...props}>
  116. {options.map(({ key, value }) => (
  117. <option key={value} value={value}>
  118. {key}
  119. </option>
  120. ))}
  121. </StyledSelect>
  122. );
  123. Select.defaultProps = {
  124. value: "",
  125. height: [40, 44],
  126. py: 0,
  127. px: [3, 24],
  128. fontSize: [14, 15]
  129. };
  130. interface ChecknoxInputProps {
  131. checked: boolean;
  132. id?: string;
  133. name: string;
  134. onChange: any;
  135. }
  136. const CheckboxInput = styled(Flex).attrs({
  137. as: "input",
  138. type: "checkbox",
  139. m: 0,
  140. p: 0,
  141. width: 0,
  142. height: 0,
  143. opacity: 0
  144. })<ChecknoxInputProps>`
  145. position: relative;
  146. opacity: 0;
  147. `;
  148. const CheckboxBox = styled(Flex).attrs({
  149. alignItems: "center",
  150. justifyContent: "center"
  151. })<{ checked: boolean }>`
  152. position: relative;
  153. transition: color 0.3s ease-out;
  154. border-radius: 4px;
  155. background-color: white;
  156. box-shadow: 0 2px 4px rgba(50, 50, 50, 0.2);
  157. cursor: pointer;
  158. input:focus + & {
  159. outline: 3px solid rgba(65, 164, 245, 0.5);
  160. }
  161. ${ifProp(
  162. "checked",
  163. css`
  164. box-shadow: 0 3px 5px rgba(50, 50, 50, 0.4);
  165. :after {
  166. content: "";
  167. position: absolute;
  168. width: 80%;
  169. height: 80%;
  170. display: block;
  171. border-radius: 2px;
  172. background-color: #9575cd;
  173. box-shadow: 0 2px 4px rgba(50, 50, 50, 0.2);
  174. cursor: pointer;
  175. animation: ${keyframes`
  176. from {
  177. opacity: 0;
  178. transform: scale(0, 0);
  179. }
  180. to {
  181. opacity: 1;
  182. transform: scale(1, 1);
  183. }
  184. `} 0.1s ease-in;
  185. }
  186. `
  187. )}
  188. `;
  189. interface CheckboxProps extends ChecknoxInputProps, BoxProps {
  190. label: string;
  191. }
  192. export const Checkbox: FC<CheckboxProps> = ({
  193. checked,
  194. height,
  195. id,
  196. label,
  197. name,
  198. width,
  199. onChange,
  200. ...rest
  201. }) => {
  202. return (
  203. <Flex
  204. flex="0 0 auto"
  205. as="label"
  206. alignItems="center"
  207. style={{ cursor: "pointer" }}
  208. {...(rest as any)}
  209. >
  210. <CheckboxInput
  211. onChange={onChange}
  212. name={name}
  213. id={id}
  214. checked={checked}
  215. />
  216. <CheckboxBox checked={checked} width={width} height={height} />
  217. <Span ml={[10, 12]} mt="1px" color="#555">
  218. {label}
  219. </Span>
  220. </Flex>
  221. );
  222. };
  223. Checkbox.defaultProps = {
  224. width: [16, 18],
  225. height: [16, 18],
  226. fontSize: [15, 16]
  227. };