From ba59ce08b3f3f29630b86585f98e5a642f31d751 Mon Sep 17 00:00:00 2001 From: rebeccahongsf Date: Mon, 14 Oct 2024 16:42:13 -0700 Subject: [PATCH] swap out select list for accordion --- src/components/patterns/accordion.tsx | 80 +++++++++++++++++++++++++ src/components/patterns/on-the-page.tsx | 80 +++++++++++++------------ src/lib/hooks/useAccordion.tsx | 49 +++++++++++++++ 3 files changed, 172 insertions(+), 37 deletions(-) create mode 100644 src/components/patterns/accordion.tsx create mode 100644 src/lib/hooks/useAccordion.tsx diff --git a/src/components/patterns/accordion.tsx b/src/components/patterns/accordion.tsx new file mode 100644 index 00000000..c51cb19e --- /dev/null +++ b/src/components/patterns/accordion.tsx @@ -0,0 +1,80 @@ +"use client" + +import {HTMLAttributes, JSX, useId} from "react" +import {ChevronDownIcon, ChevronUpIcon} from "@heroicons/react/20/solid" +import {twMerge} from "tailwind-merge" +import useAccordion from "@/lib/hooks/useAccordion" + +type Props = HTMLAttributes & { + /** + * Button clickable element or string. + */ + button: JSX.Element | string + /** + * Heading level element. + */ + headingLevel?: "h2" | "h3" | "h4" + /** + * If the accordion should be visible on first render. + */ + initiallyVisible?: boolean + /** + * Button click event if the component is controlled. + */ + onClick?: () => void + /** + * Panel visibility state if the component is controlled. + */ + isVisible?: boolean + /** + * Extra attributes on the button element. + */ + buttonProps?: HTMLAttributes + /** + * Extra attributes on the panel element. + */ + panelProps?: HTMLAttributes +} + +const Accordion = ({button, children, headingLevel = "h2", ...props}: Props) => { + const id = useId() + const {buttonProps, panelProps, expanded, ref} = useAccordion({buttonId: `${id}-button`}) + + const Heading = headingLevel === "h2" ? "h2" : headingLevel === "h3" ? "h3" : "h3" + return ( +
+ + + + +
+
{children}
+
+
+ ) +} +export default Accordion diff --git a/src/components/patterns/on-the-page.tsx b/src/components/patterns/on-the-page.tsx index 654d55ce..fe46f908 100644 --- a/src/components/patterns/on-the-page.tsx +++ b/src/components/patterns/on-the-page.tsx @@ -3,10 +3,9 @@ import React, {useState, useEffect} from "react" import {Link, Maybe} from "@/lib/gql/__generated__/drupal.d" import {twMerge} from "tailwind-merge" -import DrupalLink from "./elements/drupal-link" +import DrupalLink from "@/components/patterns/elements/drupal-link" +import Accordion from "./accordion" import SelectList from "./elements/select-list" -import {SelectOptionDefinition} from "@mui/base/useSelect" -import {useRouter} from "next/navigation" interface OnThePageProps { relLinkHeading?: Maybe @@ -19,7 +18,6 @@ interface Heading { } const OnThePageLink = ({relLinkHeading, relLinks}: OnThePageProps) => { - const router = useRouter() const [headings, setHeadings] = useState([]) const [activeHeading, setActiveHeading] = useState("") @@ -42,12 +40,6 @@ const OnThePageLink = ({relLinkHeading, relLinks}: OnThePageProps) => { const observerCallback: IntersectionObserverCallback = entries => { entries.forEach(entry => { - const top = entry.boundingClientRect.top - - console.log( - `Observer | Target: ${entry.target.id} | isIntersecting: ${entry.isIntersecting} | intersectionRatio: ${entry.intersectionRatio}` - ) - if (entry.isIntersecting) { setActiveHeading(entry.target.id) } @@ -69,39 +61,53 @@ const OnThePageLink = ({relLinkHeading, relLinks}: OnThePageProps) => { } }, []) - const options: SelectOptionDefinition[] = [ - ...headings.map(heading => ({ - value: heading.id, - label: heading.text, - })), - { - value: "related-links-header", - label: relLinkHeading || "Related content", - disabled: true, - }, - ...(relLinks?.map(link => ({ - value: String(link.url), - label: String(link.title), - })) || []), - ] - return (
{ - if (value) { - const selectedHeading = document.getElementById(value as string) - if (selectedHeading) { - selectedHeading.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"}) - } else { - router.push(value as string) - } - } - }} + options={[ + {value: "option1", label: "option1"}, + {value: "option2", label: "option2"}, + ]} /> + + + {relLinks && ( +
+

+ {relLinkHeading || "Related content"} +

+
    + {relLinks.map((link, index) => ( +
  • + {link.url && ( + + {link.title} + + )} +
  • + ))} +
+
+ )} +