Multistage transitions in react spring - react-spring

I have a react-spring Transition starts when the component mounts. I want it to wait for 'x' seconds when enter is complete, then flip the show state so it can start leave.
<Transition
items={show}
from={{ ...styles, position: "absolute", opacity: 0 }}
enter={{ opacity: 1 }}
leave={{ opacity: 0 }}
>
{show => show && (props => <div style={props}>{content}</div>)}
</Transition>

You must put the timeout to the componentDidMount lifecycle method. So it shows your content and the after 1 second it fades out and unmouts it. Do you need something like it?:
class App extends React.Component {
state = {
show: true
};
componentDidMount() {
setTimeout(() => this.setState({ show: false }), 1000);
}
render() {
const { show } = this.state;
const content = <div>eeeeeeeee</div>;
return (
<div className="App">
<Transition
items={[show]}
from={{ position: "absolute", opacity: 0 }}
enter={{ opacity: 1 }}
leave={{ opacity: 0 }}
>
{show =>
show &&
(props => <animated.div style={props}>{content}</animated.div>)
}
</Transition>
</div>
);
}
}
https://codesandbox.io/s/keen-almeida-5wlk7

Related

Change the background color of the draggable allotment pane

I have made a draggable split panel by https://github.com/johnwalley/allotment.
I would like to make the background of the pane below green. But after dragging the split, the background color is not systematically updated in that area.
Does anyone know how to amend the code to achieve that?
https://codesandbox.io/s/reset-forked-rfifun?file=/src/App.js
import React from "react";
import { Allotment } from "allotment";
import "allotment/dist/style.css";
import styles from "./App.module.css";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
toExpand: true
};
this.myRef = React.createRef();
}
handleChange = (sizes) => {
if (sizes.length > 1) {
if (sizes[1] < 31) {
this.setState({ toExpand: true });
} else {
this.setState({ toExpand: false });
}
}
};
render() {
return (
<div>
<div className={styles.container}>
<Allotment vertical onChange={this.handleChange} ref={this.myRef}>
<Allotment.Pane>Main Area</Allotment.Pane>
<Allotment.Pane preferredSize="0%">
<div
style={{ backgroundColor: "green" }}
onClick={() => {
if (this.state.toExpand) {
this.myRef.current.resize([50, 50]);
} else {
this.myRef.current.resize([10000, 0]);
}
}}
>
Console
{this.state.toExpand ? "ArrowUp" : "ArrowDown"}
</div>
</Allotment.Pane>
</Allotment>
</div>
</div>
);
}
}
It seems that the content div can be set to take full height of the panel:
Forked demo with modification: codesandbox
<Allotment.Pane preferredSize="0%">
<div
// 👇 Set the content div to take full height
style={{ backgroundColor: "green", height: "100%" }}
onClick={() => {
if (this.state.toExpand) {
this.myRef.current.resize([50, 50]);
} else {
this.myRef.current.resize([10000, 0]);
}
}}
>
Console
{this.state.toExpand ? "ArrowUp" : "ArrowDown"}
</div>
</Allotment.Pane>;

React prevent css animation restarting every state change

I have two child components, an image gallery and a hidden components which will display the clicked image of the gallery at full size.
const [selectedIndex, setSelectedtIndex] = useState(0);
const [galleryVisible, setGalleryVisible] = useState(false);
const FirstComponent = () => {
return (
<div className={'gallery-container'}>
<div class='img fade-1' onClick={() => handleClick(1)}>Image 1</div>
<div class='img fade-2' onClick={() => handleClick(2)}>Image 2</div>
<div class='img fade-3' onClick={() => handleClick(3)}>Image 3</div>
[...]
</div>
)
}
const handleClick = (index) => {
setSelectedtIndex(index)
setGalleryVisible(true)
}
const SecondComponent = ({ index }) => {
return (
<div className={`selected-img`}>Selected : {index} (But the fading animation shouldn't restart è_é)</div>
)
}
return (
<>
<FirstComponent/>
{galleryVisible &&
<SecondComponent index={selectedIndex} />
}
</>
)
The issue is that I also have a fade-in animation on the first component, and every time I click on an image to display the second component, that animation resets due to the rerender of react on state change.
&.fade-1 {
animation-delay: 0s
}
&.fade-2 {
animation-delay: 0.5s
}
&.fade-3 {
animation-delay: 1s
}
I don't know how can I only change the second component when the state is changed from a click on the first one... I tried to play with useMemo but couldn't get it to work.
Here is a codepen reproducing the issue : https://codepen.io/disgallion/pen/zYjqPBE
Move the first component outside of App and pass handleClick to its props:
const FirstComponent = ({handleClick}) => {
return (
<div className={'gallery-container'}>
<div class='img fade-1' onClick={() => handleClick(1)}>1</div>
<div class='img fade-2' onClick={() => handleClick(2)}>2</div>
<div class='img fade-3' onClick={() => handleClick(3)}>3</div>
</div>
)
}
const App = () => {
const [selectedIndex, setSelectedtIndex] = useState(0);
const [galleryVisible, setGalleryVisible] = useState(false);
const handleClick = (index) => {
console.log('click')
setSelectedtIndex(index)
setGalleryVisible(true)
}
const SecondComponent = ({ index }) => {
return (
<div className={`selected-img`}>Selected : {index} (But the fading animation shouldn't restart è_é)</div>
)
}
return (
<>
Click on an image to open the fullsize gallery:
<FirstComponent handleClick={handleClick} />
{galleryVisible &&
<SecondComponent index={selectedIndex} />
}
</>
)
}
ReactDOM.render(<App />,
document.getElementById("root"))
Now the state change of App will not trigger a re-render in FirstComponent

Change color of bottom border and dropdown arrow in Material UI Autocomplete

I want to make the line underneath 'Search' and the arrow on the right white but I can't figure out how to do it for the life of me. I've tried using styled on the .MuiAutocomplete-root css class but it didn't work. I can't figure out which CSS class to apply the color to. If I inspect it, it says that the class is MuiInput-root which I also tried with styled and that didn't work either.
Thanks
My code (copy pasted from the docs with some minor adjustments):
function sleep(delay = 0) {
return new Promise((resolve) => {
setTimeout(resolve, delay);
});
}
export default function AutocompleteSearch() {
const [open, setOpen] = useState(false);
const [options, setOptions] = useState([]);
const loading = open && options.length === 0;
useEffect(() => {
let active = true;
if (!loading) {
return undefined;
}
(async () => {
await sleep(1e3); // For demo purposes.
if (active) {
//api call then setOptions
}
})();
return () => {
active = false;
};
}, [loading]);
useEffect(() => {
if (!open) {
setOptions([]);
}
}, [open]);
return (
<Autocomplete
id="size-small-standard"
size="small"
sx={{
width: 300,
}}
open={open}
onOpen={() => {
setOpen(true);
}}
onClose={() => {
setOpen(false);
}}
isOptionEqualToValue={(option, value) => option.title === value.title}
getOptionLabel={(option) => option.title}
options={options}
groupBy={(option) => option.type}
loading={loading}
renderInput={(params) => (
<TextField
{...params}
variant="standard"
label="Search"
//makes label white
InputLabelProps={{
style: {color: '#fff'},
}}
InputProps={{
...params.InputProps,
//makes the selected option white when added to the box
sx: {color: '#fff'},
endAdornment: (
<>
{loading ? <CircularProgress color="inherit" size={20}/> : null}
{params.InputProps.endAdornment}
</>
),
}}
/>
)}
/>
);
}
Add color to the following CSS classes.
.MuiSvgIcon-root {
color: white;
}
.css-ghsjzk-MuiInputBase-root-MuiInput-root:before {
border-bottom-color: white !important;
}
.css-ghsjzk-MuiInputBase-root-MuiInput-root:after {
border-bottom-color: white !important;
}
Play around with the code here
I used red color in my codesandbox example so that it can be visible on white screen

Is there a way to update the children before the framer motion disassembles the items?

I would like to update the content and the border before the element dismounts.
https://codesandbox.io/s/agitated-cerf-siq8e?file=/src/App.js
You are never allowing the content to change as you are testing for true only:
{isOpen && (
The value will never be false within the component.
You can simplify the example by removing AnimatedPresense and introducing useCycle to cycle efficiently between animation variants.
import { motion, useCycle } from "framer-motion";
import * as React from "react";
const variants = {
open: {
height: "auto" ,
transition: { duration: 0.8, ease: "easeInOut" }
},
collapsed: {
height: 0 ,
transition: { duration: 0.8, ease: "easeInOut" }
}
}
export default function App() {
const [variant, toggleVariant] = useCycle('open', 'collapsed');
return (
<div className="App">
<motion.section
style={{ overflow: "hidden" }}
variants={variants}
animate={variant}
>
<div
style={{
border: `5px solid ${variant === 'open' ? "red" : "blue"}`,
height: 100
}}
>
{variant}
</div>
</motion.section>
<button onClick={toggleVariant}>
{variant === 'open' ? 'collapse me': 'expand me'}
</button>
</div>
);
}
Codesandbox

Save function not re-rendering while creating block

Save function while creating a block is not re-rendering in the front end. I made a component for the save which should re-render on state change but it is not. Edit function is working fine for admin.
Basically the setState function is not working for me.
I tried to enqueue the style but it also didn't worked for me.
My Save.js :
const { Component } = wp.element;
import './MyCss.css';
const { Icon } = wp.components;
import unsplash from './unsplash';
export class Save extends React.Component {
constructor(props) {
super(props)
this.state = {
images: [],
currentIndex: 0,
translateValue: 0,
translateValueSmall: 0
}
}
async componentDidMount(){
const response = await unsplash.get('/search/photos',{
params:{query: "cat"},
});
response.data.results.map(result=>{
this.setState(prevState => ({
images: [...prevState.images, result.urls.thumb]
}))
});
}
goToPrevSlide(){
console.log("previous slide");
if(this.state.currentIndex === 0)
return;
this.setState(prevState => ({
currentIndex: prevState.currentIndex - 1,
translateValue: prevState.translateValue + this.slideWidth(),
translateValueSmall: prevState.translateValueSmall + this.slideWidthSmall()/2
}))
}
goToNextSlide(){
if(this.state.currentIndex === this.state.images.length - 1) {
return this.setState({
currentIndex: 0,
translateValue: 0,
translateValueSmall: 0
})
}
this.setState(prevState => ({
currentIndex: prevState.currentIndex + 1,
translateValue: prevState.translateValue + -(this.slideWidth()),
translateValueSmall: prevState.translateValueSmall + -(this.slideWidthSmall())/2
}));
}
slideWidth(){
return document.querySelector('.slide').clientWidth
}
slideWidthSmall(){
return document.querySelector('.sliders').clientWidth
}
render() {
return (
<div className="box" onClick={()=>this.goToPrevSlide()}>
<div className="slider">
<div className="slider-wrapper"
style={{
transform: `translateX(${this.state.translateValue}px)`,
transition: 'transform ease-out 0.95s'
}}>
{
this.state.images.map((image, i) => (
<Slide key={i} image={image} />
))
}
</div>
</div>
<div className="sliders">
<LeftArrow
goToPrevSlide={()=>this.goToPrevSlide()}
/>
<RightArrow
goToNextSlide={()=>this.goToNextSlide()}
/>
<div className="chaitali"
style={{
transform: `translateX(${this.state.translateValueSmall}px)`,
transition: 'transform ease-out 0.95s'
}}>
{
this.state.images.map((image, i) => (
<Slide key={i} image={image} />
))
}
</div>
</div>
</div>
);
}
}
const Slide = ({ image }) => {
const styles = {
backgroundImage: `url(${image})`,
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundPosition: '50% 60%'
}
return <div className="slide" style={styles}></div>
}
const LeftArrow = (props) => {
return (
<div onClick={props.goToPrevSlide}>
<Icon className="back arrow" icon="arrow-left"/>
</div>
);
}
const RightArrow = (props) => {
return (
<div onClick={props.goToNextSlide}>
<Icon className="next arrow" icon="arrow-right"/>
</div>
);
}

Resources