fix: more robust moving of each item nodes (#11254)

* move then link

* fix: more robust moving of each item nodes

* test
pull/11236/head
Rich Harris 3 months ago committed by GitHub
parent a8ca2a4904
commit 0ad0f04b0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: more robust moving of each item nodes

@ -323,7 +323,6 @@ function reconcile(array, state, anchor, render_fn, flags, get_key) {
if (matched.length < stashed.length) {
// more efficient to move later items to the front
var start = stashed[0];
var local_anchor = start.o;
var j;
prev = start.prev;
@ -331,18 +330,18 @@ function reconcile(array, state, anchor, render_fn, flags, get_key) {
var a = matched[0];
var b = matched[matched.length - 1];
link(a.prev, b.next);
link(prev, a);
link(b, start);
for (j = 0; j < matched.length; j += 1) {
move(matched[j], local_anchor);
move(matched[j], start, anchor);
}
for (j = 0; j < stashed.length; j += 1) {
seen.delete(stashed[j]);
}
link(a.prev, b.next);
link(prev, a);
link(b, start);
current = start;
prev = b;
i -= 1;
@ -352,7 +351,7 @@ function reconcile(array, state, anchor, render_fn, flags, get_key) {
} else {
// more efficient to move earlier items to the back
seen.delete(item);
move(item, current ? current.o : anchor);
move(item, current, anchor);
link(item.prev, item.next);
link(item, prev.next);
@ -492,21 +491,19 @@ function create_item(open, anchor, prev, next, value, key, index, render_fn, fla
/**
* @param {import('#client').EachItem} item
* @param {import('#client').EachItem | null} next
* @param {Text | Element | Comment} anchor
*/
function move(item, anchor) {
anchor.before(item.o);
function move(item, next, anchor) {
var end = item.next ? item.next.o : anchor;
var dest = next ? next.o : anchor;
var dom = item.e.dom;
var node = /** @type {import('#client').TemplateNode} */ (item.o);
if (dom !== null) {
if (is_array(dom)) {
for (var i = 0; i < dom.length; i++) {
anchor.before(dom[i]);
}
} else {
anchor.before(dom);
}
while (node !== end) {
var next_node = /** @type {import('#client').TemplateNode} */ (node.nextSibling);
dest.before(node);
node = next_node;
}
}

@ -0,0 +1,43 @@
import { flushSync } from 'svelte';
import { ok, test } from '../../test';
let ascending = `
<button>reverse</button>
<p>1</p>
<p>(1)</p>
<p>2</p>
<p>(2)</p>
<p>3</p>
<p>(3)</p>
`;
let descending = `
<button>reverse</button>
<p>3</p>
<p>(3)</p>
<p>2</p>
<p>(2)</p>
<p>1</p>
<p>(1)</p>
`;
export default test({
html: ascending,
async test({ assert, target }) {
const btn = target.querySelector('button');
ok(btn);
flushSync(() => btn.click());
assert.htmlEqual(target.innerHTML, descending);
flushSync(() => btn.click());
assert.htmlEqual(target.innerHTML, ascending);
flushSync(() => btn.click());
assert.htmlEqual(target.innerHTML, descending);
flushSync(() => btn.click());
assert.htmlEqual(target.innerHTML, ascending);
}
});

@ -0,0 +1,12 @@
<script>
let array = $state([1, 2, 3]);
</script>
<button onclick={() => array.reverse()}>reverse</button>
{#each array as item (item)}
<p>{item}</p>
{#if true}
<p>({item})</p>
{/if}
{/each}
Loading…
Cancel
Save