add dropdown inputs

This commit is contained in:
NCanggoro 2023-10-03 14:38:49 +07:00
parent 9fb697f4ef
commit 13391b18eb
3 changed files with 234 additions and 0 deletions

View File

@ -0,0 +1,128 @@
import { ChangeEvent, useEffect, useRef, useState } from "react";
import "./style.css";
const Icon = () => {
return (
<svg height="20" width="20" viewBox="0 0 20 20" fill={"white"}>
<path d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"></path>
</svg>
);
};
interface dropdownProps {
placeholder: string,
options: Array<any>,
labelPropsName: string,
isSearchable: boolean,
onChange: Function
}
const DropdownInput = ({
placeholder,
options,
isSearchable,
labelPropsName,
onChange
}: dropdownProps) => {
const [showMenu, setShowMenu] = useState<boolean>(false);
const [selectedValue, setSelectedValue] = useState<any>();
const [searchValue, setSearchValue] = useState("");
const searchRef = useRef<any>();
const inputRef = useRef<any>();
useEffect(() => {
setSearchValue("");
if (showMenu && searchRef.current) {
searchRef.current.focus();
}
}, [showMenu]);
useEffect(() => {
const handler = (e: any) => {
if (inputRef.current && !inputRef.current.contains(e.target)) {
setShowMenu(false);
}
};
window.addEventListener("click", handler);
return () => {
window.removeEventListener("click", handler);
};
});
const handleInputClick = () => {
setShowMenu(!showMenu);
};
const getDisplay = () => {
if (!selectedValue) {
return placeholder;
}
return selectedValue[labelPropsName]
};
const onItemClick = (option: any) => {
setSelectedValue(option)
onChange(option);
};
const isSelected = (option: any) => {
if (!selectedValue) {
return false;
}
return selectedValue[labelPropsName] === option[labelPropsName];
};
const onSearch = (e: ChangeEvent) => {
const event = e.target as HTMLInputElement
setSearchValue(event.value);
};
const getIDropdownInputPropss = () => {
if (!searchValue) {
return options;
}
return options.filter(
(option: any) =>
option[labelPropsName].toLowerCase().indexOf(searchValue.toLowerCase()) >= 0
);
};
return (
<div className="dropdown-container">
<div ref={inputRef} onClick={handleInputClick} className="dropdown-input">
<div className="dropdown-selected-value text-sm">{getDisplay()}</div>
<div className="dropdown-tools">
<div className="dropdown-tool">
<Icon />
</div>
</div>
</div>
{showMenu && (
<div className="dropdown-item-menu">
{isSearchable && (
<div className="search-box bg-secondary">
<input className={'bg-primary text-sm'} onChange={onSearch} value={searchValue} ref={searchRef} />
</div>
)}
<div class={'dropdown-item-container'}>
{getIDropdownInputPropss().map((option: any) => (
<div
onClick={() => onItemClick(option)}
key={option[labelPropsName]}
className={`dropdown-item text-sm ${isSelected(option) && "selected"}`}
>
{option[labelPropsName]}
</div>
))}
</div>
</div>
)}
</div>
);
};
export default DropdownInput;

View File

@ -0,0 +1,104 @@
.dropdown-container {
text-align: left;
border: 1px solid #474747;
position: relative;
border-radius: 5px;
min-width: 325px;
max-width: 450px;
width: 100%;
}
.dropdown-input {
padding: 5px;
display: flex;
align-items: center;
justify-content: space-between;
user-select: none;
}
.dropdown-input-menu {
display: block;
position: absolute;
transform: translateY(4px);
width: 100%;
border: 1px solid #ccc;
border-radius: 5px;
overflow: auto;
max-height: 150px;
background-color: #fff;
}
.dropdown-item-container {
max-height: 200px;
overflow-y: scroll;
}
/* width */
.dropdown-item-container::-webkit-scrollbar {
width: 8px;
}
/* Track */
.dropdown-item-container::-webkit-scrollbar-track {
background: #212121;
}
/* Handle */
.dropdown-item-container::-webkit-scrollbar-thumb {
background: #888;
}
/* Handle on hover */
.dropdown-item-container::-webkit-scrollbar-thumb:hover {
background: #555;
}
.dropdown-item {
padding: 5px 10px;
cursor: pointer;
}
.dropdown-item:hover {
background-color: #9fc3f870;
}
.dropdown-item.selected {
background-color: #a8adb3;
color: #fff;
}
.dropdown-selected-value {
padding: 5px 10px;
}
.dropdown-tags {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.dropdown-tag-item {
background-color: #ddd;
padding: 2px 4px;
border-radius: 2px;
display: flex;
align-items: center;
}
.dropdown-tag-close {
display: flex;
align-items: center;
}
.search-box {
padding: 5px;
background-color: #eee;
}
.search-box input {
width: 100%;
box-sizing: border-box;
padding: 5px 10px;
border-radius: 5px;
}

View File

@ -3,6 +3,7 @@ import SeparatorWithAnchor from "./Separator/WithAnchor";
import DefaultSeparator from "./Separator/Default"; import DefaultSeparator from "./Separator/Default";
import Footer from './Footer/'; import Footer from './Footer/';
import CustomInterweave from "./CustomInterweave"; import CustomInterweave from "./CustomInterweave";
import DropdownInput from "./DropdownInput";
import SpinnerLoading from "./Loading/Spinner"; import SpinnerLoading from "./Loading/Spinner";
@ -12,6 +13,7 @@ export {
DefaultSeparator, DefaultSeparator,
Footer, Footer,
CustomInterweave, CustomInterweave,
DropdownInput,
SpinnerLoading, SpinnerLoading,
} }