Output/GPT4_Turbo/JS/extracted_code/generation/GenerateBaseComponent/index.tsx (85 lines of code) (raw):
import React, { useState, useRef, useEffect, KeyboardEvent, ChangeEvent } from 'react';
import './index.css';
interface Option {
value: string;
label: string;
}
interface SearchableSelectProps {
options: Option[];
placeholder?: string;
onChange: (value: string) => void;
}
const SearchableSelect: React.FC<SearchableSelectProps> = ({ options, placeholder, onChange }) => {
const [isOpen, setIsOpen] = useState(false);
const [searchTerm, setSearchTerm] = useState('');
const [highlightedIndex, setHighlightedIndex] = useState(0);
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
setIsOpen(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
const filteredOptions = options.filter(option =>
option.label.toLowerCase().includes(searchTerm.toLowerCase())
);
const handleSelect = (value: string) => {
onChange(value);
setIsOpen(false);
setSearchTerm('');
};
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
switch (event.key) {
case 'Enter':
isOpen ? handleSelect(filteredOptions[highlightedIndex].value) : setIsOpen(true);
break;
case 'ArrowDown':
setHighlightedIndex((prevIndex) =>
prevIndex < filteredOptions.length - 1 ? prevIndex + 1 : prevIndex
);
break;
case 'ArrowUp':
setHighlightedIndex((prevIndex) => (prevIndex > 0 ? prevIndex - 1 : prevIndex));
break;
case 'Escape':
setIsOpen(false);
break;
default:
break;
}
};
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setSearchTerm(event.target.value);
setHighlightedIndex(0);
};
return (
<div className="select-container" ref={containerRef} onKeyDown={handleKeyDown} tabIndex={0}>
<input
className="select-input"
placeholder={placeholder}
value={searchTerm}
onChange={handleChange}
onClick={() => setIsOpen(!isOpen)}
readOnly={!isOpen}
/>
{isOpen && (
<ul className="select-dropdown">
{filteredOptions.map((option, index) => (
<li
key={option.value}
className={`select-option ${index === highlightedIndex ? 'highlighted' : ''}`}
onClick={() => handleSelect(option.value)}
onMouseEnter={() => setHighlightedIndex(index)}
>
{option.label}
</li>
))}
</ul>
)}
</div>
);
};
export default SearchableSelect;