Move inputs and profile components
This commit is contained in:
65
src/input/Input.jsx
Normal file
65
src/input/Input.jsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import React, { forwardRef } from "react";
|
||||
import classNames from "classnames";
|
||||
import styles from "./Input.module.css";
|
||||
import { ReactComponent as CheckIcon } from "../icons/Check.svg";
|
||||
|
||||
export function FieldRow({ children, rightAlign, className, ...rest }) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
styles.fieldRow,
|
||||
{ [styles.rightAlign]: rightAlign },
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function Field({ children, className, ...rest }) {
|
||||
return <div className={classNames(styles.field, className)}>{children}</div>;
|
||||
}
|
||||
|
||||
export const InputField = forwardRef(
|
||||
(
|
||||
{ id, label, className, type, checked, prefix, suffix, disabled, ...rest },
|
||||
ref
|
||||
) => {
|
||||
return (
|
||||
<Field
|
||||
className={classNames(
|
||||
type === "checkbox" ? styles.checkboxField : styles.inputField,
|
||||
{
|
||||
[styles.prefix]: !!prefix,
|
||||
[styles.disabled]: disabled,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{prefix && <span>{prefix}</span>}
|
||||
<input
|
||||
id={id}
|
||||
{...rest}
|
||||
ref={ref}
|
||||
type={type}
|
||||
checked={checked}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<label htmlFor={id}>
|
||||
{type === "checkbox" && (
|
||||
<div className={styles.checkbox}>
|
||||
<CheckIcon />
|
||||
</div>
|
||||
)}
|
||||
{label}
|
||||
</label>
|
||||
{suffix && <span>{suffix}</span>}
|
||||
</Field>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export function ErrorMessage({ children }) {
|
||||
return <p className={styles.errorMessage}>{children}</p>;
|
||||
}
|
||||
169
src/input/Input.module.css
Normal file
169
src/input/Input.module.css
Normal file
@@ -0,0 +1,169 @@
|
||||
.fieldRow {
|
||||
display: flex;
|
||||
margin-bottom: 32px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.field {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.fieldRow.rightAlign {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.fieldRow > * {
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
.fieldRow > :last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.inputField {
|
||||
border-radius: 4px;
|
||||
transition: border-color 0.25s;
|
||||
border: 1px solid var(--inputBorderColor);
|
||||
}
|
||||
|
||||
.inputField input {
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 12px 9px 10px 9px;
|
||||
color: var(--textColor1);
|
||||
background-color: var(--bgColor1);
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.inputField.disabled input,
|
||||
.inputField.disabled span {
|
||||
color: var(--textColor2);
|
||||
}
|
||||
|
||||
.inputField span {
|
||||
padding: 11px 9px;
|
||||
}
|
||||
|
||||
.inputField span:first-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.inputField input::placeholder {
|
||||
transition: color 0.25s ease-in 0s;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.inputField input:placeholder-shown:focus::placeholder {
|
||||
transition: color 0.25s ease-in 0.1s;
|
||||
color: var(--textColor2);
|
||||
}
|
||||
|
||||
.inputField label {
|
||||
transition: font-size 0.25s ease-out 0.1s, color 0.25s ease-out 0.1s,
|
||||
top 0.25s ease-out 0.1s, background-color 0.25s ease-out 0.1s;
|
||||
color: var(--textColor3);
|
||||
background-color: transparent;
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
margin: 9px 8px;
|
||||
padding: 2px;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.inputField:focus-within {
|
||||
border-color: var(--inputBorderColorFocused);
|
||||
}
|
||||
|
||||
.inputField input:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.inputField input:focus + label,
|
||||
.inputField input:not(:placeholder-shown) + label,
|
||||
.inputField.prefix input + label {
|
||||
background-color: var(--bgColor2);
|
||||
transition: font-size 0.25s ease-out 0s, color 0.25s ease-out 0s,
|
||||
top 0.25s ease-out 0s, background-color 0.25s ease-out 0s;
|
||||
font-size: 10px;
|
||||
top: -13px;
|
||||
padding: 0 2px;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.inputField input:focus + label {
|
||||
color: var(--inputBorderColorFocused);
|
||||
}
|
||||
|
||||
.checkboxField {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.checkboxField label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.checkboxField input {
|
||||
outline: 0;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border: 1.5px solid rgba(185, 190, 198, 0.5);
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.checkbox svg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.checkbox svg * {
|
||||
stroke: #fff;
|
||||
}
|
||||
|
||||
.checkboxField input[type="checkbox"]:checked + label > .checkbox {
|
||||
background: var(--primaryColor);
|
||||
border-color: var(--primaryColor);
|
||||
}
|
||||
|
||||
.checkboxField input[type="checkbox"]:checked + label > .checkbox svg {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.checkboxField:focus-within .checkbox {
|
||||
border: 1.5px solid var(--inputBorderColorFocused) !important;
|
||||
}
|
||||
|
||||
.errorMessage {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
color: #ff5b55;
|
||||
font-weight: 600;
|
||||
}
|
||||
57
src/input/SelectInput.jsx
Normal file
57
src/input/SelectInput.jsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import React, { useRef } from "react";
|
||||
import { HiddenSelect, useSelect } from "@react-aria/select";
|
||||
import { useButton } from "@react-aria/button";
|
||||
import { useSelectState } from "@react-stately/select";
|
||||
import { Popover } from "../popover/Popover";
|
||||
import { ListBox } from "../ListBox";
|
||||
import styles from "./SelectInput.module.css";
|
||||
import classNames from "classnames";
|
||||
import { ReactComponent as ArrowDownIcon } from "../icons/ArrowDown.svg";
|
||||
|
||||
export function SelectInput(props) {
|
||||
const state = useSelectState(props);
|
||||
|
||||
const ref = useRef();
|
||||
const { labelProps, triggerProps, valueProps, menuProps } = useSelect(
|
||||
props,
|
||||
state,
|
||||
ref
|
||||
);
|
||||
|
||||
const { buttonProps } = useButton(triggerProps, ref);
|
||||
|
||||
return (
|
||||
<div className={classNames(styles.selectInput, props.className)}>
|
||||
<h4 {...labelProps} className={styles.label}>
|
||||
{props.label}
|
||||
</h4>
|
||||
<HiddenSelect
|
||||
state={state}
|
||||
triggerRef={ref}
|
||||
label={props.label}
|
||||
name={props.name}
|
||||
/>
|
||||
<button {...buttonProps} ref={ref} className={styles.selectTrigger}>
|
||||
<span {...valueProps} className={styles.selectedItem}>
|
||||
{state.selectedItem
|
||||
? state.selectedItem.rendered
|
||||
: "Select an option"}
|
||||
</span>
|
||||
<ArrowDownIcon />
|
||||
</button>
|
||||
{state.isOpen && (
|
||||
<Popover
|
||||
isOpen={state.isOpen}
|
||||
onClose={state.close}
|
||||
className={styles.popover}
|
||||
>
|
||||
<ListBox
|
||||
{...menuProps}
|
||||
state={state}
|
||||
optionClassName={styles.option}
|
||||
/>
|
||||
</Popover>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
42
src/input/SelectInput.module.css
Normal file
42
src/input/SelectInput.module.css
Normal file
@@ -0,0 +1,42 @@
|
||||
.selectInput {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-bottom: 28px;
|
||||
max-width: 444px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.selectTrigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 12px;
|
||||
background-color: var(--bgColor1);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--inputBorderColor);
|
||||
font-size: 15px;
|
||||
color: var(--textColor1);
|
||||
height: 40px;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.selectedItem {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.popover {
|
||||
position: absolute;
|
||||
margin-top: 5px;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
Reference in New Issue
Block a user