refactor: optimized contextmenu, style update, ui bug fixes

This commit is contained in:
2025-08-22 17:43:16 +05:30
parent f3d23755dd
commit ddf521dc6a
11 changed files with 3471 additions and 3048 deletions

View File

@@ -1,4 +1,5 @@
import React, { useState, useEffect, useRef } from "react";
import { createPortal } from "react-dom";
interface DropdownProps {
header: string;
@@ -14,32 +15,35 @@ const RegularDropDown: React.FC<DropdownProps> = ({
options,
onSelect,
search = true,
onClick,
onChange,
}) => {
const [isOpen, setIsOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState<string | null>(null);
const [searchTerm, setSearchTerm] = useState(""); // State to store search term
const [filteredOptions, setFilteredOptions] = useState<string[]>(options); // State for filtered options
const dropdownRef = useRef<HTMLDivElement>(null); // Ref for the dropdown container
const [searchTerm, setSearchTerm] = useState("");
const [filteredOptions, setFilteredOptions] = useState<string[]>(options);
const dropdownRef = useRef<HTMLDivElement>(null);
const [position, setPosition] = useState<{ top: number; left: number; width: number }>({
top: 0,
left: 0,
width: 0,
});
// Reset selectedOption when the dropdown closes
// Reset when closed
useEffect(() => {
if (!isOpen) {
setSelectedOption(null);
setSearchTerm(""); // Clear the search term when the dropdown closes
setFilteredOptions(options); // Reset filtered options when the dropdown closes
setSearchTerm("");
setFilteredOptions(options);
}
}, [isOpen, options]);
// Reset selectedOption when the header prop changes
// Reset when header changes
useEffect(() => {
setSelectedOption(null);
setSearchTerm(""); // Reset search term if header changes
setFilteredOptions(options); // Reset options if header changes
setSearchTerm("");
setFilteredOptions(options);
}, [header, options]);
// Close dropdown if clicked outside
// Close if clicked outside
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
@@ -49,77 +53,88 @@ const RegularDropDown: React.FC<DropdownProps> = ({
setIsOpen(false);
}
};
document.addEventListener("click", handleClickOutside);
return () => {
document.removeEventListener("click", handleClickOutside);
};
return () => document.removeEventListener("click", handleClickOutside);
}, []);
// Toggle the dropdown
const toggleDropdown = () => {
setIsOpen((prev) => !prev);
};
// Recalculate position when opening
useEffect(() => {
if (isOpen && dropdownRef.current) {
const rect = dropdownRef.current.getBoundingClientRect();
setPosition({
top: rect.bottom + window.scrollY,
left: rect.left + window.scrollX,
width: rect.width,
});
}
}, [isOpen]);
const toggleDropdown = () => setIsOpen((prev) => !prev);
// Handle option selection
const handleOptionClick = (option: string) => {
setSelectedOption(option);
onSelect(option);
setIsOpen(false);
};
// Handle search input change
const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const term = event.target.value;
setSearchTerm(term);
// Filter options based on the search term
const filtered = options.filter((option) =>
option.toLowerCase().includes(term.toLowerCase())
setFilteredOptions(
options.filter((option) =>
option.toLowerCase().includes(term.toLowerCase())
)
);
setFilteredOptions(filtered);
};
return (
<div className="regularDropdown-container" ref={dropdownRef}>
{/* Dropdown Header */}
{/* Header */}
<div className="dropdown-header flex-sb" onClick={toggleDropdown}>
<div className="key">{selectedOption || header}</div>
<div className="icon"></div>
</div>
{/* Dropdown Options */}
{isOpen && (
<div className="dropdown-options">
{/* Search Bar */}
{search && (
<div className="dropdown-search">
<input
type="text"
placeholder="Search..."
value={searchTerm}
onChange={handleSearchChange}
/>
</div>
)}
{/* Filtered Options */}
{filteredOptions.length > 0 ? (
filteredOptions.map((option, index) => (
<div
className="option"
key={index}
onClick={() => handleOptionClick(option)}
>
{option}
{/* Options rendered in portal */}
{isOpen &&
createPortal(
<div
className="dropdown-options"
style={{
position: "absolute",
top: position.top,
left: position.left,
width: position.width,
zIndex: 9999,
}}
>
{search && (
<div className="dropdown-search">
<input
type="text"
placeholder="Search..."
value={searchTerm}
onChange={handleSearchChange}
/>
</div>
))
) : (
<div className="no-options">No options found</div>
)}
</div>
)}
)}
{filteredOptions.length > 0 ? (
filteredOptions.map((option, index) => (
<div
className="option"
key={index}
onClick={() => handleOptionClick(option)}
title={option}
>
{option}
</div>
))
) : (
<div className="no-options">No options found</div>
)}
</div>,
document.body
)}
</div>
);
};