diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-02-25 19:17:09 +0100 | 
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-02-25 19:17:09 +0100 | 
| commit | e26d821f738525477472e631d170d9ed218c1603 (patch) | |
| tree | 70ec0c29d003d462de6926f1faa09354e3ff6d90 /src/components/FormElements/Field | |
| parent | cb4764f8670f67627c407591c89b8d3637c190a7 (diff) | |
chore: combine input/textarea/select in a single component
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); | 
