Rotate Image on hover fails - javascript

I have the working example for rotating an image on hover here
It uses scale(), rotate() and transition properties when hovering over the parent element to animate the image.
And overflow: hidden on the parent element to hide the excess from the image transformation.
When I try to replicate the same effect on React I see the image but the image does not rotate when i hover. But its all the same? What am I missing here?
import React from 'react';
import { Box } from '#mui/material';
import Image from 'mui-image';
const styles = {
hoverRotate: {
overflow: 'hidden',
margin: '8px',
minWidth: '240px',
maxWidth: '320px',
width: '100%',
},
'hoverRotate img': {
transition: 'all 0.3s',
boxSizing: 'border-box',
maxWidth: '100%',
},
'hoverRotate:hover img': {
transform: 'scale(1.3) rotate(5deg)',
},
};
function Rotate() {
return (
<Box style={styles.hoverRotate}>
<Image src="https://picsum.photos/id/669/600/800.jpg" />
</Box>
);
}
export { Rotate };

This way of styling doesn't detect hovers, hence use useState to set the hover state of the image (import it using import { useState } from "react";)
const [isHover, setIsHover] = useState(false);
Now, check if the Box is hovered or not, if hovered, set isHover to true, if not hovered, set it to false.
<Box
style={styles.hoverRotate}
onMouseEnter={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
>
{/* code */}
</Box>
Move your styles into the Rotate function. You are not assigning the key "hoverRotate img" to any of the styles hence it doesn't get applied. So change its name to something like image and add the hover code conditionally to it as shown below. The reason for moving styles into the Rotate function so that isHover stays in scope to get it's value.
const styles = {
hoverRotate: {
overflow: "hidden",
margin: "8px",
minWidth: "240px",
maxWidth: "320px",
width: "100%"
},
image: {
transition: "all 0.3s",
boxSizing: "border-box",
maxWidth: "100%",
transform: isHover && "scale(1.3) rotate(5deg)"
}
};
Finally, set the image style to Image
<Image
src="https://picsum.photos/id/669/600/800.jpg"
style={styles.image}
/>
Checkout this sandbox: https://codesandbox.io/s/distracted-matan-c43ufb?file=/src/App.js:829-928

With the new #mui/system styling solution (sx prop), you just need to pass the styles object to the sx prop:
import React from "react";
import { Box } from "#mui/material";
const boxSx = {
overflow: "hidden",
margin: "8px",
minWidth: "240px",
maxWidth: "320px",
width: "100%",
"& > img": {
transition: "all 0.3s",
boxSizing: "border-box",
maxWidth: "100%"
},
"&:hover > img": {
transform: "scale(1.3) rotate(5deg)"
}
};
function Rotate() {
return (
<Box sx={ boxSx }>
<img src="https://picsum.photos/id/669/600/800.jpg" />
</Box>
);
}
export { Rotate };
If you are missing the old #mui/styles (now deprecated) styling solution, you are missing makeStlyes, and then passing the resulting styles to the className prop:
import React from "react";
import Box from "#material-ui/core/Box";
import makeStyles from "#material-ui/core/styles/makeStyles";
const useStyles = makeStyles({
hoverRotate: {
overflow: "hidden",
margin: "8px",
minWidth: "240px",
maxWidth: "320px",
width: "100%",
"& > img": {
transition: "all 0.3s",
boxSizing: "border-box",
maxWidth: "100%"
},
"&:hover > img": {
transform: "scale(1.3) rotate(5deg)"
}
}
});
function Rotate() {
const styles = useStyles();
return (
<Box className={ styles.hoverRotate }>
<img src="https://picsum.photos/id/669/600/800.jpg" />
</Box>
);
}
export { Rotate };

Related

How do I get an animated gradient working with an icon in Javascript?

I'm trying to get an icon to change color from the bottom up.
I was able to accomplish the desired results with normal text but the icon just goes invisible (or whatever color you set with color) instead of having a gradient fill.
I've tried various solutions from other posts but for whatever reason they have not worked out for me.
In the example code below, this color change should happen when the button is clicked.
import "./styles.css";
import React from "react";
import { FaHourglass } from "react-icons/fa";
import { Button, styled } from "#mui/material";
import clsx from "clsx";
export default function App() {
const [fill, setFill] = React.useState(false);
const handleClick = () => {
setFill(!fill);
};
return (
<Root className="App">
<FaHourglass
id="fillThisIcon"
className={clsx({ icon: true, iconFill: fill })}
/>
<Button variant="contained" onClick={handleClick}>
Press to fill
</Button>
<b className={clsx({ icon: true, iconFill: fill })}>TESTING</b>
</Root>
);
}
const Root = styled("div")(({ theme }) => ({
width: "100%",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
gap: 10,
"& > .icon": {
fontSize: 100,
color: "LightGrey"
},
"& > .iconFill": {
fontSize: 100,
color: "transparent",
animation: "fillIcon infinite",
animationDuration: "5s",
animationTimingFunction: "ease-out",
backgroundImage: "linear-gradient(to top, SandyBrown 50%, LightGrey 50%)",
backgroundSize: "100% 200%",
backgroundPosition: "0% 0%",
backgroundClip: "text"
},
"#keyframes fillIcon": {
"0%": {
backgroundPosition: "0% 0%"
},
"100%": {
backgroundPosition: "0% 100%"
}
}
}));

remove MUI Accordion gap when expanded

I'm trying to have the Accordion MUI component NOT move and NOT apply top and bottom margins to summary elements while it is in the expanded mode. I add this code to the summary element but that's not working. what do you offer me? it worth mentioning that it works on the first accordion but not the others!!!!!!!!!!
sx={{
"&.Mui-expanded": {
minHeight: 0,
margin: '12px 0',
},
"& .MuiAccordionSummary-content.Mui-expanded": {
margin: 0,
}
}}
I used MUI customized accordion and I change its setting to it:
I used my icon. it has a white background and no border and additional padding or margin :))))
export const Accordion = styled((props: AccordionProps) => (
<MuiAccordion disableGutters elevation={0} square {...props} />
))(({ theme }) => ({
position: 'unset',
border: 'none',
boxShadow: 'none',
maxWidth: 720,
margin: '12 0',
'&:before': {
display: 'none',
border: 'none'
}
}));
export const AccordionSummary = styled((props: AccordionSummaryProps) => (
<MuiAccordionSummary expandIcon={<ExpandMoreIcon />} {...props} />
))(({ theme }) => ({
backgroundColor: 'white',
padding: 0,
flexDirection: 'row',
'& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': {
transform: 'rotate(180deg)'
}
}));
export const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({
padding: 0,
border: 'none'
}));
export const FAQText = styled(Typography)({
maxWidth: 628
});
Are you setting this prop on Accordion or AccordionSummary? I've tested your code on StackBlitz by setting it on Accordion element and it worked properly.

How to change material-ui slider thumb style when it's disabled

I am able to modify the Slider style using withStyles:
const CustomSlider = withStyles(theme => ({
disabled: {
color: theme.palette.primary.main
},
thumb: {
height: 24,
width: 24,
},
}))(Slider);
but the height and width of the thumb is only applied when the component is disabled={false}.
is there a simple way to change the slider height and width on disabled={true}?
Demo:
https://codesandbox.io/s/slide-thumb-size-gxb4g?file=/demo.js
Reason
The style is been overridden by className Mui-disabled
You can see the color will keep.
How to solve it
Override the style of MuiSlider-thumb or Mui-disabled
One option: use MUI className nesting selector
"& .MuiSlider-thumb": {
height: 24,
width: 24
}
Notice withStyles attributes refer to the CSS API, you can use className + style hooks instead to customize the className which is not exposed by the CSS API like that
Full code:
import React from "react";
import Slider from "#material-ui/core/Slider";
import Paper from "#material-ui/core/Paper";
import { withStyles, makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles(theme => ({
margin: {
margin: theme.spacing(10),
"& .MuiSlider-thumb": {
height: 24,
width: 24
}
}
}));
const CustomSlider = withStyles(theme => ({
disabled: {
color: theme.palette.primary.main
},
thumb: {
// color: "red"
}
}))(Slider);
export default function MyCustomSlider() {
const classes = useStyles();
return (
<div>
<Paper className={classes.margin}>
<CustomSlider
defaultValue={[10, 15]}
min={0}
max={20}
valueLabelDisplay="on"
disabled={true}
/>{" "}
<CustomSlider
defaultValue={[5, 7]}
min={0}
max={20}
valueLabelDisplay="on"
disabled={false}
/>{" "}
</Paper>
</div>
);
}
Update
For withStyles
const styles = theme =>
createStyles({
margin: {
margin: theme.spacing(10)
},
thumb: {
"& .MuiSlider-thumb": {
height: 24,
width: 24
}
}
});
function MyCustomSlider(props) {
// const classes = useStyles();
return (
<div>
<Paper className={props.classes.margin}>
<Slider
defaultValue={[10, 15]}
min={0}
max={20}
valueLabelDisplay="on"
disabled={true}
className={props.classes.thumb}
/>{" "}
<Slider
defaultValue={[5, 7]}
min={0}
max={20}
valueLabelDisplay="on"
disabled={false}
/>{" "}
</Paper>
</div>
);
}
export default withStyles(styles)(MyCustomSlider);
disabled: {
"& .MuiSlider-thumb ": {
display: "none",
},
"& .MuiSlider-track": {
backgroundColor: "#e0e0e0",
},
},
This is withStyle solution , where user can change the styling of slider and its sub component.

Set background color of Material UI Snackbar

When I set a className to change the background of Snackbar it does not overwrite it. Instead, when the page renders it momentarily displays the background color that I want and then is immediately overwritten.
I looked at some other Stackoverflow answers and I still can't get it working.
// imports....
import Snackbar from '#material-ui/core/Snackbar';
import createClientsStyle from "../../../PageComponents/Landing/CreateClients/style";
function CreateClients(props) {
//....code
const { classes } = props;
return (
//............code
<div>
<Snackbar
className={classes.snackbarStyle} //<--- here
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={true}
autoHideDuration={6000}
ContentProps={{
'aria-describedby': 'message-id',
}}
message={<span id="message-id"><div>Hi there! Some message.</div></span>}
/>
</div>
);
}
CreateClients.propTypes = {
classes: PropTypes.object.isRequired
}
const styles = (theme)=>(createClientsStyle(theme));
export default withStyles(styles)(CreateClients)
Stylesheet
const createClientsStyle = function(theme){
return {
root: {
flexGrow: 1,
position:"relative",
top:"175px"
},
logoContainer:{
position:"relative",
margin:"0 auto",
top:"120px"
},
container: {
marginTop:"0px",
padding: theme.spacing(2),
textAlign: 'center',
color: theme.palette.text.secondary,
},
clientItem:{
fontSize:"2em",
display:"inline-block",
textAlign:"center",
width:"100%",
color:"grey",
'&:hover': {
background: "#8a0eff3b",
transition: "0.4s"
},
},
clientItemSelected: {
background: "#8a0eff3b",
fontSize:"2em",
display:"inline-block",
textAlign:"center",
color:"grey",
'&:hover': {
background: "#8a0eff3b",
transition: "0.4s"
},
},
textField:{
width:"25em",
},
listItem:{
fontSize:'35px',//Insert your required size
},
clientButton:{
backgroundColor:"purple"
},
tinyTextClickMe:{
position:"relative",
fontSize:"0.5em",
right:"10%"
},
snackbarStyle:{
backgroundColor:"orange"
}
}
}
export default createClientsStyle
The Snackbar component handles open/close state, transitions, and positioning, but Snackbar delegates control of the look of the Snackbar (e.g. background color, typography, padding) to the SnackbarContent component.
If you look at the Customized snackbars demo, you'll see that it changes the background color by specifying a className on the SnackbarContent element rather than on the Snackbar element. You can also achieve the same effect by specifying the className within the ContentProps.
The example below demonstrates both approaches for specifying the class name for the content.
import React from "react";
import ReactDOM from "react-dom";
import Snackbar from "#material-ui/core/Snackbar";
import SnackbarContent from "#material-ui/core/SnackbarContent";
import { withStyles } from "#material-ui/core/styles";
const styles = {
snackbarStyleViaContentProps: {
backgroundColor: "orange"
},
snackbarStyleViaNestedContent: {
backgroundColor: "lightgreen",
color: "black"
}
};
function App({ classes }) {
return (
<div>
<Snackbar
anchorOrigin={{
vertical: "top",
horizontal: "right"
}}
open={true}
ContentProps={{
"aria-describedby": "message-id",
className: classes.snackbarStyleViaContentProps
}}
message={
<span id="message-id">
<div>Hi there! Some message.</div>
</span>
}
/>
<Snackbar
anchorOrigin={{
vertical: "bottom",
horizontal: "right"
}}
open={true}
>
<SnackbarContent
aria-describedby="message-id2"
className={classes.snackbarStyleViaNestedContent}
message={
<span id="message-id2">
<div>Hi there! Message 2.</div>
</span>
}
/>
</Snackbar>
</div>
);
}
const StyledApp = withStyles(styles)(App);
const rootElement = document.getElementById("root");
ReactDOM.render(<StyledApp />, rootElement);

Inline styles and ReactCSSTransitionGroup

I it possible to use ReactCSSTransitionGroup from react-addons-css-transition-group with React inline styles? If so, how?
The component I'm working on:
import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import { removeNotification } from '../actionCreators'
import Notification from './Notification'
const mapStateToProps = state => ({
notifications: state.notifications
})
const mapDispatchToProps = dispatch => ({
actions: bindActionCreators({ removeNotification }, dispatch)
})
class Notifications extends Component {
render() {
var style = {
position: 'fixed',
top: 20,
right: 20,
width: 300,
zIndex: 99
}
var tstyle = {
'notification-enter': {
visibility: 'hidden',
transform: 'translate3d(100%,0,0)'
},
'notification-leave': {
visibility: 'visible',
transform: 'translate3d(0,0,0)'
},
'notification-enter-notification-enter-active': {
visibility: 'visible',
transform: 'translate3d(0,0,0)',
transition: 'all 0.4s'
},
'notification-leave-notification-leave-active': {
visibility: 'hidden',
transform: 'translate3d(100%,0,0)',
transition: 'all 0.4s'
}
}
return (
<ul style={style}>
<ReactCSSTransitionGroup
style={tstyle}
transitionName='notification'
transitionEnterTimeout={400}
transitionLeaveTimeout={400}>
{this.props.notifications.map((notification, index) => {
return <Notification
key={index}
type={notification.type}
message={notification.message}
timeout={10000}
remove={this.props.actions.removeNotification} />
})}
</ReactCSSTransitionGroup>
</ul>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Notifications)
ReactCSSTransitionGroup is not compatible with inline styles because it adds or removes class names to/from DOM nodes to trigger the transitions. But you can use ReactTransitionGroup to make your own component that does the same thing ReactCSSTransitionGroup does, but with inline styles.
If you don't want to develop your own, you can use one that I wrote some time ago installing it with npm: ReactInlineTransitionGroup.
It has some advantages over ReactCSSTransitionGroup, like the fact that you can write your CSS transitions and not worry about setting timeout properties in the component, and that you can pass callbacks to check when a child entered or left your group.
DO THIS
style={{
// flex: over ? 1 : null,
display: 'flex',
width: wide ? 400 : null,
paddingBottom: wide ? 500 : null,
border: over ? '4px solid greenyellow' : null,
borderRadius: wide ? 30 : null,
paddingVertical: over ? 500 : null,
background: over ? 'black' : 'white',
transition:
'background 500ms',
cursor: 'pointer',
}}
Or if you wanna get multiple properties
style={{
display: 'flex',
width: wide ? 400 : null,
paddingBottom: wide ? 500 : null,
border: over ? '4px solid greenyellow' : null,
borderRadius: wide ? 30 : null,
paddingVertical: over ? 500 : null,
background: over ? 'black' : 'white',
transition:
'background 500ms, padding 500ms, width 500ms, border 500ms',
cursor: 'pointer',
}}

Categories

Resources