add dropdown inputs
This commit is contained in:
parent
9fb697f4ef
commit
13391b18eb
128
src/components/DropdownInput/index.tsx
Normal file
128
src/components/DropdownInput/index.tsx
Normal 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;
|
104
src/components/DropdownInput/style.css
Normal file
104
src/components/DropdownInput/style.css
Normal 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;
|
||||||
|
}
|
@ -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,
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user