-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add Spring class #11519
base: main
Are you sure you want to change the base?
feat: add Spring class #11519
Conversation
|
Correct me if I'm wrong, but the value of the spring would get out of sync with the external state if you try to set it directly, no? let { number } = $props();
const thing = new Spring(() => number);
thing.set(5); // oops now we’re out of sync I think a value change callback could be added to avoid such cases. let { number = $bindable() } = $props();
const thing = new Spring(() => number, {
onChange: (v) => (number = v)
});
thing.set(5); // still in sync |
Yes, and the solution is 'don't do that'. In general you wouldn't need to let progress = $state(0);
let spring = new Spring(() => progress);
function increment() {
if (progress === 10) {
spring.set(0, { instant: true });
progress = 0;
} else {
progress += 1;
}
} It would be strange to have an |
Yeah fair. I just worry this might cause weird bugs because you expect the values to always be in sync. |
Possible to sneak in this as well? #9141 (comment) |
Because of the function case, it feels like it might be better to have some kind of Like:
This works even if you're using
I like that this way you no longer have to know what the final spring position is in order to skip the animation. That seems really nice for the function case. I also think a |
I'd love to have |
I'd love to see this in 5.0 and would like to work on it, @Rich-Harris do you have any input on the proposed APIs or should I just work on merge conflicts and the Tween class? |
This adds a
Spring
class as an alternative to the existingspring
store factory. The behaviour is essentially identical, but the API is slightly different:instant
andpreserveMomentum
are clearer thanhard
andsoft
, which seem like they're somehow symmetrical but are in fact unrelated.As an alternative to providing an initial value, you can provide a function, making it easy to keep a spring in sync with some other value:
In this case it's still possible to do
thing.set(value, opts)
, since you might (e.g.) need to use{ instant: true }
, and making it 'readonly' in the function case could be overly restrictive.Initially I envisaged that there'd be a
spring.target
property, and you'd update the spring by updating that value. But reading through #2627 made me realise that there are many cases where you need programmatic control (e.g. gesture-based interactions) so we need aspring.set(...)
method, and having two ways to do the same thing could be confusing.That said, it might be nice to be able to do this sort of thing...
...and so the possibility is left open.
A nice thing about using classes: you can do
const spring = new Spring(...)
instead of always having to come up with a more descriptive name.TODO
Tween
class to go withSpring
spring
tests to adapt — not totally sure what tests would look like here)Before submitting the PR, please make sure you do the following
feat:
,fix:
,chore:
, ordocs:
.Tests and linting
pnpm test
and lint the project withpnpm lint