import { Fragment, useCallback, useState } from "react"; import { Ico, Icon } from "components/Ico"; import { cIf, cJoin } from "helpers/className"; import { useToggle } from "hooks/useToggle"; /* * ╭─────────────╮ * ───────────────────────────────────────╯ COMPONENT ╰─────────────────────────────────────────── */ interface Props { value: number; options: string[]; selected?: number; allowEmpty?: boolean; className?: string; onChange: (value: number) => void; } // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ export const Select = ({ className, value, options, allowEmpty, onChange, }: Props): JSX.Element => { const [opened, setOpened] = useState(false); const toggleOpened = useToggle(setOpened); const tryToggling = useCallback(() => { const optionCount = options.length + (value === -1 ? 1 : 0); if (optionCount > 1) toggleOpened(); }, [options.length, value, toggleOpened]); return ( <div className={cJoin( "relative text-center transition-[filter]", cIf(opened, "z-10 drop-shadow-shade-lg"), className )} > <div className={cJoin( `grid cursor-pointer grid-flow-col grid-cols-[1fr_auto_auto] place-items-center rounded-[1em] bg-light p-1 outline outline-2 outline-offset-[-2px] outline-mid transition-all hover:bg-mid hover:outline-[transparent]`, cIf(opened, "rounded-b-none bg-highlight outline-[transparent]") )} > <p onClick={tryToggling} className="w-full"> {value === -1 ? "—" : options[value]} </p> {value >= 0 && allowEmpty && ( <Ico icon={Icon.Close} className="!text-xs" onClick={() => { onChange(-1); setOpened(false); }} /> )} <Ico onClick={tryToggling} icon={opened ? Icon.ArrowDropUp : Icon.ArrowDropDown} /> </div> <div className={cJoin( "left-0 right-0 rounded-b-[1em]", cIf(opened, "absolute", "hidden") )} > {options.map((option, index) => ( <Fragment key={index}> {index !== value && ( <div className={cJoin( "cursor-pointer p-1 transition-colors last-of-type:rounded-b-[1em] hover:bg-mid", cIf(opened, "bg-highlight", "bg-light") )} id={option} onClick={() => { setOpened(false); onChange(index); }} > {option} </div> )} </Fragment> ))} </div> </div> ); };