saving progress...

pull/4742/head
pushkine 6 years ago
parent 654bcfda7e
commit a26a75eba6

@ -1,9 +1,9 @@
module.exports = {
root: true,
rules: {
indent: 'off',
'indent': 'off',
'no-unused-vars': 'off',
semi: [2, 'always'],
'semi': [2, 'always'],
'keyword-spacing': [2, { before: true, after: true }],
'space-before-blocks': [2, 'always'],
'no-mixed-spaces-and-tabs': [2, 'smart-tabs'],
@ -16,7 +16,6 @@ module.exports = {
'no-unreachable': 2,
'valid-typeof': 2,
'quote-props': [2, 'as-needed'],
'one-var': [2, 'never'],
'prefer-arrow-callback': 2,
'prefer-const': [2, { destructuring: 'all' }],
'arrow-spacing': 2,
@ -32,57 +31,51 @@ module.exports = {
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_'
}
argsIgnorePattern: '^_',
},
],
'@typescript-eslint/no-object-literal-type-assertion': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/prefer-interface': 'off'
'@typescript-eslint/prefer-interface': 'off',
},
globals: {
globalThis: false
globalThis: false,
},
env: {
es6: true,
browser: true,
node: true,
mocha: true
mocha: true,
},
extends: [
'eslint:recommended',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:import/typescript',
'plugin:@typescript-eslint/recommended'
'plugin:@typescript-eslint/recommended',
],
parserOptions: {
ecmaVersion: 9,
sourceType: 'module'
sourceType: 'module',
},
plugins: ['svelte3'],
settings: {
'import/core-modules': [
'svelte',
'svelte/internal',
'svelte/store',
'svelte/easing',
'estree'
],
'svelte3/compiler': require('./compiler')
'import/core-modules': ['svelte', 'svelte/internal', 'svelte/store', 'svelte/easing', 'estree'],
'svelte3/compiler': require('./compiler'),
},
overrides: [
{
files: ['*.js'],
rules: {
'@typescript-eslint/no-var-requires': 'off'
}
'@typescript-eslint/no-var-requires': 'off',
},
},
{
files: ['*.svelte'],
processor: 'svelte3/svelte3',
rules: {
'@typescript-eslint/indent': 'off'
}
}
]
'@typescript-eslint/indent': 'off',
},
},
],
};

@ -7,106 +7,95 @@ import sucrase from '@rollup/plugin-sucrase';
import typescript from '@rollup/plugin-typescript';
import pkg from './package.json';
const esm = { format: 'esm' };
const cjs = { format: 'cjs' };
const is_publish = !!process.env.PUBLISH;
const ts_plugin = is_publish
? typescript({
include: 'src/**',
typescript: require('typescript')
})
: sucrase({
transforms: ['typescript']
});
? typescript({ include: 'src/**', typescript: require('typescript') })
: sucrase({ transforms: ['typescript'] });
const external = id => id.startsWith('svelte/');
const external = (id) => id.startsWith('svelte/');
const version = replace({ __VERSION__: pkg.version });
fs.writeFileSync(`./compiler.d.ts`, `export { compile, parse, preprocess, VERSION } from './types/compiler/index';`);
const output = (obj) =>
Object.keys(obj).flatMap((name) =>
[esm, cjs].map(({ format }) => ({
format,
file: `${name !== 'default' ? name + '/' : ''}${obj[name].file}.${format === 'esm' ? 'mjs' : 'js'}`,
paths: (id) => external(id) && `${id.replace('svelte', obj[name].path)}`,
plugins: (defaults.plugins || []).concat([replace({ __DEV__: name === 'dev' })]),
}))
);
function writeFileSync(...arr) {
arr.filter(Boolean).forEach(({ dir, content }) => fs.writeFileSync(dir, content));
}
export default [
/* runtime */
/* runtime main */
{
input: `src/runtime/index.ts`,
output: [
{
file: `index.mjs`,
format: 'esm',
paths: id => id.startsWith('svelte/') && `${id.replace('svelte', '.')}`
},
{
file: `index.js`,
format: 'cjs',
paths: id => id.startsWith('svelte/') && `${id.replace('svelte', '.')}`
}
],
output: output({
default: { file: 'index', path: '.' },
dev: { file: 'index', path: '.' },
}),
external,
plugins: [ts_plugin]
plugins: [ts_plugin],
},
...fs.readdirSync('src/runtime')
.filter(dir => fs.statSync(`src/runtime/${dir}`).isDirectory())
.map(dir => ({
/* svelte/[library] */
...fs
.readdirSync('src/runtime')
.filter((dir) => fs.statSync(`src/runtime/${dir}`).isDirectory())
.map((dir) => ({
input: `src/runtime/${dir}/index.ts`,
output: [
{
file: `${dir}/index.mjs`,
format: 'esm',
paths: id => id.startsWith('svelte/') && `${id.replace('svelte', '..')}`
},
{
file: `${dir}/index.js`,
format: 'cjs',
paths: id => id.startsWith('svelte/') && `${id.replace('svelte', '..')}`
}
],
output: output({
[dir]: { file: 'index', path: '..' },
dev: { file: dir, path: '.' },
}),
external,
plugins: [
replace({
__VERSION__: pkg.version
}),
version,
ts_plugin,
{
writeBundle(bundle) {
if (dir === 'internal') {
const mod = bundle['index.mjs'];
if (mod) {
fs.writeFileSync('src/compiler/compile/internal_exports.ts', `// This file is automatically generated\nexport default new Set(${JSON.stringify(mod.exports)});`);
}
}
fs.writeFileSync(`${dir}/package.json`, JSON.stringify({
main: './index',
module: './index.mjs',
types: './index.d.ts'
}, null, ' '));
fs.writeFileSync(`${dir}/index.d.ts`, `export * from '../types/runtime/${dir}/index';`);
}
writeFileSync(
dir === 'internal' &&
bundle['index.mjs'] && {
dir: `src/compiler/compile/internal_exports.ts`,
content: `
// This file is automatically generated
export default new Set(${JSON.stringify(bundle['index.mjs'].exports)});`,
},
{
dir: `${dir}/package.json`,
content: `{
"main": "./index",
"module": "./index.mjs",
"types": "./index.d.ts"
}`,
},
{
dir: `${dir}/index.d.ts`,
content: `export * from '../types/runtime/${dir}/index';`,
}
]
);
},
},
],
})),
/* compiler.js */
{
input: 'src/compiler/index.ts',
plugins: [
replace({
__VERSION__: pkg.version
}),
resolve(),
commonjs({
include: ['node_modules/**']
}),
json(),
ts_plugin
],
plugins: [version, resolve(), commonjs({ include: ['node_modules/**'] }), json(), ts_plugin],
output: {
file: 'compiler.js',
format: is_publish ? 'umd' : 'cjs',
name: 'svelte',
sourcemap: true,
},
external: is_publish
? []
: id => id === 'acorn' || id === 'magic-string' || id.startsWith('css-tree')
}
external: is_publish ? [] : (id) => id === 'acorn' || id === 'magic-string' || id.startsWith('css-tree'),
},
];

@ -41,11 +41,11 @@ export default class InlineComponentWrapper extends Wrapper {
block.add_dependencies(this.node.expression.dependencies);
}
this.node.attributes.forEach(attr => {
this.node.attributes.forEach((attr) => {
block.add_dependencies(attr.dependencies);
});
this.node.bindings.forEach(binding => {
this.node.bindings.forEach((binding) => {
if (binding.is_contextual) {
// we need to ensure that the each block creates a context including
// the list and the index, if they're not otherwise referenced
@ -58,7 +58,7 @@ export default class InlineComponentWrapper extends Wrapper {
block.add_dependencies(binding.expression.dependencies);
});
this.node.handlers.forEach(handler => {
this.node.handlers.forEach((handler) => {
if (handler.expression) {
block.add_dependencies(handler.expression.dependencies);
}
@ -66,16 +66,17 @@ export default class InlineComponentWrapper extends Wrapper {
this.var = {
type: 'Identifier',
name: (
this.node.name === 'svelte:self' ? renderer.component.name.name :
this.node.name === 'svelte:component' ? 'switch_instance' :
sanitize(this.node.name)
).toLowerCase()
name: (this.node.name === 'svelte:self'
? renderer.component.name.name
: this.node.name === 'svelte:component'
? 'switch_instance'
: sanitize(this.node.name)
).toLowerCase(),
};
if (this.node.children.length) {
this.node.lets.forEach(l => {
extract_names(l.value || l.name).forEach(name => {
this.node.lets.forEach((l) => {
extract_names(l.value || l.name).forEach((name) => {
renderer.add_to_context(name, true);
});
});
@ -83,7 +84,7 @@ export default class InlineComponentWrapper extends Wrapper {
const default_slot = block.child({
comment: create_debugging_comment(node, renderer.component),
name: renderer.component.get_unique_name(`create_default_slot`),
type: 'slot'
type: 'slot',
});
this.renderer.blocks.push(default_slot);
@ -94,7 +95,7 @@ export default class InlineComponentWrapper extends Wrapper {
const dependencies: Set<string> = new Set();
// TODO is this filtering necessary? (I *think* so)
default_slot.dependencies.forEach(name => {
default_slot.dependencies.forEach((name) => {
if (!this.node.scope.is_let(name)) {
dependencies.add(name);
}
@ -121,11 +122,7 @@ export default class InlineComponentWrapper extends Wrapper {
}
}
render(
block: Block,
parent_node: Identifier,
parent_nodes: Identifier
) {
render(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
this.warn_if_reactive();
const { renderer } = this;
@ -143,14 +140,14 @@ export default class InlineComponentWrapper extends Wrapper {
const default_slot = this.slots.get('default');
this.fragment.nodes.forEach((child) => {
child.render(default_slot.block, null, x`#nodes` as unknown as Identifier);
child.render(default_slot.block, null, (x`#nodes` as unknown) as Identifier);
});
}
let props;
const name_changes = block.get_unique_name(`${name.name}_changes`);
const uses_spread = !!this.node.attributes.find(a => a.is_spread);
const uses_spread = !!this.node.attributes.find((a) => a.is_spread);
// removing empty slot
for (const slot of this.slots.keys()) {
@ -160,7 +157,8 @@ export default class InlineComponentWrapper extends Wrapper {
}
}
const initial_props = this.slots.size > 0
const initial_props =
this.slots.size > 0
? [
p`$$slots: {
${Array.from(this.slots).map(([name, slot]) => {
@ -169,14 +167,14 @@ export default class InlineComponentWrapper extends Wrapper {
}`,
p`$$scope: {
ctx: #ctx
}`
}`,
]
: [];
const attribute_object = uses_spread
? x`{ ${initial_props} }`
: x`{
${this.node.attributes.map(attr => p`${attr.name}: ${attr.get_value(block)}`)},
${this.node.attributes.map((attr) => p`${attr.name}: ${attr.get_value(block)}`)},
${initial_props}
}`;
@ -198,8 +196,8 @@ export default class InlineComponentWrapper extends Wrapper {
}
const fragment_dependencies = new Set(this.fragment ? ['$$scope'] : []);
this.slots.forEach(slot => {
slot.block.dependencies.forEach(name => {
this.slots.forEach((slot) => {
slot.block.dependencies.forEach((name) => {
const is_let = slot.scope.is_let(name);
const variable = renderer.component.var_lookup.get(name);
@ -207,9 +205,12 @@ export default class InlineComponentWrapper extends Wrapper {
});
});
const dynamic_attributes = this.node.attributes.filter(a => a.get_dependencies().length > 0);
const dynamic_attributes = this.node.attributes.filter((a) => a.get_dependencies().length > 0);
if (!uses_spread && (dynamic_attributes.length > 0 || this.node.bindings.length > 0 || fragment_dependencies.size > 0)) {
if (
!uses_spread &&
(dynamic_attributes.length > 0 || this.node.bindings.length > 0 || fragment_dependencies.size > 0)
) {
updates.push(b`const ${name_changes} = {};`);
}
@ -222,14 +223,15 @@ export default class InlineComponentWrapper extends Wrapper {
const all_dependencies: Set<string> = new Set();
this.node.attributes.forEach(attr => {
this.node.attributes.forEach((attr) => {
add_to_set(all_dependencies, attr.dependencies);
});
this.node.attributes.forEach((attr, i) => {
const { name, dependencies } = attr;
const condition = dependencies.size > 0 && (dependencies.size !== all_dependencies.size)
const condition =
dependencies.size > 0 && dependencies.size !== all_dependencies.size
? renderer.dirty(Array.from(dependencies))
: null;
const unchanged = dependencies.size === 0;
@ -251,19 +253,11 @@ export default class InlineComponentWrapper extends Wrapper {
}
changes.push(
unchanged
? x`${levels}[${i}]`
: condition
? x`${condition} && ${change_object}`
: change_object
unchanged ? x`${levels}[${i}]` : condition ? x`${condition} && ${change_object}` : change_object
);
});
block.chunks.init.push(b`
const ${levels} = [
${initial_props}
];
`);
block.chunks.init.push(b`const ${levels} = [${initial_props}];`);
statements.push(b`
for (let #i = 0; #i < ${levels}.length; #i += 1) {
@ -275,9 +269,7 @@ export default class InlineComponentWrapper extends Wrapper {
const condition = renderer.dirty(Array.from(all_dependencies));
updates.push(b`
const ${name_changes} = ${condition} ? @get_spread_update(${levels}, [
${changes}
]) : {}
const ${name_changes} = ${condition} ? @get_spread_update(${levels}, [${changes}]) : {};
`);
} else {
updates.push(b`
@ -305,7 +297,7 @@ export default class InlineComponentWrapper extends Wrapper {
}`);
}
const munged_bindings = this.node.bindings.map(binding => {
const munged_bindings = this.node.bindings.map((binding) => {
component.has_reactive_assignments = true;
if (binding.name === 'this') {
@ -321,17 +313,13 @@ export default class InlineComponentWrapper extends Wrapper {
const snippet = binding.expression.manipulate(block);
statements.push(b`
if (${snippet} !== void 0) {
${props}.${binding.name} = ${snippet};
}`
);
statements.push(b`if (${snippet} !== undefined) ${props}.${binding.name} = ${snippet};`);
updates.push(b`
if (!${updating} && ${renderer.dirty(Array.from(binding.expression.dependencies))}) {
${updating} = true;
${name_changes}.${binding.name} = ${snippet};
@add_flush_callback(() => ${updating} = false);
@add_flush_callback(() => {${updating} = false;});
}
`);
@ -350,48 +338,31 @@ export default class InlineComponentWrapper extends Wrapper {
}
const params = [x`#value`];
if (contextual_dependencies.length > 0) {
const args = [];
contextual_dependencies.forEach(name => {
params.push({
type: 'Identifier',
name
});
let args = [];
contextual_dependencies.forEach((name) => {
params.push({ type: 'Identifier', name });
renderer.add_to_context(name, true);
args.push(renderer.reference(name));
// TODO put this somewhere more logical
block.maintain_context = true;
});
block.chunks.init.push(b`
function ${id}(#value) {
${callee}.call(null, #value, ${args});
${callee}.call(null, #value, ${args.length ? args : null});
}
`);
block.maintain_context = true; // TODO put this somewhere more logical
} else {
block.chunks.init.push(b`
function ${id}(#value) {
${callee}.call(null, #value);
}
`);
}
const body = b`
component.partly_hoisted.push(b`
function ${id}(${params}) {
${lhs} = #value;
${renderer.invalidate(dependencies[0])};
}
`;
component.partly_hoisted.push(body);
`);
return b`@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${id}));`;
});
const munged_handlers = this.node.handlers.map(handler => {
const munged_handlers = this.node.handlers.map((handler) => {
const event_handler = new EventHandler(handler, this);
let snippet = event_handler.get_snippet(block);
if (handler.modifiers.has('once')) snippet = x`@once(${snippet})`;
@ -409,8 +380,7 @@ export default class InlineComponentWrapper extends Wrapper {
var ${switch_value} = ${snippet};
function ${switch_props}(#ctx) {
${(this.node.attributes.length > 0 || this.node.bindings.length > 0) && b`
${props && b`let ${props} = ${attribute_object};`}`}
${props && (this.node.attributes.length || this.node.bindings.length) && b`let ${props} = ${attribute_object};`}
${statements}
return ${component_opts};
}
@ -423,14 +393,10 @@ export default class InlineComponentWrapper extends Wrapper {
}
`);
block.chunks.create.push(
b`if (${name}) @create_component(${name}.$$.fragment);`
);
block.chunks.create.push(b`if (${name} && ${name}.$$.fragment) ${name}.$$.fragment.c();`);
if (parent_nodes && this.renderer.options.hydratable) {
block.chunks.claim.push(
b`if (${name}) @claim_component(${name}.$$.fragment, ${parent_nodes});`
);
block.chunks.claim.push(b`if (${name} && ${name}.$$.fragment) ${name}.$$.fragment.l(${parent_nodes});`);
}
block.chunks.mount.push(b`
@ -465,7 +431,7 @@ export default class InlineComponentWrapper extends Wrapper {
${munged_bindings}
${munged_handlers}
@create_component(${name}.$$.fragment);
if(${name}.$$.fragment) ${name}.$$.fragment.c();
@transition_in(${name}.$$.fragment, 1);
@mount_component(${name}, ${update_mount_node}, ${anchor});
} else {
@ -480,19 +446,18 @@ export default class InlineComponentWrapper extends Wrapper {
if (${name}) @transition_in(${name}.$$.fragment, #local);
`);
block.chunks.outro.push(
b`if (${name}) @transition_out(${name}.$$.fragment, #local);`
);
block.chunks.outro.push(b`if (${name}) @transition_out(${name}.$$.fragment, #local);`);
block.chunks.destroy.push(b`if (${name}) @destroy_component(${name}, ${parent_node ? null : 'detaching'});`);
} else {
const expression = this.node.name === 'svelte:self'
? component.name
: this.renderer.reference(this.node.name);
const expression = this.node.name === 'svelte:self' ? component.name : this.renderer.reference(this.node.name);
block.chunks.init.push(b`
${(this.node.attributes.length > 0 || this.node.bindings.length > 0) && b`
${props && b`let ${props} = ${attribute_object};`}`}
${
(this.node.attributes.length > 0 || this.node.bindings.length > 0) &&
b`
${props && b`let ${props} = ${attribute_object};`}`
}
${statements}
const ${name} = new ${expression}(${component_opts});
@ -500,12 +465,10 @@ export default class InlineComponentWrapper extends Wrapper {
${munged_handlers}
`);
block.chunks.create.push(b`@create_component(${name}.$$.fragment);`);
block.chunks.create.push(b`if(${name}.$$.fragment) ${name}.$$.fragment.c();`);
if (parent_nodes && this.renderer.options.hydratable) {
block.chunks.claim.push(
b`@claim_component(${name}.$$.fragment, ${parent_nodes});`
);
block.chunks.claim.push(b`if(${name}.$$.fragment) ${name}.$$.fragment.l(${parent_nodes});`);
}
block.chunks.mount.push(
@ -527,9 +490,7 @@ export default class InlineComponentWrapper extends Wrapper {
@destroy_component(${name}, ${parent_node ? null : 'detaching'});
`);
block.chunks.outro.push(
b`@transition_out(${name}.$$.fragment, #local);`
);
block.chunks.outro.push(b`@transition_out(${name}.$$.fragment, #local);`);
}
}
}

@ -1,14 +1,6 @@
import { cubicOut } from 'svelte/easing';
import { is_function } from 'svelte/internal';
import { AnimationConfig } from 'svelte/internal';
// todo: same as Transition, should it be shared?
export interface AnimationConfig {
delay?: number;
duration?: number;
easing?: (t: number) => number;
css?: (t: number, u: number) => string;
tick?: (t: number, u: number) => void;
}
interface FlipParams {
delay: number;
@ -16,27 +8,23 @@ interface FlipParams {
easing: (t: number) => number;
}
export function flip(node: Element, animation: { from: DOMRect; to: DOMRect }, params: FlipParams): AnimationConfig {
const style = getComputedStyle(node);
const transform = style.transform === 'none' ? '' : style.transform;
export function flip(
node: Element,
animation: { from: DOMRect; to: DOMRect },
{ delay = 0, duration = (d: number) => Math.sqrt(d) * 120, easing = cubicOut }: FlipParams
): AnimationConfig {
const style = getComputedStyle(node).transform;
const transform = style === 'none' ? '' : style;
const scaleX = animation.from.width / node.clientWidth;
const scaleY = animation.from.height / node.clientHeight;
const dx = (animation.from.left - animation.to.left) / scaleX;
const dy = (animation.from.top - animation.to.top) / scaleY;
const d = Math.sqrt(dx * dx + dy * dy);
const {
delay = 0,
duration = (d: number) => Math.sqrt(d) * 120,
easing = cubicOut
} = params;
return {
delay,
duration: is_function(duration) ? duration(d) : duration,
duration: typeof duration === 'function' ? duration(Math.sqrt(dx * dx + dy * dy)) : duration,
easing,
css: (_t, u) => `transform: ${transform} translate(${u * dx}px, ${u * dy}px);`
css: (_t, u) => `transform: ${transform} translate(${u * dx}px, ${u * dy}px);`,
};
}

@ -1,171 +1,69 @@
/*
Adapted from https://github.com/mattdesl
Distributed under MIT License https://github.com/mattdesl/eases/blob/master/LICENSE.md
*/
export { identity as linear } from 'svelte/internal';
export function backInOut(t: number) {
const 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: number) {
const s = 1.70158;
return t * t * ((s + 1) * t - s);
}
export function backOut(t: number) {
const s = 1.70158;
return --t * t * ((s + 1) * t + s) + 1;
}
export function bounceOut(t: number) {
const a = 4.0 / 11.0;
const b = 8.0 / 11.0;
const c = 9.0 / 10.0;
const ca = 4356.0 / 361.0;
const cb = 35442.0 / 1805.0;
const cc = 16061.0 / 1805.0;
const 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: number) {
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: number) {
return 1.0 - bounceOut(1.0 - t);
}
export function circInOut(t: number) {
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: number) {
return 1.0 - Math.sqrt(1.0 - t * t);
}
export function circOut(t: number) {
return Math.sqrt(1 - --t * t);
}
export function cubicInOut(t: number) {
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: number) {
return t * t * t;
}
export function cubicOut(t: number) {
const f = t - 1.0;
return f * f * f + 1.0;
}
export function elasticInOut(t: number) {
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: number) {
return Math.sin((13.0 * t * Math.PI) / 2) * Math.pow(2.0, 10.0 * (t - 1.0));
}
export function elasticOut(t: number) {
return (
Math.sin((-13.0 * (t + 1.0) * Math.PI) / 2) * Math.pow(2.0, -10.0 * t) + 1.0
);
}
export function expoInOut(t: number) {
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: number) {
return t === 0.0 ? t : Math.pow(2.0, 10.0 * (t - 1.0));
}
export function expoOut(t: number) {
return t === 1.0 ? t : 1.0 - Math.pow(2.0, -10.0 * t);
}
export function quadInOut(t: number) {
t /= 0.5;
if (t < 1) return 0.5 * t * t;
t--;
return -0.5 * (t * (t - 2) - 1);
}
export function quadIn(t: number) {
return t * t;
}
export function quadOut(t: number) {
return -t * (t - 2.0);
}
export function quartInOut(t: number) {
return t < 0.5
? +8.0 * Math.pow(t, 4.0)
: -8.0 * Math.pow(t - 1.0, 4.0) + 1.0;
}
export function quartIn(t: number) {
return Math.pow(t, 4.0);
}
export function quartOut(t: number) {
return Math.pow(t - 1.0, 3.0) * (1.0 - t) + 1.0;
}
export function quintInOut(t: number) {
if ((t *= 2) < 1) return 0.5 * t * t * t * t * t;
return 0.5 * ((t -= 2) * t * t * t * t + 2);
}
export function quintIn(t: number) {
return t * t * t * t * t;
}
export function quintOut(t: number) {
return --t * t * t * t * t + 1;
}
export function sineInOut(t: number) {
return -0.5 * (Math.cos(Math.PI * t) - 1);
}
export function sineIn(t: number) {
const v = Math.cos(t * Math.PI * 0.5);
if (Math.abs(v) < 1e-14) return 1;
else return 1 - v;
}
export function sineOut(t: number) {
return Math.sin((t * Math.PI) / 2);
}
export const quadIn = (t: number) => t ** 2;
export const quadOut = (t: number) => 1.0 - (1.0 - t) ** 2;
export const quadInOut = (t: number) => 0.5 * (t >= 0.5 ? 2 - 2 * (1.0 - t) ** 2 : (2 * t) ** 2);
export const cubicIn = (t: number) => t ** 3;
export const cubicOut = (t: number) => 1.0 - (1.0 - t) ** 3;
export const cubicInOut = (t: number) => 0.5 * (t >= 0.5 ? 2 - (2 * (1.0 - t)) ** 3 : (2 * t) ** 3);
export const quartIn = (t: number) => t ** 4;
export const quartOut = (t: number) => 1.0 - (1.0 - t) ** 4;
export const quartInOut = (t: number) => 0.5 * (t >= 0.5 ? 2 - (2 * (1.0 - t)) ** 4 : (2 * t) ** 4);
export const easeIn = quartIn;
export const easeOut = quartOut;
export const easeInOut = quartInOut;
export const quintIn = (t: number) => t ** 5;
export const quintOut = (t: number) => 1.0 - (1.0 - t) ** 5;
export const quintInOut = (t: number) => 0.5 * (t >= 0.5 ? 2 - (2 * (1.0 - t)) ** 5 : (2 * t) ** 5);
export const backIn = (t: number) => t * t * (2.6 * t - 1.6);
export const backOut = (t: number) => 1 - (t = 1.0 - t) * t * (2.6 * t - 1.6);
export const backInOut = (t: number) =>
0.5 * (t >= 0.5 ? 2 - (t = 2 * (1 - t)) * t * (2.6 * t - 1.6) : (t = 2 * t) * t * (2.6 * t - 1.6));
export const expoIn = (t: number) => (t ? Math.pow(2.0, 10.0 * (t - 1.0)) : t);
export const expoOut = (t: number) => (t ? 1.0 - Math.pow(2.0, -10.0 * t) : t);
export const expoInOut = (t: number) =>
!t || 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 const elasticIn = (t: number) => Math.sin((13.0 * t * Math.PI) / 2) * Math.pow(2.0, 10.0 * (t - 1.0));
export const elasticOut = (t: number) => Math.sin((-13.0 * (t + 1.0) * Math.PI) / 2) * Math.pow(2.0, -10.0 * t) + 1.0;
export const elasticInOut = (t: number) =>
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 const bounceOut = (t: number) =>
4 / 11 > t
? 7.5625 * t * t
: 8 / 11 > t
? 3.4 + 9.075 * t * t - 9.9 * t
: 9 / 10 > t
? 16061.0 / 1805.0 + (4356.0 * t * t) / 361.0 - (35442.0 * t) / 1805.0
: 10.72 + 10.8 * t * t - 20.52 * t;
export const bounceIn = (t: number) => 1.0 - bounceOut(1.0 - t);
export const bounceInOut = (t: number) =>
t < 0.5 ? 0.5 * (1.0 - bounceOut(1.0 - t * 2.0)) : 0.5 * bounceOut(t * 2.0 - 1.0) + 0.5;
export const sineIn = (t: number) => (1e-14 > Math.abs((t = Math.cos(t * Math.PI * 0.5))) ? 1.0 : 1.0 - t);
export const sineOut = (t: number) => Math.sin((t * Math.PI) / 2);
export const sineInOut = (t: number) => -0.5 * (Math.cos(Math.PI * t) - 1);
export const circIn = (t: number) => 1 - Math.sin(Math.acos(t));
export const circOut = (t: number) => Math.sin(Math.acos(1 - t));
export const circInOut = (t: number) =>
0.5 * (t >= 0.5 ? 2.0 - Math.sin(Math.acos(1.0 - 2.0 * (1.0 - t))) : Math.sin(Math.acos(1.0 - 2.0 * t)));
export const cubicBezier = (x1: number, y1: number, x2: number, y2: number) => {
const ax = 1.0 - (x2 = 3.0 * (x2 - x1) - (x1 = 3.0 * x1)) - x1,
ay = 1.0 - (y2 = 3.0 * (y2 - y1) - (y1 = 3.0 * y1)) - y1;
let r = Number.NaN,
s = Number.NaN,
d = Number.NaN,
x = Number.NaN;
return (t: number) => {
r = t;
for (let i = 0; 32 > i; i++)
if (1e-5 > Math.abs((x = r * r * (r * ax + x1 + x2) - t))) return r * (r * (r * ay + y2) + y1);
else if (1e-5 > Math.abs((d = r * (r * ax * 3.0 + x2 * 2.0) + x1))) break;
else r = r - x / d;
if ((s = 0.0) > (r = t)) return 0;
else if ((d = 1.0) > r) return 1;
while (d > s)
if (1e-5 > Math.abs((x = r * (r * (r * ax + x2) + x1)) - t)) break;
else t > x ? (s = r) : (d = r), (r = 0.5 * (d - s) + s);
return r * (r * (r * ay + y2) + y1);
};
};

@ -1,22 +1,32 @@
import { add_render_callback, flush, schedule_update, dirty_components } from './scheduler';
import { add_render_callback, flush, schedule_update } from './scheduler';
import { current_component, set_current_component } from './lifecycle';
import { blank_object, is_function, run, run_all, noop } from './utils';
import { blank_object, is_function, run_all, noop } from './utils';
import { children, detach } from './dom';
import { transition_in } from './transitions';
interface Fragment {
export interface Fragment {
key: string | null;
first: null;
/* create */ c: () => void;
/* claim */ l: (nodes: any) => void;
/**
* create
* run once
* runs hydrate if exists
*/
c: () => void;
/**
* claim
* runs hydrate if exists
* */
l: (nodes: any) => void;
/* hydrate */ h: () => void;
/* mount */ m: (target: HTMLElement, anchor: any) => void;
/* mount */ m: (target: HTMLElement, anchor: any, is_remount: boolean) => void;
/* update */ p: (ctx: any, dirty: any) => void;
/* measure */ r: () => void;
/* fix */ f: () => void;
/* animate */ a: () => void;
/* intro */ i: (local: any) => void;
/* outro */ o: (local: any) => void;
/* intro */ i: (local: 0 | 1) => void;
/* outro */ o: (local: 0 | 1) => void;
/* destroy */ d: (detaching: 0 | 1) => void;
}
// eslint-disable-next-line @typescript-eslint/class-name-casing
@ -36,43 +46,25 @@ interface T$$ {
on_destroy: any[];
}
export function bind(component, name, callback) {
const index = component.$$.props[name];
if (index === undefined) return;
component.$$.bound[index] = callback;
callback(component.$$.ctx[index]);
export function bind({ $$: { props, bound, ctx } }, name: string, callback: (prop: any) => void) {
if (!(name in props)) return;
const index = props[name];
bound[index] = callback;
callback(ctx[index]);
}
export function create_component(block) {
if (block) block.c();
}
export function claim_component(block, parent_nodes) {
if (block) block.l(parent_nodes);
}
export function mount_component(component, target, anchor) {
const { fragment, on_mount, on_destroy, after_update } = component.$$;
export function mount_component({ $$: { fragment, on_mount, on_destroy, after_update } }, target, anchor) {
if (fragment) fragment.m(target, anchor);
// onMount happens before the initial afterUpdate
add_render_callback(() => {
const new_on_destroy = on_mount.map(run).filter(is_function);
if (on_destroy) {
on_destroy.push(...new_on_destroy);
} else {
// Edge case - component was destroyed immediately,
// most likely as a result of a binding initialising
run_all(new_on_destroy);
}
component.$$.on_mount = [];
for (let i = 0, res; i < on_mount.length; i++)
if (is_function((res = on_mount[i]())))
if (on_destroy) on_destroy.push(res);
else res(); // component already destroyed
on_mount.length = 0;
for (let i = 0; i < after_update.length; i++) after_update[i]();
});
after_update.forEach(add_render_callback);
}
export function destroy_component({ $$ }, detaching) {
export function destroy_component({ $$ }, detaching: 0 | 1) {
if ($$.fragment === null) return;
run_all($$.on_destroy);
@ -84,17 +76,8 @@ export function destroy_component({ $$ }, detaching) {
$$.ctx = [];
}
function make_dirty(component, i) {
if (component.$$.dirty[0] === -1) {
dirty_components.push(component);
schedule_update();
component.$$.dirty.fill(0);
}
component.$$.dirty[(i / 31) | 0] |= 1 << i % 31;
}
export function init(
component,
component: SvelteComponent,
{ props: prop_values = {}, target, hydrate, intro, anchor },
instance,
create_fragment,
@ -131,8 +114,14 @@ export function init(
$$.ctx = instance
? instance(component, prop_values, (i, res, val = res) => {
if ($$.ctx && not_equal($$.ctx[i], ($$.ctx[i] = val))) {
if ($$.bound[i]) $$.bound[i](val);
if (ready) make_dirty(component, i);
if (i in $$.bound) $$.bound[i](val);
if (ready) {
if (!~$$.dirty) {
schedule_update(component);
$$.dirty.fill(0);
}
$$.dirty[(i / 31) | 0] |= 1 << i % 31;
}
}
return res;
})
@ -144,18 +133,24 @@ export function init(
run_all($$.before_update);
// false when empty fragment
// false when empty
$$.fragment = create_fragment ? create_fragment($$.ctx) : false;
if (target) {
if ($$.fragment) {
if (hydrate) {
const nodes = children(target);
if ($$.fragment) $$.fragment.l(nodes);
$$.fragment.l(nodes);
nodes.forEach(detach);
} else {
if ($$.fragment) $$.fragment.c();
$$.fragment.c();
}
if (intro) {
transition_in($$.fragment);
}
} else if (hydrate) {
children(target).forEach(detach);
}
if (intro) transition_in(component.$$.fragment);
mount_component(component, target, anchor);
flush();
}

@ -1,7 +1,14 @@
import { noop } from './utils';
import { AnimationConfig } from '../animate';
import { run_transition } from './transitions';
export interface AnimationConfig {
delay?: number;
duration?: number;
easing?: (t: number) => number;
css?: (t: number, u?: number) => string;
tick?: (t: number, u?: number) => void;
}
//todo: documentation says it is DOMRect, but in IE it would be ClientRect
type PositionRect = DOMRect | ClientRect;
@ -19,28 +26,24 @@ export function run_animation(node: HTMLElement, from: PositionRect, fn: Animati
}
export function fix_position(node: HTMLElement) {
const style = getComputedStyle(node);
if (style.position !== 'absolute' && style.position !== 'fixed') {
const { width, height } = style;
const a = node.getBoundingClientRect();
const { position, width, height } = getComputedStyle(node);
if (position === 'absolute' || position === 'fixed') return noop;
const current_position = node.getBoundingClientRect();
const { position: og_position, width: og_width, height: og_height } = node.style;
node.style.position = 'absolute';
node.style.width = width;
node.style.height = height;
add_transform(node, a);
add_transform(node, current_position);
return () => {
node.style.position = og_position;
node.style.width = og_width;
node.style.height = og_height;
node.style.transform = '';
node.style.transform = ''; // unsafe
};
}
}
export function add_transform(node: HTMLElement, a: PositionRect) {
const b = node.getBoundingClientRect();
if (a.left !== b.left || a.top !== b.top) {
const style = getComputedStyle(node);
const transform = style.transform === 'none' ? '' : style.transform;

@ -1,22 +1,51 @@
import { custom_event, append, insert, detach, listen, attr } from './dom';
import { SvelteComponent } from './Component';
export function dispatch_dev<T=any>(type: string, detail?: T) {
import {
get_current_component,
beforeUpdate,
onMount,
afterUpdate,
onDestroy,
createEventDispatcher,
setContext,
getContext,
} from './lifecycle';
import { cubicBezier } from 'svelte/easing';
export const [
beforeUpdate_dev,
onMount_dev,
afterUpdate_dev,
onDestroy_dev,
createEventDispatcher_dev,
setContext_dev,
getContext_dev,
] = [beforeUpdate, onMount, afterUpdate, onDestroy, createEventDispatcher, setContext, getContext].map(
(fn) => (a?, b?) => {
if (!get_current_component()) throw new Error(`${fn.name} cannot be called outside of component initialization`);
return fn(a, b);
}
);
export function cubicBezier_dev(mX1, mY1, mX2, mY2) {
if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) throw new Error('CubicBezier x values must be { 0 < x < 1 }');
return cubicBezier(mX1, mY1, mX2, mY2);
}
export function dispatch_dev<T = any>(type: string, detail?: T) {
document.dispatchEvent(custom_event(type, { version: '__VERSION__', ...detail }));
}
export function append_dev(target: Node, node: Node) {
dispatch_dev("SvelteDOMInsert", { target, node });
dispatch_dev('SvelteDOMInsert', { target, node });
append(target, node);
}
export function insert_dev(target: Node, node: Node, anchor?: Node) {
dispatch_dev("SvelteDOMInsert", { target, node, anchor });
dispatch_dev('SvelteDOMInsert', { target, node, anchor });
insert(target, node, anchor);
}
export function detach_dev(node: Node) {
dispatch_dev("SvelteDOMRemove", { node });
dispatch_dev('SvelteDOMRemove', { node });
detach(node);
}
@ -38,16 +67,23 @@ export function detach_after_dev(before: Node) {
}
}
export function listen_dev(node: Node, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | EventListenerOptions, has_prevent_default?: boolean, has_stop_propagation?: boolean) {
const modifiers = options === true ? [ "capture" ] : options ? Array.from(Object.keys(options)) : [];
export function listen_dev(
node: Node,
event: string,
handler: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions | EventListenerOptions,
has_prevent_default?: boolean,
has_stop_propagation?: boolean
) {
const modifiers = options === true ? ['capture'] : options ? Array.from(Object.keys(options)) : [];
if (has_prevent_default) modifiers.push('preventDefault');
if (has_stop_propagation) modifiers.push('stopPropagation');
dispatch_dev("SvelteDOMAddEventListener", { node, event, handler, modifiers });
dispatch_dev('SvelteDOMAddEventListener', { node, event, handler, modifiers });
const dispose = listen(node, event, handler, options);
return () => {
dispatch_dev("SvelteDOMRemoveEventListener", { node, event, handler, modifiers });
dispatch_dev('SvelteDOMRemoveEventListener', { node, event, handler, modifiers });
dispose();
};
}
@ -55,27 +91,27 @@ export function listen_dev(node: Node, event: string, handler: EventListenerOrEv
export function attr_dev(node: Element, attribute: string, value?: string) {
attr(node, attribute, value);
if (value == null) dispatch_dev("SvelteDOMRemoveAttribute", { node, attribute });
else dispatch_dev("SvelteDOMSetAttribute", { node, attribute, value });
if (value == null) dispatch_dev('SvelteDOMRemoveAttribute', { node, attribute });
else dispatch_dev('SvelteDOMSetAttribute', { node, attribute, value });
}
export function prop_dev(node: Element, property: string, value?: any) {
node[property] = value;
dispatch_dev("SvelteDOMSetProperty", { node, property, value });
dispatch_dev('SvelteDOMSetProperty', { node, property, value });
}
export function dataset_dev(node: HTMLElement, property: string, value?: any) {
node.dataset[property] = value;
dispatch_dev("SvelteDOMSetDataset", { node, property, value });
dispatch_dev('SvelteDOMSetDataset', { node, property, value });
}
export function set_data_dev(text, data) {
data = '' + data;
if (text.data === data) return;
dispatch_dev("SvelteDOMSetData", { node: text, data });
dispatch_dev('SvelteDOMSetData', { node: text, data });
text.data = data;
}

@ -1,4 +1,4 @@
import { has_prop } from "./utils";
import { has_prop } from './utils';
export function append(target: Node, node: Node) {
target.appendChild(node);
@ -25,14 +25,13 @@ export function element<K extends keyof HTMLElementTagNameMap>(name: K) {
export function element_is<K extends keyof HTMLElementTagNameMap>(name: K, is: string) {
return document.createElement<K>(name, { is });
}
export function object_without_properties<T, K extends keyof T>(obj: T, exclude: K[]) {
const target = {} as Pick<T, Exclude<keyof T, K>>;
for (const k in obj) {
if (
has_prop(obj, k)
has_prop(obj, k) &&
// @ts-ignore
&& exclude.indexOf(k) === -1
exclude.indexOf(k) === -1
) {
// @ts-ignore
target[k] = obj[k];
@ -57,13 +56,18 @@ export function empty() {
return text('');
}
export function listen(node: EventTarget, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | EventListenerOptions) {
export function listen(
node: EventTarget,
event: string,
handler: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions | EventListenerOptions
) {
node.addEventListener(event, handler, options);
return () => node.removeEventListener(event, handler, options);
}
export function prevent_default(fn) {
return function(event) {
return function (event) {
event.preventDefault();
// @ts-ignore
return fn.call(this, event);
@ -71,7 +75,7 @@ export function prevent_default(fn) {
}
export function stop_propagation(fn) {
return function(event) {
return function (event) {
event.stopPropagation();
// @ts-ignore
return fn.call(this, event);
@ -79,7 +83,7 @@ export function stop_propagation(fn) {
}
export function self(fn) {
return function(event) {
return function (event) {
// @ts-ignore
if (event.target === this) fn.call(this, event);
};
@ -98,7 +102,7 @@ export function set_attributes(node: Element & ElementCSSInlineStyle, attributes
node.removeAttribute(key);
} else if (key === 'style') {
node.style.cssText = attributes[key];
} else if (key === '__value' || descriptors[key] && descriptors[key].set) {
} else if (key === '__value' || (descriptors[key] && descriptors[key].set)) {
node[key] = attributes[key];
} else {
attr(node, key, attributes[key]);
@ -144,9 +148,7 @@ export function time_ranges_to_array(ranges) {
return array;
}
export function children(element) {
return Array.from(element.childNodes);
}
export const children = (element: HTMLElement) => Array.from(element.childNodes);
export function claim_element(nodes, name, attributes, svg) {
for (let i = 0; i < nodes.length; i += 1) {
@ -231,7 +233,7 @@ export function select_value(select) {
}
export function select_multiple_value(select) {
return [].map.call(select.querySelectorAll(':checked'), option => option.__value);
return [].map.call(select.querySelectorAll(':checked'), (option) => option.__value);
}
// unfortunately this can't be a constant as that wouldn't be tree-shakeable
@ -263,7 +265,8 @@ export function add_resize_listener(node: HTMLElement, fn: () => void) {
}
const iframe = element('iframe');
iframe.setAttribute('style',
iframe.setAttribute(
'style',
`display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; ` +
`overflow: hidden; border: 0; opacity: 0; pointer-events: none; z-index: ${z_index};`
);
@ -296,7 +299,7 @@ export function toggle_class(element, name, toggle) {
element.classList[toggle ? 'add' : 'remove'](name);
}
export function custom_event<T=any>(type: string, detail?: T) {
export function custom_event<T = any>(type: string, detail?: T) {
const e: CustomEvent<T> = document.createEvent('CustomEvent');
e.initCustomEvent(type, false, false, detail);
return e;

@ -1,18 +1,16 @@
import { noop } from './utils';
export const is_client = typeof window !== 'undefined';
export const is_iframe = is_client && window.location !== window.parent.location;
export let now: () => number = is_client
? () => window.performance.now()
: () => Date.now();
export let now = is_client ? window.performance.now : () => Date.now();
export let raf = is_client ? cb => requestAnimationFrame(cb) : noop;
export let raf = is_client ? window.requestAnimationFrame : noop;
// used internally for testing
export function set_now(fn) {
now = fn;
}
export function set_raf(fn) {
raf = fn;
}

@ -2,9 +2,7 @@ import { custom_event } from './dom';
export let current_component;
export function set_current_component(component) {
current_component = component;
}
export const set_current_component = (component) => (current_component = component);
export function get_current_component() {
if (!current_component) throw new Error(`Function called outside component initialization`);
@ -32,15 +30,13 @@ export function createEventDispatcher() {
return (type: string, detail?: any) => {
const callbacks = component.$$.callbacks[type];
if (callbacks) {
if (!callbacks) return;
// TODO are there situations where events could be dispatched
// in a server (non-DOM) environment?
const event = custom_event(type, detail);
callbacks.slice().forEach(fn => {
callbacks.forEach((fn) => {
fn.call(component, event);
});
}
};
}
@ -59,6 +55,6 @@ export function bubble(component, event) {
const callbacks = component.$$.callbacks[event.type];
if (callbacks) {
callbacks.slice().forEach(fn => fn(event));
callbacks.slice().forEach((fn) => fn(event));
}
}

@ -43,37 +43,35 @@ export function loop(callback: TaskCallback): Task {
};
}
function add(c) {
function add(c: TaskCallback) {
const task = { c, f: noop };
if (!tasks.size) raf(run_tasks);
tasks.add(task);
return () => tasks.delete(task);
}
const timed_tasks = [];
type TimeoutTask = { t: number; c: (now: number) => void };
// sorted descending
const timed_tasks: Array<TimeoutTask> = [];
/**
* Callback on 1st frame after timestamp
* basically
* (fn, t) => setTimeout( () => raf(fn), t )
*/
export function raf_timeout(callback: () => void, timestamp: number) {
export function setAnimationTimeout(callback: () => void, timestamp: number) {
let i = timed_tasks.length;
let v;
const task = { c: callback, t: timestamp };
if (i) {
while (i > 0 && timestamp > (v = timed_tasks[i - 1]).t) {
// bubble sort descending until timestamp < task.timestamp
timed_tasks[i--] = v;
}
while (i > 0 && timestamp > (v = timed_tasks[i - 1]).t) timed_tasks[i--] = v;
timed_tasks[i] = task;
} else {
timed_tasks.push(task);
add((now) => {
let i = timed_tasks.length;
while (i > 0 && now >= timed_tasks[--i].t) {
// pop() until now < task.timestamp
timed_tasks.pop().c(now);
}
return timed_tasks.length;
while (i > 0 && now >= timed_tasks[--i].t) timed_tasks.pop().c(now);
return !!timed_tasks.length;
});
}
return () => {
@ -81,11 +79,10 @@ export function raf_timeout(callback: () => void, timestamp: number) {
if (~index) timed_tasks.splice(index, 1);
};
}
export function loopThen(delay: number, run: (now: number) => void, stop: () => void, end_time: number) {
const fn = () => add((now) => (now < end_time ? (run(now), true) : (stop(), false)));
if (delay < 16) return fn();
else {
let cancel = raf_timeout(() => (cancel = fn()), now() + delay - 16.6667);
return () => cancel();
}
}
export const loopThen = (run: (now: number) => void, stop: () => void, duration: number, end_time: number) =>
add((t) => {
t = (end_time - t) / duration;
if (t >= 1) return void run(1), stop();
else if (t >= 0) run(t);
return true;
});

@ -1,34 +1,25 @@
import { run_all } from './utils';
import { set_current_component } from './lifecycle';
export const dirty_components = [];
export const intros = { enabled: false };
export const binding_callbacks = [];
const render_callbacks = [];
const flush_callbacks = [];
const dirty_components = [];
const resolved_promise = Promise.resolve();
let update_scheduled = false;
export function schedule_update() {
let update_scheduled = false;
export function schedule_update(component) {
dirty_components.push(component);
if (update_scheduled) return;
update_scheduled = true;
resolved_promise.then(flush);
(update_scheduled = true), resolved_promise.then(flush);
}
export function tick() {
schedule_update();
if (!update_scheduled) (update_scheduled = true), resolved_promise.then(flush);
return resolved_promise;
}
export const binding_callbacks = [];
const render_callbacks = [];
export const add_render_callback = (fn) => render_callbacks.push(fn);
export function add_render_callback(fn) {
render_callbacks.push(fn);
}
export function add_flush_callback(fn) {
flush_callbacks.push(fn);
}
const flush_callbacks = [];
export const add_flush_callback = (fn) => flush_callbacks.push(fn);
let flushing = false;
const seen_callbacks = new Set();
@ -36,45 +27,36 @@ export function flush() {
if (flushing) return;
flushing = true;
do {
for (; dirty_components.length; ) {
// update components + beforeUpdate
for (let i = 0, component; i < dirty_components.length; i++) {
set_current_component((component = dirty_components[i]));
update(component.$$);
for (let i = 0, $$; i < dirty_components.length; i++) {
({ $$ } = set_current_component(dirty_components[i]));
if ($$.fragment === null) continue;
const { update, before_update, dirty, after_update } = $$;
update();
for (let j = 0; j < before_update.length; j++) before_update[j]();
$$.dirty = [-1];
if ($$.fragment) $$.fragment.p($$.ctx, dirty);
render_callbacks.push(...after_update);
}
dirty_components.length = 0;
// update bindings
for (let i = 0; i < binding_callbacks.length; i++) {
binding_callbacks[i]();
}
// update bindings in reverse order
for (let i = binding_callbacks.length - 1; i; i--) binding_callbacks[i]();
binding_callbacks.length = 0;
// afterUpdate
for (let i = 0, callback; i < render_callbacks.length; i++) {
if (seen_callbacks.has((callback = render_callbacks[i]))) continue;
seen_callbacks.add(callback);
callback();
seen_callbacks.add(callback), callback();
}
render_callbacks.length = 0;
} while (dirty_components.length);
for (let i = 0; i < flush_callbacks.length; i++) {
flush_callbacks[i]();
}
for (let i = 0; i < flush_callbacks.length; i++) flush_callbacks[i]();
flush_callbacks.length = 0;
seen_callbacks.clear();
update_scheduled = false;
flushing = false;
seen_callbacks.clear();
}
function update($$) {
if ($$.fragment === null) return;
$$.update();
run_all($$.before_update);
const dirty = $$.dirty;
$$.dirty = [-1];
$$.fragment && $$.fragment.p($$.ctx, dirty);
$$.after_update.forEach(add_render_callback);
}

@ -1,71 +1,74 @@
import { element } from './dom';
import { raf } from './environment';
const enum SVELTE {
RULE = `__svelte_`,
STYLESHEET = `__svelte_stylesheet`,
RULESET = `__svelte_rules`,
}
const svelte_rule = `__svelte_`;
let FRAME_RATE;
function calc_framerate() {
const f24 = 1000 / 24,
f60 = 1000 / 60,
f144 = 1000 / 144;
raf((t1) => {
raf((d) => {
FRAME_RATE = (d = d - t1) > f144 ? f144 : d < f24 ? f24 : d;
});
});
return (FRAME_RATE = f60);
}
interface ExtendedDoc extends Document {
__svelte_stylesheet: CSSStyleSheet;
__svelte_rules: Set<string>;
[SVELTE.STYLESHEET]: CSSStyleSheet;
[SVELTE.RULESET]: Set<string>;
}
const active_documents = new Set<ExtendedDoc>();
let running_animations = 0;
function rulesheet({ ownerDocument }): [CSSStyleSheet, Set<string>] {
const doc = ownerDocument as ExtendedDoc;
if (!active_documents.has(doc)) {
active_documents.add(doc);
if (!doc.__svelte_stylesheet) {
doc.__svelte_stylesheet = doc.head.appendChild(element('style')).sheet as CSSStyleSheet;
function add_rule(node, name, rule): [CSSStyleSheet, Set<string>] {
const { ownerDocument } = node;
if (!active_documents.has(ownerDocument)) {
active_documents.add(ownerDocument);
if (!(SVELTE.STYLESHEET in ownerDocument))
ownerDocument[SVELTE.STYLESHEET] = ownerDocument.head.appendChild(element('style')).sheet;
if (!(SVELTE.RULESET in ownerDocument)) ownerDocument[SVELTE.RULESET] = new Set();
}
if (!doc.__svelte_rules) {
doc.__svelte_rules = new Set();
}
}
return [doc.__svelte_stylesheet, doc.__svelte_rules];
return [ownerDocument[SVELTE.STYLESHEET], ownerDocument[SVELTE.RULESET]];
}
// https://github.com/darkskyapp/string-hash/blob/master/index.js
function hash(str: string) {
let hash = 5381;
let i = str.length;
while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
return hash >>> 0;
}
export function generate_rule(
node: HTMLElement,
a: number,
b: number,
duration: number,
delay: number,
ease: (t: number) => number,
fn: (t: number, u: number) => string
) {
const step = 16.6667 / duration;
const gen = (t, step, css) => {
let rule = '{\n';
for (let p = 0, t = 0; p <= 1; p += step) {
t = a + (b - a) * ease(p);
rule += p * 100 + `%{${fn(t, 1 - t)}}\n`;
}
rule += `100% {${fn(b, 1 - b)}}\n}`;
const name = `${svelte_rule}${hash(rule)}`;
const [stylesheet, rules] = rulesheet(node);
for (; t < 1; t += step) rule += `${100 * t}%{${css(t)}}\n`;
rule += `100% {${css(1)}}\n}`;
const name = SVELTE.RULE + hash(rule);
return [name, `@keyframes ${name} ${rule}`];
};
export function animate_css(css: (t: number) => string, node: HTMLElement, duration: number, t = 0) {
const [name, rule] = gen(t, duration / (FRAME_RATE || calc_framerate()), css);
const [stylesheet, rules] = add_rule(node, rule);
if (!rules.has(name)) {
rules.add(name);
stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length);
stylesheet.insertRule(rule, stylesheet.cssRules.length);
}
const previous = node.style.animation || '';
node.style.animation = `${previous ? `${previous}, ` : ``}${name} ${duration}ms linear ${delay}ms 1 both`;
const previous = node.style.animation;
node.style.animation = (previous ? previous + ', ' : '') + `${duration}ms linear 0ms 1 normal both running ${name}`;
running_animations++;
return () => {
const prev = (node.style.animation || '').split(', ');
const next = prev.filter((anim) => !anim.includes(name));
if (prev.length === next.length) return;
node.style.animation = next.join(', ');
if (prev.length !== next.length) node.style.animation = next.join(', ');
if (--running_animations) return;
active_documents.forEach(({ __svelte_stylesheet, __svelte_rules }) => {
let i = __svelte_stylesheet.cssRules.length;
while (i--) __svelte_stylesheet.deleteRule(i);
__svelte_rules.clear();
active_documents.forEach(({ [SVELTE.STYLESHEET]: stylesheet, [SVELTE.RULESET]: ruleset }) => {
let i = stylesheet.cssRules.length;
while (i--) stylesheet.deleteRule(i);
ruleset.clear();
});
active_documents.clear();
};
@ -75,7 +78,7 @@ export function delete_rule(node: HTMLElement, name?: string) {
const next = previous.filter(
name
? (anim) => anim.indexOf(name) < 0 // remove specific animation
: (anim) => anim.indexOf('__svelte') === -1 // remove all Svelte animations
: (anim) => anim.indexOf(SVELTE.RULE) === -1 // remove all Svelte animations
);
const deleted = previous.length - next.length;
if (deleted) {

@ -1,10 +1,11 @@
import { identity as linear, run_all, is_function } from './utils';
import { run_all } from './utils';
import { now } from './environment';
import { raf_timeout, loopThen } from './loop';
import { generate_rule } from './style_manager';
import { setAnimationTimeout, loopThen } from './loop';
import { animate_css } from './style_manager';
import { custom_event } from './dom';
import { TransitionConfig } from '../transition';
import { add_render_callback, add_flush_callback } from './scheduler';
import { Fragment } from './Component';
function startStopDispatcher(node: Element, direction: boolean) {
add_render_callback(() => node.dispatchEvent(custom_event(`${direction ? 'intro' : 'outro'}start`)));
@ -12,13 +13,13 @@ function startStopDispatcher(node: Element, direction: boolean) {
}
const outroing = new Set();
let outros;
let outros;
export function group_outros() {
outros = {
/* parent group */ p: outros,
/* remaining outros */ r: 0,
/* callbacks */ c: [],
/* remaining outros */ r: 0,
};
}
@ -27,13 +28,13 @@ export function check_outros() {
outros = outros.p;
}
export function transition_in(block, local?: 0 | 1) {
export function transition_in(block: Fragment, local?: 0 | 1) {
if (!block || !block.i) return;
outroing.delete(block);
block.i(local);
}
export function transition_out(block, local?: 0 | 1, detach?: 0 | 1, callback?: () => void) {
export function transition_out(block: Fragment, local?: 0 | 1, detach?: 0 | 1, callback?: () => void) {
if (!block || !block.o || outroing.has(block)) return;
outroing.add(block);
outros.c.push(() => {
@ -46,15 +47,16 @@ export function transition_out(block, local?: 0 | 1, detach?: 0 | 1, callback?:
block.o(local);
}
const null_transition: TransitionConfig = { duration: 0 };
const eased = (fn: (t: number) => any, easing: (t: number) => number) => (easing ? (t: number) => fn(easing(t)) : fn);
const runner = (fn: (t0: number, t1: number) => any, reversed: boolean) =>
reversed ? (t: number) => fn(1 - t, t) : (t: number) => fn(t, 1 - t);
type TransitionFn = (node: HTMLElement, params: any) => TransitionConfig;
export function run_transition(
node: HTMLElement,
fn: TransitionFn,
is_intro: boolean,
params?: any,
reversed_from?: number
is_intro = true,
params = {},
reversed_from = -1
): StopResetReverse {
let config = fn(node, params);
let running = true;
@ -62,51 +64,48 @@ export function run_transition(
let cancel_css;
let cancel_raf;
let dispatch_end;
let start_time;
let end_time;
const group = outros;
if (!is_intro) group.r++;
function start({ delay = 0, duration = 300, easing = linear, tick, css } = null_transition) {
function start({ delay = 0, duration = 300, easing, tick, css }: TransitionConfig) {
if (!running) return;
const run = tick && (is_intro ? tick : (a, b) => tick(b, a));
if (reversed_from) delay += duration - (now() - reversed_from);
start_time = now() + delay;
const end_time = start_time + duration;
cancel_css = css && generate_rule(node, +!is_intro, +is_intro, duration, delay, easing, css);
dispatch_end = startStopDispatcher(node, is_intro);
cancel_raf = cancel_raf = !run
? raf_timeout(stop, end_time)
: loopThen(
delay,
(t) => ((t = easing((t - start_time) / duration)), run(t, 1 - t)),
() => (run(1, 0), stop()),
end_time
const start_time = ~reversed_from ? reversed_from : now() + delay;
end_time = start_time + duration;
if (css)
cancel_css = animate_css(
runner(eased(css, easing), is_intro),
node,
duration,
(end_time - start_time) / duration
);
dispatch_end = startStopDispatcher(node, is_intro);
cancel_raf = tick
? loopThen(runner(eased(tick, easing), is_intro), stop, duration, end_time)
: setAnimationTimeout(stop, end_time);
}
function stop(reset_reverse?: 1 | 2) {
if (!is_intro && reset_reverse === 1 && config && 'tick' in config) config.tick(1, 0);
function stop(reset_reverse?: 1 | -1) {
if (!is_intro && 1 === reset_reverse && config && 'tick' in config) config.tick(1, 0);
if (!running) return;
else running = false;
if (cancel_css) cancel_css();
if (cancel_raf) cancel_raf();
if (dispatch_end) dispatch_end();
if (!is_intro && !--group.r) run_all(group.c);
if (reset_reverse === 2) return run_transition(node, fn, !is_intro, params, start_time);
if (!is_intro && !--group.r) for (let i = 0; i < group.c.length; i++) group.c[i]();
if (!~reset_reverse) return run_transition(node, fn, !is_intro, params, end_time);
else if (!~reversed_from) running_bidi.delete(node);
}
// @ts-ignore
if (is_function(config)) add_flush_callback(() => start((config = config())));
if (typeof config === 'function') add_flush_callback(() => start((config = config())));
else start(config);
return stop;
}
export type StopResetReverse = (reset_reverse?: 1 | 2) => StopResetReverse;
export type StopResetReverse = (reset_reverse?: 1 | -1) => StopResetReverse;
const running_bidi: Map<HTMLElement, StopResetReverse> = new Map();
export function run_bidirectional_transition(node: HTMLElement, fn: TransitionFn, is_intro: boolean, params: any) {
if (running_bidi.has(node)) {
running_bidi.set(node, running_bidi.get(node)(2));
} else {
running_bidi.set(node, run_transition(node, fn, is_intro, params, -1));
}
let cancel;
if (running_bidi.has(node)) running_bidi.set(node, (cancel = running_bidi.get(node)(-1)));
else running_bidi.set(node, (cancel = run_transition(node, fn, is_intro, params, -1)));
return cancel;
}

@ -1,6 +1,6 @@
export function noop() {}
export const identity = x => x;
export const identity = (x) => x;
export function assign<T, S>(tar: T, src: S): T & S {
// @ts-ignore
@ -14,7 +14,7 @@ export function is_promise<T = any>(value: any): value is PromiseLike<T> {
export function add_location(element, file, line, column, char) {
element.__svelte_meta = {
loc: { file, line, column, char }
loc: { file, line, column, char },
};
}
@ -35,7 +35,7 @@ export function is_function(thing: any): thing is Function {
}
export function safe_not_equal(a, b) {
return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');
return a != a ? b == b : a !== b || (a && typeof a === 'object') || typeof a === 'function';
}
export function not_equal(a, b) {
@ -49,16 +49,14 @@ export function validate_store(store, name) {
}
export function subscribe(store, ...callbacks) {
if (store == null) {
return noop;
}
if (store == null) return noop;
const unsub = store.subscribe(...callbacks);
return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub;
}
export function get_store_value(store) {
let value;
subscribe(store, _ => value = _)();
subscribe(store, (_) => (value = _))();
return value;
}
@ -74,9 +72,7 @@ export function create_slot(definition, ctx, $$scope, fn) {
}
export function get_slot_context(definition, ctx, $$scope, fn) {
return definition[1] && fn
? assign($$scope.ctx.slice(), definition[1](fn(ctx)))
: $$scope.ctx;
return definition[1] && fn ? assign($$scope.ctx.slice(), definition[1](fn(ctx))) : $$scope.ctx;
}
export function get_slot_changes(definition, $$scope, dirty, fn) {
@ -112,13 +108,14 @@ export function exclude_internal_props(props) {
export function compute_rest_props(props, keys) {
const rest = {};
keys = new Set(keys);
for (const k in props) if (!keys.has(k) && k[0] !== '$') rest[k] = props[k];
let k: string;
for (k in props) if (!keys.has(k) && k[0] !== '$') rest[k] = props[k];
return rest;
}
export function once(fn) {
let ran = false;
return function(this: any, ...args) {
return function (this: any, ...args) {
if (ran) return;
ran = true;
fn.call(this, ...args);
@ -139,3 +136,5 @@ export const has_prop = (obj, prop) => Object.prototype.hasOwnProperty.call(obj,
export function action_destroyer(action_result) {
return action_result && is_function(action_result.destroy) ? action_result.destroy : noop;
}
export const minmax = (min: number, max: number) => (v: number) => (v > min ? (v > max ? max : v) : min);

@ -1,5 +1,4 @@
import { cubicOut, cubicInOut, linear } from 'svelte/easing';
import { is_function } from 'svelte/internal';
type EasingFunction = (t: number) => number;
@ -7,8 +6,8 @@ export interface TransitionConfig {
delay?: number;
duration?: number;
easing?: EasingFunction;
css?: (t: number, u: number) => string;
tick?: (t: number, u: number) => void;
css?: (t: number, u?: number) => string;
tick?: (t: number, u?: number) => void;
}
interface BlurParams {
@ -96,21 +95,20 @@ export function slide(node: Element, { delay = 0, duration = 400, easing = cubic
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;`,
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;`,
};
}
@ -129,10 +127,8 @@ export function scale(
const style = getComputedStyle(node);
const target_opacity = +style.opacity;
const transform = style.transform === 'none' ? '' : style.transform;
const sd = 1 - start;
const od = target_opacity * (1 - opacity);
return {
delay,
duration,
@ -152,27 +148,13 @@ interface DrawParams {
}
export function draw(
node: SVGElement & { getTotalLength(): number },
node: SVGPathElement | SVGGeometryElement,
{ delay = 0, speed, duration, easing = cubicInOut }: DrawParams
): TransitionConfig {
const len = node.getTotalLength();
if (duration === undefined) {
if (speed === undefined) {
duration = 800;
} else {
duration = len / speed;
}
} else if (typeof duration === 'function') {
duration = duration(len);
}
return {
delay,
duration,
easing,
css: (t, u) => `stroke-dasharray: ${t * len} ${u * len};`,
};
if (duration === undefined) duration = speed ? len / speed : 800;
else if (typeof duration === 'function') duration = duration(len);
return { delay, duration, easing, css: (t, u) => `stroke-dasharray: ${t * len} ${u * len};` };
}
interface CrossfadeParams {
@ -190,12 +172,13 @@ type ElementMap = Map<string, Element>;
export function crossfade({
delay: default_delay = 0,
easing: default_easing = cubicOut,
duration: default_duration = (d) => Math.sqrt(d) * 30,
easing: default_easing = cubicOut,
fallback,
}: CrossFadeConfig) {
const to_receive: ElementMap = new Map();
const to_send: ElementMap = new Map();
function crossfade(
from_node: Element,
to_node: Element,
@ -207,31 +190,30 @@ export function crossfade({
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(to_node);
const transform = style.transform === 'none' ? '' : style.transform;
const opacity = +style.opacity;
const { transform, opacity } = getComputedStyle(to_node);
const prev = transform === 'none' ? '' : transform;
return {
delay,
easing,
duration: is_function(duration) ? duration(d) : duration,
duration: typeof duration === 'function' ? duration(Math.sqrt(dx * dx + dy * dy)) : duration,
css: (t, u) => `
opacity: ${t * opacity};
opacity: ${t * +opacity};
transform-origin: top left;
transform: ${transform} translate(${u * dx}px,${u * dy}px) scale(${t + (1 - t) * dw}, ${t + (1 - t) * dh});
transform: ${prev} translate(${u * dx}px,${u * dy}px) scale(${t + (1 - t) * dw}, ${t + (1 - t) * dh});
`,
} as TransitionConfig;
}
function transition(a: ElementMap, b: ElementMap, is_intro: boolean) {
return (node: Element, params: MarkedCrossFadeConfig) => {
a.set(params.key, node);
const key = params.key;
a.set(key, node);
return () => {
if (b.has(params.key)) {
const from_node = b.get(params.key);
b.delete(params.key);
if (b.has(key)) {
const from_node = b.get(key);
b.delete(key);
return crossfade(from_node, node, params);
} else {
a.delete(params.key);
a.delete(key);
return fallback && fallback(node, params, is_intro);
}
};

Loading…
Cancel
Save