@endorphinjs/template-runtime
Advanced tools
Comparing version 0.4.0 to 0.4.2
@@ -0,8 +1,41 @@ | ||
export declare type EasingFunction = (t: number, b: number, c: number, d: number) => number; | ||
export declare type AnimationCallback = (elem: HTMLElement, options: TweenOptions) => void; | ||
export declare type AnimationStep = (elem: HTMLElement, pos: number, options: TweenOptions) => void; | ||
export declare type TweenFactory = (elem: HTMLElement, options?: TweenOptions) => TweenOptions; | ||
declare type Callback = () => void; | ||
export interface TweenOptions { | ||
/** Animation duration, ms */ | ||
duration?: number; | ||
/** Delay before actual animation start, ms */ | ||
delay?: number; | ||
/** Easing function */ | ||
easing?: EasingFunction; | ||
/** Callback for animation start */ | ||
start?: AnimationCallback; | ||
/** Callback for each animation step */ | ||
step?: AnimationStep; | ||
/** Callback for animation end */ | ||
complete?: AnimationCallback; | ||
} | ||
/** | ||
* Sets CSS animation to given element and waits until it finishes | ||
* Starts animation on given element | ||
*/ | ||
export declare function animate(elem: HTMLElement, animation: string, callback?: () => void): void; | ||
export declare function animate(elem: HTMLElement, animation: string | TweenFactory, callback?: Callback): void; | ||
/** | ||
* Starts CSS animation on given element | ||
*/ | ||
export declare function cssAnimate(elem: HTMLElement, animation: string, callback?: Callback): void; | ||
/** | ||
* Starts JS animation on given element | ||
*/ | ||
export declare function tweenAnimate(elem: HTMLElement, animation: TweenFactory, callback?: () => void): void; | ||
/** | ||
* Creates animation CSS value with scoped animation name | ||
*/ | ||
export declare function createAnimation(animation: string, cssScope?: string): string; | ||
/** | ||
* Composes two tween options objects into single one: instead of simple `assign`, | ||
* callbacks from both tweens will be composed into a single call | ||
*/ | ||
export declare function composeTween(tween1?: TweenOptions, tween2?: TweenOptions): TweenOptions; | ||
export {}; |
@@ -6,1 +6,2 @@ import endorphin from './runtime'; | ||
export { Changes } from './types'; | ||
export { TweenOptions, TweenFactory, composeTween } from './animation'; |
@@ -216,3 +216,3 @@ 'use strict'; | ||
function runtimeError(host, error) { | ||
(host.root || host).dispatchEvent(new CustomEvent('runtime-error', { | ||
host.dispatchEvent(new CustomEvent('runtime-error', { | ||
bubbles: true, | ||
@@ -1704,20 +1704,73 @@ cancelable: true, | ||
const pool = []; | ||
const defaultTween = { | ||
duration: 500, | ||
delay: 0, | ||
easing(t, b, c, d) { | ||
return c * t / d + b; | ||
} | ||
}; | ||
/** | ||
* Sets CSS animation to given element and waits until it finishes | ||
* Starts animation on given element | ||
*/ | ||
function animate(elem, animation, callback) { | ||
if (animation && isAttached(elem)) { | ||
/** @param {AnimationEvent} evt */ | ||
const handler = (evt) => { | ||
if (evt.target === elem) { | ||
elem[animatingKey] = false; | ||
elem.removeEventListener('animationend', handler); | ||
elem.removeEventListener('animationcancel', handler); | ||
callback && callback(); | ||
} | ||
// Stop previous animation, if any | ||
stopAnimation(elem); | ||
if (isAttached(elem) && animation) { | ||
// We should run animation only if element is attached to DOM | ||
if (typeof animation === 'function') { | ||
tweenAnimate(elem, animation, callback); | ||
} | ||
else { | ||
cssAnimate(elem, animation, callback); | ||
} | ||
} | ||
else if (callback) { | ||
callback(); | ||
} | ||
} | ||
/** | ||
* Starts CSS animation on given element | ||
*/ | ||
function cssAnimate(elem, animation, callback) { | ||
const prevAnimation = elem.style.animation; | ||
elem[animatingKey] = () => { | ||
elem.removeEventListener('animationend', handler); | ||
elem.removeEventListener('animationcancel', handler); | ||
elem.style.animation = prevAnimation; | ||
callback && callback(); | ||
}; | ||
const handler = (evt) => evt.target === elem && stopAnimation(elem); | ||
elem.addEventListener('animationend', handler); | ||
elem.addEventListener('animationcancel', handler); | ||
elem.style.animation = animation; | ||
} | ||
/** | ||
* Starts JS animation on given element | ||
*/ | ||
function tweenAnimate(elem, animation, callback) { | ||
let options = animation(elem); | ||
if (options) { | ||
options = assign({}, defaultTween, options); | ||
if (typeof options.easing !== 'function') { | ||
throw new Error('Easing must be a function'); | ||
} | ||
const now = performance.now(); | ||
const start = now + options.delay; | ||
const anim = { | ||
elem, | ||
options, | ||
start, | ||
end: start + options.duration, | ||
started: false | ||
}; | ||
elem[animatingKey] = true; | ||
elem.addEventListener('animationend', handler); | ||
elem.addEventListener('animationcancel', handler); | ||
elem.style.animation = animation; | ||
pool.push(anim); | ||
elem[animatingKey] = () => { | ||
pool.splice(pool.indexOf(anim), 1); | ||
options.complete && options.complete(elem, options); | ||
callback && callback(); | ||
}; | ||
if (pool.length === 1) { | ||
tweenLoop(now); | ||
} | ||
} | ||
@@ -1748,2 +1801,50 @@ else if (callback) { | ||
/** | ||
* Composes two tween options objects into single one: instead of simple `assign`, | ||
* callbacks from both tweens will be composed into a single call | ||
*/ | ||
function composeTween(tween1, tween2) { | ||
const next = assign({}, tween1, tween2); | ||
const callbacks = ['start', 'step', 'complete']; | ||
for (let i = 0; i < callbacks.length; i++) { | ||
const cbName = callbacks[i]; | ||
const cb1 = tween1 && tween1[cbName]; | ||
const cb2 = tween2 && tween2[cbName]; | ||
if (cb1 && cb2) { | ||
next[cbName] = (elem, p1, p2) => { | ||
cb1(elem, p1, p2); | ||
cb2(elem, p1, p2); | ||
}; | ||
} | ||
} | ||
return next; | ||
} | ||
function tweenLoop(now) { | ||
for (let i = pool.length - 1, anim; i >= 0; i--) { | ||
anim = pool[i]; | ||
const { elem, options } = anim; | ||
if (now >= anim.start) { | ||
if (!anim.started) { | ||
anim.started = true; | ||
options.start && options.start(elem, options); | ||
} | ||
const finished = now >= anim.end; | ||
const pos = finished ? 1 : options.easing(now - anim.start, 0, 1, options.duration); | ||
options.step && options.step(elem, pos, options); | ||
if (finished) { | ||
stopAnimation(elem); | ||
} | ||
} | ||
} | ||
if (pool.length) { | ||
requestAnimationFrame(tweenLoop); | ||
} | ||
} | ||
function stopAnimation(elem) { | ||
const callback = elem[animatingKey]; | ||
if (callback) { | ||
elem[animatingKey] = null; | ||
callback(); | ||
} | ||
} | ||
/** | ||
* Concatenates two strings with optional separator | ||
@@ -1856,2 +1957,3 @@ * @param {string} name | ||
exports.call = call; | ||
exports.composeTween = composeTween; | ||
exports.createAnimation = createAnimation; | ||
@@ -1862,2 +1964,3 @@ exports.createComponent = createComponent; | ||
exports.createSlot = createSlot; | ||
exports.cssAnimate = cssAnimate; | ||
exports.default = endorphin; | ||
@@ -1911,2 +2014,3 @@ exports.disposeBlock = disposeBlock; | ||
exports.text = text; | ||
exports.tweenAnimate = tweenAnimate; | ||
exports.unmountBlock = unmountBlock; | ||
@@ -1913,0 +2017,0 @@ exports.unmountComponent = unmountComponent; |
@@ -212,3 +212,3 @@ /** | ||
function runtimeError(host, error) { | ||
(host.root || host).dispatchEvent(new CustomEvent('runtime-error', { | ||
host.dispatchEvent(new CustomEvent('runtime-error', { | ||
bubbles: true, | ||
@@ -1700,20 +1700,73 @@ cancelable: true, | ||
const pool = []; | ||
const defaultTween = { | ||
duration: 500, | ||
delay: 0, | ||
easing(t, b, c, d) { | ||
return c * t / d + b; | ||
} | ||
}; | ||
/** | ||
* Sets CSS animation to given element and waits until it finishes | ||
* Starts animation on given element | ||
*/ | ||
function animate(elem, animation, callback) { | ||
if (animation && isAttached(elem)) { | ||
/** @param {AnimationEvent} evt */ | ||
const handler = (evt) => { | ||
if (evt.target === elem) { | ||
elem[animatingKey] = false; | ||
elem.removeEventListener('animationend', handler); | ||
elem.removeEventListener('animationcancel', handler); | ||
callback && callback(); | ||
} | ||
// Stop previous animation, if any | ||
stopAnimation(elem); | ||
if (isAttached(elem) && animation) { | ||
// We should run animation only if element is attached to DOM | ||
if (typeof animation === 'function') { | ||
tweenAnimate(elem, animation, callback); | ||
} | ||
else { | ||
cssAnimate(elem, animation, callback); | ||
} | ||
} | ||
else if (callback) { | ||
callback(); | ||
} | ||
} | ||
/** | ||
* Starts CSS animation on given element | ||
*/ | ||
function cssAnimate(elem, animation, callback) { | ||
const prevAnimation = elem.style.animation; | ||
elem[animatingKey] = () => { | ||
elem.removeEventListener('animationend', handler); | ||
elem.removeEventListener('animationcancel', handler); | ||
elem.style.animation = prevAnimation; | ||
callback && callback(); | ||
}; | ||
const handler = (evt) => evt.target === elem && stopAnimation(elem); | ||
elem.addEventListener('animationend', handler); | ||
elem.addEventListener('animationcancel', handler); | ||
elem.style.animation = animation; | ||
} | ||
/** | ||
* Starts JS animation on given element | ||
*/ | ||
function tweenAnimate(elem, animation, callback) { | ||
let options = animation(elem); | ||
if (options) { | ||
options = assign({}, defaultTween, options); | ||
if (typeof options.easing !== 'function') { | ||
throw new Error('Easing must be a function'); | ||
} | ||
const now = performance.now(); | ||
const start = now + options.delay; | ||
const anim = { | ||
elem, | ||
options, | ||
start, | ||
end: start + options.duration, | ||
started: false | ||
}; | ||
elem[animatingKey] = true; | ||
elem.addEventListener('animationend', handler); | ||
elem.addEventListener('animationcancel', handler); | ||
elem.style.animation = animation; | ||
pool.push(anim); | ||
elem[animatingKey] = () => { | ||
pool.splice(pool.indexOf(anim), 1); | ||
options.complete && options.complete(elem, options); | ||
callback && callback(); | ||
}; | ||
if (pool.length === 1) { | ||
tweenLoop(now); | ||
} | ||
} | ||
@@ -1744,2 +1797,50 @@ else if (callback) { | ||
/** | ||
* Composes two tween options objects into single one: instead of simple `assign`, | ||
* callbacks from both tweens will be composed into a single call | ||
*/ | ||
function composeTween(tween1, tween2) { | ||
const next = assign({}, tween1, tween2); | ||
const callbacks = ['start', 'step', 'complete']; | ||
for (let i = 0; i < callbacks.length; i++) { | ||
const cbName = callbacks[i]; | ||
const cb1 = tween1 && tween1[cbName]; | ||
const cb2 = tween2 && tween2[cbName]; | ||
if (cb1 && cb2) { | ||
next[cbName] = (elem, p1, p2) => { | ||
cb1(elem, p1, p2); | ||
cb2(elem, p1, p2); | ||
}; | ||
} | ||
} | ||
return next; | ||
} | ||
function tweenLoop(now) { | ||
for (let i = pool.length - 1, anim; i >= 0; i--) { | ||
anim = pool[i]; | ||
const { elem, options } = anim; | ||
if (now >= anim.start) { | ||
if (!anim.started) { | ||
anim.started = true; | ||
options.start && options.start(elem, options); | ||
} | ||
const finished = now >= anim.end; | ||
const pos = finished ? 1 : options.easing(now - anim.start, 0, 1, options.duration); | ||
options.step && options.step(elem, pos, options); | ||
if (finished) { | ||
stopAnimation(elem); | ||
} | ||
} | ||
} | ||
if (pool.length) { | ||
requestAnimationFrame(tweenLoop); | ||
} | ||
} | ||
function stopAnimation(elem) { | ||
const callback = elem[animatingKey]; | ||
if (callback) { | ||
elem[animatingKey] = null; | ||
callback(); | ||
} | ||
} | ||
/** | ||
* Concatenates two strings with optional separator | ||
@@ -1846,3 +1947,3 @@ * @param {string} name | ||
export default endorphin; | ||
export { Store, addClass, addEvent, addStaticEvent, animate, assign, call, createAnimation, createComponent, createInjector, createScope, createSlot, disposeBlock, domInsert, domRemove, elem, elemNS, elemNSWithText, elemWithText, emptyBlockContent, enterScope, exitScope, filter, finalizeAttributes, finalizeEvents, finalizeRefs, find, get, getProp, getScope, getSlotContext, getState, getVar, injectBlock, insert, isolateElement, mountBlock, mountComponent, mountInnerHTML, mountIterator, mountKeyIterator, mountPartial, mountSlot, move, normalizeClassName, notifySlotUpdate, prepareScope, removeStaticEvent, renderComponent, safeEventListener, scheduleRender, setAttribute, setAttributeNS, setRef, setScope, setStaticRef, setVar, subscribeStore, text, unmountBlock, unmountComponent, unmountInnerHTML, unmountIterator, unmountKeyIterator, unmountPartial, unmountSlot, updateAttribute, updateBlock, updateComponent, updateDefaultSlot, updateIncomingSlot, updateInnerHTML, updateIterator, updateKeyIterator, updatePartial, updateProps, updateText }; | ||
export { Store, addClass, addEvent, addStaticEvent, animate, assign, call, composeTween, createAnimation, createComponent, createInjector, createScope, createSlot, cssAnimate, disposeBlock, domInsert, domRemove, elem, elemNS, elemNSWithText, elemWithText, emptyBlockContent, enterScope, exitScope, filter, finalizeAttributes, finalizeEvents, finalizeRefs, find, get, getProp, getScope, getSlotContext, getState, getVar, injectBlock, insert, isolateElement, mountBlock, mountComponent, mountInnerHTML, mountIterator, mountKeyIterator, mountPartial, mountSlot, move, normalizeClassName, notifySlotUpdate, prepareScope, removeStaticEvent, renderComponent, safeEventListener, scheduleRender, setAttribute, setAttributeNS, setRef, setScope, setStaticRef, setVar, subscribeStore, text, tweenAnimate, unmountBlock, unmountComponent, unmountInnerHTML, unmountIterator, unmountKeyIterator, unmountPartial, unmountSlot, updateAttribute, updateBlock, updateComponent, updateDefaultSlot, updateIncomingSlot, updateInnerHTML, updateIterator, updateKeyIterator, updatePartial, updateProps, updateText }; | ||
//# sourceMappingURL=runtime.es.js.map |
{ | ||
"name": "@endorphinjs/template-runtime", | ||
"version": "0.4.0", | ||
"version": "0.4.2", | ||
"description": "EndorphinJS template runtime, embedded with template bundles", | ||
@@ -25,3 +25,3 @@ "main": "./dist/runtime.cjs.js", | ||
"devDependencies": { | ||
"@endorphinjs/template-compiler": "^0.4.0", | ||
"@endorphinjs/template-compiler": "^0.4.2", | ||
"@types/mocha": "^5.2.6", | ||
@@ -51,3 +51,4 @@ "@types/node": "^11.13.10", | ||
"spec": "./test/*.ts" | ||
} | ||
}, | ||
"gitHead": "79ef0731130a11dd744bf317e78a495def6e5b66" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
408916
4782