diff options
Diffstat (limited to 'src/components/FormElements/Field')
| -rw-r--r-- | src/components/FormElements/Field/Field.module.scss | 48 | ||||
| -rw-r--r-- | src/components/FormElements/Field/Field.tsx | 106 |
2 files changed, 154 insertions, 0 deletions
diff --git a/src/components/FormElements/Field/Field.module.scss b/src/components/FormElements/Field/Field.module.scss new file mode 100644 index 0000000..3836856 --- /dev/null +++ b/src/components/FormElements/Field/Field.module.scss @@ -0,0 +1,48 @@ +@use "@styles/abstracts/functions" as fun; + +.field { + background: var(--color-bg-tertiary); + border: fun.convert-px(2) solid var(--color-border); + box-shadow: fun.convert-px(3) fun.convert-px(3) 0 0 var(--color-shadow); + transition: all 0.25s linear 0s; + + &:not(.select) { + width: 100%; + padding: var(--spacing-2xs) var(--spacing-xs); + } + + &:hover { + box-shadow: fun.convert-px(5) fun.convert-px(5) 0 fun.convert-px(1) + var(--color-shadow); + transform: translate(#{fun.convert-px(-3)}, #{fun.convert-px(-3)}); + } + + &:focus { + background: var(--color-bg); + border-color: var(--color-primary); + box-shadow: 0 0 0 0 var(--color-shadow); + transform: translate(#{fun.convert-px(3)}, #{fun.convert-px(3)}); + outline: none; + transition: all 0.2s ease-in-out 0s, transform 0.3s ease-out 0s; + } +} + +.select { + padding: fun.convert-px(3) var(--spacing-xs); + cursor: pointer; + + &:hover { + box-shadow: fun.convert-px(4) fun.convert-px(4) 0 fun.convert-px(1) + var(--color-shadow); + transform: translate(#{fun.convert-px(-2)}, #{fun.convert-px(-2)}); + } + + &:focus { + box-shadow: 0 0 0 0 var(--color-shadow); + transform: translate(#{fun.convert-px(3)}, #{fun.convert-px(3)}); + } +} + +.textarea { + min-height: fun.convert-px(200); +} diff --git a/src/components/FormElements/Field/Field.tsx b/src/components/FormElements/Field/Field.tsx new file mode 100644 index 0000000..c8df0f9 --- /dev/null +++ b/src/components/FormElements/Field/Field.tsx @@ -0,0 +1,106 @@ +import { + ChangeEvent, + ForwardedRef, + forwardRef, + ReactElement, + SetStateAction, +} from 'react'; +import styles from './Field.module.scss'; + +type FieldType = 'email' | 'number' | 'search' | 'select' | 'text' | 'textarea'; +type SelectOptions = { + id: string; + name: string; + value: string; +}; + +const Field = ( + { + id, + name, + value, + setValue, + required = false, + kind = 'text', + label, + options, + }: { + id: string; + name: string; + value: string; + setValue: (value: SetStateAction<string>) => void; + required?: boolean; + kind?: FieldType; + label?: ReactElement; + options?: SelectOptions[]; + }, + ref: ForwardedRef<HTMLInputElement | HTMLTextAreaElement> +) => { + const updateValue = ( + e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement> + ) => { + setValue(e.target.value); + }; + + const getOptions = () => { + return options + ? options.map((option) => ( + <option key={option.id} value={option.value}> + {option.name} + </option> + )) + : ''; + }; + + const getField = () => { + switch (kind) { + case 'select': + return ( + <select + name={name} + id={id} + value={value} + onChange={updateValue} + required={required} + className={`${styles.field} ${styles.select}`} + > + {getOptions()} + </select> + ); + case 'textarea': + return ( + <textarea + ref={ref as ForwardedRef<HTMLTextAreaElement>} + id={id} + name={name} + value={value} + required={required} + onChange={updateValue} + className={`${styles.field} ${styles.textarea}`} + /> + ); + default: + return ( + <input + ref={ref as ForwardedRef<HTMLInputElement>} + type={kind} + id={id} + name={name} + value={value} + required={required} + onChange={updateValue} + className={styles.field} + /> + ); + } + }; + + return ( + <> + {label} + {getField()} + </> + ); +}; + +export default forwardRef(Field); |
