Skip to content

Commit

Permalink
Merge branch 'master' into gh-543
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed May 6, 2017
2 parents e9def64 + 2faf788 commit 00c41e2
Show file tree
Hide file tree
Showing 27 changed files with 326 additions and 46 deletions.
8 changes: 4 additions & 4 deletions src/generators/dom/visitors/Element/addTransitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ export default function addTransitions ( generator, block, state, node, intro, o
block.builders.intro.addBlock( deindent`
${block.component}._renderHooks.push( function () {
if ( !${name} ) ${name} = ${wrapTransition}( ${state.name}, ${fn}, ${snippet}, true, null );
${name}.run( ${name}.t, 1, function () {
${name}.run( true, function () {
${block.component}.fire( 'intro.end', { node: ${state.name} });
});
});
` );

block.builders.outro.addBlock( deindent`
${name}.run( ${name}.t, 0, function () {
${name}.run( false, function () {
${block.component}.fire( 'outro.end', { node: ${state.name} });
if ( --${block.alias( 'outros' )} === 0 ) ${block.alias( 'outrocallback' )}();
${name} = null;
Expand Down Expand Up @@ -49,7 +49,7 @@ export default function addTransitions ( generator, block, state, node, intro, o
block.builders.intro.addBlock( deindent`
${block.component}._renderHooks.push( function () {
${introName} = ${wrapTransition}( ${state.name}, ${fn}, ${snippet}, true, null );
${introName}.run( 0, 1, function () {
${introName}.run( true, function () {
${block.component}.fire( 'intro.end', { node: ${state.name} });
});
});
Expand All @@ -66,7 +66,7 @@ export default function addTransitions ( generator, block, state, node, intro, o
// group) prior to their removal from the DOM
block.builders.outro.addBlock( deindent`
${outroName} = ${wrapTransition}( ${state.name}, ${fn}, ${snippet}, false, null );
${outroName}.run( 1, 0, function () {
${outroName}.run( false, function () {
${block.component}.fire( 'outro.end', { node: ${state.name} });
if ( --${block.alias( 'outros' )} === 0 ) ${block.alias( 'outrocallback' )}();
});
Expand Down
83 changes: 50 additions & 33 deletions src/shared/transitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function generateKeyframes ( a, b, delta, duration, ease, fn, node, style
}

export function wrapTransition ( node, fn, params, intro, outgroup ) {
var obj = fn( node, params, intro );
var obj = fn( node, params );
var duration = obj.duration || 300;
var ease = obj.easing || linear;

Expand All @@ -40,47 +40,62 @@ export function wrapTransition ( node, fn, params, intro, outgroup ) {
if ( intro && obj.tick ) obj.tick( 0 );

return {
start: null,
end: null,
a: null,
b: null,
d: null,
running: false,
t: intro ? 0 : 1,
callback: null,
run: function ( a, b, callback ) {
this.a = a;
this.b = b;
this.delta = b - a;
this.start = window.performance.now() + ( obj.delay || 0 );
this.duration = duration * Math.abs( b - a );
this.end = this.start + this.duration;

this.callback = callback;

if ( obj.css ) {
generateKeyframes( this.a, this.b, this.delta, this.duration, ease, obj.css, node, style );
running: false,
program: null,
pending: null,
run: function ( intro, callback ) {
var program = {
start: window.performance.now() + ( obj.delay || 0 ),
intro: intro,
callback: callback
};

if ( obj.delay ) {
this.pending = program;
} else {
this.start( program );
}

if ( !this.running ) {
this.running = true;
transitionManager.add( this );
}
},
start: function ( program ) {
program.a = this.t;
program.b = program.intro ? 1 : 0;
program.delta = program.b - program.a;
program.duration = duration * Math.abs( program.b - program.a );
program.end = program.start + program.duration;

if ( obj.css ) {
generateKeyframes( program.a, program.b, program.delta, program.duration, ease, obj.css, node, style );
}

this.program = program;
this.pending = null;
},
update: function ( now ) {
var p = now - this.start;
this.t = this.a + this.delta * ease( p / this.duration );
var program = this.program;
if ( !program ) return;

var p = now - program.start;
this.t = program.a + program.delta * ease( p / program.duration );
if ( obj.tick ) obj.tick( this.t );
},
done: function () {
if ( obj.tick ) obj.tick( intro ? 1 : 0 );
this.t = this.program.b;
if ( obj.tick ) obj.tick( this.t );
if ( obj.css ) document.head.removeChild( style );
this.callback();
this.running = false;
this.program.callback();
this.program = null;
this.running = !!this.pending;
},
abort: function () {
if ( obj.tick ) obj.tick( 1 );
if ( obj.css ) document.head.removeChild( style );
this.program = this.pending = null;
this.running = false;
}
};
Expand Down Expand Up @@ -108,16 +123,18 @@ export var transitionManager = {
while ( i-- ) {
var transition = transitionManager.transitions[i];

if ( transition.running ) {
if ( now >= transition.end ) {
transition.running = false;
transition.done();
} else if ( now > transition.start ) {
transition.update( now );
}
if ( transition.program && now >= transition.program.end ) {
transition.done();
}

if ( transition.pending && now >= transition.pending.start ) {
transition.start( transition.pending );
}

if ( transition.running ) {
transition.update( now );
transitionManager.running = true;
} else {
} else if ( !transition.pending ) {
transitionManager.transitions.splice( i, 1 );
}
}
Expand Down
28 changes: 27 additions & 1 deletion src/validate/html/validateElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import validateEventHandler from './validateEventHandler.js';
export default function validateElement ( validator, node ) {
const isComponent = node.name === ':Self' || validator.components.has( node.name );

let hasIntro;
let hasOutro;
let hasTransition;

node.attributes.forEach( attribute => {
if ( !isComponent && attribute.type === 'Binding' ) {
const { name } = attribute;
Expand Down Expand Up @@ -46,9 +50,31 @@ export default function validateElement ( validator, node ) {
}
}

if ( attribute.type === 'EventHandler' ) {
else if ( attribute.type === 'EventHandler' ) {
validateEventHandler( validator, attribute );
}

else if ( attribute.type === 'Transition' ) {
const bidi = attribute.intro && attribute.outro;

if ( hasTransition ) {
if ( bidi ) validator.error( `An element can only have one 'transition' directive`, attribute.start );
validator.error( `An element cannot have both a 'transition' directive and an '${attribute.intro ? 'in' : 'out'}' directive`, attribute.start );
}

if ( ( hasIntro && attribute.intro ) || ( hasOutro && attribute.outro ) ) {
if ( bidi ) validator.error( `An element cannot have both an '${hasIntro ? 'in' : 'out'}' directive and a 'transition' directive`, attribute.start );
validator.error( `An element can only have one '${hasIntro ? 'in' : 'out'}' directive`, attribute.start );
}

if ( attribute.intro ) hasIntro = true;
if ( attribute.outro ) hasOutro = true;
if ( bidi ) hasTransition = true;

if ( !validator.transitions.has( attribute.name ) ) {
validator.error( `Missing transition '${attribute.name}'`, attribute.start );
}
}
});
}

Expand Down
3 changes: 2 additions & 1 deletion src/validate/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export default function validate ( parsed, source, { onerror, onwarn, name, file
properties: {},
components: new Map(),
methods: new Map(),
helpers: new Map()
helpers: new Map(),
transitions: new Map()
};

try {
Expand Down
2 changes: 1 addition & 1 deletion src/validate/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default function validateJs ( validator, js ) {
}
});

[ 'components', 'methods', 'helpers' ].forEach( key => {
[ 'components', 'methods', 'helpers', 'transitions' ].forEach( key => {
if ( validator.properties[ key ] ) {
validator.properties[ key ].value.properties.forEach( prop => {
validator[ key ].set( prop.key.name, prop.value );
Expand Down
24 changes: 24 additions & 0 deletions test/runtime/samples/transition-js-delay-in-out/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export default {
test ( assert, component, target, window, raf ) {
component.set({ visible: true });
const div = target.querySelector( 'div' );
assert.equal( div.foo, 0 );

raf.tick( 50 );
assert.equal( div.foo, 0 );

raf.tick( 150 );
assert.equal( div.foo, 1 );

component.set({ visible: false });
assert.equal( div.bar, undefined );

raf.tick( 200 );
assert.equal( div.bar, 1 );

raf.tick( 300 );
assert.equal( div.bar, 0 );

component.destroy();
}
};
29 changes: 29 additions & 0 deletions test/runtime/samples/transition-js-delay-in-out/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{{#if visible}}
<div in:foo out:bar>delayed</div>
{{/if}}

<script>
export default {
transitions: {
foo: function ( node, params ) {
return {
delay: 50,
duration: 100,
tick: t => {
node.foo = t;
}
};
},

bar: function ( node, params ) {
return {
delay: 50,
duration: 100,
tick: t => {
node.bar = t;
}
};
}
}
};
</script>
29 changes: 29 additions & 0 deletions test/runtime/samples/transition-js-delay/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export default {
test ( assert, component, target, window, raf ) {
component.set({ visible: true });
const div = target.querySelector( 'div' );
assert.equal( div.foo, 0 );

raf.tick( 50 );
assert.equal( div.foo, 0 );

raf.tick( 100 );
assert.equal( div.foo, 0.5 );

component.set({ visible: false });

raf.tick( 125 );
assert.equal( div.foo, 0.75 );

raf.tick( 150 );
assert.equal( div.foo, 1 );

raf.tick( 175 );
assert.equal( div.foo, 0.75 );

raf.tick( 250 );
assert.equal( div.foo, 0 );

component.destroy();
}
};
19 changes: 19 additions & 0 deletions test/runtime/samples/transition-js-delay/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{#if visible}}
<div transition:foo>delayed</div>
{{/if}}

<script>
export default {
transitions: {
foo: function ( node, params ) {
return {
delay: 50,
duration: 100,
tick: t => {
node.foo = t;
}
};
}
}
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,26 @@ export default {
const div = target.querySelector( 'div' );
assert.equal( div.foo, 0 );

raf.tick( 300 );
raf.tick( 75 );
component.set({ name: 'everybody' });
assert.equal( div.foo, 0.75 );
assert.htmlEqual( div.innerHTML, 'hello everybody!' );

component.set({ visible: false, name: 'again' });
assert.htmlEqual( div.innerHTML, 'hello everybody!' );

raf.tick( 500 );
raf.tick( 125 );
assert.equal( div.foo, 0.25 );

component.set({ visible: true });
raf.tick( 700 );
raf.tick( 175 );
assert.equal( div.foo, 0.75 );
assert.htmlEqual( div.innerHTML, 'hello again!' );

raf.tick( 800 );
raf.tick( 200 );
assert.equal( div.foo, 1 );

raf.tick( 900 );
raf.tick( 225 );

component.destroy();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
foo: function ( node, params ) {
global.count += 1;
return {
duration: 400,
duration: 100,
tick: t => {
node.foo = t;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[{
"message": "An element cannot have both an 'in' directive and a 'transition' directive",
"loc": {
"line": 1,
"column": 12
},
"pos": 12
}]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div in:foo transition:bar>...</div>

<script>
export default {
transitions: {
foo,
bar
}
};
</script>
Loading

0 comments on commit 00c41e2

Please sign in to comment.