diff --git a/src/compile/Compiler.ts b/src/compile/Compiler.ts index ac584816b1..e022689aac 100644 --- a/src/compile/Compiler.ts +++ b/src/compile/Compiler.ts @@ -99,6 +99,7 @@ export default class Compiler { components: Set; events: Set; methods: Set; + animations: Set; transitions: Set; actions: Set; importedComponents: Map; @@ -149,6 +150,7 @@ export default class Compiler { this.components = new Set(); this.events = new Set(); this.methods = new Set(); + this.animations = new Set(); this.transitions = new Set(); this.actions = new Set(); this.importedComponents = new Map(); @@ -475,7 +477,7 @@ export default class Compiler { templateProperties[getName(prop.key)] = prop; }); - ['helpers', 'events', 'components', 'transitions', 'actions'].forEach(key => { + ['helpers', 'events', 'components', 'transitions', 'actions', 'animations'].forEach(key => { if (templateProperties[key]) { templateProperties[key].value.properties.forEach((prop: Node) => { this[key].add(getName(prop.key)); @@ -685,6 +687,12 @@ export default class Compiler { }); } + if (templateProperties.animations) { + templateProperties.animations.value.properties.forEach((property: Node) => { + addDeclaration(getName(property.key), property.value, false, 'animations'); + }); + } + if (templateProperties.actions) { templateProperties.actions.value.properties.forEach((property: Node) => { addDeclaration(getName(property.key), property.value, false, 'actions'); diff --git a/src/compile/dom/Block.ts b/src/compile/dom/Block.ts index 6730d416b0..cde0eb0f3f 100644 --- a/src/compile/dom/Block.ts +++ b/src/compile/dom/Block.ts @@ -40,6 +40,7 @@ export default class Block { }; maintainContext: boolean; + animation?: string; hasIntroMethod: boolean; hasOutroMethod: boolean; outros: number; @@ -77,6 +78,7 @@ export default class Block { destroy: new CodeBuilder(), }; + this.animation = null; this.hasIntroMethod = false; // a block could have an intro method but not intro transitions, e.g. if a sibling block has intros this.hasOutroMethod = false; this.outros = 0; @@ -127,6 +129,10 @@ export default class Block { this.outros += 1; } + addAnimation(name) { + this.animation = name; + } + addVariable(name: string, init?: string) { if (this.variables.has(name) && this.variables.get(name) !== init) { throw new Error( @@ -183,6 +189,11 @@ export default class Block { this.builders.hydrate.addLine(`this.first = ${this.first};`); } + if (this.animation) { + properties.addBlock(`node: null,`); + this.builders.hydrate.addLine(`this.node = ${this.animation};`); + } + if (this.builders.create.isEmpty() && this.builders.hydrate.isEmpty()) { properties.addBlock(`c: @noop,`); } else { diff --git a/src/compile/nodes/Animation.ts b/src/compile/nodes/Animation.ts new file mode 100644 index 0000000000..8041f26485 --- /dev/null +++ b/src/compile/nodes/Animation.ts @@ -0,0 +1,18 @@ +import Node from './shared/Node'; +import Expression from './shared/Expression'; + +export default class Animation extends Node { + type: 'Animation'; + name: string; + expression: Expression; + + constructor(compiler, parent, scope, info) { + super(compiler, parent, scope, info); + + this.name = info.name; + + this.expression = info.expression + ? new Expression(compiler, this, scope, info.expression) + : null; + } +} \ No newline at end of file diff --git a/src/compile/nodes/EachBlock.ts b/src/compile/nodes/EachBlock.ts index cee550d5fe..bfd5d92e9f 100644 --- a/src/compile/nodes/EachBlock.ts +++ b/src/compile/nodes/EachBlock.ts @@ -315,10 +315,12 @@ export default class EachBlock extends Node { const dynamic = this.block.hasUpdateMethod; block.builders.update.addBlock(deindent` - var ${this.each_block_value} = ${snippet}; + const ${this.each_block_value} = ${snippet}; ${this.block.hasOutroMethod && `@transitionManager.groupOutros();`} + ${this.block.animation && `const rects = @measure(${blocks});`} ${blocks} = @updateKeyedEach(${blocks}, #component, changed, ${get_key}, ${dynamic ? '1' : '0'}, ctx, ${this.each_block_value}, ${lookup}, ${updateMountNode}, ${String(this.block.hasOutroMethod)}, ${create_each_block}, "${mountOrIntro}", ${anchor}, ${this.get_each_context}); + ${this.block.animation && `@animate(${blocks}, rects, %animations-${this.children[0].animation.name}, {});`} `); if (this.compiler.options.nestedTransitions) { diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts index 18dfb374da..9749aa09fb 100644 --- a/src/compile/nodes/Element.ts +++ b/src/compile/nodes/Element.ts @@ -13,6 +13,7 @@ import Attribute from './Attribute'; import Binding from './Binding'; import EventHandler from './EventHandler'; import Transition from './Transition'; +import Animation from './Animation'; import Action from './Action'; import Text from './Text'; import * as namespaces from '../../utils/namespaces'; @@ -30,8 +31,9 @@ export default class Element extends Node { actions: Action[]; bindings: Binding[]; handlers: EventHandler[]; - intro: Transition; - outro: Transition; + intro?: Transition; + outro?: Transition; + animation?: Animation; children: Node[]; ref: string; @@ -54,6 +56,7 @@ export default class Element extends Node { this.intro = null; this.outro = null; + this.animation = null; if (this.name === 'textarea') { // this is an egregious hack, but it's the easiest way to get