diff --git a/src/components/Common/ButtonWithDropdown/index.tsx b/src/components/Common/ButtonWithDropdown/index.tsx index bf98cdae..36c79364 100644 --- a/src/components/Common/ButtonWithDropdown/index.tsx +++ b/src/components/Common/ButtonWithDropdown/index.tsx @@ -1,77 +1,29 @@ -import useClickOutside from '@app/hooks/useClickOutside'; +import Dropdown from '@app/components/Common/Dropdown'; import { withProperties } from '@app/utils/typeHelpers'; -import { Transition } from '@headlessui/react'; +import { Menu } from '@headlessui/react'; import { ChevronDownIcon } from '@heroicons/react/24/solid'; -import type { - AnchorHTMLAttributes, - ButtonHTMLAttributes, - RefObject, -} from 'react'; -import { Fragment, useRef, useState } from 'react'; +import type { AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react'; -interface DropdownItemProps extends AnchorHTMLAttributes { - buttonType?: 'primary' | 'ghost'; -} - -const DropdownItem = ({ - children, - buttonType = 'primary', - ...props -}: DropdownItemProps) => { - let styleClass = 'button-md text-white'; - - switch (buttonType) { - case 'ghost': - styleClass += - ' bg-transparent rounded hover:bg-gradient-to-br from-indigo-600 to-purple-600 text-white focus:border-gray-500 focus:text-white'; - break; - default: - styleClass += - ' bg-indigo-600 rounded hover:bg-indigo-500 focus:border-indigo-700 focus:text-white'; - } - return ( - - {children} - - ); -}; - -interface ButtonWithDropdownProps { +type ButtonWithDropdownProps = { text: React.ReactNode; dropdownIcon?: React.ReactNode; buttonType?: 'primary' | 'ghost'; -} -interface ButtonProps - extends ButtonHTMLAttributes, - ButtonWithDropdownProps { - as?: 'button'; -} -interface AnchorProps - extends AnchorHTMLAttributes, - ButtonWithDropdownProps { - as: 'a'; -} +} & ( + | ({ as?: 'button' } & ButtonHTMLAttributes) + | ({ as: 'a' } & AnchorHTMLAttributes) +); const ButtonWithDropdown = ({ - as, text, children, dropdownIcon, className, buttonType = 'primary', ...props -}: ButtonProps | AnchorProps) => { - const [isOpen, setIsOpen] = useState(false); - const buttonRef = useRef(null); - useClickOutside(buttonRef, () => setIsOpen(false)); - +}: ButtonWithDropdownProps) => { const styleClasses = { mainButtonClasses: 'button-md text-white border', dropdownSideButtonClasses: 'button-md border', - dropdownClasses: 'button-md', }; switch (buttonType) { @@ -79,72 +31,40 @@ const ButtonWithDropdown = ({ styleClasses.mainButtonClasses += ' bg-transparent border-gray-600 hover:border-gray-200 focus:border-gray-100 active:border-gray-100'; styleClasses.dropdownSideButtonClasses = styleClasses.mainButtonClasses; - styleClasses.dropdownClasses += - ' bg-gray-800 border border-gray-700 bg-opacity-80 p-1 backdrop-blur'; break; default: styleClasses.mainButtonClasses += ' bg-indigo-600 border-indigo-500 bg-opacity-80 hover:bg-opacity-100 hover:border-indigo-500 active:bg-indigo-700 active:border-indigo-700 focus:ring-blue'; styleClasses.dropdownSideButtonClasses += ' bg-indigo-600 bg-opacity-80 border-indigo-500 hover:bg-opacity-100 active:bg-opacity-100 focus:ring-blue'; - styleClasses.dropdownClasses += ' bg-indigo-600 p-1'; } + const TriggerElement = props.as ?? 'button'; + return ( - - {as === 'a' ? ( - } - {...(props as AnchorHTMLAttributes)} - > - {text} - - ) : ( - - )} + + )} + > + {text} + {children && ( - - -
-
-
{children}
-
-
-
+ + {children}
)} - +
); }; -export default withProperties(ButtonWithDropdown, { Item: DropdownItem }); +export default withProperties(ButtonWithDropdown, { Item: Dropdown.Item }); diff --git a/src/components/Common/Dropdown/index.tsx b/src/components/Common/Dropdown/index.tsx new file mode 100644 index 00000000..2d052398 --- /dev/null +++ b/src/components/Common/Dropdown/index.tsx @@ -0,0 +1,133 @@ +import { withProperties } from '@app/utils/typeHelpers'; +import { Menu, Transition } from '@headlessui/react'; +import { ChevronDownIcon } from '@heroicons/react/24/solid'; +import { + Fragment, + useRef, + type AnchorHTMLAttributes, + type ButtonHTMLAttributes, + type HTMLAttributes, +} from 'react'; + +interface DropdownItemProps extends AnchorHTMLAttributes { + buttonType?: 'primary' | 'ghost'; +} + +const DropdownItem = ({ + children, + buttonType = 'primary', + ...props +}: DropdownItemProps) => { + let styleClass = 'button-md text-white'; + + switch (buttonType) { + case 'ghost': + styleClass += + ' bg-transparent rounded hover:bg-gradient-to-br from-indigo-600 to-purple-600 text-white focus:border-gray-500 focus:text-white'; + break; + default: + styleClass += + ' bg-indigo-600 rounded hover:bg-indigo-500 focus:border-indigo-700 focus:text-white'; + } + return ( + + + {children} + + + ); +}; + +type DropdownItemsProps = HTMLAttributes & { + dropdownType: 'primary' | 'ghost'; +}; + +const DropdownItems = ({ + children, + className, + dropdownType, + ...props +}: DropdownItemsProps) => { + let dropdownClasses: string; + + switch (dropdownType) { + case 'ghost': + dropdownClasses = + 'bg-gray-800 border border-gray-700 bg-opacity-80 p-1 backdrop-blur'; + break; + default: + dropdownClasses = 'bg-indigo-600 p-1'; + } + + return ( + + +
{children}
+
+
+ ); +}; + +interface DropdownProps extends ButtonHTMLAttributes { + text: React.ReactNode; + dropdownIcon?: React.ReactNode; + buttonType?: 'primary' | 'ghost'; +} + +const Dropdown = ({ + text, + children, + dropdownIcon, + className, + buttonType = 'primary', + ...props +}: DropdownProps) => { + const buttonRef = useRef(null); + let dropdownButtonClasses = 'button-md text-white border'; + + switch (buttonType) { + case 'ghost': + dropdownButtonClasses += + ' bg-transparent border-gray-600 hover:border-gray-200 focus:border-gray-100 active:border-gray-100'; + break; + default: + dropdownButtonClasses += + ' bg-indigo-600 border-indigo-500 bg-opacity-80 hover:bg-opacity-100 hover:border-indigo-500 active:bg-indigo-700 active:border-indigo-700 focus:ring-blue'; + } + + return ( + + + {text} + {children && (dropdownIcon ? dropdownIcon : )} + + {children && ( + {children} + )} + + ); +}; +export default withProperties(Dropdown, { + Item: DropdownItem, + Items: DropdownItems, +});