diff --git a/.gitignore b/.gitignore index bf38bbc4e..2c8e89efc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ node_modules /index.js /internal.* /store.js +/easing.js +/transition.js /scratch/ /coverage/ /coverage.lcov/ diff --git a/easing.mjs b/easing.mjs new file mode 100644 index 000000000..87298b7cf --- /dev/null +++ b/easing.mjs @@ -0,0 +1,173 @@ +/* +Adapted from https://github.com/mattdesl +Distributed under MIT License https://github.com/mattdesl/eases/blob/master/LICENSE.md +*/ + +export function backInOut(t) { + var s = 1.70158 * 1.525; + if ((t *= 2) < 1) return 0.5 * (t * t * ((s + 1) * t - s)); + return 0.5 * ((t -= 2) * t * ((s + 1) * t + s) + 2); +} + +export function backIn(t) { + var s = 1.70158; + return t * t * ((s + 1) * t - s); +} + +export function backOut(t) { + var s = 1.70158; + return --t * t * ((s + 1) * t + s) + 1; +} + +export function bounceOut(t) { + var a = 4.0 / 11.0; + var b = 8.0 / 11.0; + var c = 9.0 / 10.0; + + var ca = 4356.0 / 361.0; + var cb = 35442.0 / 1805.0; + var cc = 16061.0 / 1805.0; + + var t2 = t * t; + + return t < a + ? 7.5625 * t2 + : t < b + ? 9.075 * t2 - 9.9 * t + 3.4 + : t < c + ? ca * t2 - cb * t + cc + : 10.8 * t * t - 20.52 * t + 10.72; +} + +export function bounceInOut(t) { + return t < 0.5 + ? 0.5 * (1.0 - bounceOut(1.0 - t * 2.0)) + : 0.5 * bounceOut(t * 2.0 - 1.0) + 0.5; +} + +export function bounceIn(t) { + return 1.0 - bounceOut(1.0 - t); +} + +export function circInOut(t) { + if ((t *= 2) < 1) return -0.5 * (Math.sqrt(1 - t * t) - 1); + return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1); +} + +export function circIn(t) { + return 1.0 - Math.sqrt(1.0 - t * t); +} + +export function circOut(t) { + return Math.sqrt(1 - --t * t); +} + +export function cubicInOut(t) { + return t < 0.5 ? 4.0 * t * t * t : 0.5 * Math.pow(2.0 * t - 2.0, 3.0) + 1.0; +} + +export function cubicIn(t) { + return t * t * t; +} + +export function cubicOut(t) { + var f = t - 1.0; + return f * f * f + 1.0; +} + +export function elasticInOut(t) { + return t < 0.5 + ? 0.5 * + Math.sin(((+13.0 * Math.PI) / 2) * 2.0 * t) * + Math.pow(2.0, 10.0 * (2.0 * t - 1.0)) + : 0.5 * + Math.sin(((-13.0 * Math.PI) / 2) * (2.0 * t - 1.0 + 1.0)) * + Math.pow(2.0, -10.0 * (2.0 * t - 1.0)) + + 1.0; +} + +export function elasticIn(t) { + return Math.sin((13.0 * t * Math.PI) / 2) * Math.pow(2.0, 10.0 * (t - 1.0)); +} + +export function elasticOut(t) { + return ( + Math.sin((-13.0 * (t + 1.0) * Math.PI) / 2) * Math.pow(2.0, -10.0 * t) + 1.0 + ); +} + +export function expoInOut(t) { + return t === 0.0 || t === 1.0 + ? t + : t < 0.5 + ? +0.5 * Math.pow(2.0, 20.0 * t - 10.0) + : -0.5 * Math.pow(2.0, 10.0 - t * 20.0) + 1.0; +} + +export function expoIn(t) { + return t === 0.0 ? t : Math.pow(2.0, 10.0 * (t - 1.0)); +} + +export function expoOut(t) { + return t === 1.0 ? t : 1.0 - Math.pow(2.0, -10.0 * t); +} + +export function linear(t) { + return t; +} + +export function quadInOut(t) { + t /= 0.5; + if (t < 1) return 0.5 * t * t; + t--; + return -0.5 * (t * (t - 2) - 1); +} + +export function quadIn(t) { + return t * t; +} + +export function quadOut(t) { + return -t * (t - 2.0); +} + +export function quarticInOut(t) { + return t < 0.5 + ? +8.0 * Math.pow(t, 4.0) + : -8.0 * Math.pow(t - 1.0, 4.0) + 1.0; +} + +export function quarticIn(t) { + return Math.pow(t, 4.0); +} + +export function quarticOut(t) { + return Math.pow(t - 1.0, 3.0) * (1.0 - t) + 1.0; +} + +export function qinticInOut(t) { + if ((t *= 2) < 1) return 0.5 * t * t * t * t * t; + return 0.5 * ((t -= 2) * t * t * t * t + 2); +} + +export function qinticIn(t) { + return t * t * t * t * t; +} + +export function qinticOut(t) { + return --t * t * t * t * t + 1; +} + +export function sineInOut(t) { + return -0.5 * (Math.cos(Math.PI * t) - 1); +} + +export function sineIn(t) { + var v = Math.cos(t * Math.PI * 0.5); + if (Math.abs(v) < 1e-14) return 1; + else return 1 - v; +} + +export function sineOut(t) { + return Math.sin((t * Math.PI) / 2); +} diff --git a/rollup.config.js b/rollup.config.js index 1bb01c928..7e1947ec4 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -52,16 +52,6 @@ export default [ experimentalCodeSplitting: true }, - /* index.js */ - { - input: 'index.mjs', - output: { - file: 'index.js', - format: 'cjs' - }, - external: name => name !== 'index.mjs' - }, - /* internal.[m]js */ { input: 'src/internal/index.js', @@ -77,13 +67,13 @@ export default [ ] }, - /* store.js */ - { - input: 'store.mjs', + // runtime API + ...['index', 'store', 'easing', 'transition'].map(name => ({ + input: `${name}.mjs`, output: { - file: 'store.js', + file: `${name}.js`, format: 'cjs' }, - external: name => name !== 'store.mjs' - }, + external: id => id !== `${name}.mjs` + })) ]; diff --git a/transition.mjs b/transition.mjs new file mode 100644 index 000000000..1b6fbec60 --- /dev/null +++ b/transition.mjs @@ -0,0 +1,82 @@ +import { cubicOut, cubicInOut } from './easing'; + +export function fade(node, { + delay = 0, + duration = 400 +}) { + const o = +getComputedStyle(node).opacity; + + return { + delay, + duration, + css: t => `opacity: ${t * o}` + }; +} + +export function fly(node, { + delay = 0, + duration = 400, + easing = cubicOut, + x = 0, + y = 0 +}) { + const style = getComputedStyle(node); + const opacity = +style.opacity; + const transform = style.transform === 'none' ? '' : style.transform; + + return { + delay, + duration, + easing, + css: t => ` + transform: ${transform} translate(${(1 - t) * x}px, ${(1 - t) * y}px); + opacity: ${t * opacity}` + }; +} + +export function slide(node, { + delay = 0, + duration = 400, + easing = cubicOut +}) { + const style = getComputedStyle(node); + const opacity = +style.opacity; + const height = parseFloat(style.height); + const padding_top = parseFloat(style.paddingTop); + const padding_bottom = parseFloat(style.paddingBottom); + const margin_top = parseFloat(style.marginTop); + const margin_bottom = parseFloat(style.marginBottom); + const border_top_width = parseFloat(style.borderTopWidth); + const border_bottom_width = parseFloat(style.borderBottomWidth); + + return { + delay, + duration, + easing, + css: t => + `overflow: hidden;` + + `opacity: ${Math.min(t * 20, 1) * opacity};` + + `height: ${t * height}px;` + + `padding-top: ${t * padding_top}px;` + + `padding-bottom: ${t * padding_bottom}px;` + + `margin-top: ${t * margin_top}px;` + + `margin-bottom: ${t * margin_bottom}px;` + + `border-top-width: ${t * border_top_width}px;` + + `border-bottom-width: ${t * border_bottom_width}px;` + }; +} + +export function draw(node, { + delay = 0, + duration = 800, + easing = cubicInOut +}) { + const len = node.getTotalLength(); + + return { + delay, + duration, + easing, + css: (t, u) => `stroke-dasharray: ${t * len} ${u * len}` + }; +} \ No newline at end of file