Repository: sveltejs/svelte (JavaScript)
Date: 2022-02-18 19:20:17+00:00
Task type: Bug Fix

Issue:
Bug of local transition with keyed clause
Is this about svelte@next? This project is currently in a pre-release stage and breaking changes may occur at any time. Please do not post any kind of bug reports or questions on GitHub about it.

No

**Describe the bug**
When using the `{#key }` clause, the local transitions do not work well.

**To Reproduce**

https://svelte.dev/repl/f20a688175914fb2a0f5ff45a75360b5?version=3.32.1

**Expected behavior**
In the provided REPL, the expected behavior is for the items to enter and exit in a smooth manner, with or without local modifier. It only happens with the keyed clause, and works well with an `{#each }` clause: https://svelte.dev/repl/b0c3bafb93a6463d81e846d30f80f5ba?version=3.32.1

**Information about your Svelte project:**

The REPL uses Svelte 3.32.1. Reproduced on Safari 14.0.2 and Chrome 88 on OSX 11.1

**Severity**
It prevents me from using local transitions in an image carousel: https://strollyn.com/explore . I'd like the transition not to run when mounting or changing page.
Some workarounds are possible (using scroll for the carrousel maybe), but the severity is not that large




Issue discussion:
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Also having this issue: https://svelte.dev/repl/33f123d7c2c24b37b8fc580219de1ead?version=3.38.3
Having this issue as well: https://svelte.dev/repl/c5b0e5731caf4531bfb024f828a6c344?version=3.38.3
I'm facing this same issue (also in trying to create a carousel). It seems to me that the `|local` modifier for transitions should also apply if the element is being rendered due to an immediate parent `{#key}` re-rendering.
My test case https://svelte.dev/repl/9ade56926d33497980edd41af6597c70?version=3.44.2
and if you need a workaround, use
```html
{#each [key] as k(k)}
  your code
{/each}
```
instead of `#key` block
`in:blur={{duration:1000, delay: 1000}} out:blur={{duration:1000}}`

Solution patch:
diff --git a/src/compiler/compile/render_dom/wrappers/KeyBlock.ts b/src/compiler/compile/render_dom/wrappers/KeyBlock.ts
--- a/src/compiler/compile/render_dom/wrappers/KeyBlock.ts
+++ b/src/compiler/compile/render_dom/wrappers/KeyBlock.ts
@@ -1,7 +1,6 @@
 import Wrapper from './shared/Wrapper';
 import Renderer from '../Renderer';
 import Block from '../Block';
-import EachBlock from '../../nodes/EachBlock';
 import KeyBlock from '../../nodes/KeyBlock';
 import create_debugging_comment from './shared/create_debugging_comment';
 import FragmentWrapper from './Fragment';
@@ -19,7 +18,7 @@ export default class KeyBlockWrapper extends Wrapper {
 		renderer: Renderer,
 		block: Block,
 		parent: Wrapper,
-		node: EachBlock,
+		node: KeyBlock,
 		strip_whitespace: boolean,
 		next_sibling: Wrapper
 	) {
@@ -107,7 +106,7 @@ export default class KeyBlockWrapper extends Wrapper {
 			}
 			${this.var} = ${this.block.name}(#ctx);
 			${this.var}.c();
-			${has_transitions && b`@transition_in(${this.var})`}
+			${has_transitions && b`@transition_in(${this.var}, 1)`}
 			${this.var}.m(${this.get_update_mount_node(anchor)}, ${anchor});
 		`;
 


Test patch:
diff --git a/test/runtime/samples/key-block-transition-local/_config.js b/test/runtime/samples/key-block-transition-local/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/key-block-transition-local/_config.js
@@ -0,0 +1,37 @@
+export default {
+	props: {
+		x: false,
+		y: 1
+	},
+
+	test({ assert, component, target, raf }) {
+		component.x = true;
+
+		let div = target.querySelector('div');
+		assert.equal(div.foo, undefined);
+
+		// play both in and out transition when changed with `{#key}`
+		component.y = 2;
+		assert.htmlEqual(target.innerHTML, '<div></div><div></div>');
+		const [leaving, incoming] = target.querySelectorAll('div');
+
+		raf.tick(50);
+		assert.equal(leaving.foo, 0.5);
+		assert.equal(incoming.foo, 0.5);
+
+		raf.tick(100);
+		assert.htmlEqual(target.innerHTML, '<div></div>');
+		assert.equal(leaving.foo, 0);
+		assert.equal(incoming.foo, 1);
+
+		// do not play out transition when removed by `{#if}`
+		component.x = false;
+		assert.htmlEqual(target.innerHTML, '');
+
+		// do not play in transition when added back with `{#if}`
+		component.x = true;
+		assert.htmlEqual(target.innerHTML, '<div></div>');
+		div = target.querySelector('div');
+		assert.equal(div.foo, undefined);
+	}
+};
diff --git a/test/runtime/samples/key-block-transition-local/main.svelte b/test/runtime/samples/key-block-transition-local/main.svelte
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/key-block-transition-local/main.svelte
@@ -0,0 +1,19 @@
+<script>
+	export let x;
+	export let y;
+
+	function foo(node, _params) {
+		return {
+			duration: 100,
+			tick: t => {
+				node.foo = t;
+			}
+		};
+	}
+</script>
+
+{#if x}
+	{#key y}
+		<div transition:foo|local></div>
+	{/key}
+{/if}
\ No newline at end of file