feat: Improve PageAssistSelect component
This commit enhances the `PageAssistSelect` component with the following improvements: - Adds a `ref` to the options container to automatically scroll to the selected option when the dropdown is opened. - Fixes an issue where the `selectedOption` was not being correctly determined when the `options` array was updated. - Improves the rendering of the selected option, ensuring that the loading state, placeholder, and selected option are displayed correctly. - Adds a `data-value` attribute to the option elements to facilitate scrolling to the selected option. These changes improve the overall user experience and functionality of the `PageAssistSelect` component.
This commit is contained in:
parent
c4d9e3aeed
commit
726d3e3427
@ -43,6 +43,7 @@ export const PageAssistSelect: React.FC<SelectProps> = ({
|
|||||||
const [searchTerm, setSearchTerm] = useState("")
|
const [searchTerm, setSearchTerm] = useState("")
|
||||||
const [filteredOptions, setFilteredOptions] = useState<SelectOption[]>([])
|
const [filteredOptions, setFilteredOptions] = useState<SelectOption[]>([])
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
|
const optionsContainerRef = useRef<HTMLDivElement>(null)
|
||||||
const [activeIndex, setActiveIndex] = useState(-1)
|
const [activeIndex, setActiveIndex] = useState(-1)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -59,6 +60,21 @@ export const PageAssistSelect: React.FC<SelectProps> = ({
|
|||||||
return () => document.removeEventListener("mousedown", handleClickOutside)
|
return () => document.removeEventListener("mousedown", handleClickOutside)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
try {
|
||||||
|
if (isOpen && optionsContainerRef.current && value) {
|
||||||
|
const selectedOptionElement = optionsContainerRef.current.querySelector(
|
||||||
|
`[data-value="${value}"]`
|
||||||
|
)
|
||||||
|
if (selectedOptionElement) {
|
||||||
|
selectedOptionElement.scrollIntoView({ block: "nearest" })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error scrolling to selected option:", error)
|
||||||
|
}
|
||||||
|
}, [isOpen, value])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!options) return
|
if (!options) return
|
||||||
|
|
||||||
@ -193,7 +209,7 @@ export const PageAssistSelect: React.FC<SelectProps> = ({
|
|||||||
|
|
||||||
const selectedOption = useMemo(() => {
|
const selectedOption = useMemo(() => {
|
||||||
if (!value || !options) return null
|
if (!value || !options) return null
|
||||||
return options?.find(opt => opt.value === value)
|
return options?.find((opt) => opt.value === value)
|
||||||
}, [value, options])
|
}, [value, options])
|
||||||
|
|
||||||
if (!options) {
|
if (!options) {
|
||||||
@ -221,7 +237,13 @@ export const PageAssistSelect: React.FC<SelectProps> = ({
|
|||||||
className={`${defaultSelectClass} ${className}`}>
|
className={`${defaultSelectClass} ${className}`}>
|
||||||
<span className="!truncate flex items-center gap-2 ">
|
<span className="!truncate flex items-center gap-2 ">
|
||||||
{isLoading && <LoadingIndicator />}
|
{isLoading && <LoadingIndicator />}
|
||||||
{isLoading ? loadingText : selectedOption ? selectedOption.label : <span className="dark:text-gray-400 text-sm">{placeholder}</span>}
|
{isLoading ? (
|
||||||
|
loadingText
|
||||||
|
) : selectedOption ? (
|
||||||
|
selectedOption.label
|
||||||
|
) : (
|
||||||
|
<span className="dark:text-gray-400 text-sm">{placeholder}</span>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
<ChevronDown
|
<ChevronDown
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
@ -232,7 +254,7 @@ export const PageAssistSelect: React.FC<SelectProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<div
|
<div
|
||||||
id="select-dropdown"
|
id="select-dropdown"
|
||||||
role="listbox"
|
role="listbox"
|
||||||
className={`${defaultDropdownClass} ${dropdownClassName}`}>
|
className={`${defaultDropdownClass} ${dropdownClassName}`}>
|
||||||
@ -247,7 +269,10 @@ export const PageAssistSelect: React.FC<SelectProps> = ({
|
|||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
aria-label="Search options"
|
aria-label="Search options"
|
||||||
/>
|
/>
|
||||||
<Search aria-hidden="true" className="absolute left-2 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
|
<Search
|
||||||
|
aria-hidden="true"
|
||||||
|
className="absolute left-2 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400"
|
||||||
|
/>
|
||||||
{onRefresh && (
|
{onRefresh && (
|
||||||
<button
|
<button
|
||||||
onClick={handleRefresh}
|
onClick={handleRefresh}
|
||||||
@ -265,7 +290,9 @@ export const PageAssistSelect: React.FC<SelectProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="max-h-60 overflow-y-auto custom-scrollbar">
|
<div
|
||||||
|
ref={optionsContainerRef}
|
||||||
|
className="max-h-60 overflow-y-auto custom-scrollbar">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="p-4 text-center text-gray-500 flex items-center justify-center gap-2">
|
<div className="p-4 text-center text-gray-500 flex items-center justify-center gap-2">
|
||||||
<LoadingIndicator />
|
<LoadingIndicator />
|
||||||
@ -281,6 +308,7 @@ export const PageAssistSelect: React.FC<SelectProps> = ({
|
|||||||
key={option.value}
|
key={option.value}
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected={value === option.value}
|
aria-selected={value === option.value}
|
||||||
|
data-value={option.value}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onChange(option)
|
onChange(option)
|
||||||
setIsOpen(false)
|
setIsOpen(false)
|
||||||
@ -300,4 +328,4 @@ export const PageAssistSelect: React.FC<SelectProps> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user