In the previous chapter, we used deferred transitions to create the movement of elements as they moved from one TODO list to another.
To complete the effect, we also need to apply motion to elements without transition. To do this, we use the animate directive.
First, import the flip function from svelte/animate -flip stands for “First, Last, Invert, Play” :
import { flip } from 'svelte/animate';
Copy the code
Then add it to the
<label
in:receive="{{key: todo.id}}"
out:send="{{key: todo.id}}"
animate:flip
>
Copy the code
In this case, the movement is a bit slow, so we can add a duration argument:
<label
in:receive="{{key: todo.id}}"
out:send="{{key: todo.id}}"
animate:flip="{{duration: 200}}"
>
Copy the code
Duration can also be a d => milliseconds function, where d is the pixel value that the element must move.
Note that all transitions and animations are applied in CSS rather than JavaScript, which means they do not block (or be blocked) the main thread.
Complete code:
<script>
import { quintOut } from 'svelte/easing';
import { crossfade } from 'svelte/transition';
import { flip } from 'svelte/animate';
const [send, receive] = crossfade({
duration: d= > Math.sqrt(d * 200),
fallback(node, params) {
const style = getComputedStyle(node);
const transform = style.transform === 'none' ? ' ' : style.transform;
return {
duration: 600.easing: quintOut,
css: t= > `
transform: ${transform} scale(${t});
opacity: ${t}
`}; }});let uid = 1;
let todos = [
{ id: uid++, done: false.description: 'write some docs' },
{ id: uid++, done: false.description: 'start writing blog post' },
{ id: uid++, done: true.description: 'buy some milk' },
{ id: uid++, done: false.description: 'mow the lawn' },
{ id: uid++, done: false.description: 'feed the turtle' },
{ id: uid++, done: false.description: 'fix some bugs'},];function add(input) {
const todo = {
id: uid++,
done: false.description: input.value
};
todos = [todo, ...todos];
input.value = ' ';
}
function remove(todo) {
todos = todos.filter(t= >t ! == todo); }function mark(todo, done) {
todo.done = done;
remove(todo);
todos = todos.concat(todo);
}
</script>
<div class='board'>
<input
placeholder="what needs to be done?"
on:keydown={e= > e.key === 'Enter' && add(e.target)}
>
<div class='left'>
<h2>todo</h2>{#each todos.filter(t => ! t.done) as todo (todo.id)}<label
in:receive="{{key: todo.id}}"
out:send="{{key: todo.id}}"
animate:flip
>
<input type=checkbox on:change={()= > mark(todo, true)}>
{todo.description}
<button on:click="{() => remove(todo)}">remove</button>
</label>
{/each}
</div>
<div class='right'>
<h2>done</h2>
{#each todos.filter(t => t.done) as todo (todo.id)}
<label
class="done"
in:receive="{{key: todo.id}}"
out:send="{{key: todo.id}}"
animate:flip
>
<input type=checkbox checked on:change={()= > mark(todo, false)}>
{todo.description}
<button on:click="{() => remove(todo)}">remove</button>
</label>
{/each}
</div>
</div>
<style>
.board {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 1em;
max-width: 36em;
margin: 0 auto;
}
.board > input {
font-size: 1.4 em;
grid-column: 1/3;
}
h2 {
font-size: 2em;
font-weight: 200;
user-select: none;
margin: 0 0 0.5 em 0;
}
label {
position: relative;
line-height: 1.2;
padding: 0.5 em 2.5 em 0.5 em 2em;
margin: 0 0 0.5 em 0;
border-radius: 2px;
user-select: none;
border: 1px solid hsl(240.8%.70%);
background-color:hsl(240.8%.93%);
color: # 333;
}
input[type="checkbox"] {
position: absolute;
left: 0.5 em;
top: 0.6 em;
margin: 0;
}
.done {
border: 1px solid hsl(240.8%.90%);
background-color:hsl(240.8%.98%);
}
button {
position: absolute;
top: 0;
right: 0.2 em;
width: 2em;
height: 100%;
background: no-repeat 50% 50% url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23676778' D ='M12, 2c17.53,22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53,12C2,6.47 6.47,2 M17 12, 2, 7 h14. 5 l13. 5 or 6 H10.5 L9.5, 7 h7v9h17v7m9, 18 h15a1, 16 or 17 V10H8V17A1 1 0 0, 0, 1, 0, 0, 0 9, 18 '% 3 e % 3 c/Z path % 3 e % 3 c/SVG % 3 e");
background-size: 1.4 em 1.4 em;
border: none;
opacity: 0;
transition: opacity 0.2 s;
text-indent: -9999px;
cursor: pointer;
}
label:hover button {
opacity: 1;
}
</style>
Copy the code
Check out the animate website