import React, { ReactNode, useEffect, useCallback, useState, useMemo, useRef } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import ProgressDiscreteBar from './ProgressDiscreteBar'; import ProgressItemDetail from './ProgressItemDetail'; import ProgressItem from './ProgressItem'; import { Icons } from '../Icons'; import { ProgressDropdownOption, ProgressDropdownOptionPropType } from './types'; const ProgressDropdown = ({ options: optionsProps, value, children, dropDownWidth = '170', onChange, }: { options: ProgressDropdownOption[]; value?: string; children?: ReactNode; onChange?: ({ selectedOption }) => void; }): JSX.Element => { const element = useRef(null); const [open, setOpen] = useState(false); const toggleOpen = () => setOpen(s => !s); const [options, setOptions] = useState(optionsProps); const [selectedOption, setSelectedOption] = useState(undefined); const selectedOptionIndex = useMemo( () => options.findIndex(option => option.value === selectedOption?.value), [options, selectedOption] ); const canMoveNext = useMemo( () => selectedOptionIndex < options.length - 1, [selectedOptionIndex, options] ); const handleOptionSelected = useCallback( (newSelectedOption?: ProgressDropdownOption): void => { if (newSelectedOption?.value === selectedOption?.value) { return; } setOpen(false); setSelectedOption(newSelectedOption); if (newSelectedOption) { newSelectedOption.activated = true; newSelectedOption.onSelect?.(); } if (onChange) { onChange({ selectedOption: newSelectedOption }); } }, [selectedOption, onChange] ); const handleNextButtonClick = useCallback(() => { if (canMoveNext) { handleOptionSelected(options[selectedOptionIndex + 1]); } }, [options, selectedOptionIndex, canMoveNext, handleOptionSelected]); // Update the options in case the options from props has changed useEffect(() => setOptions(optionsProps), [optionsProps]); // Updates the selected item based on the value from props useEffect(() => { if (!value) { return; } const newOption = value ? options.find(option => option.value === value) : undefined; handleOptionSelected(newOption); }, [value, options, handleOptionSelected]); // Listen to any click event outside of the dropdown context to hide the options useEffect(() => { const handleDocumentClick = e => { if (element.current && !element.current.contains(e.target)) { setOpen(false); } }; document.addEventListener('click', handleDocumentClick); if (!open) { document.removeEventListener('click', handleDocumentClick); } }, [open]); return (