Convert src/runtime/transition/index.ts to JavaScript

pull/8569/head
S. Elliott Johnson 3 years ago
parent 0f69187008
commit ae9e0fd3d0

@ -1,289 +1,254 @@
import { cubicOut, cubicInOut, linear } from '../easing'; import { cubicOut, cubicInOut, linear } from '../easing';
import { assign, split_css_unit, is_function } from '../internal'; import { assign, split_css_unit, is_function } from '../internal';
/** @param {Element} node
export type EasingFunction = (t: number) => number; * @param {BlurParams}
* @returns {import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").TransitionConfig}
export interface TransitionConfig { */
delay?: number; export function blur(node, { delay = 0, duration = 400, easing = cubicInOut, amount = 5, opacity = 0 } = {}) {
duration?: number; const style = getComputedStyle(node);
easing?: EasingFunction; const target_opacity = +style.opacity;
css?: (t: number, u: number) => string; const f = style.filter === 'none' ? '' : style.filter;
tick?: (t: number, u: number) => void; const od = target_opacity * (1 - opacity);
} const [value, unit] = split_css_unit(amount);
return {
export interface BlurParams { delay,
delay?: number; duration,
duration?: number; easing,
easing?: EasingFunction; css: (_t, u) => `opacity: ${target_opacity - od * u}; filter: ${f} blur(${u * value}${unit});`
amount?: number | string; };
opacity?: number;
} }
/** @param {Element} node
export function blur( * @param {FadeParams}
node: Element, * @returns {import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").TransitionConfig}
{ delay = 0, duration = 400, easing = cubicInOut, amount = 5, opacity = 0 }: BlurParams = {} */
): TransitionConfig { export function fade(node, { delay = 0, duration = 400, easing = linear } = {}) {
const style = getComputedStyle(node); const o = +getComputedStyle(node).opacity;
const target_opacity = +style.opacity; return {
const f = style.filter === 'none' ? '' : style.filter; delay,
duration,
const od = target_opacity * (1 - opacity); easing,
const [value, unit] = split_css_unit(amount); css: (t) => `opacity: ${t * o}`
return { };
delay,
duration,
easing,
css: (_t, u) => `opacity: ${target_opacity - od * u}; filter: ${f} blur(${u * value}${unit});`
};
}
export interface FadeParams {
delay?: number;
duration?: number;
easing?: EasingFunction;
}
export function fade(
node: Element,
{ delay = 0, duration = 400, easing = linear }: FadeParams = {}
): TransitionConfig {
const o = +getComputedStyle(node).opacity;
return {
delay,
duration,
easing,
css: (t) => `opacity: ${t * o}`
};
} }
/** @param {Element} node
export interface FlyParams { * @param {FlyParams}
delay?: number; * @returns {import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").TransitionConfig}
duration?: number; */
easing?: EasingFunction; export function fly(node, { delay = 0, duration = 400, easing = cubicOut, x = 0, y = 0, opacity = 0 } = {}) {
x?: number | string; const style = getComputedStyle(node);
y?: number | string; const target_opacity = +style.opacity;
opacity?: number; const transform = style.transform === 'none' ? '' : style.transform;
} const od = target_opacity * (1 - opacity);
const [xValue, xUnit] = split_css_unit(x);
export function fly( const [yValue, yUnit] = split_css_unit(y);
node: Element, return {
{ delay = 0, duration = 400, easing = cubicOut, x = 0, y = 0, opacity = 0 }: FlyParams = {} delay,
): TransitionConfig { duration,
const style = getComputedStyle(node); easing,
const target_opacity = +style.opacity; css: (t, u) => `
const transform = style.transform === 'none' ? '' : style.transform;
const od = target_opacity * (1 - opacity);
const [xValue, xUnit] = split_css_unit(x);
const [yValue, yUnit] = split_css_unit(y);
return {
delay,
duration,
easing,
css: (t, u) => `
transform: ${transform} translate(${(1 - t) * xValue}${xUnit}, ${(1 - t) * yValue}${yUnit}); transform: ${transform} translate(${(1 - t) * xValue}${xUnit}, ${(1 - t) * yValue}${yUnit});
opacity: ${target_opacity - od * u}` opacity: ${target_opacity - od * u}`
}; };
}
export interface SlideParams {
delay?: number;
duration?: number;
easing?: EasingFunction;
axis?: 'x' | 'y';
} }
/** @param {Element} node
export function slide( * @param {SlideParams}
node: Element, * @returns {import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").TransitionConfig}
{ delay = 0, duration = 400, easing = cubicOut, axis = 'y' }: SlideParams = {} */
): TransitionConfig { export function slide(node, { delay = 0, duration = 400, easing = cubicOut, axis = 'y' } = {}) {
const style = getComputedStyle(node); const style = getComputedStyle(node);
const opacity = +style.opacity; const opacity = +style.opacity;
const primary_property = axis === 'y' ? 'height' : 'width'; const primary_property = axis === 'y' ? 'height' : 'width';
const primary_property_value = parseFloat(style[primary_property]); const primary_property_value = parseFloat(style[primary_property]);
const secondary_properties = axis === 'y' ? ['top', 'bottom'] : ['left', 'right']; const secondary_properties = axis === 'y' ? ['top', 'bottom'] : ['left', 'right'];
const capitalized_secondary_properties = secondary_properties.map( const capitalized_secondary_properties = secondary_properties.map((e) => `${e[0].toUpperCase()}${e.slice(1)}`);
(e) => `${e[0].toUpperCase()}${e.slice(1)}` const padding_start_value = parseFloat(style[`padding${capitalized_secondary_properties[0]}`]);
); const padding_end_value = parseFloat(style[`padding${capitalized_secondary_properties[1]}`]);
const padding_start_value = parseFloat(style[`padding${capitalized_secondary_properties[0]}`]); const margin_start_value = parseFloat(style[`margin${capitalized_secondary_properties[0]}`]);
const padding_end_value = parseFloat(style[`padding${capitalized_secondary_properties[1]}`]); const margin_end_value = parseFloat(style[`margin${capitalized_secondary_properties[1]}`]);
const margin_start_value = parseFloat(style[`margin${capitalized_secondary_properties[0]}`]); const border_width_start_value = parseFloat(style[`border${capitalized_secondary_properties[0]}Width`]);
const margin_end_value = parseFloat(style[`margin${capitalized_secondary_properties[1]}`]); const border_width_end_value = parseFloat(style[`border${capitalized_secondary_properties[1]}Width`]);
const border_width_start_value = parseFloat( return {
style[`border${capitalized_secondary_properties[0]}Width`] delay,
); duration,
const border_width_end_value = parseFloat( easing,
style[`border${capitalized_secondary_properties[1]}Width`] css: (t) => 'overflow: hidden;' +
); `opacity: ${Math.min(t * 20, 1) * opacity};` +
return { `${primary_property}: ${t * primary_property_value}px;` +
delay, `padding-${secondary_properties[0]}: ${t * padding_start_value}px;` +
duration, `padding-${secondary_properties[1]}: ${t * padding_end_value}px;` +
easing, `margin-${secondary_properties[0]}: ${t * margin_start_value}px;` +
css: (t) => `margin-${secondary_properties[1]}: ${t * margin_end_value}px;` +
'overflow: hidden;' + `border-${secondary_properties[0]}-width: ${t * border_width_start_value}px;` +
`opacity: ${Math.min(t * 20, 1) * opacity};` + `border-${secondary_properties[1]}-width: ${t * border_width_end_value}px;`
`${primary_property}: ${t * primary_property_value}px;` + };
`padding-${secondary_properties[0]}: ${t * padding_start_value}px;` +
`padding-${secondary_properties[1]}: ${t * padding_end_value}px;` +
`margin-${secondary_properties[0]}: ${t * margin_start_value}px;` +
`margin-${secondary_properties[1]}: ${t * margin_end_value}px;` +
`border-${secondary_properties[0]}-width: ${t * border_width_start_value}px;` +
`border-${secondary_properties[1]}-width: ${t * border_width_end_value}px;`
};
} }
/** @param {Element} node
export interface ScaleParams { * @param {ScaleParams}
delay?: number; * @returns {import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").TransitionConfig}
duration?: number; */
easing?: EasingFunction; export function scale(node, { delay = 0, duration = 400, easing = cubicOut, start = 0, opacity = 0 } = {}) {
start?: number; const style = getComputedStyle(node);
opacity?: number; const target_opacity = +style.opacity;
} const transform = style.transform === 'none' ? '' : style.transform;
const sd = 1 - start;
export function scale( const od = target_opacity * (1 - opacity);
node: Element, return {
{ delay = 0, duration = 400, easing = cubicOut, start = 0, opacity = 0 }: ScaleParams = {} delay,
): TransitionConfig { duration,
const style = getComputedStyle(node); easing,
const target_opacity = +style.opacity; css: (_t, u) => `
const transform = style.transform === 'none' ? '' : style.transform;
const sd = 1 - start;
const od = target_opacity * (1 - opacity);
return {
delay,
duration,
easing,
css: (_t, u) => `
transform: ${transform} scale(${1 - sd * u}); transform: ${transform} scale(${1 - sd * u});
opacity: ${target_opacity - od * u} opacity: ${target_opacity - od * u}
` `
}; };
} }
/** @param {SVGElement & { getTotalLength(): number }} node
export interface DrawParams { * @param {DrawParams}
delay?: number; * @returns {import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").TransitionConfig}
speed?: number; */
duration?: number | ((len: number) => number); export function draw(node, { delay = 0, speed, duration, easing = cubicInOut } = {}) {
easing?: EasingFunction; let len = node.getTotalLength();
} const style = getComputedStyle(node);
if (style.strokeLinecap !== 'butt') {
export function draw( len += parseInt(style.strokeWidth);
node: SVGElement & { getTotalLength(): number }, }
{ delay = 0, speed, duration, easing = cubicInOut }: DrawParams = {} if (duration === undefined) {
): TransitionConfig { if (speed === undefined) {
let len = node.getTotalLength(); duration = 800;
const style = getComputedStyle(node); }
if (style.strokeLinecap !== 'butt') { else {
len += parseInt(style.strokeWidth); duration = len / speed;
} }
}
if (duration === undefined) { else if (typeof duration === 'function') {
if (speed === undefined) { duration = duration(len);
duration = 800; }
} else { return {
duration = len / speed; delay,
} duration,
} else if (typeof duration === 'function') { easing,
duration = duration(len); css: (_, u) => `
}
return {
delay,
duration,
easing,
css: (_, u) => `
stroke-dasharray: ${len}; stroke-dasharray: ${len};
stroke-dashoffset: ${u * len}; stroke-dashoffset: ${u * len};
` `
}; };
} }
/**
export interface CrossfadeParams { * @param {CrossfadeParams & {
delay?: number; * fallback?: (node: Element, params: CrossfadeParams, intro: boolean) => TransitionConfig;
duration?: number | ((len: number) => number); * }}
easing?: EasingFunction; * @returns {[(node: any, params: import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").CrossfadeParams & { key: any; }) => () => import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").TransitionConfig, (node: any, params: import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").CrossfadeParams & { key: any; }) => () => import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").TransitionConfig]}
} */
export function crossfade({ fallback, ...defaults }) {
type ClientRectMap = Map<any, Element>; /** @type {ClientRectMap} */
const to_receive = new Map();
export function crossfade({ /** @type {ClientRectMap} */
fallback, const to_send = new Map();
...defaults /** @param {Element} from_node
}: CrossfadeParams & { * @param {Element} node
fallback?: (node: Element, params: CrossfadeParams, intro: boolean) => TransitionConfig; * @param {CrossfadeParams} params
}): [ * @returns {import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").TransitionConfig}
( */
node: Element, function crossfade(from_node, node, params) {
params: CrossfadeParams & { const { delay = 0, duration = (d) => Math.sqrt(d) * 30, easing = cubicOut } = assign(assign({}, defaults), params);
key: any; const from = from_node.getBoundingClientRect();
} const to = node.getBoundingClientRect();
) => () => TransitionConfig, const dx = from.left - to.left;
( const dy = from.top - to.top;
node: Element, const dw = from.width / to.width;
params: CrossfadeParams & { const dh = from.height / to.height;
key: any; const d = Math.sqrt(dx * dx + dy * dy);
} const style = getComputedStyle(node);
) => () => TransitionConfig const transform = style.transform === 'none' ? '' : style.transform;
] { const opacity = +style.opacity;
const to_receive: ClientRectMap = new Map(); return {
const to_send: ClientRectMap = new Map(); delay,
duration: is_function(duration) ? duration(d) : duration,
function crossfade(from_node: Element, node: Element, params: CrossfadeParams): TransitionConfig { easing,
const { css: (t, u) => `
delay = 0,
duration = (d) => Math.sqrt(d) * 30,
easing = cubicOut
} = assign(assign({}, defaults), params);
const from = from_node.getBoundingClientRect();
const to = node.getBoundingClientRect();
const dx = from.left - to.left;
const dy = from.top - to.top;
const dw = from.width / to.width;
const dh = from.height / to.height;
const d = Math.sqrt(dx * dx + dy * dy);
const style = getComputedStyle(node);
const transform = style.transform === 'none' ? '' : style.transform;
const opacity = +style.opacity;
return {
delay,
duration: is_function(duration) ? duration(d) : duration,
easing,
css: (t, u) => `
opacity: ${t * opacity}; opacity: ${t * opacity};
transform-origin: top left; transform-origin: top left;
transform: ${transform} translate(${u * dx}px,${u * dy}px) scale(${t + (1 - t) * dw}, ${ transform: ${transform} translate(${u * dx}px,${u * dy}px) scale(${t + (1 - t) * dw}, ${t + (1 - t) * dh});
t + (1 - t) * dh
});
` `
}; };
} }
/** @param {ClientRectMap} items
function transition(items: ClientRectMap, counterparts: ClientRectMap, intro: boolean) { * @param {ClientRectMap} counterparts
return (node: Element, params: CrossfadeParams & { key: any }) => { * @param {boolean} intro
items.set(params.key, node); * @returns {(node: any, params: import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").CrossfadeParams & { key: any; }) => () => import("/Users/elliottjohnson/dev/sveltejs/svelte/index.ts-to-jsdoc").TransitionConfig}
*/
return () => { function transition(items, counterparts, intro) {
if (counterparts.has(params.key)) { return (node, params) => {
const other_node = counterparts.get(params.key); items.set(params.key, node);
counterparts.delete(params.key); return () => {
if (counterparts.has(params.key)) {
return crossfade(other_node, node, params); const other_node = counterparts.get(params.key);
} counterparts.delete(params.key);
return crossfade(other_node, node, params);
}
// if the node is disappearing altogether
// (i.e. wasn't claimed by the other list)
// then we need to supply an outro
items.delete(params.key);
return fallback && fallback(node, params, intro);
};
};
}
return [transition(to_send, to_receive, false), transition(to_receive, to_send, true)];
}
// if the node is disappearing altogether
// (i.e. wasn't claimed by the other list)
// then we need to supply an outro
items.delete(params.key);
return fallback && fallback(node, params, intro);
};
};
}
return [transition(to_send, to_receive, false), transition(to_receive, to_send, true)]; /** @typedef {(t: number) => number} EasingFunction */
} /** @typedef {Map<any, Element>} ClientRectMap */
/** @typedef {Object} TransitionConfig
* @property {number} [delay]
* @property {number} [duration]
* @property {EasingFunction} [easing]
* @property {(t:number,u:number)=>string} [css]
* @property {(t:number,u:number)=>void} [tick]
*/
/** @typedef {Object} BlurParams
* @property {number} [delay]
* @property {number} [duration]
* @property {EasingFunction} [easing]
* @property {number|string} [amount]
* @property {number} [opacity]
*/
/** @typedef {Object} FadeParams
* @property {number} [delay]
* @property {number} [duration]
* @property {EasingFunction} [easing]
*/
/** @typedef {Object} FlyParams
* @property {number} [delay]
* @property {number} [duration]
* @property {EasingFunction} [easing]
* @property {number|string} [x]
* @property {number|string} [y]
* @property {number} [opacity]
*/
/** @typedef {Object} SlideParams
* @property {number} [delay]
* @property {number} [duration]
* @property {EasingFunction} [easing]
* @property {'x'|'y'} [axis]
*/
/** @typedef {Object} ScaleParams
* @property {number} [delay]
* @property {number} [duration]
* @property {EasingFunction} [easing]
* @property {number} [start]
* @property {number} [opacity]
*/
/** @typedef {Object} DrawParams
* @property {number} [delay]
* @property {number} [speed]
* @property {number|((len:number)=>number)} [duration]
* @property {EasingFunction} [easing]
*/
/** @typedef {Object} CrossfadeParams
* @property {number} [delay]
* @property {number|((len:number)=>number)} [duration]
* @property {EasingFunction} [easing]
*/
Loading…
Cancel
Save