Skip to content
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

Animation features #134

Open
raquo opened this issue Jan 6, 2023 · 0 comments
Open

Animation features #134

raquo opened this issue Jan 6, 2023 · 0 comments
Labels
enhancement need to find time https://falseknees.com/297.html

Comments

@raquo
Copy link
Owner

raquo commented Jan 6, 2023

Currently if you want to use animation in Laminar, you can use native CSS transitions and/or Kit's Animus library.

There are two main aspects to animation when it comes to the DOM:

  1. Smooth transitions of an element's property (e.g. width, opacity)
  2. Smooth transitions when adding / removing elements in the DOM.

Animating individual properties is relatively easy. You can already do a lot with CSS transitions alone, but if you need custom code for one reason or another, the main challenge to implementing those in Laminar is that Airstream's transaction system is poorly suited for rapid-fire animation events. So, instead of implementing animation in terms of observables, you might want a special implementation of animations, with syntax perhaps like:

div(
  height.transition(30.ms) <-- heightSignal,
  color.transition(someConfig) <-- colorSignal
)

Animus has more advanced features like deriving Animatable of case classes, but that's too much for Laminar core.


Animating removal / addition of elements in the DOM is a more complex problem. Typically a dynamic list of elements is rendered from an observable of a list of models, which is then split by some id key. Well, you know how the split operator works.

So, for example, if you want to remove an element, the source observable needs to emit an updated list of models where the corresponding model is now missing. The split operator detects this change, and removes the element from the list of elements that it emits. Then Laminar's children <-- algorithm receives the new list of elements, detects the missing element, and removes it from the DOM. So, if we want to e.g. fade-out the removal of this element, it needs to be done at one of two stages:

  1. In the split operator, or
  2. In the children reconciliation algorithm

Either way, when removal is triggered, we need to trigger the fade-out animation, and keep the original element in the list until the animation finishes, and then remove it from the list. It gets a lot more complicated when you consider that the source observable can re-add the model corresponding to this element before it finishes animating out, etc.

Currently Animus has a custom implementation of the split operator that does this, but the split operator is perhaps the most complex / fragile code in Airstream, and maintaining a separate copy of that algorithm long term will take a lot of effort. I'm also not sure if it's entirely 100% robust, as it sort of plays fast and loose with Transactions (for the sake of performance I guess).

Without using Laminar animations or Animus, in cases where an element's removal is triggered by a user interaction, one workaround is for that interaction to trigger the fade-out animation, and then only trigger the element's removal after that is finished. But of course this is not ideal because you need to code such logic yourself, and it's not trivial to get it right.

Bottom line – it would be great to add some kind of delayed-element-removal support either to children <-- or to the Airstream split operator. Note that animated addition of elements is trivial because you can just add the element first and then animate it onMount, whereas in case of removal, you need to actually delay the removal to allow the animation to run first.


Personally I'm not a big fan of animations (that go beyond simple and quick CSS transitions) so I won't be rushing to implement any of this any time soon, but if there's enough demand for this, it can potentially be done.

@raquo raquo added enhancement need to find time https://falseknees.com/297.html labels Jan 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement need to find time https://falseknees.com/297.html
Projects
None yet
Development

No branches or pull requests

1 participant