Comments (16)
@dindonus
You can help it out a little by providing more context:
<div style={{ position: 'relative'}}>
<h1>
<button onClick={toggle}>Toggle</button>
</h1>
<Spring from={{ height: 0 }} to={{ height: on ? "auto" : 0 }}>
{styles => (
<div style={{ ...styles, overflow: 'hidden' }}>
Now the lower div container is part of the parent-div instead of the app/root-div (in css absolute/relative is always relative to the previous container that's absolute/relative, even if it's not the direct parent). When it's set to 'absolute' by react-spring for measurement it'll retain bounds. I know this stuff can be confusing and i wish there'd be an easier way, but it's css after all.
More on that here: https://github.com/drcmda/react-spring/blob/master/API-OVERVIEW.md#animating-auto
from react-spring.
@nathanmarks It's out under @5.1.3, i actually thought i already did publish hence the close - must've been confused. 😵
from react-spring.
@taylorlapeyre Could you try it? You don't have to fork, make a local copy of this file: https://github.com/drcmda/react-spring/blob/master/src/animated/targets/react-dom/fix-auto.js
Replace import AnimatedValue from '../../AnimatedValue'
with import { AnimatedValue } from 'react-spring'
+ your changes to the measuring strategy
And then do this:
import MyOwnFix from './local-fix-auto'
<Spring inject={MyOwnFix} ... />
If it works we can upstream it.
It could also happen if the object doesn't have bounds, because it is projected to the document root without any container that restricts it. If if doesn't already at least a width, it can cause wrong measurement. This can be fixed in userland by measuring out the cell width of your grid and applying it to the objects styles.
The reason i don't render it directly where it is supposed to be is that i fear it would cause flicker. The object would appear and cause a paint, then we measure bounds and make it disappear again, causing another paint. It would potentially push away other elements for two frames that way.
from react-spring.
PS. You can remove the portal simply by omitting "createPortal" and return the <div ...>
inside as is, then it will render inside your grid. Maybe the browser does it so fast that there isn't any flicker - who knows.
function fixAuto(spring, props) {
const { native, children, from, to } = props
// Dry-route props back if nothing's using 'auto' in there
if (![...getValues(from), ...getValues(to)].some(check)) return
const forward = spring.getForwardProps(props)
const allProps = Object.entries({ ...from, ...to })
// Collect to-state props
const componentProps = native ? allProps.reduce(convert, forward) : { ...from, ...to, ...forward }
// Render to-state vdom to portal
return (
<div
style={{ visibility: 'hidden' }}
ref={ref => {
if (ref) {
// Once it's rendered out, fetch bounds
const height = ref.clientHeight
const width = ref.clientWidth
// Defer to next frame, or else the springs updateToken is canceled
requestAnimationFrame(() =>
spring.updateProps(
{
...props,
from: Object.entries(from).reduce(overwrite(width, height), from),
to: Object.entries(to).reduce(overwrite(width, height), to)
},
true
)
)
}
}}>
{children(componentProps)}
</div>
)
}
from react-spring.
@drcmda thanks! While trying this out I ran into a small issue - we are using Transition
here, not Spring
directly. Is there any way to inject my new version of fixAuto
with this setup?
from react-spring.
Should be the same, Transitions should be able to take in injects as well.
from react-spring.
I've also encountered this problem. I tried patching with getBoundingClientRect()
, but it resolved the same height as clientHeight
. I did notice when logging the rect that the width was massively different from the actual element bounds; close to the total width of the page instead of the smaller area my collapsible element was contained in.
Removing the portal fixed this, now it behaves as I'd expect. Makes sense.
I didn't understand @drcmda at first, but yeah, I guess you said that would happen 😄
It could also happen if the object doesn't have bounds, because it is projected to the document root without any container that restricts it. If if doesn't already at least a width, it can cause wrong measurement. This can be fixed in userland by measuring out the cell width of your grid and applying it to the objects styles.
I'm not totally satisfied by the userland solution though. I'd love to be able to apply springs to any arbitrary elements without having to think about measuring bounds or adhering to a strict grid.
I wonder if there's another possible hack... like rendering it with overflow-y: auto; height: 0;
and measuring the client width and scroll height?
Update: just tried it myself, seems to work acceptably to me. There may be some browser quirks with scrollHeight
I'm not aware of though.
import React from 'react';
import ReactDOM from 'react-dom';
import { AnimatedValue } from 'react-spring';
const getValues = object => Object.keys(object).map(k => object[k]);
const check = value => value === 'auto';
const convert = (acc, [name, value]) => ({
...acc,
[name]: new AnimatedValue(value),
});
const overwrite = (width, height) => (acc, [name, value]) => ({
...acc,
[name]: value === 'auto' ? (name === 'height' ? height : width) : value,
});
export default function fixAuto(spring, props) {
const { native, children, from, to } = props;
// Dry-route props back if nothing's using 'auto' in there
if (![...getValues(from), ...getValues(to)].some(check)) return;
const forward = spring.getForwardProps(props);
const allProps = Object.entries({ ...from, ...to });
// Collect to-state props
const componentProps = native
? allProps.reduce(convert, forward)
: { ...from, ...to, ...forward };
return (
<div
style={{ overflowY: 'auto', height: 0 }}
ref={ref => {
if (ref) {
// Once it's rendered out, fetch bounds
const height = ref.scrollHeight;
const width = ref.clientWidth;
// Defer to next frame, or else the springs updateToken is canceled
requestAnimationFrame(() =>
spring.updateProps(
{
...props,
from: Object.entries(from).reduce(
overwrite(width, height),
from,
),
to: Object.entries(to).reduce(overwrite(width, height), to),
},
true,
),
);
}
}}
>
{children(componentProps)}
</div>
);
}
from react-spring.
@a-type The first solution, just leaving out the portal, worked? Or did you run into another issue with that. I don't quite follow with the scrollheight stuff. And did you notice any flicker? It's weird, there should be, but i haven't seen any - but anyway, the inject stuff is the right way, userland shouldn't be too complex i agree fully. We only need to hack out a good strategy for it and i'll update.
from react-spring.
@drcmda The portal was my problem. clientHeight
was no different from getClientBounds
, so that was a red herring. But removing the portal fixed the size.
I didn't see any flicker when I removed the portal, but just to be sure, I suggested another solution which I posted the code for above. Basically, you render the element in place with height: 0; overflow-y: auto
. Then, you have an accurate width. Instead of taking clientHeight
, you take scrollHeight
.
While this hack works for me, I'm not sure it would work for everyone.
from react-spring.
Now I get it, that‘s really clever! Is that a common thing or did you just unearth it? Could you click the PR button on your fork, it’s only missing width and we could merge.
from react-spring.
Just occurred to me as I was tinkering with it. I'll open a PR soon.
from react-spring.
@a-type Sorry for the wait, i merged, and will publish soon.
from react-spring.
@drcmda Do you know when you might release this? Deciding whether to add the fix to my codebase or wait it out
from react-spring.
@a-type @taylorlapeyre ran into some crazy issues recently with the previous approaches, the flicker is real - on mobile i could see it, and in some cases the calculation was off depending on box-sizing: border-box/content-box. I've made a couple of revisions cherry picking from everything we've discussed so far - it doesn't get clientHeight any longer but calculates using getComputedStyles, pretty much like jquery does, also checking for the box model. Also tried position: absolute.
Would be glad if you could try it again, if it still works in your projects.
from react-spring.
@drcmda I didn't have luck with position: absolute
originally, but would be willing to test your changes. Box model improvements sound welcome.
from react-spring.
Hi there :)
I'm having the exact same issue with react-spring 5.3.8.
Here is my code sandbox: https://codesandbox.io/s/2o9pxo895y
Any browser width > 300px will cause the problem. If you fix the content width (see comment at bottom), then it always works fine.
from react-spring.
Related Issues (20)
- [bug]: Swipe card on X axis will cause window to scroll when Youtube iframe is playing HOT 3
- [bug]: createInterpolate deprecation warning results in app crash with IE11 HOT 1
- [bug]: Event Handlers not getting called in StrictMode HOT 1
- [bug]: Immediate does not work when to is an array
- [bug]: Promise returned by Controller.start is not resolved consistently
- [bug]: When included in a module, react-spring resolves to the string "/static/media/react-spring_web.development.34d7028f586cc8ee5e8e.cjs" HOT 2
- why require('react-spring') returns string instead of object HOT 1
- [bug]: @react-spring/konva + typescript HOT 3
- [bug]: Noise demo page - CodeSandbox still using 9.5.5 version
- [feat]: Integration of Tailwind CSS with React Spring for Declarative and Styled Animations
- [bug]: Wrong source-maps
- [bug]: ./node_modules/@react-spring/shared/dist/react-spring_shared.legacy-esm.js 1023:7 HOT 3
- [bug]: update transform
- [bug]: react-spring Identifier 'React' has already been declared HOT 3
- [bug]: Incorrect tooltips in useTransition docs HOT 1
- [bug]: React-Spring.dev main website down HOT 1
- [bug]: useResize is jumpy
- [bug]: The leave option in config object behaves inconsistently when using useTransition HOT 1
- [bug]: Website with docs not working in chrome (120.0.6099.72) HOT 3
- [bug]: Documentation website is broken after the first visit on most desktop browser HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-spring.