Add Select, InputButtonWithIcon components

This commit is contained in:
Lindsey 2021-09-24 01:09:13 -04:00
parent 1b0815b477
commit a8e3774bc8
18 changed files with 433 additions and 164 deletions

28
package-lock.json generated
View File

@ -5583,6 +5583,23 @@
"loader-utils": "^2.0.0"
}
},
"@tanem/svg-injector": {
"version": "10.1.5",
"resolved": "https://registry.npmjs.org/@tanem/svg-injector/-/svg-injector-10.1.5.tgz",
"integrity": "sha512-2Njc+5WPHQhe3Wgz8AurDAhyNBsFEf4hu18/cFYrzm2PX6WVodbyfiyfH2W6Rz3WgvletRXMbAFVl27DjcT/Ww==",
"requires": {
"@babel/runtime": "^7.15.4",
"content-type": "^1.0.4",
"tslib": "^2.3.1"
},
"dependencies": {
"tslib": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
}
}
},
"@testing-library/dom": {
"version": "7.31.2",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz",
@ -17176,6 +17193,17 @@
"throttle-debounce": "^3.0.1"
}
},
"react-svg": {
"version": "14.0.13",
"resolved": "https://registry.npmjs.org/react-svg/-/react-svg-14.0.13.tgz",
"integrity": "sha512-jN8cFlThjC5kMgK9+dLAikzLXtJlOQhqCiLqAtc4J0y6Hvnap1dAVB1JNxzliCwZNI+VkYD3PViltHvpkpeeOQ==",
"requires": {
"@babel/runtime": "^7.15.4",
"@tanem/svg-injector": "^10.1.5",
"@types/prop-types": "^15.7.4",
"prop-types": "^15.7.2"
}
},
"react-syntax-highlighter": {
"version": "13.5.3",
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz",

View File

@ -14,6 +14,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"react-svg": "^14.0.13",
"styled-components": "^5.3.1",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1"

View File

@ -6,22 +6,36 @@ import Header1 from "./stories/Header1";
import Header2 from "./stories/Header2";
import Button from "./stories/Button";
import InputButtonWithIcon from "./stories/InputButtonWithIcon";
import Label from "./stories/Label";
import Input from "./stories/Input";
import FileInput from "./stories/FileInput";
import TextArea from "./stories/TextArea";
import Select from "./stories/Select";
import CenteredContainer from "./stories/CenteredContainer";
import SpaceBetweenContainer from "./stories/SpaceBetweenContainer";
import Spacer from "./stories/Spacer";
import TextAlignWrapper from "./stories/TextAlignWrapper";
import CenteredContainer from "./stories/utilities/CenteredContainer";
import SpaceBetweenContainer from "./stories/utilities/SpaceBetweenContainer";
import Spacer from "./stories/utilities/Spacer";
import TextAlignWrapper from "./stories/utilities/TextAlignWrapper";
function App() {
const [input1, setInput1] = useState("");
const [input2, setInput2] = useState("");
const [select, setSelect] = useState("github");
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const handleInputChange1 = (e: React.ChangeEvent<HTMLInputElement>) => {
setInput1(e.target.value);
};
const handleInputChange2 = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setInput2(e.target.value);
};
const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setSelect(e.target.value);
};
return (
<CenteredContainer fullscreen>
<CenteredContainer>
@ -34,18 +48,39 @@ function App() {
<Label htmlFor="testInput">Testing label</Label>
</TextAlignWrapper>
<Input
variant="disabled-medium"
variant="disabled-light"
name="testInput"
value={input1}
onChange={handleInputChange}
onChange={handleInputChange1}
placeholder="testing 1 2 3"
/>
<Spacer />
<InputButtonWithIcon
id="testinputbutton"
value="https://wanderinginn.com"
variant="download"
onClick={() => {}}
/>
<Spacer />
<FileInput id="fileInput" />
<Spacer />
<Select
name="selectService"
value={select}
onChange={handleSelectChange}
/>
<Spacer />
<SpaceBetweenContainer>
<Label htmlFor="testInput2">Testing label left</Label>
<Label htmlFor="testInput2">Testing label right</Label>
</SpaceBetweenContainer>
<input type="text" name="testInput2" style={{ width: "100%" }} />
<TextArea
name="testTextArea"
value={input2}
onChange={handleInputChange2}
placeholder="Tell me your secrets"
disabled
/>
<Spacer />
<SpaceBetweenContainer>
<Button variant="primary" onClick={() => {}}>

31
src/App2.tsx Normal file
View File

@ -0,0 +1,31 @@
import React from "react";
import styled from "styled-components";
import InputButtonWithIcon from "./stories/InputButtonWithIcon";
import Icon from "./stories/Icon";
import { ReactComponent as CopyIcon } from "./stories/assets/copy.svg";
function App2() {
return (
<StyledDiv>
<InputButtonWithIcon
id="inputtest"
variant="download"
onClick={() => {}}
value="https://wanderinginn.com"
/>
<div style={{ margin: "50px" }}></div>
<Icon iconName="download" onClick={() => {}} />
<CopyIcon />
</StyledDiv>
);
}
export default App2;
const StyledDiv = styled.div`
height: 80vh;
background-color: black;
padding: 40px;
`;

View File

@ -1,12 +1,14 @@
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import App2 from "./App2";
import { GlobalStyle } from "../src/shared/global";
ReactDOM.render(
<React.StrictMode>
<GlobalStyle />
<App />
{/* <App /> */}
<App2 />
</React.StrictMode>,
document.getElementById("root")
);

View File

@ -21,8 +21,14 @@ export const typography = {
},
};
export const input = {
padding: "2rem",
borderRadius: "12px",
fontSize: "1.6rem",
export const padding = {
medium: "2rem",
};
export const borderRadius = {
medium: "12px",
};
export const fontSize = {
medium: "1.6rem",
};

View File

@ -1,59 +0,0 @@
import React, { FC, ReactNode } from "react";
import styled, { css } from "styled-components";
import CSS from "csstype";
import { color } from "../shared/styles";
interface CenteredContainerProps {
children: ReactNode | null;
style?: CSS.Properties;
fullscreen?: boolean;
wide?: boolean;
}
const CenteredContainer: FC<CenteredContainerProps> = ({
children,
style,
fullscreen = false,
wide = false,
}) => {
return (
<StyledDiv style={style} fullscreen={fullscreen} wide={wide}>
{children}
</StyledDiv>
);
};
export default CenteredContainer;
const StyledDiv = styled.div<CenteredContainerProps>`
height: 100vh;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
${(props) =>
props.fullscreen &&
css`
width: 100vw;
background-color: ${color.background};
`}
${(props) =>
!props.fullscreen &&
css`
max-width: 600px;
width: 100%;
padding: 0 30px;
`}
${(props) =>
!props.fullscreen &&
props.wide &&
css`
max-width: 1200px;
`}
`;

56
src/stories/FileInput.tsx Normal file
View File

@ -0,0 +1,56 @@
import React, { FC } from "react";
import styled, { css } from "styled-components";
import CSS from "csstype";
import { rgba } from "polished";
import {
color,
opacity,
typography,
borderRadius,
fontSize,
padding,
} from "../shared/styles";
export interface FileInputProps {
style?: CSS.Properties;
variant?: "primary" | "disabled-light" | "disabled-medium";
id: string;
/* onChange: (e: React.ChangeEvent<HTMLInputElement>) => void; */
placeholder?: string;
}
const FileInput: FC<FileInputProps> = ({
style,
variant = "primary",
id,
placeholder = "",
}) => {
return (
<StyledInput
style={style}
variant={variant}
id={id}
placeholder={placeholder}
type="file"
/>
);
};
export default FileInput;
const StyledInput = styled.input<FileInputProps>`
border-radius: ${borderRadius.medium};
border: 5px dotted black;
padding: ${padding.medium};
width: 100%;
font-size: ${fontSize.medium};
font-family: ${typography.primary};
font-weight: ${typography.weight.regular};
appearance: none;
&:focus-visible {
outline: none;
}
`;

87
src/stories/Icon.tsx Normal file
View File

@ -0,0 +1,87 @@
import React, { FC } from "react";
import styled, { css } from "styled-components";
import CSS from "csstype";
import { ReactSVG } from "react-svg";
type IconNames = "copy" | "download";
export interface IconProps {
style?: CSS.Properties;
iconName: IconNames;
onClick: () => void;
}
const Icon: FC<IconProps> = ({ style, iconName, onClick }) => {
const generateIcon = (iconName: IconNames) => {
if (iconName === "download") {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
height="3rem"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
/>
</svg>
);
}
if (iconName === "copy") {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
height="3rem"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2"
/>
</svg>
);
}
};
return (
<StyledSpan iconName={iconName} onClick={onClick}>
{generateIcon(iconName)}
</StyledSpan>
);
};
export default Icon;
const StyledSpan = styled.span<IconProps>`
position: absolute;
top: calc(50% - 1.5rem);
right: 2rem;
z-index: 100;
width: 3rem;
height: 3rem;
font-size: 1.6rem;
cursor: pointer;
${(props) =>
props.iconName === "copy" &&
css`
color: black;
`}
${(props) =>
props.iconName === "download" &&
css`
color: white;
`}
`;

View File

@ -3,7 +3,14 @@ import styled, { css } from "styled-components";
import CSS from "csstype";
import { rgba } from "polished";
import { color, opacity, typography, input } from "../shared/styles";
import {
color,
opacity,
typography,
borderRadius,
fontSize,
padding,
} from "../shared/styles";
export interface InputProps {
style?: CSS.Properties;
@ -45,12 +52,12 @@ const Input: FC<InputProps> = ({
export default Input;
const StyledInput = styled.input<InputProps>`
border-radius: ${input.borderRadius};
border-radius: ${borderRadius.medium};
border: none;
padding: ${input.padding};
padding: ${padding.medium};
width: 100%;
font-size: ${input.fontSize};
font-size: ${fontSize.medium};
font-family: ${typography.primary};
font-weight: ${typography.weight.regular};
@ -63,8 +70,8 @@ const StyledInput = styled.input<InputProps>`
(props.variant === "disabled-light" ||
props.variant === "disabled-medium") &&
css`
color: ${color.white};
cursor: not-allowed;
color: ${color.white};
&::placeholder {
color: ${color.white};

View File

@ -0,0 +1,81 @@
import React, { FC, ReactNode } from "react";
import styled, { css } from "styled-components";
import CSS from "csstype";
import { rgba } from "polished";
import Icon from "./Icon";
import {
color,
padding,
borderRadius,
typography,
fontSize,
opacity,
} from "../shared/styles";
export interface InputButtonWithIconProps {
style?: CSS.Properties;
id: string;
variant: "copy" | "download";
value: string;
onClick: () => void;
}
const InputButtonWithIcon: FC<InputButtonWithIconProps> = ({
style,
id,
variant,
value,
onClick,
}) => {
return (
<StyledDiv>
<StyledInput
style={style}
id={id}
variant={variant}
value={value}
onClick={onClick}
/>
<Icon iconName={variant} onClick={onClick} />
</StyledDiv>
);
};
export default InputButtonWithIcon;
const StyledDiv = styled.div`
position: relative;
width: 100%;
`;
const StyledInput = styled.input<InputButtonWithIconProps>`
border: 0;
border-radius: ${borderRadius.medium};
cursor: pointer;
padding: ${padding.medium};
padding-right: 6rem;
width: 100%;
overflow: hidden;
font-size: ${fontSize.medium};
font-family: ${typography.primary};
font-weight: ${typography.weight.heavy};
text-align: left;
${(props) =>
props.variant === "copy" &&
css`
background-color: ${color.white};
color: ${color.black};
`}
${(props) =>
props.variant === "download" &&
css`
background-color: ${rgba(color.white, opacity.medium)};
color: ${color.white};
`}
`;

72
src/stories/Select.tsx Normal file
View File

@ -0,0 +1,72 @@
import React, { FC } from "react";
import styled, { css } from "styled-components";
import CSS from "csstype";
import { typography, borderRadius, fontSize, padding } from "../shared/styles";
export interface SelectProps {
style?: CSS.Properties;
name: string;
value: string;
onChange: (e: React.ChangeEvent<HTMLSelectElement>) => void;
}
const Select: FC<SelectProps> = ({ style, name, value, onChange }) => {
return (
<StyledSelect style={style} name={name} value={value} onChange={onChange}>
<option value="github">Github</option>
<option value="facebook">Facebook</option>
<option value="Google">Google</option>
</StyledSelect>
);
};
export default Select;
const StyledSelect = styled.select<SelectProps>`
font-size: ${fontSize.medium};
font-family: ${typography.primary};
font-weight: ${typography.weight.regular};
padding: ${padding.medium};
width: 100%;
border: none;
box-shadow: 0 1px 0 1px rgba(0, 0, 0, 0.04);
border-radius: ${borderRadius.medium};
appearance: none;
background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke%3D%22black%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22M19%209l-7%207-7-7%22%20%2F%3E%0A%3C%2Fsvg%3E");
background-repeat: no-repeat, repeat;
/* arrow icon position (1em from the right, 50% vertical) , then gradient position*/
/* background-position: right 1.2rem top 50%, 0 0 */
background-position: right 1.4rem top 50%;
/* icon size, then gradient */
/* background-size: 3rem auto, 100%; */
background-size: 2rem auto;
&:focus-visible {
outline: none;
}
`;
/*
const StyledSelect = styled.select<SelectProps>`
border-radius: ${borderRadius.medium};
border: none;
padding: ${padding.medium};
width: 100%;
margin: 0.7rem auto;
font-size: ${fontSize.medium};
font-family: ${typography.primary};
font-weight: ${typography.weight.regular};
cursor: pointer;
&:focus-visible {
outline: none;
}
`;
*/

View File

@ -1,33 +0,0 @@
import React, { FC, ReactNode } from "react";
import styled, { css } from "styled-components";
import CSS from "csstype";
interface SpaceBetweenContainerProps {
children: ReactNode | null;
style?: CSS.Properties;
width100pct?: boolean;
}
const SpaceBetweenContainer: FC<SpaceBetweenContainerProps> = ({
children,
style,
width100pct = true,
}) => {
return (
<StyledDiv style={style} width100pct={width100pct}>
{children}
</StyledDiv>
);
};
export default SpaceBetweenContainer;
const StyledDiv = styled.div<SpaceBetweenContainerProps>`
display: flex;
justify-content: space-between;
${(props) =>
props.width100pct &&
css`
width: 100%;
`}
`;

View File

@ -1,18 +0,0 @@
import React, { FC } from "react";
import styled from "styled-components";
import CSS from "csstype";
interface SpacerProps {
style?: CSS.Properties;
space?: string;
}
const Spacer: FC<SpacerProps> = ({ style, space = "20px" }) => {
return <StyledDiv style={style} space={space} />;
};
export default Spacer;
const StyledDiv = styled.div<SpacerProps>`
height: ${(props) => props.space};
`;

View File

@ -1,36 +0,0 @@
import React, { FC, ReactNode } from "react";
import styled, { css } from "styled-components";
import CSS from "csstype";
interface TextAlignWrapperProps {
children: ReactNode | null;
style?: CSS.Properties;
align: "left" | "center" | "right";
marginBottom?: boolean;
}
const TextAlignWrapper: FC<TextAlignWrapperProps> = ({
children,
style,
align = "left",
marginBottom = true,
}) => {
return (
<StyledDiv style={style} align={align} marginBottom={marginBottom}>
{children}
</StyledDiv>
);
};
export default TextAlignWrapper;
const StyledDiv = styled.div<TextAlignWrapperProps>`
text-align: ${(props) => props.align};
width: 100%;
${(props) =>
props.marginBottom &&
css`
margin-bottom: 0.7rem;
`}
`;

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2" />
</svg>

After

Width:  |  Height:  |  Size: 341 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="black">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>

After

Width:  |  Height:  |  Size: 188 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" " fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>

After

Width:  |  Height:  |  Size: 245 B