import * as React from 'react'; import { useEffect, useRef, useState } from 'react'; import classNames from 'classnames'; import { useTranslations } from '@shoptet/ui-core-web'; import type { SafePick } from '@shoptet/utils'; import { useScreenSize } from '../../../hooks/useScreenSize'; import type { ButtonProps } from '../../Button/Button'; import { DropdownButton } from '../../DropdownButton/DropdownButton'; import { DropdownButtonContext } from '../../DropdownButton/DropdownButtonContext'; import type { DropdownButtonListItemProps } from '../../DropdownButton/DropdownButtonList/DropdownButtonListItem'; import { dictionary } from './dictionary'; interface SectionControlsDropdownButtonListItemProps extends SafePick, SafePick, React.PropsWithChildren {} /** * For Mobile section controls * We map any component to DropdownButton.Item - only onClick, icons, href and children are consumed */ const toDropdownItems = (children: React.ReactNode, keyPrefix: string): React.ReactNode => React.Children.toArray(children).flatMap((child, index) => { if (React.isValidElement(child)) { const key = `${keyPrefix}${child.key ?? index}`; if (child.type === React.Fragment) { return toDropdownItems(child.props.children, `${key}-`); } if (child.type === DropdownButton) { return React.cloneElement(child, { key }); } return ( ); } return []; }); const toDesktopItems = (children: React.ReactNode, keyPrefix: string): React.ReactNode => React.Children.toArray(children).flatMap((child, index) => { if (React.isValidElement(child)) { const key = `${keyPrefix}${child.key ?? index}`; if (child.type === React.Fragment) { return toDesktopItems(child.props.children, `${key}-`); } return React.cloneElement(child, { key }); } return child; }); const MOBILE_SECTION_CONTROLS_HEIGHT = 58; export interface SectionControlsPriorityProps { /** * Primary button should be one and of variant 'action' */ primaryButton?: React.ReactElement | null | false; /** * Secondary button should be one and of variant 'action' */ secondaryButton?: React.ReactElement | null | false; /** * Additional buttons or dropdowns of variant 'primary' */ buttons?: never; } export interface SectionControlsMoreButtonsProps { /** * Primary button should be one and of variant 'action' */ primaryButton: React.ReactElement | null | false; /** * Secondary button should be one and of variant 'action' */ secondaryButton: React.ReactElement | null | false; /** * Additional buttons or dropdowns of variant 'primary' */ buttons?: React.ReactNode; } export interface SectionControlsOwnProps { help?: React.ReactNode; } export type SectionControlsProps = (SectionControlsPriorityProps | SectionControlsMoreButtonsProps) & SectionControlsOwnProps; export const SectionControls: React.FC = ({ primaryButton, secondaryButton, buttons, help, ...rest }) => { const [isFloating, setIsFloating] = useState(false); const containerRef = useRef(null); const translations = useTranslations(dictionary); useEffect(() => { const headerOffset = (containerRef.current?.getBoundingClientRect().top || 0) + window.scrollY; const handleScroll = () => { const scrollTop = window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0; setIsFloating(scrollTop > headerOffset); }; window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, [containerRef]); const isDesktop = useScreenSize() === 'large'; useEffect(() => { const htmlElement = document.body.parentElement; htmlElement?.classList.remove('drawer-visible'); return () => { htmlElement?.classList.remove('drawer-visible'); }; }, []); const toggleButton = buttons ? ( {toDropdownItems( <> {secondaryButton} {buttons} , 'dropdown-item' )} ) : null; return (
{isDesktop ? ( toDesktopItems( <> {primaryButton} {secondaryButton} {buttons} , 'desktop-item' ) ) : (
{toggleButton || secondaryButton} {primaryButton}
)} {help && {help}}
); };