Skip to content

Commit 1078bae

Browse files
authored
Merge pull request #525 from sveltejs/gh-7
Transitions
2 parents 8ff66f3 + 90adb3b commit 1078bae

File tree

54 files changed

+4318
-155
lines changed

Some content is hidden

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

54 files changed

+4318
-155
lines changed

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
"precodecov": "npm run coverage",
1818
"lint": "eslint src test/*.js",
1919
"build": "npm run build:main && npm run build:shared && npm run build:ssr",
20-
"build:main": "rollup -c rollup/rollup.config.main.js",
20+
"build:main": "node src/shared/_build.js && rollup -c rollup/rollup.config.main.js",
2121
"build:shared": "rollup -c rollup/rollup.config.shared.js",
2222
"build:ssr": "rollup -c rollup/rollup.config.ssr.js",
23+
"dev": "node src/shared/_build.js && rollup -c rollup/rollup.config.main.js -w",
24+
"dev:shared": "rollup -c rollup/rollup.config.shared.js -w",
2325
"pretest": "npm run build",
24-
"prepublish": "npm run lint && npm run build"
26+
"prepublish": "npm run build && npm run lint"
2527
},
2628
"repository": {
2729
"type": "git",
@@ -72,6 +74,7 @@
7274
"rollup-plugin-commonjs": "^7.0.0",
7375
"rollup-plugin-json": "^2.1.0",
7476
"rollup-plugin-node-resolve": "^2.0.0",
77+
"rollup-watch": "^3.2.2",
7578
"source-map": "^0.5.6",
7679
"source-map-support": "^0.4.8"
7780
},

src/generators/Generator.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export default class Generator {
2424
this.helpers = new Set();
2525
this.components = new Set();
2626
this.events = new Set();
27+
this.transitions = new Set();
2728
this.importedComponents = new Map();
2829

2930
this.bindingGroups = [];
@@ -328,7 +329,7 @@ export default class Generator {
328329
});
329330
}
330331

331-
[ 'helpers', 'events', 'components' ].forEach( key => {
332+
[ 'helpers', 'events', 'components', 'transitions' ].forEach( key => {
332333
if ( templateProperties[ key ] ) {
333334
templateProperties[ key ].value.properties.forEach( prop => {
334335
this[ key ].add( prop.key.name );

src/generators/dom/Block.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,17 @@ export default class Block {
2424
create: new CodeBuilder(),
2525
mount: new CodeBuilder(),
2626
update: new CodeBuilder(),
27+
intro: new CodeBuilder(),
28+
outro: new CodeBuilder(),
2729
detach: new CodeBuilder(),
2830
detachRaw: new CodeBuilder(),
2931
destroy: new CodeBuilder()
3032
};
3133

34+
this.hasIntroMethod = false; // a block could have an intro method but not intro transitions, e.g. if a sibling block has intros
35+
this.hasOutroMethod = false;
36+
this.outros = 0;
37+
3238
this.aliases = new Map();
3339
this.variables = new Map();
3440
this.getUniqueName = this.generator.getUniqueNameMaker( options.params );
@@ -100,6 +106,20 @@ export default class Block {
100106
}
101107

102108
render () {
109+
let introing;
110+
const hasIntros = !this.builders.intro.isEmpty();
111+
if ( hasIntros ) {
112+
introing = this.getUniqueName( 'introing' );
113+
this.addVariable( introing );
114+
}
115+
116+
let outroing;
117+
const hasOutros = !this.builders.outro.isEmpty();
118+
if ( hasOutros ) {
119+
outroing = this.getUniqueName( 'outroing' );
120+
this.addVariable( outroing );
121+
}
122+
103123
if ( this.variables.size ) {
104124
const variables = Array.from( this.variables.keys() )
105125
.map( key => {
@@ -157,6 +177,50 @@ export default class Block {
157177
}
158178
}
159179

180+
if ( this.hasIntroMethod ) {
181+
if ( hasIntros ) {
182+
properties.addBlock( deindent`
183+
intro: function ( ${this.target}, anchor ) {
184+
if ( ${introing} ) return;
185+
${introing} = true;
186+
${hasOutros && `${outroing} = false;`}
187+
188+
${this.builders.intro}
189+
190+
this.mount( ${this.target}, anchor );
191+
},
192+
` );
193+
} else {
194+
properties.addBlock( deindent`
195+
intro: function ( ${this.target}, anchor ) {
196+
this.mount( ${this.target}, anchor );
197+
},
198+
` );
199+
}
200+
}
201+
202+
if ( this.hasOutroMethod ) {
203+
if ( hasOutros ) {
204+
properties.addBlock( deindent`
205+
outro: function ( ${this.alias( 'outrocallback' )} ) {
206+
if ( ${outroing} ) return;
207+
${outroing} = true;
208+
${hasIntros && `${introing} = false;`}
209+
210+
var ${this.alias( 'outros' )} = ${this.outros};
211+
212+
${this.builders.outro}
213+
},
214+
` );
215+
} else {
216+
properties.addBlock( deindent`
217+
outro: function ( outrocallback ) {
218+
outrocallback();
219+
},
220+
` );
221+
}
222+
}
223+
160224
if ( this.builders.destroy.isEmpty() ) {
161225
properties.addBlock( `destroy: ${this.generator.helper( 'noop' )}` );
162226
} else {

src/generators/dom/index.js

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import MagicString from 'magic-string';
2-
import { parse } from 'acorn';
2+
import { parseExpressionAt } from 'acorn';
33
import annotateWithScopes from '../../utils/annotateWithScopes.js';
44
import isReference from '../../utils/isReference.js';
55
import { walk } from 'estree-walker';
66
import deindent from '../../utils/deindent.js';
77
import CodeBuilder from '../../utils/CodeBuilder.js';
88
import visit from './visit.js';
9-
import { nameMap, sharedMap } from './sharedNames.js';
9+
import shared from './shared.js';
1010
import Generator from '../Generator.js';
1111
import preprocess from './preprocess.js';
1212

@@ -25,7 +25,7 @@ class DomGenerator extends Generator {
2525
}
2626

2727
helper ( name ) {
28-
if ( this.options.dev && sharedMap.has( `${name}Dev` ) ) {
28+
if ( this.options.dev && `${name}Dev` in shared ) {
2929
name = `${name}Dev`;
3030
}
3131

@@ -138,7 +138,7 @@ export default function dom ( parsed, source, options ) {
138138
builders.init.addLine( `if ( !${generator.alias( 'added_css' )} ) ${generator.alias( 'add_css' )}();` );
139139
}
140140

141-
if ( generator.hasComponents ) {
141+
if ( generator.hasComponents || generator.hasIntroTransitions ) {
142142
builders.init.addLine( `this._renderHooks = [];` );
143143
}
144144

@@ -158,7 +158,7 @@ export default function dom ( parsed, source, options ) {
158158
` );
159159
}
160160

161-
if ( generator.hasComponents ) {
161+
if ( generator.hasComponents || generator.hasIntroTransitions ) {
162162
const statement = `this._flush();`;
163163

164164
builders.init.addBlock( statement );
@@ -168,7 +168,7 @@ export default function dom ( parsed, source, options ) {
168168
if ( templateProperties.oncreate ) {
169169
builders.init.addBlock( deindent`
170170
if ( options._root ) {
171-
options._root._renderHooks.push({ fn: ${generator.alias( 'template' )}.oncreate, context: this });
171+
options._root._renderHooks.push( ${generator.alias( 'template' )}.oncreate.bind( this ) );
172172
} else {
173173
${generator.alias( 'template' )}.oncreate.call( this );
174174
}
@@ -218,7 +218,7 @@ export default function dom ( parsed, source, options ) {
218218
219219
this._handlers = Object.create( null );
220220
221-
this._root = options._root;
221+
this._root = options._root || this;
222222
this._yield = options._yield;
223223
224224
${builders.init}
@@ -275,20 +275,20 @@ export default function dom ( parsed, source, options ) {
275275
);
276276
} else {
277277
generator.uses.forEach( key => {
278-
const str = sharedMap.get( key );
278+
const str = shared[ key ];
279279
const code = new MagicString( str );
280-
const fn = parse( str ).body[0];
280+
const expression = parseExpressionAt( str, 0 );
281281

282-
let scope = annotateWithScopes( fn );
282+
let scope = annotateWithScopes( expression );
283283

284-
walk( fn, {
284+
walk( expression, {
285285
enter ( node, parent ) {
286286
if ( node._scope ) scope = node._scope;
287287

288288
if ( node.type === 'Identifier' && isReference( node, parent ) && !scope.has( node.name ) ) {
289-
if ( nameMap.has( node.name ) ) {
289+
if ( node.name in shared ) {
290290
// this helper function depends on another one
291-
const dependency = nameMap.get( node.name );
291+
const dependency = node.name;
292292
generator.uses.add( dependency );
293293

294294
const alias = generator.alias( dependency );
@@ -302,10 +302,18 @@ export default function dom ( parsed, source, options ) {
302302
}
303303
});
304304

305-
const alias = generator.alias( key );
306-
if ( alias !== fn.id.name ) code.overwrite( fn.id.start, fn.id.end, alias );
305+
if ( key === 'transitionManager' ) { // special case
306+
const global = `_svelteTransitionManager`;
307307

308-
builders.main.addBlock( code.toString() );
308+
builders.main.addBlock(
309+
`var ${generator.alias( 'transitionManager' )} = window.${global} || ( window.${global} = ${code});`
310+
);
311+
} else {
312+
const alias = generator.alias( expression.id.name );
313+
if ( alias !== expression.id.name ) code.overwrite( expression.id.start, expression.id.end, alias );
314+
315+
builders.main.addBlock( code.toString() );
316+
}
309317
});
310318
}
311319

src/generators/dom/preprocess.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ const preprocessors = {
5959
IfBlock: ( generator, block, state, node ) => {
6060
const blocks = [];
6161
let dynamic = false;
62+
let hasIntros = false;
63+
let hasOutros = false;
6264

6365
function attachBlocks ( node ) {
6466
const dependencies = block.findDependencies( node.expression );
@@ -78,6 +80,9 @@ const preprocessors = {
7880
block.addDependencies( node._block.dependencies );
7981
}
8082

83+
if ( node._block.hasIntroMethod ) hasIntros = true;
84+
if ( node._block.hasOutroMethod ) hasOutros = true;
85+
8186
if ( isElseIf( node.else ) ) {
8287
attachBlocks( node.else.children[0] );
8388
} else if ( node.else ) {
@@ -101,6 +106,8 @@ const preprocessors = {
101106

102107
blocks.forEach( block => {
103108
block.hasUpdateMethod = dynamic;
109+
block.hasIntroMethod = hasIntros;
110+
block.hasOutroMethod = hasOutros;
104111
});
105112

106113
generator.blocks.push( ...blocks );
@@ -200,6 +207,14 @@ const preprocessors = {
200207
const dependencies = block.findDependencies( attribute.value );
201208
block.addDependencies( dependencies );
202209
}
210+
211+
else if ( attribute.type === 'Transition' ) {
212+
if ( attribute.intro ) generator.hasIntroTransitions = block.hasIntroMethod = true;
213+
if ( attribute.outro ) {
214+
generator.hasOutroTransitions = block.hasOutroMethod = true;
215+
block.outros += 1;
216+
}
217+
}
203218
});
204219

205220
if ( node.children.length ) {

src/generators/dom/sharedNames.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/generators/dom/visitors/Component/Component.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export default function visitComponent ( generator, block, state, node ) {
9292

9393
const componentInitProperties = [
9494
`target: ${!isToplevel ? state.parentNode: 'null'}`,
95-
`_root: ${block.component}._root || ${block.component}`
95+
`_root: ${block.component}._root`
9696
];
9797

9898
// Component has children, put them in a separate {{yield}} block

0 commit comments

Comments
 (0)