Flower Delivery Website 구현: (8)UI 컴포넌트 구현 /InputStepper

김 주현·2023년 8월 16일
0

InputStepper

import React, { useState } from "react";

import { ReactComponent as MinusIcon } from "@Static/Icons/minus.svg";
import { ReactComponent as PlusIcon } from "@Static/Icons/plus.svg";

const MemoiedMinusIcon = React.memo(MinusIcon, (p, n) => p.width === n.width);
const MemoiedPlusIcon = React.memo(PlusIcon, (p, n) => p.width === n.width);

type InputStepperProp = {
  onChange?: (value: number) => void;
  defaultValue?: number;
  min?: number;
  max?: number;
};

const InputStepper = ({
  onChange,
  defaultValue = 5,
  min = 1,
  max = 10,
}: InputStepperProp) => {
  const [step, setStep] = useState(defaultValue);

  const handleMinusClick = () => {
    if (step === min) return;

    setStep(step - 1);

    if (onChange) onChange(step - 1);
  };

  const handlePlusClick = () => {
    if (step === max) return;

    setStep(step + 1);

    if (onChange) onChange(step + 1);
  };

  return (
    <div className="flex w-[45.93vw] flex-row items-center justify-between border tablet:w-[19.14vw] desktop:w-[10.20vw]">
      <button
        disabled={min && step <= min ? true : false}
        className="group h-m48 w-m48 border-r leading-none tablet:h-t48 tablet:w-t48 desktop:h-d48 desktop:w-d48"
        onClick={() => handleMinusClick()}
      >
        <MemoiedMinusIcon className="w-full group-disabled:fill-gray" />
      </button>
      <div>
        <p className="body">{step}</p>
      </div>
      <button
        disabled={max && step >= max ? true : false}
        className="group h-m48 w-m48 border-l tablet:h-t48 tablet:w-t48 desktop:h-d48 desktop:w-d48"
        onClick={() => handlePlusClick()}
      >
        <MemoiedPlusIcon className="w-full group-disabled:fill-gray" />
      </button>
    </div>
  );
};

export default InputStepper;

Usage

  return (
    <>
      <div className="mx-auto mt-6 flex h-screen w-[90%] flex-col place-items-center">
        <p>현재 선택된 value: {value}</p>
        <InputStepper
          defaultValue={value}
          onChange={(value) => setValue(value)}
        />
      </div>
    </>
  );

구현

Step Count만 하면 되는 간단한 UI Component라 딱히 설명할 게 없긴 하다.

min, max

사실 Figma에서는 min, max에 대한 유스케이스를 다루진 않았다. 그러나 이 UI Component를 사용한다면 분명이 필요한 속성이라고 생각해서 임의로 추가했다.

disabled

엣지 케이스에 대해 생각해보자. value가 min일 때 minus를 한다면 다음과 같은 선택을 할 수 있겠다.

  1. 그대로 -1하기
  2. max로 넘어가기
  3. 아무 동작 안 하기.

보통은 3번이겠다. 그러면 이 3번을 구현하려면 어떤 식으로 하는 게 좋을까?

  1. value가 min일 때 클릭하면 아무 동작 안 하기
  2. value가 min이 되면 클릭 버튼 비활성화 하기

UX적으론 2번이 맞겠다. 1번처럼 동작하게 되면, 사용자 입장에서는 개수를 줄일 수 있을 것처럼 만들어놨기 때문에 기능을 제대로 안 한다고 느낄 수도 있다. 2번처럼 버튼을 비활성화 하면 누를 수 없는 상태라고 인지하기 때문에 근본적인 오류를 처리할 수 있다.

비활성화 상태를 표시하는 것은 따로 flag state를 만들어서 관리를 하는 것이 아니라, button의 disabled 속성을 이용하는 것이 좋다. 이것이 시멘틱 웹으로도 알맞은 방향이라고 생각!

tailwind로 disabled 관리

  1. disabled 속성을 지정할 element에 group를 선언해준다.
<button disabled={disabled} className="group">
  1. disabled 속성에 따라 변할 element에 group-disabled를 지정해준다.
<button disabled={disabled} className="group">
  <Icon className="group-disabled:fill-gray" />
</button>
profile
FE개발자 가보자고🥳

0개의 댓글