import React, { useEffect, useRef, useState } from 'react' import Button from '../Button/Button' import Image from '../Image/Image' import LabelAndData from '../LabelAndData/LabelAndData' import Tag from '../Tag/Tag' import TrimText from '../TrimText/TrimText' import { useMediaQuery } from '../../hooks/responsiveHooks' import { type LabelAndDataProps } from '../LabelAndData/LabelAndData' import { type TagProps } from '../Tag/Tag' import ScrollingContainer from '../ScrollingContainer/ScrollingContainer' import styles from './_information-pane.module.scss' type Header = { /** The header label and data that appears in the left side of the header */ labelAndData?: Omit< LabelAndDataProps, 'children' | 'customClass' | 'labelClass' > /** The tag that appears in the right side of the header */ tag?: TagProps /** The edit function to be passed into the edit icon in the right side of the header */ edit?: () => void } export type InformationPaneProps = { /** InformationPane will accept any children elements. It is recommended to use the components defined in this file - ImageAndName, Section, CustomSection, and Divider - to achieve the desired design. */ children: React.ReactNode /** The header that will be displayed when `simple` is not defined. This will always be displayed in the desktop view, even if `simple` is defined. */ header?: Header /** Optional prop to simplify the mobile view for this component. */ simple?: SimpleProps /** Indicates if the page has a PageFooter component, which affects container height calculations */ includePageFooterHeight?: boolean /** Optionally hide gradient overlays in the scrolling container */ hideGradients?: boolean /** Optional prop to add a test id to the InformationPane for QA testing */ qaTestId?: string } const InformationPane = ({ header, children, simple, includePageFooterHeight = false, hideGradients = false, qaTestId = 'information-pane', }: InformationPaneProps): React.JSX.Element => { const mobileView = useMediaQuery({ type: 'max', breakpoint: 'sm' }) return simple && mobileView ? ( ) : (
{children}
) } type HeaderProps = InformationPaneProps['header'] const HeaderComponent = ({ labelAndData, tag, edit }: HeaderProps = {}) => { return (
{labelAndData ? : null} {tag && !edit ? : null} {edit ?
{tag && edit ? : null}
) } type ImageAndNameProps = { /** The url of the product image */ imgUrl?: string /** The product name and associated marketplace url */ product: { name: string; url?: string } } const ImageAndName = ({ imgUrl, product, }: ImageAndNameProps): React.JSX.Element => { return (
{product.name} {product.url ? ( {product.name} ) : ( {product.name} )}
) } type SectionProps = { /** Array of LabelAndData props that will populate in this section */ data: Omit[] /** Boolean used to style the section into 1 or 2 columns. 1 column is the default. */ isTwoColumns?: boolean } const Section = ({ data, isTwoColumns }: SectionProps): React.JSX.Element => { return (
{data.map((d, index) => (
))}
) } type CustomSectionProps = { /** The children elements to be passed into the component. */ children: React.ReactNode } const CustomSection = ({ children }: CustomSectionProps) => { return
{children}
} const Divider = (): React.JSX.Element => { return
} type SimpleProps = ImageAndNameProps & { /** The product identifier */ identifier: string /** Optional prop to add a test id to the Simple for QA testing */ qaTestId?: string } const Simple = ({ imgUrl, product, identifier, qaTestId, }: SimpleProps): React.JSX.Element => { const [touchY, setTouchY] = useState(0) const [direction, setDirection] = useState<'down' | 'up'>('down') const ref = useRef(null) useEffect(() => { let prevScrollPos = ref.current?.getBoundingClientRect().y || 0 const scroll = () => { const currentScrollPos = ref.current?.getBoundingClientRect().y || 0 if (ref.current) { if (prevScrollPos > currentScrollPos) { setDirection('up') } if (currentScrollPos > prevScrollPos) { setDirection('down') } prevScrollPos = currentScrollPos } } window.addEventListener('wheel', scroll) return () => { window.removeEventListener('wheel', scroll) } }, []) useEffect(() => { const handleTouchMove = (event: TouchEvent) => { const newY = event.touches[0].clientY if (touchY !== null) { const deltaY = newY - touchY if (deltaY > 0) { setDirection('down') } else if (deltaY < 0) { setDirection('up') } } setTouchY(newY) } window.addEventListener('touchmove', handleTouchMove) return () => { window.removeEventListener('touchmove', handleTouchMove) } }, [touchY]) const imageSmallSize = 72 //The image size is set to small when scrolling up for a more compact view const imageLargeSize = 175 //The image size is set to large when scrolling down for a more detailed view const imageSize = direction === 'up' ? imageSmallSize : imageLargeSize const ProductName = ({ className = '' }: { className?: string }) => { const classes = `${styles.productName} ${className}` return direction === 'up' ? ( ) : ( {product.name} ) } return (
{product.name}
{product.url ? ( {ProductName({ className: styles.link })} ) : ( ProductName({}) )} {identifier}
) } InformationPane.ImageAndName = ImageAndName InformationPane.Section = Section InformationPane.CustomSection = CustomSection InformationPane.Divider = Divider InformationPane.Simple = Simple export { InformationPane }