Skip to Content
UIComponentsSplitButton

SplitButton

Description

The split button component.

Parameters

No parameters

Example

With loading

Inspect

Source code

/packages/react-ui/SplitButton/SplitButton.tsx
import { Button, ButtonGroup, type ButtonGroupProps, Popper, Paper, MenuItem, MenuList, ClickAwayListener, CircularProgress } from '@mui/material'; import { ArrowDropDown } from '@mui/icons-material'; import { useState, useEffect, useRef, forwardRef, MouseEvent } from 'react'; /** * Split button props. * @public */ export type SplitButtonProps = Omit<ButtonGroupProps, "onChange" | "onClick"> & { options: Array<{ key: string, value: string }>, loading?: boolean, onClick?: (event: React.MouseEvent<HTMLButtonElement>, option: { key: string, value: string }) => void, onChange?: (event: React.MouseEvent<HTMLLIElement>, option: { key: string, value: string }) => void, } /** * The split button component. * @param props - The props. * @param ref - The reference. * @returns The react function component. * @public */ const SplitButton = forwardRef<HTMLButtonElement, SplitButtonProps>((props, ref) => { const { children, onClick, onChange, disabled, options, loading, variant = "contained", ...rest } = props; const [open, setOpen] = useState(false); const [selectedIndex, setSelectedIndex] = useState<number | null>(null); const anchorRef = useRef(null); // Reset selection useEffect(() => { setSelectedIndex(null); }, [options]); /** * Handle on main button click * @param event - The event. */ const handleClick = (event: MouseEvent<HTMLButtonElement>) => { if (disabled || selectedIndex === null || selectedIndex === undefined) { return; } const selectedItem = options[selectedIndex]; if (onClick) { onClick(event, selectedItem); } }; /** * Handle menu item click * @param event The event. * @param index Selected index. */ const handleMenuItemClick = (event: MouseEvent<HTMLLIElement>, index: number) => { setSelectedIndex(index); if (onChange) { onChange(event, options[index]); } setOpen(false); }; /** * Handle on toggle button click */ const handleToggle = () => setOpen((prevOpen) => !prevOpen); /** * Handle on close */ const handleClose = () => setOpen(false); return ( <> <ButtonGroup disabled={disabled} variant={variant} {...rest}> <Button ref={ref} disabled={loading} onClick={handleClick} variant={variant} sx={{ position: 'relative', '&.Mui-disabled': { pointerEvents: 'auto' }, color: loading ? 'transparent !important' : undefined, }} > {loading && <CircularProgress size={16} sx={{ position: 'absolute', left: '50%', transform: 'translateX(-50%)', }} />} {children} </Button> <Button onClick={handleToggle} ref={anchorRef}> <ArrowDropDown /> </Button> </ButtonGroup> <Popper open={open} anchorEl={anchorRef.current} > <Paper> <ClickAwayListener onClickAway={handleClose}> <MenuList autoFocusItem> {options?.length > 0 ? options.map((option, index) => ( <MenuItem key={option.key} selected={index === selectedIndex} onClick={(e) => handleMenuItemClick(e, index)} > {option.value} </MenuItem> )) : ( <MenuItem disabled>Nema elemenata</MenuItem> )} </MenuList> </ClickAwayListener> </Paper> </Popper> </> ); }); SplitButton.displayName = 'SplitButton'; export { SplitButton };
Last updated on