How do I programatically show "ripple effect" with MUI? - reactjs

Basically the title. I want to manually show the ripple effect on my collection of MUI's Buttons - the ripple effect works when I click the button, but I can't find a way to show the ripple effect programmatically.
Do I need to disable the MUI's ripple effect and then make my own ripple effect function, that I can attach to onClick?
{this.buttons.map((button) => (
<React.Fragment key={button.name}>
{button.render ? (
<div className="col-3">
<Button
autoFocus={true}
className="w-100 p-3"
variant="contained"
color="primary"
classes={{root: classes.button}}
disableElevation
onClick={() => {updateState(button.onClick(text))}}
>
{button.keyCode}
</Button>
</div>
) : (<></>)}
</React.Fragment>
))}

Button uses ButtonBase which uses TouchRipple under the hood. Here is a snippet of ButtonBase definition:
function ButtonBase(props) {
// ...
return (
<ButtonBaseRoot>
{children}
<TouchRipple ref={rippleRef} center={centerRipple} {...TouchRippleProps} />
</ButtonBaseRoot>
)
}
There is no API to trigger the ripple manually. It's handled internally inside the button, so in order to do that, you need to create and control your own ripple component provided by MUI:
import TouchRipple from '#mui/material/ButtonBase/TouchRipple';
const rippleRef = React.useRef(null);
const buttonRef = React.useRef(null);
const triggerRipple = () => {
const container = buttonRef.current;
const rect = container.getBoundingClientRect();
rippleRef.current.start(
{
clientX: rect.left + rect.width / 2,
clientY: rect.top + rect.height / 2,
},
// when center is true, the ripple doesn't travel to the border of the container
{ center: false },
);
setTimeout(() => rippleRef.current.stop({}), 320);
};
return (
<div>
<Button onClick={triggerRipple}>start ripple</Button>
<Box display="flex" justifyContent="center" m={10}>
<Button
variant="contained"
color="primary"
ref={buttonRef}
sx={{ display: 'relative' }}
>
My little ripple
<TouchRipple ref={rippleRef} center />
</Button>
</Box>
</div>
);
Live Demo
Related answers
Is it possible to use the touch ripple effect of mui on a div?

Related

How to use custom isOpen with a chakra component

I am relatively new to react and not sure why isOpen is not working as expected.
Please see the code below for the example that I am working with
I have a menu icon that is using isOpen to open navlinks:
const { isOpen, onOpen, onClose } = useDisclosure();
<IconButton variant={"unstyled"} bgColor={"white"} color={"black"} size={"s"} icon={isOpen ? <Hamburger size={"24"} /> : <Hamburger size={"24"} />} aria-label={"Open Menu"} display={{ md: "none" }} onClick={isOpen ? onClose : onOpen} />
{isOpen ? (
<Box color={"#b8860b"} pb={4} display={{ md: "none" }}>
<Stack as={"nav"} spacing={5}>
{Links.map(link => (
<Link key={link.name} href={link.route}>
<Flex paddingBottom="40px" h="40px" borderBottom="1px" borderColor="black" justifyContent={'left'}>
<Flex paddingLeft={"10px"} paddingTop={"3%"}> {link.icon}</Flex>
<Text p={2} color={"black"} >
{link.name}
</Text>
</Flex>
</Link>
))}
</Stack>
</Box>
) : null}
When I try using a custom isOpen to open a drawer component, i just cant get it to work..
What am I doing wrong?:
const { isOpenMenu, onOpenMenu, onCloseMenu } = useDisclosure()
<Button
bgColor={"white"}
onClick={isOpenMenu}
>
<BsCart4 size={"26px"} color={"black"} />
{cartItemCount > 0 && <Badge ml='1' fontSize='0.9em' colorScheme='green'>{cartItemCount}</Badge>}
</Button>
<Drawer
isOpen={isOpenMenu}
placement='right'
onClose={onCloseMenu}
finalFocusRef={btnRef}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader>Create your account</DrawerHeader>
<DrawerBody>
<Input placeholder='Type here...' />
</DrawerBody>
<DrawerFooter>
<Button variant='outline' mr={3} onClick={onCloseMenu}>
Cancel
</Button>
<Button colorScheme='blue'>Save</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
```
When I use isOpen for the drawer it works fine so I thought having another isOpen but custom would open the drawer but its not working as expected.
Can someone help understand why my thinking isnt right based on how to use isOpen correctly?
It seems like only isOpen works when I switch it from using the menu bar and drawer
First of all, if you want to use custom names to the useDisclosure states, you have to set them like this:
const { isOpen: isOpenMenu, onOpen: onOpenMenu, onClose: onCloseMenu } = useDisclosure()
Also, the onClose prop of the drawer component is just a event handler, dont put your onCloseMenu function ther, just call it when you want to close the drawer, as you made on the cancel button, example:
<Button onClick={onCloseMenu} ... />

Slide Up MUI both on open and on dismiss

I am using MUI Slide Transition component to display a dialog.
On the click of a button I succeeded in displaying the Dialog with a SlideUp Transition.
Now, on dismiss I also want it to Slide Up again to dismiss. How can that be achieved.
Here is the transition I used:
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide
direction="up"
mountOnEnter
unmountOnExit
ref={ref} {...props} />;
});
<Dialog
open={openDialog}
TransitionComponent={Transition}
keepMounted
onClose={handleClickAway}
>
You can change the direction prop dynamically based on the current state of the component. Below is a component that slides up in both the in/out transitions:
function SlideUp(props) {
const [direction, setDirection] = React.useState('up');
return (
<Slide
{...props}
direction={direction}
onEntered={() => setDirection('down')}
onExited={() => setDirection('up')}
/>
);
}
Usage
<SlideUp in={checked} mountOnEnter unmountOnExit>
{icon}
</SlideUp>
Live Demo

Showing a VisX graph inside a Semantic-UI-React Modal causes problems with z-index

I'm adding a VisX graph inside Semantic-UI-React Modal.
The graph by itself shows the tooltip, crosshair and series glyphs correctly:
But when it's in a modal, all those appear beneath the modal:
I can reconstruct the tooltip with a higher z-index in the component I supply for the renderTooltip property, but it's lacking the crosshair and series glyph:
As these elements are added to the DOM on hover, it's impossible for me to catch them int he devtools and see what styles they have and inherit.
Is there some way I can set their z-index or fix this in some other way?
const Visx: FC = () => {
return (
<Modal open>
<Modal.Content>
<XYChart width={900} height={500} xScale={{ type: 'time' }} yScale={{ type: 'linear' }}>
<Grid rows numTicks={maxCount + 1} />
<Axis
orientation="left"
label="Play count"
numTicks={maxCount + 1}
tickFormat={(value) => {
return value;
}}
/>
<Axis orientation="bottom" label="Date" />
<LineSeries dataKey="plays" data={data} {...accessors} />
<Tooltip
showHorizontalCrosshair
showVerticalCrosshair
snapTooltipToDatumX
snapTooltipToDatumY
showSeriesGlyphs
showDatumGlyph
renderTooltip={({ tooltipData }) => {
const datum = tooltipData.nearestDatum?.datum as DataPoint | null;
return (
<div>
{datum?.count || 'no'} plays on {moment(datum?.date).format('MMM D, YYYY')}
</div>
);
}}
/>
</XYChart>
</Modal.Content>
</Modal>
);
};
Fixed it by adding this global CSS style:
.visx-tooltip {
z-index: 9999; /* or whatever height is appropriate */
}

How to make the Collapse position to bottom-right after clicking on expand icon in AntD

I am using AntD Collapse for displaying a list of items after expand icon is clicked.
I want the position of expandIcon to go to bottom-right after all the list of the data when expand icon is clicked (just like in google news), but found only two options (left|right) for 'expandIconPosition', no option for top or bottom.
How can we align the expandIcon to bottom-right, when expand icon is clicked?
Few lines from the code for reference:
<Collapse
ghost
style={{ marginTop: "-1vh" }}
expandIcon={({ isActive }) => (
<DownOutlined
style={{ marginTop: "-2vh" }}
rotate={isActive ? 180 : 0}
/>
)}
expandIconPosition="right"
>
<Panel>
<div>
{list()} //list of items
</div>
</Panel>
</Collapse>
Here's one possible solution. Make Collapse a controlled component by specifying activeKey prop and then the value of it will be based on state. Then, by tracking the activeKeys state you can now do a conditional rendering (hide and show) on icons:
const [activePanelKeys, setActivePanelKeys] = useState([]);
const handlePanelIconClick = (panelKey, makeActive) => {
if (makeActive) {
setActivePanelKeys([...activePanelKeys, panelKey]);
} else {
setActivePanelKeys(activePanelKeys.filter((aPK) => aPK !== panelKey));
}
};
<Collapse
activeKey={activePanelKeys}
expandIconPosition="right"
expandIcon={() => <DownOutlined />}
// expandIcon={(panelProps) => (
// <DownOutlined
// onClick={() => handlePanelIconClick(panelProps.panelKey, true)}
// />
// )}
onChange={e => setActivePanelKeys(e)} //if you want to click only icon, comment this and uncomment the above expandedIcon
>
<Panel
header="This is panel header 1"
key="p1"
showArrow={activePanelKeys.indexOf("p1") === -1}
>
<div>{text}</div>
{activePanelKeys.indexOf("p1") !== -1 && (
<div style={{ textAlign: "right", marginTop: 10 }}>
<UpOutlined onClick={() => handlePanelIconClick("p1", false)} />
</div>
)}
</Panel>
{/* <PanelContent header="This is panel header 2" key="p2">
{text}
</PanelContent> */}
</Collapse>;
Here is the complete sample code:
Note: I tried to make a reusable Panel component but it seems that the reveal animation were gone. You can uncomment the commented PanelContent on the code to see the difference.
Hope that I hit what you want.

Is there a way to use <Collapse> as my Transition component while using the <Popper> component to display a Menu onHover?

The following question is regarding React and Material-UI:
I am trying to use the <Collapse> transition component when displaying my <Menu> onMouseEnter. However, there seems to be an issue in the Material-UI library when it comes to the way the <Collapse> component and the <Popper> / <Popover> component. The issue is currently open and can be seen here.
Has anyone found a good workaround for this? Basically, I am just hoping to have a subnav Menu appear when you hover over a link with this specific transition.
I have tried using the <Grow> component and the transition works just fine, but we specifically are trying to use the <Collapse> transition.
export const NavBarItem = ({ navItem }) => {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
function handleToggle() {
setOpen(prevOpen => !prevOpen);
}
function handleClose(event) {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
}
return (
<React.Fragment>
<Link className={classes.link} href={BASE_HOMEPAGE + navItem.path}>
<Typography
className={classes.title}
ref={anchorRef}
aria-controls="menu-list-grow"
aria-haspopup="true"
onMouseEnter={handleToggle}
onMouseLeave={handleToggle}
>
{navItem.title}
</Typography>
</Link>
<Popper
open={open}
anchorEl={anchorRef.current}
onMouseEnter={handleToggle}
onMouseLeave={handleToggle}
transition
disablePortal
placement="bottom-start"
>
<Collapse in={open}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={handleClose}>
<MenuList className={classes.paperMenu}>
{navItem.menuItems.map(item => (
<Link
className={classes.link}
href={
item.external ? item.path : BASE_HOMEPAGE + item.path
}
>
<MenuItem
className={classes.paperMenuItem}
onClick={handleClose}
>
{item.text}
</MenuItem>
</Link>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Collapse>
</Popper>
</React.Fragment>
);
};
The code shown above is for a specific NavItem in a NavComponent. It is essentially just a dropdown component to show a subnav when you hover over a specific link.
Thank you for your help and please let me know if you need anymore additional information.
You can try to use the TransitionProps given by the Popper when using the transition props, as shown in the documentation
<Popper id={id} open={open} anchorEl={anchorEl} transition>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
<div className={classes.paper}>The content of the Popper.</div>
</Fade>
)}
</Popper>
For smoother UI you can also use the keepMounted property in Popper:
<Popper id={id} open={open} anchorEl={anchorEl} transition keepMounted>

Resources