aboutsummaryrefslogtreecommitdiff
path: root/client/src/components/CustomSelect/CustomSelect.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/components/CustomSelect/CustomSelect.jsx')
-rw-r--r--client/src/components/CustomSelect/CustomSelect.jsx111
1 files changed, 98 insertions, 13 deletions
diff --git a/client/src/components/CustomSelect/CustomSelect.jsx b/client/src/components/CustomSelect/CustomSelect.jsx
index 3155700..4a906bd 100644
--- a/client/src/components/CustomSelect/CustomSelect.jsx
+++ b/client/src/components/CustomSelect/CustomSelect.jsx
@@ -1,35 +1,110 @@
import React, { useEffect, useState, useRef } from "react";
+import { SUPPORTED_LANGUAGES } from "../../utils/constants";
+
import styles from "./CustomSelect.module.css";
-const CustomSelect = ({ options, onSelect }) => {
+const CustomSelect = ({ onSelect, textAreaRef, isModalOpen }) => {
const [isOpen, setIsOpen] = useState(false);
+ const [options, setOptions] = useState(SUPPORTED_LANGUAGES);
const [selectedOption, setSelectedOption] = useState(
options.length > 0 ? options[0] : null,
);
+ const [focusedOptionIndex, setFocusedOptionIndex] = useState(0);
const selectRef = useRef(null);
+ const searchRef = useRef(null);
+ const optionsRef = useRef([]);
const toggleDropdown = () => {
setIsOpen(!isOpen);
};
- const handleOptionClick = (option) => {
+ const handleOptionClick = (option, index) => {
setSelectedOption(option);
onSelect(option.value);
+ setFocusedOptionIndex(index);
setIsOpen(false);
+ setOptions(SUPPORTED_LANGUAGES);
+ if (textAreaRef.current) {
+ textAreaRef.current.focus();
+ }
};
const handleClickOutside = (event) => {
if (selectRef.current && !selectRef.current.contains(event.target)) {
setIsOpen(false);
+ setOptions(SUPPORTED_LANGUAGES);
+
+ if (textAreaRef.current) {
+ textAreaRef.current.focus();
+ }
+ }
+ };
+
+ const handleChange = (e) => {
+ const searchVal = e.target.value;
+ const filteredOptions =
+ searchVal.length > 0
+ ? SUPPORTED_LANGUAGES.filter((option) =>
+ option.label.toLowerCase().includes(searchVal.toLowerCase()),
+ )
+ : SUPPORTED_LANGUAGES;
+
+ setOptions(filteredOptions);
+ setFocusedOptionIndex(0);
+ };
+
+ const handleKeyDown = (event) => {
+ if (isOpen) {
+ switch (event.key) {
+ case "ArrowDown":
+ setFocusedOptionIndex((prevIndex) => {
+ const newIndex =
+ prevIndex < options.length - 1 ? prevIndex + 1 : prevIndex;
+ optionsRef.current[newIndex].scrollIntoView({ block: "nearest" });
+ return newIndex;
+ });
+ break;
+ case "ArrowUp":
+ setFocusedOptionIndex((prevIndex) => {
+ const newIndex = prevIndex > 0 ? prevIndex - 1 : prevIndex;
+ optionsRef.current[newIndex].scrollIntoView({ block: "nearest" });
+ return newIndex;
+ });
+ break;
+ case "Enter":
+ event.preventDefault();
+ handleOptionClick(options[focusedOptionIndex], focusedOptionIndex);
+ break;
+ case "Escape":
+ setIsOpen(false);
+ setOptions(SUPPORTED_LANGUAGES);
+ if (textAreaRef.current) {
+ textAreaRef.current.focus();
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (!isModalOpen && event.ctrlKey && event.key === "l") {
+ event.preventDefault();
+ setIsOpen(true);
}
};
useEffect(() => {
document.addEventListener("mousedown", handleClickOutside);
+ document.addEventListener("keydown", handleKeyDown);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
+ document.removeEventListener("keydown", handleKeyDown);
};
- }, []);
+ }, [isOpen, options, focusedOptionIndex]);
+
+ useEffect(() => {
+ if (isOpen && searchRef.current) {
+ searchRef.current.focus();
+ }
+ }, [isOpen]);
return (
<div className={styles.select} ref={selectRef}>
@@ -45,16 +120,26 @@ const CustomSelect = ({ options, onSelect }) => {
)}
</div>
{isOpen && (
- <div className={styles.options}>
- {options.map((option) => (
- <div
- key={option.value}
- className={styles.option}
- onClick={() => handleOptionClick(option)}
- >
- {option.label}
- </div>
- ))}
+ <div className={styles.options__container}>
+ <input
+ onChange={handleChange}
+ className={styles.options__search}
+ ref={searchRef}
+ placeholder="Search..."
+ />
+ <div className={styles.options}>
+ {options.map((option, index) => (
+ <div
+ key={option.value}
+ className={`${styles.option} ${index === focusedOptionIndex ? styles.focused : ""}`}
+ onClick={() => handleOptionClick(option, index)}
+ tabIndex={0}
+ ref={(el) => (optionsRef.current[index] = el)}
+ >
+ {option.label}
+ </div>
+ ))}
+ </div>
</div>
)}
</div>