I am using accordion material-mui. at first all of accordions are opened. when I scroll the page and I reach to the second accordion, I want to close the first accordion and when I reach to the third accordion , I want to close the previous ones and so on. the log of ref.current.offsetTop is always bigger than newScrollYPosition and when I change the if to > and it removes accordions[0].id but it did not close the accordion. How can I do that? my simple code is in the below link.
https://stackblitz.com/edit/vitejs-vite-nzp98t?file=src%2FApp.tsx,src%2FApp.css&terminal=dev
import { Accordion as MuiAccordion } from '@mui/material'
export const Accordion = ({
className,
accordions,
scrollableContainerRef,
}: AccordionProps) => {
const [expandedIds, setExpandedIds] = useState<string[]>(
accordions.map(({ id }) => id)
)
const accordionRefs = useRef<(React.RefObject<HTMLDivElement> | null)[]>(
accordions.map(() => React.createRef())
)
const handleScroll = () => {
const newScrollYPosition = scrollableContainerRef.current?.scrollTop || 0
accordionRefs.current.forEach((ref) => {
if (ref.current) {
if (ref.current.offsetTop < newScrollYPosition) {
setExpandedIds((prevExpandedIds) =>
prevExpandedIds.filter((id) => id !== accordions[0].id)
)
}
}
})
}
useEffect(() => {
if (scrollableContainerRef.current) {
scrollableContainerRef.current.addEventListener('scroll', handleScroll)
}
return () => {
if (scrollableContainerRef.current) {
scrollableContainerRef.current.removeEventListener(
'scroll',
handleScroll
)
}
}
}, [scrollableContainerRef])
const accordionsList = useMemo(() => {
return accordions.map(({ id, title, content, disabled }, index) => (
<MuiAccordion
key={id}
disabled={disabled}
defaultExpanded={expandedIds.includes(id)}
ref={accordionRefs.current[index]}
>
<AccordionSummary expandIcon={<ExpandMoreIcon />} id={id}>
{title}
</AccordionSummary>
<AccordionDetails>{content}</AccordionDetails>
</MuiAccordion>
))
}, [accordions, expandedIds])
return (
<div className={classNames('accordion', className)}>{accordionsList}</div>
)
}
export const Accordion = ({ className, accordions }: AccordionProps) => {
const accordionRefs = useRef<(React.RefObject<HTMLDivElement> | null)[]>(
accordions.map(() => React.createRef())
)
const scrollableContainerRef = useRef<HTMLDivElement>(null)
const [expandedIds, setExpandedIds] = useState<string[]>(
accordions.map(({ id }) => id)
)
const handleScroll = () => {
const newScrollYPosition = scrollableContainerRef.current?.scrollTop || 0
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const accordionId = entry.target.getAttribute('data-id')
if (
accordionId &&
newScrollYPosition > entry.boundingClientRect.top
) {
setExpandedIds((prevExpandedIds) =>
prevExpandedIds.filter(
(expandedId) => expandedId !== accordionId
)
)
}
}
})
},
{
threshold: 0.5,
root: document.querySelector('.accordion'),
}
)
accordionRefs.current.forEach((ref, index) => {
if (ref && ref.current) {
observer.observe(ref.current)
ref.current.setAttribute('data-id', accordions[index].id) // Add a unique identifier to each accordion
}
})
return () => observer.disconnect()
}
//
const onChange = (id: string) => {
setExpandedIds((prevIds) => {
const isExpanded = prevIds.includes(id)
return isExpanded
? prevIds.filter((expandedId) => expandedId !== id)
: [...prevIds, id]
})
}
const accordionsList = useMemo(() => {
return accordions.map(({ id, title, content, disabled }, index) => (
<MuiAccordion
key={id}
disabled={disabled}
expanded={expandedIds.includes(id)}
ref={accordionRefs.current[index]}
onChange={() => onChange(id)}
>
<AccordionSummary expandIcon={<ExpandMoreIcon />} id={id}>
{title}
</AccordionSummary>
<AccordionDetails>{content}</AccordionDetails>
</MuiAccordion>
))
}, [accordions, expandedIds])
useEffect(() => {
if (scrollableContainerRef.current) {
scrollableContainerRef.current.addEventListener('scroll', handleScroll)
}
return () => {
if (scrollableContainerRef.current) {
scrollableContainerRef.current.removeEventListener(
'scroll',
handleScroll
)
}
}
}, [scrollableContainerRef])
return (
<div
className={classNames('accordion', className)}
ref={scrollableContainerRef}
>
{accordionsList}
</div>
)
}