Input Option

Input Option คือ view ที่ใช้ไอคอน Option ในการกดเพื่อแสดงเมนูให้เลือก

Source Code

ReactJs Styled Component
Copy
import { useState } from "react";
import styled from "styled-components";

import useOutsideClick from "../../util/useOutsideClick";
import IconOption from "../element/icon/IconOption";

export default function InputOption({
  onChange,
  dataList, //[{text:'All',value:'all'}] or //['all','none']
  width = 200,
  maxHeight = 200,
  className,
  style,
  optionColor = "var(--txt-normal)",
  textTransform = "capitalize",
  borderRadius = "8px",
}) {
  const outerRef = useOutsideClick(() => setIsFocus(false));
  const [isFocus, setIsFocus] = useState(false);
  const [listPosition, setListPosition] = useState();

  const handleOnChange = (item) => {
    setIsFocus(false);
    if (onChange) {
      onChange(item.value || item || "");
    }
  };

  const handleClickDropdown = (e) => {
    setIsFocus((prev) => !prev);

    const globalMousePos = { y: e.clientY || 0, x: e.clientX || 0 };
    const windowSize = {
      height: e.view.innerHeight || 0,
      width: e.view.innerWidth || 0,
    };

    let tmpPosition;
    //vertical axis
    if (globalMousePos.y + maxHeight < windowSize.height) {
      tmpPosition = {
        ...listPosition,
        top: outerRef.current.clientHeight + dropDownGap,
        bottom: null,
      };
    } else {
      tmpPosition = {
        ...listPosition,
        bottom: outerRef.current.clientHeight + dropDownGap,
        top: null,
      };
    }

    //horizontal axis
    if (globalMousePos?.x + width > windowSize.width) {
      tmpPosition = { ...tmpPosition, left: null, right: 5 };
    } else if (globalMousePos?.x - width <= 0) {
      tmpPosition = { ...tmpPosition, left: 5, right: null };
    } else {
      tmpPosition = {
        ...tmpPosition,
        left: -(width / 2 + -outerRef.current.clientWidth / 2),
        right: null,
      };
    }

    setListPosition(tmpPosition);
  };

  return (
    <Styled
      className={className}
      style={style}
      $width={width}
      $maxHeight={maxHeight}
      $borderRadius={borderRadius}
      $listPosition={listPosition}
      $textTransform={textTransform}
    >
      <div ref={outerRef} className={"dropdown-inner"}>
        <div className="option-wrap">
          <div className="selected-wrp" onClick={handleClickDropdown}>
            <IconOption isVertical color={optionColor} />
          </div>
        </div>
        {isFocus && dataList && (
          <ul className="list">
            {dataList.map((item, index) => (
              <li
                className="item-li"
                key={"item-" + index}
                onClick={() => handleOnChange(item)}
              >
                {item?.text || item || ""}
              </li>
            ))}
          </ul>
        )}
      </div>
    </Styled>
  );
}

const Styled = styled.div`
  position: relative;
  display: inline-flex;
  small {
    margin-bottom: 5px;
    font-weight: bold;
    display: block;
  }
  .place-item {
    color: var(--txt-normal-soft);
  }
  .dropdown-inner {
    position: relative;
    display: inline-flex;
    flex-direction: column;
    user-select: none;
    cursor: pointer;
    .list {
      position: absolute;
      margin: 0;
      background-color: var(--surface);
      min-width: 200px;
      width: ${({ $width }) => $width + "px"};
      max-height: ${({ $maxHeight }) => $maxHeight + "px"};
      z-index: 999;
      list-style: none;
      border-radius: ${({ $borderRadius }) => $borderRadius};
      padding: 0;
      top: ${({ $listPosition }) =>
        $listPosition?.top ? $listPosition.top + "px" : null};
      bottom: ${({ $listPosition }) =>
        $listPosition?.bottom ? $listPosition.bottom + "px" : null};
      left: ${({ $listPosition }) =>
        $listPosition?.left ? $listPosition.left + "px" : null};
      right: ${({ $listPosition }) =>
        $listPosition?.right ? $listPosition.right + "px" : null};
      overflow-y: auto;
      &::-webkit-scrollbar {
        width: 10px;
      }
      &::-webkit-scrollbar-track {
        background: #f1f1f1;
      }
      &::-webkit-scrollbar-thumb {
        background: #888;
        border-radius: 20px;
      }
    }
    .list li {
      padding: 10px 12px;
      text-transform: ${({ $textTransform }) => $textTransform};
      display: flex;
    }

    .selected-wrp {
      position: relative;
      padding: 12px;
    }
  }
`;

Usage

ReactJs Styled Component
Copy
import InputOption from "../../example/InputOption";

export default function TestView() {
  return (
    <div className="test-view">
      <InputOption
        onChange={(e) => console.log(e)}
        dataList={[
          { value: "option 1", text: "Option 1" },
          { value: "option 2", text: "Option 2" },
          { value: "option 3", text: "Option 3" },
          { value: "option 4", text: "Option 4" },
          { value: "option 5", text: "Option 5" },
        ]}
      />
    </div>
  );
}

Properties

Property

Description

Type

Default

onChange

ฟังก์ชันจะทำงานเมื่อมีการเปลี่ยนแปลง

function

dataList

ชุดข้อมูลภายใน view

array

width

ความกว้างของเมนู

number

200

maxHeight

ความสูงมากที่สุดของเมนู

number

200

className

คุณลักษณะเฉพาะของ view

string

style

inline style

CSSProperties

optionColor

สีของไอคอน Option

string

"var(--txt-normal)"

textTransform

ลักษณะของตัวอักษรในเมนู

string

"capitalize"

borderRadius

ความโค้งมนของเมนู

string

"8px"

Requirements

styled-component react useOutsideClick IconOption

ยักซ่า (Yakxar)
สร้างสรรค์และแบ่งปันสื่อดิจิทัลง่ายๆ ที่นี่
© 2025 ยักซ่า (Yakxar)