Animated button with React Spring - react-spring

I am coming from a React-pose background and like to try React-spring. I have a really simple case which I'd like to transfer to be used with React-spring.
I have the case written in a Codesanbox using React-pose, https://codesandbox.io/s/4wxzm60nk9
I've tried converting this myself, but I just end up confusing myself. Especially now when trying to do it with their hooks API. All help that I can get is super appriciated.
Thank you.

I just made an animated button yesterday, so I refactored it to change its size.
import React, {useState} from "react";
import { Spring, animated as a } from 'react-spring/renderprops';
const SpringButton = () => {
const [pressed, setPressed] = useState(false);
return (
<Spring native from={{scale: 1}} to={{scale: pressed? 0.8 : 1}}>
{({scale}) => (
<a.button
style={{
backgroundColor: 'red',
height: '100px',
width: '100px',
color: 'rgb(255, 255, 255)',
transform: scale.interpolate(scale => `scale(${scale})`)
}}
onMouseDown={() => setPressed(true)}
onClick={() => setPressed(false)}
onMouseLeave={() => setPressed(false)}
>
Click me
</a.button>
)}
</Spring>
);
}
Its not the hook interface yet, but I think it helps you to understand how it works. I t also uses the quicker native rendering. The event handling a bit different from react-pose. And you can tweek the config as well if you want the animation really springy.
import {config} from 'react-spring/renderprops';
<Spring config={config.wobbly} ...>
https://codesandbox.io/s/7zlrkv4kjj

Something like this probably: https://codesandbox.io/s/pyvo8mn5x0
function App() {
const [clicked, set] = useState(false)
const { scale } = useSpring({ scale: clicked ? 0.8 : 1 })
return (
<div className="App">
<animated.button
onMouseDown={() => set(true)}
onMouseUp={() => set(false)}
style={{
backgroundColor: 'red',
height: '100px',
width: '100px',
color: '#FFF',
transform: scale.interpolate(s => `scale(${s})`)
}}
children="Click me"
/>
</div>
)
}
You could also interpolate up-front if you like:
const props = useSpring({ transform: `scale(${clicked ? 0.8 : 1})` })
return <animated.button style={props} />
Unlike pose react-spring does not include gesture stuff, it choses to interface with 3rd party libs for that. For instance: https://github.com/react-spring/react-with-gesture

Related

How can I make a "squishy slide" animation in React / MUI?

I have a list of items. When I first load the page, I want them to slide in sequentially, one at a time, and then shrink slightly when they arrive at their final destination. (I've seen this animation in the past but I can't find an example and I have no idea what it's called; if anyone can find a link to an example, please post it.)
Here's my highly rudimentary attempt:
import {Button, Slide, Stack, StackProps} from '#mui/material'
import {Box} from '#mui/system'
interface ZoomStackProps extends PropsWithChildren<StackProps> {
timeout: number
}
export default function SquishSlideStack({children, timeout, ...stackProps}: ZoomStackProps) {
const [mountIndex, setMountIndex] = useState(0)
const [squozeIndex, setSquozeIndex] = useState(0)
function increment(n: number) {
if (n < React.Children.count(children) - 1) {
setMountIndex(n)
setTimeout(() => increment(n + 1), timeout)
}
}
useEffect(() => increment(1), [])
return (
<Stack {...stackProps}>
<Button onClick={() => setMountIndex(index => index + 1)}>Next</Button>
{React.Children.map(children, (child, i) =>
i > mountIndex ? (
null
) : (
<Slide
key={i}
in={true}
direction='up'
timeout={1000}
addEndListener={() => setSquozeIndex(i)}
>
<Box bgcolor='green'
width={600}
height={50}
sx={{
transform: i > squozeIndex ? 'scale(1, 1.5)' : 'scale(1, 1)',
transition: 'transform 2s ease'
}}
>
{child}
</Box>
</Slide>
)
)}
</Stack>
)
}
See Codesandbox example.
The sliding part here works, more or less, but only when I leave the squishing/scaling part off. Adding that breaks sliding and also doesn't scale correctly, for some reason.
What's the best way to achieve an animation like this in React (and hopefully in MUI, though that's not required)?

Why is my react-lightbox not going full screen in next.js

I'm using next.js and I was hoping to see my gallery collection like this on click of one of my images which is not happening. Actually, it's like I have just used a normal component, because literally nothing is happening when I click one of my images. Please help.
// this is my app component
import SimpleReactLightbox from 'simple-react-lightbox'
const MyApp = ()=>{
return(
<SimpleReactLightbox>
<Component {...pageProps} />
</SimpleReactLightbox>
)
}
// this is my collection
import { CollectionStyledTypography } from './styles/collectionStyledComponents'
import { SRLWrapper } from 'simple-react-lightbox'
import Image from 'next/image'
const Collection = ({ imagesList = [] }) => {
return (
<SRLWrapper>
<div style={{ margin: '50px' }}>
{imagesList.map((image, index) => (
<CollectionStyledTypography component="div" key={index}>
<Image src={image.src} alt={image.alt} layout="fill" />
</CollectionStyledTypography>
))}
</div>
</SRLWrapper>
)
}
export default Collection
SRL is no longer being developed, and it won't work in React 18. You will have to downgrade to 17 to make it work. I am facing the same problem, nothing happens when i click on an image.

Trouble styling TablePagination to-from on material-table

I am attempting to style the from-to of x rows number on a Material-Table, via
import MaterialTable from 'material-table'
import { TablePagination, withStyles } from '#material-ui/core'
const StyledPagination = withStyles({
caption: {
'&.MuiTypography-caption': {
fontSize: '1.5rem !important'
},
fontSize: '1.5rem !important'
}
})(TablePagination)
<MaterialTable
**Other Props Here**
components={{
Pagination: props => (
<StyledPagination
{...props}
labelRowsPerPage={<div>{props.labelRowsPerPage}</div>}
labelDisplayedRows={row => (
<div>{props.labelDisplayedRows(row)}</div>
)}
/>
)
}}
/>
I feel like those two css selectors should be redundant, but neither is working. I feel like material-table is overriding them as the computed font size is 0.75rem .MuiTypography-caption. Have also attempted styling via the root rather than caption with no difference there either.
I have been able to style the dropdown selector for number of rows to display, which seems like the same should apply to this. Originally started with this approach, which also did not work.
Ended up solving this with MuiThemeProvider, I dont think the normal ThemeProvider is working with Material-table
import { createMuiTheme, MuiThemeProvider } from '#material-ui/core/styles'
const theme = createMuiTheme({
overrides: {
MuiTypography: {
caption: {
fontSize: '1.5rem'
}
}
})
then,
<MuiThemeProvider theme={theme}>
<MaterialTable />
</MuiThemeProvider>
Although, this will style anything with class MuiTypography-caption

How to control the styles of many elements in React at one time?

I have a simple game, like this -
game
When you hover a square, it turns blue, if hover again, it turns white.
For this aim I just add styles for event.targer on hover
const handleMouseEnter = (e) => {
const hoveredDiv = e._targetInst.pendingProps.value;
e.target.className = 'blue'
if (hoveredSquares.includes(hoveredDiv)) {
dispatch(actions.removeFromHovered(hoveredDiv))
e.target.style.backgroundColor = 'white';
} else {
dispatch(actions.addToHovered(hoveredDiv))
e.target.style.backgroundColor = 'blue';
}
}
The problem is, when I change a game mode, for example, 10*10, I need to make white all squares.
It is like restart a game, but already hovered squares a still blue of course.
Below is my code for squares
const generateSquares = () => {
if (!currentMode || currentMode === 0) {
return
}
const array = Array.from(Array(currentMode), () => Array(currentMode).fill(currentMode))
return (
<Box style={{ marginTop: 20 }}>
{array.map((rowEl, rowIndex) => {
return (
<Box
key={rowIndex}
>
{rowEl.map((_, colIndex) => {
return (
<Box
value={`row ${rowIndex + 1} col ${colIndex + 1}`}
onMouseEnter={e => handleMouseEnter(e)}
key={colIndex}
></Box>
)
})}
</Box>
)
})}
</Box>
)
}
In Vanilla JS I would use querySelectorAll.
How to control the styles of many elements in React at one time? Preferable using hooks.
Thanks
You can create Base square component. After that each element has to have state.
const [isHovered, setIsHovered] = useState(false)
return <Square
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
className={isHovered ? blue : white} />
When you have to change game then you need to rerender all your components, and states will be refreshed.

How to change the colour of ReactSelect component?

Hello I am using the React select component, import ReactSelect, {ValueType} from 'react-select';
Currently my component looks like this:
This is the code for it:
<div>
<ReactSelect
className='react-select react-select-top'
classNamePrefix='react-select'
id='displayLanguage'
menuIsOpen={this.state.openMenu}
menuPortalTarget={document.body}
options={timeOptions}
clearable={false}
onChange={this.onChange}
onKeyDown={this.handleKeyDown}
value={this.state.selectedOption}
onMenuClose={this.handleMenuClose}
onMenuOpen={this.handleMenuOpen}
aria-labelledby='changeInterfaceLanguageLabel'
isDisabled={false}
/>
</div>
I want to change the colour of it to grey to look more like this but I am not sure how to:
Try this out,
found here https://react-select.com/styles
const customStyles = {
option: (provided, state) => ({
...provided,
borderBottom: '1px dotted pink',
color: grey,
padding: 20,
}),
control: () => ({
// none of react-select's styles are passed to <Control />
width: 200,
}),
singleValue: (provided, state) => {
const opacity = state.isDisabled ? 0.5 : 1;
const transition = 'opacity 300ms';
return { ...provided, opacity, transition };
}
}
const App = () => (
<Select
styles={customStyles}
options={...}
/>
);
React-select has a prop styles where you set an object that has a list of predefined properties for styling.
You can find more info here: https://react-select.com/styles
But to makes this more easy for you, in your situation you would write something like this.
<ReactSelect
className='react-select react-select-top'
classNamePrefix='react-select'
id='displayLanguage'
menuIsOpen={this.state.openMenu}
menuPortalTarget={document.body}
options={timeOptions}
clearable={false}
onChange={this.onChange}
onKeyDown={this.handleKeyDown}
value={this.state.selectedOption}
onMenuClose={this.handleMenuClose}
onMenuOpen={this.handleMenuOpen}
aria-labelledby='changeInterfaceLanguageLabel'
isDisabled={false}
styles={{
control: (styles) => ({
...styles,
background: '#eee'
})
}}
/>

Resources