mirror of https://github.com/sveltejs/svelte
parent
04498769b5
commit
a0f0e8ad67
@ -0,0 +1,35 @@
|
||||
import Expression from "./shared/Expression";
|
||||
import map_children from "./shared/map_children";
|
||||
import AbstractBlock from "./shared/AbstractBlock";
|
||||
import Element from "./Element";
|
||||
|
||||
export default class KeyBlock extends AbstractBlock {
|
||||
type: "KeyBlock";
|
||||
|
||||
expression: Expression;
|
||||
has_animation: boolean;
|
||||
|
||||
constructor(component, parent, scope, info) {
|
||||
super(component, parent, scope, info);
|
||||
|
||||
this.expression = new Expression(component, this, scope, info.expression);
|
||||
|
||||
this.has_animation = false;
|
||||
|
||||
this.children = map_children(component, this, scope, info.children);
|
||||
|
||||
if (this.has_animation) {
|
||||
if (this.children.length !== 1) {
|
||||
const child = this.children.find(
|
||||
(child) => !!(child as Element).animation
|
||||
);
|
||||
component.error((child as Element).animation, {
|
||||
code: `invalid-animation`,
|
||||
message: `An element that use the animate directive must be the sole child of a key block`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.warn_if_empty_block();
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
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";
|
||||
import { b, x } from "code-red";
|
||||
import { Identifier } from "estree";
|
||||
|
||||
export default class KeyBlockWrapper extends Wrapper {
|
||||
node: KeyBlock;
|
||||
fragment: FragmentWrapper;
|
||||
block: Block;
|
||||
dependencies: string[];
|
||||
var: Identifier = { type: "Identifier", name: "key_block" };
|
||||
|
||||
constructor(
|
||||
renderer: Renderer,
|
||||
block: Block,
|
||||
parent: Wrapper,
|
||||
node: EachBlock,
|
||||
strip_whitespace: boolean,
|
||||
next_sibling: Wrapper
|
||||
) {
|
||||
super(renderer, block, parent, node);
|
||||
|
||||
this.cannot_use_innerhtml();
|
||||
this.not_static_content();
|
||||
|
||||
this.dependencies = node.expression.dynamic_dependencies();
|
||||
|
||||
this.block = block.child({
|
||||
comment: create_debugging_comment(node, renderer.component),
|
||||
name: renderer.component.get_unique_name("create_key_block"),
|
||||
type: "key"
|
||||
});
|
||||
|
||||
this.fragment = new FragmentWrapper(
|
||||
renderer,
|
||||
this.block,
|
||||
node.children,
|
||||
parent,
|
||||
strip_whitespace,
|
||||
next_sibling
|
||||
);
|
||||
|
||||
renderer.blocks.push(this.block);
|
||||
}
|
||||
|
||||
render(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
|
||||
this.fragment.render(
|
||||
this.block,
|
||||
null,
|
||||
(x`#nodes` as unknown) as Identifier
|
||||
);
|
||||
|
||||
const has_transitions = !!(
|
||||
this.block.has_intro_method || this.block.has_outro_method
|
||||
);
|
||||
const dynamic = this.block.has_update_method;
|
||||
|
||||
block.chunks.init.push(b`
|
||||
let ${this.var} = ${this.block.name}(#ctx);
|
||||
`);
|
||||
block.chunks.create.push(b`${this.var}.c();`);
|
||||
if (this.renderer.options.hydratable) {
|
||||
block.chunks.claim.push(b`${this.var}.l(${parent_nodes});`);
|
||||
}
|
||||
block.chunks.mount.push(
|
||||
b`${this.var}.m(${parent_node || "#target"}, ${
|
||||
parent_node ? "null" : "#anchor"
|
||||
});`
|
||||
);
|
||||
const anchor = this.get_or_create_anchor(block, parent_node, parent_nodes);
|
||||
|
||||
if (this.dependencies.length) {
|
||||
const body = b`
|
||||
${
|
||||
has_transitions
|
||||
? b`
|
||||
@group_outros();
|
||||
@transition_out(${this.var}, 1, 1, @noop);
|
||||
@check_outros();
|
||||
`
|
||||
: b`${this.var}.d(1);`
|
||||
}
|
||||
${this.var} = ${this.block.name}(#ctx);
|
||||
${this.var}.c();
|
||||
${has_transitions && b`@transition_in(${this.var})`}
|
||||
${this.var}.m(${this.get_update_mount_node(anchor)}, ${anchor});
|
||||
`;
|
||||
|
||||
if (dynamic) {
|
||||
block.chunks.update.push(b`
|
||||
if (${this.renderer.dirty(this.dependencies)}) {
|
||||
${body}
|
||||
} else {
|
||||
${this.var}.p(#ctx, #dirty);
|
||||
}
|
||||
`);
|
||||
} else {
|
||||
block.chunks.update.push(b`
|
||||
if (${this.renderer.dirty(this.dependencies)}) {
|
||||
${body}
|
||||
}
|
||||
`);
|
||||
}
|
||||
} else if (dynamic) {
|
||||
block.chunks.update.push(b`${this.var}.p(#ctx, #dirty);`);
|
||||
}
|
||||
|
||||
if (has_transitions) {
|
||||
block.chunks.intro.push(b`@transition_in(${this.var})`);
|
||||
block.chunks.outro.push(b`@transition_out(${this.var})`);
|
||||
}
|
||||
|
||||
block.chunks.destroy.push(b`${this.var}.d(detaching)`);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import KeyBlock from '../../nodes/KeyBlock';
|
||||
import Renderer, { RenderOptions } from '../Renderer';
|
||||
|
||||
export default function(node: KeyBlock, renderer: Renderer, options: RenderOptions) {
|
||||
renderer.render(node.children, options);
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
export default {
|
||||
html: `<div>000</div>`,
|
||||
async test({ assert, component, target, window }) {
|
||||
let div = target.querySelector('div');
|
||||
component.value = 2;
|
||||
assert.htmlEqual(target.innerHTML, `<div>200</div>`);
|
||||
assert.notStrictEqual(div, target.querySelector('div'));
|
||||
|
||||
div = target.querySelector('div');
|
||||
|
||||
component.anotherValue = 5;
|
||||
assert.htmlEqual(target.innerHTML, `<div>250</div>`);
|
||||
assert.notStrictEqual(div, target.querySelector('div'));
|
||||
|
||||
div = target.querySelector('div');
|
||||
|
||||
component.thirdValue = 9;
|
||||
assert.htmlEqual(target.innerHTML, `<div>259</div>`);
|
||||
assert.strictEqual(div, target.querySelector('div'));
|
||||
}
|
||||
};
|
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
export let value = 0;
|
||||
export let anotherValue = 0;
|
||||
export let thirdValue = 0;
|
||||
</script>
|
||||
|
||||
{#key [value, anotherValue]}
|
||||
<div>{value}{anotherValue}{thirdValue}</div>
|
||||
{/key}
|
@ -0,0 +1,9 @@
|
||||
export default {
|
||||
html: `<div>00</div>`,
|
||||
async test({ assert, component, target, window }) {
|
||||
const div = target.querySelector('div');
|
||||
component.anotherValue = 2;
|
||||
assert.htmlEqual(target.innerHTML, `<div>02</div>`);
|
||||
assert.strictEqual(div, target.querySelector('div'));
|
||||
}
|
||||
};
|
@ -0,0 +1,8 @@
|
||||
<script>
|
||||
let value = 0;
|
||||
export let anotherValue = 0;
|
||||
</script>
|
||||
|
||||
{#key value}
|
||||
<div>{value}{anotherValue}</div>
|
||||
{/key}
|
@ -0,0 +1,24 @@
|
||||
export default {
|
||||
html: '<div>0</div>',
|
||||
async test({ assert, component, target, window, raf }) {
|
||||
component.value = 2;
|
||||
|
||||
const [div1, div2] = target.querySelectorAll('div');
|
||||
|
||||
assert.htmlEqual(div1.outerHTML, '<div>0</div>');
|
||||
assert.htmlEqual(div2.outerHTML, '<div>2</div>');
|
||||
|
||||
raf.tick(0);
|
||||
|
||||
assert.equal(div1.foo, 1);
|
||||
assert.equal(div1.oof, 0);
|
||||
|
||||
assert.equal(div2.foo, 0);
|
||||
assert.equal(div2.oof, 1);
|
||||
|
||||
raf.tick(200);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, '<div>2</div>');
|
||||
assert.equal(div2, target.querySelector('div'));
|
||||
}
|
||||
};
|
@ -0,0 +1,17 @@
|
||||
<script>
|
||||
export let value = 0;
|
||||
|
||||
function foo(node, params) {
|
||||
return {
|
||||
duration: 100,
|
||||
tick: (t, u) => {
|
||||
node.foo = t;
|
||||
node.oof = u;
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
{#key value}
|
||||
<div transition:foo>{value}</div>
|
||||
{/key}
|
@ -0,0 +1,13 @@
|
||||
export default {
|
||||
html: `<div>00</div>`,
|
||||
async test({ assert, component, target, window }) {
|
||||
const div = target.querySelector('div');
|
||||
component.reactive = 2;
|
||||
assert.htmlEqual(target.innerHTML, `<div>02</div>`);
|
||||
assert.strictEqual(div, target.querySelector('div'));
|
||||
|
||||
component.value = 5;
|
||||
assert.htmlEqual(target.innerHTML, `<div>52</div>`);
|
||||
assert.notStrictEqual(div, target.querySelector('div'));
|
||||
}
|
||||
};
|
@ -0,0 +1,8 @@
|
||||
<script>
|
||||
export let value = 0;
|
||||
export let reactive = 0;
|
||||
</script>
|
||||
|
||||
{#key value}
|
||||
<div>{value}{reactive}</div>
|
||||
{/key}
|
Loading…
Reference in new issue