summaryrefslogtreecommitdiffstats
path: root/src/components/FormElements/Field
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/FormElements/Field')
-rw-r--r--src/components/FormElements/Field/Field.module.scss48
-rw-r--r--src/components/FormElements/Field/Field.tsx106
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);