React material UI split button align - reactjs

I am trying to align to the left the dropdown menu list, whatever values I put in are not yielding this result can somone advise how to do this?
https://material-ui.com/components/button-group/#split-button
Here is what my template looks like:
<Grid container direction="column" alignItems="flex-start">
<Grid item xs={12}>
<ButtonGroup variant="contained" color="primary" ref={anchorRef} aria-label="split button">
<Button onClick={() => handleClick(options[selectedIndex])}>
{options[selectedIndex]}
</Button>
<Button
color="primary"
size="small"
aria-controls={open ? "split-button-menu" : undefined}
aria-expanded={open ? "true" : undefined}
aria-label="select mode type"
aria-haspopup="menu"
onClick={handleToggle}
>
<ArrowDropDownIcon />
</Button>
</ButtonGroup>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin: placement === "bottom" ? "left top" : "left bottom",
}}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList id="split-button-menu">
{options &&
options.map((option, index) => (
<MenuItem
key={option}
disabled={index === selectedIndex}
selected={index === selectedIndex}
onClick={(event) => handleMenuItemClick(event, index)}
>
{option}
</MenuItem>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</Grid>
</Grid>

Try this:
<Grow
{...TransitionProps}
anchorOrigin={{
horizontal: 'left',
vertical: 'bottom',
}}
transformOrigin={{
horizontal: 'left',
vertical: 'top',
}}
>
{insert children here}
</Grow>
UPDATE
This is what you want, i.e, add placement='bottom-start' to your Popper component. Thanks for giving me more context.
<Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
transition
disablePortal
placement='bottom-start'
>
{...children...}
</Popper>

Related

How to swap MUI icon on IconButton when hovering

I have these tabs that have a close button on them, if the content in them has edits then the close icon turns to a circle, similar to visual code.
{tabs.map((tab, index) => {
const child = (
<StyledTab
label={
<span>
{tab.label + ':' + tab.hasEdit}
<IconButton size="small" component="span" onClick={() => closeClickHandler(tab.value)}>
{tab.hasEdit ? (
<CircleIcon style={{ fontSize: "12px" }} />
) : (
<CloseIcon style={{ fontSize: "18px" }} />
)}
</IconButton>
</span>
}
value={tab.value}
key={index}
/>
);
return (
<DraggableTab
label={
<span>
{tab.label}
<IconButton size="small" component="span" onClick={() => {
closeClickHandler(tab.value);
}}>
{tab.hasEdit ? (
<CircleIcon style={{ fontSize: "12px" }} />
) : (
<CloseIcon style={{ fontSize: "18px" }} />
)}
</IconButton>
</span>
}
value={tab.value}
index={index}
key={index}
child={child}
/>
);
})}
What I'm having trouble with is getting the icon to change from a circle to a close icon while hovering over the button.
Could someone give me a hand on a good way to implement this please?!
You could do this by adding a state for the items. Then add a onMouseEnter and onMouseLeave events on the IconButton. When hovering we can add the index to the array and finally remove when we're leaving. To determine if a icon needs to change we can check if the index in in the hoveringItems.
const [hoveringItems, setHoveringItems] = useState([]);
function handleHover(index, isLeaving) {
setHoveringItems((prevItems) => {
if (isLeaving) return prevItems.filter((item) => item !== index);
return [...prevItems, index];
});
}
return (
<IconButton
size="small"
component="span"
onClick={() => {
closeClickHandler(tab.value);
}}
onMouseEnter={() => handleHover(index, false)}
onMouseLeave={() => handleHover(index, true)}
>
{tab.hasEdit || hoveringItems.includes(index) ? (
<CircleIcon style={{ fontSize: "12px" }} />
) : (
<CloseIcon style={{ fontSize: "18px" }} />
)}
</IconButton>
);

React MAterial UI - How to add MoreVertIcon in DataGrid?

I am implementing a functionality as shown similarly in the link
https://mui.com/x/react-data-grid/#mit-version
My confusion now is how to add MoreVertIcon at the end column of each row as shown in the code https://mui.com/material-ui/react-menu/#max-height-menu
Each row in the grid should have last column with the MoreVertIcon. Since the data is loaded from the array or JSON data, where will be best place to add this?
I tried like this but I get error in the <DataGrid> tag.
<DataGrid
rows={customers}
columns={columns}
pageSize={16}
rowsPerPageOptions={[5]}
getRowId={(row: any) => row.name}
autoPageSize={true}
rowHeight={45}
onRowClick={handleCustomerClick}
hideFooterSelectedRowCount={true}>
<div>
<IconButton
aria-label="more"
id="long-button"
aria-controls={open ? 'long-menu' : undefined}
aria-expanded={open ? 'true' : undefined}
aria-haspopup="true"
onClick={handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu
id="long-menu"
MenuListProps={{
'aria-labelledby': 'long-button',
}}
anchorEl={anchorEl}
open={open}
onClose={handleClose}
PaperProps={{
style: {
maxHeight: ITEM_HEIGHT * 4.5,
width: '20ch',
},
}}
>
{options.map((option) => (
<MenuItem key={option} selected={option === 'Pyxis'} onClick={handleClose}>
{option}
</MenuItem>
))}
</Menu>
</div>
</DataGrid>

Custom Menu Item in MUI Data Grid Toolbar

I'm currently using the Data Grid Toolbar (a feature of the Material-UI Data Grid component) because I want the Column Show/Hide component, but I also want to add my own menu item in the form of an IconButton with a Menu that opens when clicked. The issue is when you click said button, the Toolbar appears to re-render, which causes the Menu to lose its anchor and render in the upper left. Is there a special way to get an anchor within the Data Grid Toolbar for the Menu popper to appear in the correct location?
function CustomToolbar() {
return (
<GridToolbarContainer>
<Box
height="65px"
width="100%"
display="flex"
flexDirection="row"
justifyContent="center"
>
<Box width="300px" display="flex" justifyContent="flex-start" alignItems="center">
<GridToolbarColumnsButton sx={{ ml: 2 }} />
</Box>
<Box width="100%" alignSelf="center" textAlign="center">
<Typography sx={{ flex: "1 1 100%" }} variant="h6" component="div">
Title Goes Here
</Typography>
</Box>
<Box width="300px" display="flex" justifyContent="flex-end" alignItems="center">
<Tooltip title="Filter">
<IconButton
color="primary"
component="span"
disabled={loading}
sx={{ mr: 2 }}
onClick={handleMenuClick}
>
<FilterList />
</IconButton>
</Tooltip>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={() => handleClose(menuState, filters)}
transformOrigin={{ horizontal: "right", vertical: "top" }}
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
PaperProps={MenuProps}
>
<MenuItem /> //Clipped
<MenuItem /> //Clipped
<MenuItem /> //Clipped
</Menu>
</Box>
</Box>
</GridToolbarContainer>
);
}
You must create the Toolbar component outside of your component that declares the DataGrid, and get the properties you need through the DataGrid's componentsProps property.
GridToolbarCustom Component:
type Props = {
selectionModel: GridSelectionModel;
}
const GridToolbarCustom = ({ selectionModel }: Props) => {
const [anchorElMenu, setAnchorElMenu] = useState<null | HTMLButtonElement>(null);
const openMenu = Boolean(anchorElMenu);
return (
<GridToolbarContainer>
<Grid container item xs>
{/* default buttons */}
<GridToolbarColumnsButton />
<GridToolbarFilterButton />
<GridToolbarDensitySelector />
<GridToolbarExport />
</Grid>
<Grid>
<Button
variant="contained"
size="small"
disabled={selectionModel.length === 0}
startIcon={<MoreVertIcon />}
onClick={(event: MouseEvent<HTMLButtonElement>) => {
setAnchorElMenu(event.currentTarget);
}}
>
Actions
</Button>
<Menu
id="menu-options"
anchorEl={anchorElMenu}
open={openMenu}
onClose={() => {
setAnchorElMenu(null);
}}
>
<MenuItem /> //Clipped
<MenuItem /> //Clipped
<MenuItem /> //Clipped
</Menu>
</Grid>
</GridToolbarContainer>
);
}
export default GridToolbarCustom;
MyComponent:
import GridToolbarCustom from './GridToolbarCustom';
const MyComponent = () => {
const [selectionModel, setSelectionModel] = useState<GridSelectionModel>([]);
return (
<DataGrid
//Clipped
components={{
Toolbar: GridToolbarCustom,
}}
componentsProps={{
toolbar: {
selectionModel,
},
}}
checkboxSelection
onSelectionModelChange={(newSelectionModel) => {
setSelectionModel(newSelectionModel);
}}
selectionModel={selectionModel}
/>
);
};

react material ui grow on left side

How to make the context menu open not in the center of the button, but to the left of the button? With using properties Material UI.
Working example from link:
https://codesandbox.io/s/2f33z
Now this:
I want this:
Here is a link to an example from the documentation:
https://material-ui.com/components/menus/#menulist-composition
<div>
<Button
ref={anchorRef}
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
>
Toggle Menu Grow
</Button>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow" onKeyDown={handleListKeyDown}>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
Your Popper component should have a placement property of value bottom-start:
// ...
<Popper
placement="bottom-start"
// ...
>
// ...
For more options look here: https://material-ui.com/components/popper/#positioned-popper.

Material ui anchor without hooks

I have a menu component that pops open in a table. When I copy the material ui example into the cell in the table it works perfectly.
https://codesandbox.io/s/gitl9
The material ui example uses hooks and I want to change it to a class component and use redux.
When I made the change the pop-up menu does not align beside the the button you press anymore.
The anchorEl attribute is responsible for passing the location of the button that has been called.
I added these attributes allow me to move the menu pop but it does not align with button that you click to open the menu.
const options = ["View", "Edit", "Delete"];
const ITEM_HEIGHT = 48;
class ActionsOptionMenu extends Component {
state = { anchorEl: null };
render() {
return (
<div>
<IconButton
aria-label='more'
aria-controls='long-menu'
aria-haspopup='true'
>
<MoreVertIcon />
</IconButton>
<Menu
getContentAnchorEl={null}
anchorOrigin={{
height: "54px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: `0 ${padding} 0 ${padding}`,
margin: "0 auto 7px auto"
}}
transformOrigin={{ vertical: "top", horizontal: "right" }}
id='long-menu'
anchorEl={anchorEl}
keepMounted
open={true}
PaperProps={{
style: {
maxHeight: ITEM_HEIGHT * 4.5,
width: 120
}
}}
>
{options.map(option => (
<MenuItem key={option}>{option}</MenuItem>
))}
</Menu>
</div>
);
}
}
I solved the issue doing it this way.
render() {
const { open } = this.state;
return (
<div>
<IconButton
aria-label='more'
aria-controls='long-menu'
aria-haspopup='true'
buttonRef={node => {
this.anchorEl = node;
}}
onClick={event => this.handleClick(event)}
>
<MoreVertIcon />
</IconButton>
<Popper
open={open}
anchorEl={this.anchorEl}
transition
disablePortal
style={{ zIndex: 100 }}
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
id='menu-list-grow'
style={{
zIndex: 1001,
transformOrigin:
placement === "bottom" ? "center top" : "center bottom"
}}
>
<Paper>
<ClickAwayListener
onClickAway={event => this.handleClose(event)}
>
<MenuList>
<MenuItem onClick={event => this.handleClose(event)}>
Profile
</MenuItem>
<MenuItem onClick={event => this.handleClose(event)}>
My account
</MenuItem>
<MenuItem onClick={event => this.handleClose(event)}>
Logout
</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
);
}

Resources