Add a simplified `EachBlock` helper

So far this is only used in certain conditions, as the full
feature set is not implemented yet.
pull/3540/head
Arpad Borsos 6 years ago
parent 5d8ca9f07d
commit 4fea0d4383

@ -188,8 +188,6 @@ export default class EachBlockWrapper extends Wrapper {
const snippet = this.node.expression.render(block);
block.builders.init.add_line(`let ${this.vars.each_block_value} = ${snippet};`);
renderer.blocks.push(deindent`
function ${this.vars.get_each_context}(ctx, list, i) {
const child_ctx = @_Object.create(ctx);
@ -216,13 +214,28 @@ export default class EachBlockWrapper extends Wrapper {
update_mount_node
};
if (this.node.key) {
// TODO: for now we use the helper only for very limited use cases.
// This is a first step, and more use cases will be ported over to the
// helper incrementally.
const use_helper =
!this.block.has_intro_method &&
!this.block.has_outro_method &&
!this.node.key;
if (!use_helper) {
block.builders.init.add_line(`let ${this.vars.each_block_value} = ${snippet};`);
}
if (use_helper) {
this.render_helper(args);
} else if (this.node.key) {
this.render_keyed(args);
} else {
this.render_unkeyed(args);
}
if (this.block.has_intro_method || this.block.has_outro_method) {
if (!use_helper && (this.block.has_intro_method || this.block.has_outro_method)) {
block.builders.intro.add_block(deindent`
for (let #i = 0; #i < ${this.vars.data_length}; #i += 1) {
@transition_in(${this.vars.iterations}[#i]);
@ -239,7 +252,7 @@ export default class EachBlockWrapper extends Wrapper {
);
}
if (this.else) {
if (!use_helper && this.else) {
const each_block_else = component.get_unique_name(`${this.var}_else`);
block.builders.init.add_line(`let ${each_block_else} = null;`);
@ -298,6 +311,82 @@ export default class EachBlockWrapper extends Wrapper {
}
}
render_helper({
block,
parent_nodes,
snippet,
initial_anchor_node,
initial_mount_node,
update_anchor_node,
update_mount_node
}: {
block: Block;
parent_nodes: string;
snippet: string;
initial_anchor_node: string;
initial_mount_node: string;
update_anchor_node: string;
update_mount_node: string;
}) {
const {
create_each_block,
get_each_context,
iterations,
} = this.vars;
block.builders.init.add_block(deindent`
let ${iterations} = new @EachBlock(ctx, ctx => ${snippet}, ${create_each_block}, ${get_each_context}, ${this.else ? this.else.block.name : 'null'});
`)
block.builders.create.add_block(deindent`
${iterations}.c();
`);
if (parent_nodes && this.renderer.options.hydratable) {
block.builders.claim.add_block(deindent`
${iterations}.l(${parent_nodes});
`);
}
block.builders.mount.add_block(deindent`
${iterations}.m(${initial_mount_node}, ${initial_anchor_node});
`);
const all_dependencies = new Set(this.block.dependencies);
const { dependencies } = this.node.expression;
dependencies.forEach((dependency: string) => {
all_dependencies.add(dependency);
});
const condition = Array.from(all_dependencies)
.map(dependency => `changed.${dependency}`)
.join(' || ');
if (condition !== '') {
block.builders.update.add_block(deindent`
if (${condition}) {
${iterations}.p(changed, ctx, ${update_mount_node}, ${update_anchor_node});
}
`);
}
if (this.block.has_intro_method || this.block.has_outro_method) {
block.builders.intro.add_block(deindent`
${iterations}.i();
`)
}
if (this.block.has_outros) {
block.builders.outro.add_block(deindent`
${iterations}.o();
`);
}
block.builders.destroy.add_block(deindent`
${iterations}.d(detaching);
`);
}
render_keyed({
block,
parent_node,

@ -0,0 +1,189 @@
import { destroy_each } from './dom';
// import {
// transition_in,
// transition_out,
// group_outros,
// check_outros,
// } from './transitions';
type ChangedContext<Context> = {
[K in keyof Context]: boolean;
};
interface Fragment<Context> {
/** create */
c: () => void;
/** claim */
l?: (nodes: Array<Node>) => void;
/** hydrate */
h?: () => void;
/** mount */
m: (target: Node, anchor?: Node | null) => void;
/** update */
p?: (changed: ChangedContext<Context>, context: Context) => void;
/** intro */
i?: () => void;
/** outro */
o?: () => void;
/** destroy */
d: (detaching: boolean) => void;
}
type GetEachValue = (context: unknown) => Array<unknown>;
type CreateEachBlock = (context: unknown) => Fragment<unknown>;
type CreateElseBlock = CreateEachBlock;
type CreateChildContext = (
context: unknown,
each_value: unknown,
i: number
) => unknown;
export class EachBlock {
/** each_blocks */
private b: Array<Fragment<unknown>>;
/** else_block */
private eb: Fragment<unknown> | null = null;
/** get_each_value */
private ge: GetEachValue;
/** create_each_block */
private e: CreateEachBlock;
/** create_else_block */
private ce?: CreateElseBlock;
/** get_each_context */
private g: CreateChildContext;
constructor(
context: unknown,
get_each_value: GetEachValue,
create_each_block: CreateEachBlock,
get_each_context: CreateChildContext,
create_else_block: CreateElseBlock
) {
this.ge = get_each_value;
this.e = create_each_block;
this.g = get_each_context;
this.ce = create_else_block;
const each_value = get_each_value(context);
this.b = [];
for (let i = 0; i < each_value.length; i += 1) {
this.b[i] = create_each_block(get_each_context(context, each_value, i));
}
if (create_else_block && !each_value.length) {
this.eb = create_else_block(context);
// TODO: Why exactly is this here and not in the `create` hook below?
this.eb.c();
}
}
/** create */
c() {
for (const block of this.b) {
block.c();
}
// if (this.eb) {
// this.eb.c();
// }
}
/** claim */
l(nodes: Array<Node>) {
for (const block of this.b) {
if (block.l) {
block.l(nodes);
}
}
}
/** mount */
m(target: Node, anchor?: Node | null) {
for (const block of this.b) {
block.m(target, anchor);
}
if (this.eb) {
this.eb.m(target, anchor);
}
}
/** update */
p(changed: unknown, context: unknown, target: Node, anchor?: Node | null) {
const each_value = this.ge(context);
const each_blocks = this.b;
for (let i = 0; i < each_value.length; i += 1) {
const child_ctx = this.g(context, each_value, i);
let block = each_blocks[i];
if (block) {
if (block.p) {
block.p(changed, child_ctx);
}
// transition_in(block, 1);
} else {
block = each_blocks[i] = this.e(child_ctx);
block.c();
// transition_in(block, 1);
block.m(target, anchor);
}
}
// group_outros();
for (let i = each_value.length; i < each_blocks.length; i += 1) {
// TODO: make transitions work correctly…
each_blocks[i].d(true);
// transition_out(each_blocks[i], 1, 1, () => {
// each_blocks[i] = null;
// });
}
// check_outros();
each_blocks.length = each_value.length;
if (this.ce) {
let else_block = this.eb;
if (!each_value.length && else_block) {
if (else_block.p) {
else_block.p(changed, context);
}
} else if (!each_value.length) {
this.eb = else_block = this.ce(context);
else_block.c();
else_block.m(target, anchor);
} else if (this.eb) {
this.eb.d(true);
this.eb = null;
}
}
}
/** intro */
i() {
// for (const block of this.b) {
// transition_in(block);
// }
}
/** outro */
o() {
// const blocks = this.b.filter(Boolean);
// for (const block of blocks) {
// transition_out(block, 0, 0, undefined);
// }
}
/** destroy */
d(detaching: boolean) {
destroy_each(this.b, detaching);
if (this.eb) {
this.eb.d(detaching);
}
}
}

@ -13,3 +13,4 @@ export * from './transitions';
export * from './utils';
export * from './Component';
export * from './dev';
export * from './EachBlock';

@ -1,9 +1,9 @@
/* generated by Svelte vX.Y.Z */
import {
EachBlock,
SvelteComponentDev,
add_location,
append_dev,
destroy_each,
detach_dev,
dispatch_dev,
element,
@ -74,19 +74,11 @@ function create_each_block(ctx) {
function create_fragment(ctx) {
var t0, p, t1, t2;
let each_value = ctx.things;
let each_blocks = [];
for (let i = 0; i < each_value.length; i += 1) {
each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i));
}
let each_blocks = new EachBlock(ctx, ctx => ctx.things, create_each_block, get_each_context, null);
const block = {
c: function create() {
for (let i = 0; i < each_blocks.length; i += 1) {
each_blocks[i].c();
}
each_blocks.c();
t0 = space();
p = element("p");
@ -100,9 +92,7 @@ function create_fragment(ctx) {
},
m: function mount(target, anchor) {
for (let i = 0; i < each_blocks.length; i += 1) {
each_blocks[i].m(target, anchor);
}
each_blocks.m(target, anchor);
insert_dev(target, t0, anchor);
insert_dev(target, p, anchor);
@ -112,25 +102,7 @@ function create_fragment(ctx) {
p: function update(changed, ctx) {
if (changed.things) {
each_value = ctx.things;
let i;
for (i = 0; i < each_value.length; i += 1) {
const child_ctx = get_each_context(ctx, each_value, i);
if (each_blocks[i]) {
each_blocks[i].p(changed, child_ctx);
} else {
each_blocks[i] = create_each_block(child_ctx);
each_blocks[i].c();
each_blocks[i].m(t0.parentNode, t0);
}
}
for (; i < each_blocks.length; i += 1) {
each_blocks[i].d(1);
}
each_blocks.length = each_value.length;
each_blocks.p(changed, ctx, t0.parentNode, t0);
}
if (changed.foo) {
@ -142,7 +114,7 @@ function create_fragment(ctx) {
o: noop,
d: function destroy(detaching) {
destroy_each(each_blocks, detaching);
each_blocks.d(detaching);
if (detaching) {
detach_dev(t0);

@ -1,9 +1,9 @@
/* generated by Svelte vX.Y.Z */
import {
EachBlock,
SvelteComponentDev,
add_location,
append_dev,
destroy_each,
detach_dev,
dispatch_dev,
element,
@ -74,19 +74,11 @@ function create_each_block(ctx) {
function create_fragment(ctx) {
var t0, p, t1, t2;
let each_value = ctx.things;
let each_blocks = [];
for (let i = 0; i < each_value.length; i += 1) {
each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i));
}
let each_blocks = new EachBlock(ctx, ctx => ctx.things, create_each_block, get_each_context, null);
const block = {
c: function create() {
for (let i = 0; i < each_blocks.length; i += 1) {
each_blocks[i].c();
}
each_blocks.c();
t0 = space();
p = element("p");
@ -100,9 +92,7 @@ function create_fragment(ctx) {
},
m: function mount(target, anchor) {
for (let i = 0; i < each_blocks.length; i += 1) {
each_blocks[i].m(target, anchor);
}
each_blocks.m(target, anchor);
insert_dev(target, t0, anchor);
insert_dev(target, p, anchor);
@ -112,25 +102,7 @@ function create_fragment(ctx) {
p: function update(changed, ctx) {
if (changed.things) {
each_value = ctx.things;
let i;
for (i = 0; i < each_value.length; i += 1) {
const child_ctx = get_each_context(ctx, each_value, i);
if (each_blocks[i]) {
each_blocks[i].p(changed, child_ctx);
} else {
each_blocks[i] = create_each_block(child_ctx);
each_blocks[i].c();
each_blocks[i].m(t0.parentNode, t0);
}
}
for (; i < each_blocks.length; i += 1) {
each_blocks[i].d(1);
}
each_blocks.length = each_value.length;
each_blocks.p(changed, ctx, t0.parentNode, t0);
}
if (changed.foo) {
@ -142,7 +114,7 @@ function create_fragment(ctx) {
o: noop,
d: function destroy(detaching) {
destroy_each(each_blocks, detaching);
each_blocks.d(detaching);
if (detaching) {
detach_dev(t0);

@ -1,8 +1,8 @@
/* generated by Svelte vX.Y.Z */
import {
EachBlock,
SvelteComponent,
append,
destroy_each,
detach,
element,
empty,
@ -52,52 +52,24 @@ function create_each_block(ctx) {
function create_fragment(ctx) {
var each_1_anchor;
let each_value = ctx.createElement;
let each_blocks = [];
for (let i = 0; i < each_value.length; i += 1) {
each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i));
}
let each_blocks = new EachBlock(ctx, ctx => ctx.createElement, create_each_block, get_each_context, null);
return {
c() {
for (let i = 0; i < each_blocks.length; i += 1) {
each_blocks[i].c();
}
each_blocks.c();
each_1_anchor = empty();
},
m(target, anchor) {
for (let i = 0; i < each_blocks.length; i += 1) {
each_blocks[i].m(target, anchor);
}
each_blocks.m(target, anchor);
insert(target, each_1_anchor, anchor);
},
p(changed, ctx) {
if (changed.createElement) {
each_value = ctx.createElement;
let i;
for (i = 0; i < each_value.length; i += 1) {
const child_ctx = get_each_context(ctx, each_value, i);
if (each_blocks[i]) {
each_blocks[i].p(changed, child_ctx);
} else {
each_blocks[i] = create_each_block(child_ctx);
each_blocks[i].c();
each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor);
}
}
for (; i < each_blocks.length; i += 1) {
each_blocks[i].d(1);
}
each_blocks.length = each_value.length;
each_blocks.p(changed, ctx, each_1_anchor.parentNode, each_1_anchor);
}
},
@ -105,7 +77,7 @@ function create_fragment(ctx) {
o: noop,
d(detaching) {
destroy_each(each_blocks, detaching);
each_blocks.d(detaching);
if (detaching) {
detach(each_1_anchor);

@ -1,8 +1,8 @@
/* generated by Svelte vX.Y.Z */
import {
EachBlock,
SvelteComponent,
append,
destroy_each,
detach,
element,
empty,
@ -52,51 +52,24 @@ function create_each_block(ctx) {
function create_fragment(ctx) {
var each_1_anchor;
let each_value = [ctx.a, ctx.b, ctx.c, ctx.d, ctx.e];
let each_blocks = [];
for (let i = 0; i < 5; i += 1) {
each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i));
}
let each_blocks = new EachBlock(ctx, ctx => [ctx.a, ctx.b, ctx.c, ctx.d, ctx.e], create_each_block, get_each_context, null);
return {
c() {
for (let i = 0; i < 5; i += 1) {
each_blocks[i].c();
}
each_blocks.c();
each_1_anchor = empty();
},
m(target, anchor) {
for (let i = 0; i < 5; i += 1) {
each_blocks[i].m(target, anchor);
}
each_blocks.m(target, anchor);
insert(target, each_1_anchor, anchor);
},
p(changed, ctx) {
if (changed.a || changed.b || changed.c || changed.d || changed.e) {
each_value = [ctx.a, ctx.b, ctx.c, ctx.d, ctx.e];
let i;
for (i = 0; i < each_value.length; i += 1) {
const child_ctx = get_each_context(ctx, each_value, i);
if (each_blocks[i]) {
each_blocks[i].p(changed, child_ctx);
} else {
each_blocks[i] = create_each_block(child_ctx);
each_blocks[i].c();
each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor);
}
}
for (; i < 5; i += 1) {
each_blocks[i].d(1);
}
each_blocks.p(changed, ctx, each_1_anchor.parentNode, each_1_anchor);
}
},
@ -104,7 +77,7 @@ function create_fragment(ctx) {
o: noop,
d(detaching) {
destroy_each(each_blocks, detaching);
each_blocks.d(detaching);
if (detaching) {
detach(each_1_anchor);

@ -1,10 +1,10 @@
/* generated by Svelte vX.Y.Z */
import {
EachBlock,
HtmlTag,
SvelteComponent,
append,
attr,
destroy_each,
detach,
element,
init,
@ -83,19 +83,11 @@ function create_each_block(ctx) {
function create_fragment(ctx) {
var t0, p, t1;
let each_value = ctx.comments;
let each_blocks = [];
for (let i = 0; i < each_value.length; i += 1) {
each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i));
}
let each_blocks = new EachBlock(ctx, ctx => ctx.comments, create_each_block, get_each_context, null);
return {
c() {
for (let i = 0; i < each_blocks.length; i += 1) {
each_blocks[i].c();
}
each_blocks.c();
t0 = space();
p = element("p");
@ -103,9 +95,7 @@ function create_fragment(ctx) {
},
m(target, anchor) {
for (let i = 0; i < each_blocks.length; i += 1) {
each_blocks[i].m(target, anchor);
}
each_blocks.m(target, anchor);
insert(target, t0, anchor);
insert(target, p, anchor);
@ -114,25 +104,7 @@ function create_fragment(ctx) {
p(changed, ctx) {
if (changed.comments || changed.elapsed || changed.time) {
each_value = ctx.comments;
let i;
for (i = 0; i < each_value.length; i += 1) {
const child_ctx = get_each_context(ctx, each_value, i);
if (each_blocks[i]) {
each_blocks[i].p(changed, child_ctx);
} else {
each_blocks[i] = create_each_block(child_ctx);
each_blocks[i].c();
each_blocks[i].m(t0.parentNode, t0);
}
}
for (; i < each_blocks.length; i += 1) {
each_blocks[i].d(1);
}
each_blocks.length = each_value.length;
each_blocks.p(changed, ctx, t0.parentNode, t0);
}
if (changed.foo) {
@ -144,7 +116,7 @@ function create_fragment(ctx) {
o: noop,
d(detaching) {
destroy_each(each_blocks, detaching);
each_blocks.d(detaching);
if (detaching) {
detach(t0);

Loading…
Cancel
Save