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',
}}
Related
I am making a basic drop down menu in React. I am new to React and have managed to get to where the menu opens on click and such. What I would like to do is change the background of each choice to a different color only when the mouse is hovered over that specific element.
Right now the issue is that every element is highlighted when one is hovered over. I understand this is because I am changing the state which effects every element, but I cant wrap my mind around how to implement it how I would like it. Perhaps there is a React concept(s) I am unaware of that would make this easier.
Here is my code so far:
App.jsx file
import React from "react";
import InnerDiv from './components/InnerDiv';
import CountiesList from "./components/countiesList";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
menuIsOpen: false,
height: '50px'
}
this.handleClick = this.handleClick.bind(this)
}
handleClick = () => {
if (this.state.menuIsOpen == false) {
this.setState(state => ({
menuIsOpen: !state.menuIsOpen,
height: '350px'
}))
} else {
this.setState(state => ({
menuIsOpen: !state.menuIsOpen,
height: '50px'
}))
}
}
render() {
const divStyle = {
height: this.state.height,
width: '300px',
border: '2px solid cornflowerblue',
borderRadius: '12px',
position: 'absolute',
top: '50px',
left: '50px',
cursor: 'pointer',
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
alignItems: 'center',
transition: 'all 0.1s linear',
}
return (
<div onClick={this.handleClick} style={divStyle} className="App">
<InnerDiv/>
<CountiesList/>
</div>
);
}
}
export default App;
InnerDiv.jsx file
import React from "react";
const innerDivStyle = {
height: '50px',
width: '90%',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between'
}
const h1Style = {
fontSize: '20px',
WebkitTouchCallout: 'none',
WebkitUserSelect: 'none',
khtmlUserSelect: 'none',
MozUserSelect: 'none',
msUserSelect: 'none',
UserSelect: 'none'
}
const svgStyle = {
height: '30px'
}
class InnerDiv extends React.Component {
constructor(props) {
super(props);
}
render(){
return (
<div style={innerDivStyle} className="InnerDiv">
<h1 style={h1Style}>Select A Location</h1>
<svg style={svgStyle} xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 122.88 122.88"><title>round-line-bottom-arrow</title><path d="M122.85,61.45h0A61.39,61.39,0,0,0,61.45,0V0h0V0A61.38,61.38,0,0,0,0,61.43H0v0H0a61.35,61.35,0,0,0,61.4,61.38v0h0v0a61.34,61.34,0,0,0,61.38-61.4ZM61.44,91,33.92,60.47H51.5V39.2H71.38V60.47H89L61.44,91Zm48.28-29.54h0a48.36,48.36,0,0,1-48.27,48.29v0h0v0A48.35,48.35,0,0,1,13.14,61.47h0v0h0A48.27,48.27,0,0,1,61.41,13.14v0h0v0a48.3,48.3,0,0,1,48.27,48.3Z"/></svg>
</div>
)
}
}
export default InnerDiv;
countiesList.jsx file
import React from "react";
class CountiesList extends React.Component {
constructor(props) {
super(props);
this.state = {
counties: [
'Antrim',
'Armagh',
'Carlow',
'Cavan',
'Clare',
'Cork',
'Derry',
'Donegal',
'Down',
'Dublin',
'Fermanagh',
'Galway',
'Kerry',
'Kildare',
'Kilkenny',
'Laois',
'Leitrim',
'Limerick',
'Longford',
'Louth',
'Mayo',
'Meath',
'Monaghan',
'Offaly',
'Roscommon',
'Sligo',
'Tipperary',
'Tyrone',
'Waterford',
'Westmeath',
'Wexford',
'Wicklow'
],
backgroundColor: '#a9c4f5'
};
this.updateBackgroundColor = this.updateBackgroundColor.bind(this);
this.reverseBackgroundColor = this.reverseBackgroundColor.bind(this);
}
updateBackgroundColor() {
this.setState({backgroundColor: 'cornflowerblue'})
}
reverseBackgroundColor() {
this.setState({backgroundColor: '#a9c4f5'})
}
render() {
const ulStyle = {
listStyleType: 'none',
paddingInlineStart: 0,
margin: 0,
width: '100%',
height: '300px',
overflowY: 'scroll',
borderBottomLeftRadius: '12px'
}
const liItemContainer = {
height: '50px',
paddingLeft: '15px',
display: 'flex',
alignItems: 'center',
background: this.state.backgroundColor,
}
const liStyle = {
fontWeight: '700'
}
let countiesListItems = this.state.counties.map(county => {
return (
<div key={county} style={liItemContainer} onMouseEnter={this.updateBackgroundColor} onMouseOut={this.reverseBackgroundColor}>
<li style={liStyle}>{county}</li>
</div>
)
})
return (
<ul style={ulStyle}>
{countiesListItems}
</ul>
)
}
}
export default CountiesList;
Thank you for your help in advance
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 };
I have a js file handling my css where I am trying to change the value of an object, but the value stays the same.
let inputBoxInner = {
width: "80%",
marginTop: 5,
alignItems: "center",
color: "#397185",
cursor: "text",
height: 36,
border: "1px solid #80cfc6",
visibility: "visible",
opacity: 0.2,
setOpacity: function (e) {
this.opacity = e
};
};
module.exports = {
inputBoxInner
};
import React, {Component} from "react";
import {inputBoxInner} from "../css/style.js";
export default class Input extends Component {
state = {
borderOpacity: 1,
id: ""
};
return(
<div
className="input"
onClick={(e) => {
inputBoxInner.setOpacity(this.state.borderOpacity);
this.setState({id: e.target.className});
}}
style={inputBoxInner}
/>
);
};
I assume the "this.opacity" is only returning a reference and not modifying the actual object and I am unsure of how to make this object mutable.
How would I go about changing this value?
You should save a clicked state in the state and set opacity depending on it.
state = {
borderOpacity: 1,
id: "",
isClicked: false
};
return(
<div
className="input"
onClick={(e) => { this.setState({id: e.target.className, isClicked: true }); }}
style={{...inputBoxInner, opacity: this.state.isClicked ?
this.state.borderOpacity : inputBoxInner.opacity}}
/>
);
I am working in react.js project using material-ui and sass.I need to create Component like ChatBit component then i wrote it as it published.
customComponent.js file.
// #flow
import * as React from 'react';
import { useState } from 'react';
import { Avatar} from "#material-ui/core";
import useStyle from './styles';
type Props = {
children: React.Node;
}
const AbsoluteBox = ({
children
}: Props) => {
const [toggled, setToggled] = useState(false);
const styles = useStyle();
const handleClick = () => {
setToggled(!toggled);
};
const contentStyle = `container__content_${toggled ? 'show': 'hide'}`;
return (
<div className={styles.container__bottomRight}>
<div className={styles.container__header} onClick={handleClick}>
<Avatar
variant="rounded"
src="/assets/images/rebots.svg"
className={styles.container__header__avatar}
/>
</div>
<div
className={styles[contentStyle]}
>
{children}
</div>
</div>
);
};
export default AbsoluteBox;
styles.js file.
import { makeStyles } from '#material-ui/core';
export default makeStyles({
container__bottomRight: {
position: 'fixed',
right: 0,
bottom: 0,
marginRight: 12,
width: 300,
borderTopLeftRadius: 10,
borderTopRightRadius: 10,
boxShadow: '0px 0px 13px 0px rgba(0,0,0,0.51)'
},
container__header: {
paddingLeft: 10,
paddingTop: 4,
paddingBottom: 6,
backgroundColor: '#D7E0FC',
height: 38,
borderTopLeftRadius: 8,
borderTopRightRadius: 8,
cursor: 'pointer'
},
container__header__avatar: {
height: 40
},
container__content_hide: {
transition: 'height 400ms 400ms, opacity 400ms 0ms',
opacity: 0.0,
height: 0,
},
container__content_show: {
height: 400,
opacity: 1.0,
boxSizing: 'border-box',
transition: 'height 400ms 0ms, opacity 400ms 400ms',
},
});
then i call the Component like that:
<AbsoluteBox>
<h1>Hello World</h1>
</AbsoluteBox>
so the probleme which i found is when i open the box, everything is correct but when i need to close it, there white space which i don't where is it coming from.
The <h1> tag that you have inside the box has margin, which cause those issues (the margin is taking place even if the height of the contains is set to 0).
You can fix this by setting the margin-top of the h1 element to 0 (or using some other elements and style them accordingly).
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);