Crossfade
crossfade() returns a [send, receive] pair. Put out="send({ key })" on an element
leaving one spot and in="receive({ key })" on the element entering another with the same
key, and the two animate as one element flying between the positions. When a key has no
partner (an item that just disappears), the fallback transition plays instead.
Define the pair in <script>. Because crossfade is destructured, wrap the two functions as
named consts so they're callable from the template:
<script> import { crossfade, transitions } from "olum"; const _cf = crossfade({ duration: 300, fallback: transitions.scale }); const send = (node, params) => _cf[0](node, params); const receive = (node, params) => _cf[1](node, params); const state = { todos: [/* … */] }; const done = () => state.todos.filter((t) => t.done); const active = () => state.todos.filter((t) => !t.done); </script> <for each="todo of active()" key="todo.id"> <transition in="receive({ key: todo.id })" out="send({ key: todo.id })" flip> <li>{todo.text}</li> </transition> </for> <!-- a matching list of done() items with the same in/out/flip -->
crossfade({ duration?, easing?, fallback? }) — easing is a name string; fallback is any
transition function (e.g. a built-in from the transitions import, or your own). It composes
with flip so the remaining items slide into the gap.
Key off a primitive, not an object. State is deeply reactive, so
state.selected !== someItem(object identity) won't behave as you expect — compare an id (state.selectedId !== item.id) and use that id as the crossfadekey.