UNPKG

react-fast-accordion

Version:

High performance 0 dependencies accordion for React

119 lines (117 loc) 3.16 kB
// src/index.tsx import React2, { useEffect, useRef, useState } from "react"; // src/ListItem.tsx import React, { memo } from "react"; var ListItem = ({ id, isOpen, SummaryComponent, DetailComponent, ...rest }) => { return /* @__PURE__ */ React.createElement("li", { role: "button", tabIndex: 0, "aria-expanded": isOpen, "aria-controls": `acc-content-${id}`, id: id.toString(), className: "acc-item" }, /* @__PURE__ */ React.createElement(SummaryComponent, { ...rest, isOpen }), isOpen && /* @__PURE__ */ React.createElement("div", { role: "definition", className: "acc-content", id: `acc-content-${id}` }, /* @__PURE__ */ React.createElement(DetailComponent, { ...rest, isOpen }))); }; var ListItem_default = memo(ListItem); // src/index.tsx var Accordion = ({ items, multiExpand = true, ...rest }) => { const [opened, setOpened] = useState({}); const listContainerRef = useRef(null); const mutationCb = (list) => { const contentItem = list[0].target.childNodes[1] ?? null; if (!contentItem) return; if (contentItem.className !== "acc-content") return; const scrollHeight = contentItem.scrollHeight; contentItem.animate({ maxHeight: `${scrollHeight}px`, opacity: 1 }, { duration: 100, easing: "ease-in", fill: "forwards" }); }; useEffect(() => { if (!listContainerRef.current) return; const observer = new MutationObserver(mutationCb); observer.observe(listContainerRef.current, { childList: true, subtree: true }); return () => { observer.disconnect(); }; }, []); const closeAccordion = (id) => { const contentItem = document.getElementById(`acc-content-${id}`); if (!contentItem) return; contentItem.animate({ maxHeight: 0, opacity: 0 }, { duration: 100, easing: "ease-out" }).finished.then(() => { contentItem.style.display = "none"; setOpened((prv) => { const newObj = { ...prv }; delete newObj[id]; return newObj; }); }); }; const clickHandler = (e) => { let element = e.target; if (element.parentElement?.tagName === "LI") { element = element.parentElement; } if (element.tagName !== "LI") return; const id = element.getAttribute("id"); if (!id) return; const isOpen = opened[id]; if (isOpen) { return closeAccordion(id); } setOpened((prv) => ({ ...prv, [id]: true })); if (!multiExpand) { const prvAccId = Object.keys(opened)[0]; closeAccordion(prvAccId); } }; const ariaHandler = (e) => { if (e.key === " " || e.key === "Enter") { clickHandler(e); e.preventDefault(); } }; return /* @__PURE__ */ React2.createElement("ul", { onClick: clickHandler, onKeyPress: ariaHandler, ref: listContainerRef, role: "list" }, items.map(({ id, ...data }) => /* @__PURE__ */ React2.createElement(ListItem_default, { id, key: id, isOpen: opened[id], ...data, ...rest }))); }; var src_default = Accordion; export { src_default as default }; //# sourceMappingURL=index.mjs.map