Skip to content

Commit 326d5a7

Browse files
committed
Allow transitions to be local
Allows transitions to only run locally, skipping running when they are added to the DOM or removed from it. Example: ```html {#if visible} {#each things as thing} <div transition:fade|local></div> {/each} {/if} <script> export default { transitions: { fade(node, params) { return { duration: 400, css: t => { return `opacity: ${t}`; } }; } } }; </script> ``` In this example items in the each-block will fade in and fade out when they are added to or removed from `things` but the list will appear suddenly and disappear suddenly (no fade) when `visible` is toggled to `true` or `false`. This is another try at #1480.
1 parent a4d412f commit 326d5a7

File tree

79 files changed

+506
-159
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+506
-159
lines changed

src/compile/dom/Block.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ export default class Block {
241241
properties.addBlock(`m: @noop,`);
242242
} else {
243243
properties.addBlock(deindent`
244-
${dev ? 'm: function mount' : 'm'}(#target, anchor) {
244+
${dev ? 'm: function mount' : 'm'}(#target, anchor${this.compiler.options.nestedTransitions && ', introing'}) {
245245
${this.builders.mount}
246246
},
247247
`);
@@ -281,10 +281,10 @@ export default class Block {
281281
properties.addBlock(`i: @noop,`);
282282
} else {
283283
properties.addBlock(deindent`
284-
${dev ? 'i: function intro' : 'i'}(#target, anchor) {
284+
${dev ? 'i: function intro' : 'i'}(#target, anchor${this.compiler.options.nestedTransitions && ', introing'}) {
285285
if (#current) return;
286286
${this.builders.intro}
287-
this.m(#target, anchor);
287+
this.m(#target, anchor${this.compiler.options.nestedTransitions && ', introing'});
288288
},
289289
`);
290290
}
@@ -293,7 +293,7 @@ export default class Block {
293293
properties.addBlock(`o: @run,`);
294294
} else {
295295
properties.addBlock(deindent`
296-
${dev ? 'o: function outro' : 'o'}(#outrocallback) {
296+
${dev ? 'o: function outro' : 'o'}(#outrocallback${this.compiler.options.nestedTransitions && ', outroing'}) {
297297
if (!#current) return;
298298
299299
${this.outros > 1 && `#outrocallback = @callAfter(#outrocallback, ${this.outros});`}

src/compile/dom/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export default function dom(
227227
this._fragment.c();
228228
this._fragment.${block.hasIntroMethod ? 'i' : 'm'}(this.shadowRoot, null);
229229
230-
if (options.target) this._mount(options.target, options.anchor);
230+
if (options.target) this._mount(options.target, options.anchor${compiler.options.nestedTransitions && ', 1'});
231231
` : deindent`
232232
if (options.target) {
233233
${compiler.options.hydratable
@@ -239,7 +239,7 @@ export default function dom(
239239
${options.dev &&
240240
`if (options.hydrate) throw new Error("options.hydrate only works if the component was compiled with the \`hydratable: true\` option");`}
241241
this._fragment.c();`}
242-
this._mount(options.target, options.anchor);
242+
this._mount(options.target, options.anchor${compiler.options.nestedTransitions && ', 1'});
243243
244244
${(compiler.hasComponents || target.hasComplexBindings || hasInitHooks || target.hasIntroTransitions) &&
245245
`@flush(this);`}

src/compile/nodes/AwaitBlock.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ export default class AwaitBlock extends Node {
177177
const ${countdown} = @callAfter(#outrocallback, 3);
178178
for (let #i = 0; #i < 3; #i += 1) {
179179
const block = ${info}.blocks[#i];
180-
if (block) block.o(${countdown});
180+
if (block) block.o(${countdown}, 1);
181181
else ${countdown}();
182182
}
183183
`);

src/compile/nodes/Component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ export default class Component extends Node {
386386

387387
block.builders.mount.addBlock(deindent`
388388
if (${name}) {
389-
${name}._mount(${parentNode || '#target'}, ${parentNode ? 'null' : 'anchor'});
389+
${name}._mount(${parentNode || '#target'}, ${parentNode ? 'null' : 'anchor'}${compiler.options.nestedTransitions && ', introing'});
390390
${this.ref && `#component.refs.${this.ref} = ${name};`}
391391
}
392392
`);
@@ -486,7 +486,7 @@ export default class Component extends Node {
486486
}
487487

488488
block.builders.mount.addLine(
489-
`${name}._mount(${parentNode || '#target'}, ${parentNode ? 'null' : 'anchor'});`
489+
`${name}._mount(${parentNode || '#target'}, ${parentNode ? 'null' : 'anchor'}${compiler.options.nestedTransitions ? ', introing' : ''});`
490490
);
491491

492492
if (updates.length) {
@@ -505,7 +505,7 @@ export default class Component extends Node {
505505

506506
if (this.compiler.options.nestedTransitions) {
507507
block.builders.outro.addLine(
508-
`if (${name}) ${name}._fragment.o(#outrocallback);`
508+
`if (${name}) ${name}._fragment.o(#outrocallback, outroing);`
509509
);
510510
}
511511
}

src/compile/nodes/EachBlock.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ export default class EachBlock extends Node {
203203

204204
block.builders.mount.addBlock(deindent`
205205
if (${each_block_else}) {
206-
${each_block_else}.${mountOrIntro}(${parentNode || '#target'}, null);
206+
${each_block_else}.${mountOrIntro}(${parentNode || '#target'}, null${this.compiler.options.nestedTransitions && ', 1'});
207207
}
208208
`);
209209

@@ -310,12 +310,11 @@ export default class EachBlock extends Node {
310310
}
311311

312312
block.builders.mount.addBlock(deindent`
313-
for (#i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].${mountOrIntro}(${initialMountNode}, ${anchorNode});
313+
for (#i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].${mountOrIntro}(${initialMountNode}, ${anchorNode}${this.compiler.options.nestedTransitions ? ', 1' : ''});
314314
`);
315315

316316
const dynamic = this.block.hasUpdateMethod;
317317

318-
const rects = block.getUniqueName('rects');
319318
const destroy = this.block.hasAnimation
320319
? `@fixAndOutroAndDestroyBlock`
321320
: this.block.hasOutros
@@ -335,7 +334,7 @@ export default class EachBlock extends Node {
335334
const countdown = block.getUniqueName('countdown');
336335
block.builders.outro.addBlock(deindent`
337336
const ${countdown} = @callAfter(#outrocallback, ${blocks}.length);
338-
for (#i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].o(${countdown});
337+
for (#i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].o(${countdown}, 1);
339338
`);
340339
}
341340

@@ -385,7 +384,7 @@ export default class EachBlock extends Node {
385384

386385
block.builders.mount.addBlock(deindent`
387386
for (var #i = 0; #i < ${iterations}.length; #i += 1) {
388-
${iterations}[#i].${mountOrIntro}(${initialMountNode}, ${anchorNode});
387+
${iterations}[#i].${mountOrIntro}(${initialMountNode}, ${anchorNode}${this.compiler.options.nestedTransitions && ', 1'});
389388
}
390389
`);
391390

@@ -397,16 +396,17 @@ export default class EachBlock extends Node {
397396

398397
const outroBlock = this.block.hasOutros && block.getUniqueName('outroBlock')
399398
if (outroBlock) {
399+
const outroArg = this.compiler.options.nestedTransitions ? ', outroing' : '';
400400
block.builders.init.addBlock(deindent`
401-
function ${outroBlock}(i, detach, fn) {
401+
function ${outroBlock}(i, detach, fn${outroArg}) {
402402
if (${iterations}[i]) {
403403
${iterations}[i].o(() => {
404404
if (detach) {
405405
${iterations}[i].d(detach);
406406
${iterations}[i] = null;
407407
}
408408
if (fn) fn();
409-
});
409+
}${outroArg});
410410
}
411411
}
412412
`);
@@ -451,7 +451,7 @@ export default class EachBlock extends Node {
451451
if (this.block.hasOutros) {
452452
destroy = deindent`
453453
@groupOutros();
454-
for (; #i < ${iterations}.length; #i += 1) ${outroBlock}(#i, 1);
454+
for (; #i < ${iterations}.length; #i += 1) ${outroBlock}(#i, 1${this.compiler.options.nestedTransitions && ', null, 1'});
455455
`;
456456
} else {
457457
destroy = deindent`
@@ -482,7 +482,7 @@ export default class EachBlock extends Node {
482482
block.builders.outro.addBlock(deindent`
483483
${iterations} = ${iterations}.filter(Boolean);
484484
const ${countdown} = @callAfter(#outrocallback, ${iterations}.length);
485-
for (let #i = 0; #i < ${iterations}.length; #i += 1) ${outroBlock}(#i, 0, ${countdown});`
485+
for (let #i = 0; #i < ${iterations}.length; #i += 1) ${outroBlock}(#i, 0, ${countdown}${this.compiler.options.nestedTransitions && ', 1'});`
486486
);
487487
}
488488

src/compile/nodes/Element.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -745,32 +745,35 @@ export default class Element extends Node {
745745
const { intro, outro } = this;
746746

747747
if (!intro && !outro) return;
748+
const nested = this.compiler.options.nestedTransitions;
748749

749750
if (intro === outro) {
751+
const [transitionName, ...pipes] = intro.name.split('|');
752+
const local = ~pipes.indexOf('local') && 1;
750753
const name = block.getUniqueName(`${this.var}_transition`);
751754
const snippet = intro.expression
752755
? intro.expression.snippet
753756
: '{}';
754757

755758
block.addVariable(name);
756759

757-
const fn = `%transitions-${intro.name}`;
760+
const fn = `%transitions-${transitionName}`;
758761

759762
block.builders.intro.addConditional(`#component.root._intro`, deindent`
760763
if (${name}) ${name}.invalidate();
761764
762765
#component.root._aftercreate.push(() => {
763-
if (!${name}) ${name} = @wrapTransition(#component, ${this.var}, ${fn}, ${snippet}, true);
764-
${name}.run(1);
766+
if (!${name}) ${name} = @wrapTransition(#component, ${this.var}, ${fn}, ${snippet}, 1${nested && `, ${local}`});
767+
${name}.run(1${nested && ', null, introing'});
765768
});
766769
`);
767770

768771
block.builders.outro.addBlock(deindent`
769-
if (!${name}) ${name} = @wrapTransition(#component, ${this.var}, ${fn}, ${snippet}, false);
772+
if (!${name}) ${name} = @wrapTransition(#component, ${this.var}, ${fn}, ${snippet}, 0${nested && `, ${local}`});
770773
${name}.run(0, () => {
771774
#outrocallback();
772775
${name} = null;
773-
});
776+
}${nested && ', outroing'});
774777
`);
775778

776779
block.builders.destroy.addConditional('detach', `if (${name}) ${name}.abort();`);
@@ -780,11 +783,13 @@ export default class Element extends Node {
780783

781784
if (intro) {
782785
block.addVariable(introName);
786+
const [transitionName, ...pipes] = intro.name.split('|');
787+
const local = ~pipes.indexOf('local') && 1;
783788
const snippet = intro.expression
784789
? intro.expression.snippet
785790
: '{}';
786791

787-
const fn = `%transitions-${intro.name}`; // TODO add built-in transitions?
792+
const fn = `%transitions-${transitionName}`; // TODO add built-in transitions?
788793

789794
if (outro) {
790795
block.builders.intro.addBlock(deindent`
@@ -795,19 +800,21 @@ export default class Element extends Node {
795800

796801
block.builders.intro.addConditional(`#component.root._intro`, deindent`
797802
#component.root._aftercreate.push(() => {
798-
${introName} = @wrapTransition(#component, ${this.var}, ${fn}, ${snippet}, true);
799-
${introName}.run(1);
803+
${introName} = @wrapTransition(#component, ${this.var}, ${fn}, ${snippet}, 1${nested && `, ${local}`});
804+
${introName}.run(1${nested && ', null, introing'});
800805
});
801806
`);
802807
}
803808

804809
if (outro) {
805810
block.addVariable(outroName);
811+
const [transitionName, ...pipes] = outro.name.split('|');
812+
const local = ~pipes.indexOf('local') && 1;
806813
const snippet = outro.expression
807814
? outro.expression.snippet
808815
: '{}';
809816

810-
const fn = `%transitions-${outro.name}`;
817+
const fn = `%transitions-${transitionName}`;
811818

812819
block.builders.intro.addBlock(deindent`
813820
if (${outroName}) ${outroName}.abort(1);
@@ -816,8 +823,8 @@ export default class Element extends Node {
816823
// TODO hide elements that have outro'd (unless they belong to a still-outroing
817824
// group) prior to their removal from the DOM
818825
block.builders.outro.addBlock(deindent`
819-
${outroName} = @wrapTransition(#component, ${this.var}, ${fn}, ${snippet}, false);
820-
${outroName}.run(0, #outrocallback);
826+
${outroName} = @wrapTransition(#component, ${this.var}, ${fn}, ${snippet}, 0${nested && `, ${local}`});
827+
${outroName}.run(0, #outrocallback${nested && ', outroing'});
821828
`);
822829

823830
block.builders.destroy.addConditional('detach', `if (${outroName}) ${outroName}.abort();`);

src/compile/nodes/IfBlock.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ export default class IfBlock extends Node {
140140

141141
if (this.compiler.options.nestedTransitions) {
142142
block.builders.outro.addBlock(deindent`
143-
if (${name}) ${name}.o(#outrocallback);
143+
if (${name}) ${name}.o(#outrocallback, 1);
144144
else #outrocallback();
145145
`);
146146
}
@@ -152,7 +152,7 @@ export default class IfBlock extends Node {
152152

153153
if (hasOutros && this.compiler.options.nestedTransitions) {
154154
block.builders.outro.addBlock(deindent`
155-
if (${name}) ${name}.o(#outrocallback);
155+
if (${name}) ${name}.o(#outrocallback, 1);
156156
else #outrocallback();
157157
`);
158158
}
@@ -206,7 +206,7 @@ export default class IfBlock extends Node {
206206
const initialMountNode = parentNode || '#target';
207207
const anchorNode = parentNode ? 'null' : 'anchor';
208208
block.builders.mount.addLine(
209-
`${if_name}${name}.${mountOrIntro}(${initialMountNode}, ${anchorNode});`
209+
`${if_name}${name}.${mountOrIntro}(${initialMountNode}, ${anchorNode}${this.compiler.options.nestedTransitions ? ', 1' : ''});`
210210
);
211211

212212
const updateMountNode = this.getUpdateMountNode(anchor);
@@ -292,7 +292,7 @@ export default class IfBlock extends Node {
292292
const anchorNode = parentNode ? 'null' : 'anchor';
293293

294294
block.builders.mount.addLine(
295-
`${if_current_block_type_index}${if_blocks}[${current_block_type_index}].${mountOrIntro}(${initialMountNode}, ${anchorNode});`
295+
`${if_current_block_type_index}${if_blocks}[${current_block_type_index}].${mountOrIntro}(${initialMountNode}, ${anchorNode}${this.compiler.options.nestedTransitions ? ', 1' : ''});`
296296
);
297297

298298
const updateMountNode = this.getUpdateMountNode(anchor);
@@ -374,7 +374,7 @@ export default class IfBlock extends Node {
374374
const anchorNode = parentNode ? 'null' : 'anchor';
375375

376376
block.builders.mount.addLine(
377-
`if (${name}) ${name}.${mountOrIntro}(${initialMountNode}, ${anchorNode});`
377+
`if (${name}) ${name}.${mountOrIntro}(${initialMountNode}, ${anchorNode}${this.compiler.options.nestedTransitions ? ', 1' : ''});`
378378
);
379379

380380
const updateMountNode = this.getUpdateMountNode(anchor);

src/shared/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,8 @@ export function callAll(fns) {
147147
while (fns && fns.length) fns.shift()();
148148
}
149149

150-
export function _mount(target, anchor) {
151-
this._fragment[this._fragment.i ? 'i' : 'm'](target, anchor || null);
150+
export function _mount(target, anchor, introing) {
151+
this._fragment[this._fragment.i ? 'i' : 'm'](target, anchor || null, introing);
152152
}
153153

154154
export var PENDING = {};

src/shared/transitions.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function hash(str) {
2626
return hash >>> 0;
2727
}
2828

29-
export function wrapTransition(component, node, fn, params, intro) {
29+
export function wrapTransition(component, node, fn, params, intro, local) {
3030
let obj = fn.call(component, node, params);
3131
let duration;
3232
let ease;
@@ -40,28 +40,34 @@ export function wrapTransition(component, node, fn, params, intro) {
4040
program: null,
4141
pending: null,
4242

43-
run(b, callback) {
43+
run(b, callback, introOutro) {
4444
if (typeof obj === 'function') {
4545
transitionManager.wait().then(() => {
4646
obj = obj();
47-
this._run(b, callback);
47+
this._run(b, callback, introOutro);
4848
});
4949
} else {
50-
this._run(b, callback);
50+
this._run(b, callback, introOutro);
5151
}
5252
},
5353

54-
_run(b, callback) {
54+
_run(b, callback, introOutro) {
5555
duration = obj.duration || 300;
5656
ease = obj.easing || linear;
5757

58+
if (introOutro && local) {
59+
this.t = b;
60+
if (callback) callback();
61+
return;
62+
}
63+
5864
const program = {
5965
start: window.performance.now() + (obj.delay || 0),
6066
b,
6167
callback: callback || noop
6268
};
6369

64-
if (intro && !initialised) {
70+
if (b && !initialised) {
6571
if (obj.css && obj.delay) {
6672
cssText = node.style.cssText;
6773
node.style.cssText += obj.css(0, 1);

src/validate/html/validateElement.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,11 @@ export default function validateElement(
8585
if (attribute.type === 'Ref') {
8686
if (!isValidIdentifier(attribute.name)) {
8787
const suggestion = attribute.name.replace(/[^_$a-z0-9]/ig, '_').replace(/^\d/, '_$&');
88-
88+
8989
validator.error(attribute, {
9090
code: `invalid-reference-name`,
9191
message: `Reference name '${attribute.name}' is invalid — must be a valid identifier such as ${suggestion}`
92-
});
92+
});
9393
} else {
9494
if (!refs.has(attribute.name)) refs.set(attribute.name, []);
9595
refs.get(attribute.name).push(node);
@@ -213,7 +213,7 @@ export default function validateElement(
213213
validator.used.events.add(attribute.name);
214214
validateEventHandler(validator, attribute, refCallees);
215215
} else if (attribute.type === 'Transition') {
216-
validator.used.transitions.add(attribute.name);
216+
validator.used.transitions.add(attribute.name.split('|')[0]);
217217

218218
const bidi = attribute.intro && attribute.outro;
219219

@@ -249,7 +249,7 @@ export default function validateElement(
249249
if (attribute.outro) hasOutro = true;
250250
if (bidi) hasTransition = true;
251251

252-
if (!validator.transitions.has(attribute.name)) {
252+
if (!validator.transitions.has(attribute.name.split('|')[0])) {
253253
validator.error(attribute, {
254254
code: `missing-transition`,
255255
message: `Missing transition '${attribute.name}'`

0 commit comments

Comments
 (0)