From 7e33e110d1daba5aebb5a65b97235c035e956b98 Mon Sep 17 00:00:00 2001 From: pushkine Date: Tue, 12 May 2020 13:59:56 +0200 Subject: [PATCH] fix env --- .eslintignore | 4 +- .gitignore | 32 +- environment/index.js | 25 +- environment/index.mjs | 24 +- package.json | 15 +- rollup.config.js | 21 +- src/ambient.ts | 2 - src/compiler/compile/Component.ts | 35 +- src/compiler/compile/create_module.ts | 6 +- src/compiler/compile/index.ts | 2 +- .../compile/nodes/shared/Expression.ts | 64 +- src/compiler/compile/render_dom/Block.ts | 28 +- .../compile/render_dom/wrappers/EachBlock.ts | 449 ++++++------- .../render_dom/wrappers/Element/index.ts | 46 +- src/compiler/utils/names.ts | 619 +++++++++++++++++- src/runtime/environment/index.ts | 21 +- src/runtime/internal/Component.ts | 2 +- src/runtime/internal/animations.ts | 30 +- src/runtime/internal/dev.legacy.ts | 2 +- src/runtime/internal/dev.utils.ts | 2 +- src/runtime/internal/dom.ts | 17 +- src/runtime/internal/environment.ts | 30 - src/runtime/internal/index.ts | 4 +- src/runtime/internal/keyed_each.ts | 8 +- src/runtime/internal/loop.ts | 5 +- src/runtime/internal/scheduler.ts | 10 +- src/runtime/internal/style_manager.ts | 53 +- src/runtime/internal/transitions.ts | 10 +- src/runtime/transition/index.ts | 22 +- tsconfig.json | 7 +- 30 files changed, 1061 insertions(+), 534 deletions(-) delete mode 100644 src/runtime/internal/environment.ts diff --git a/.eslintignore b/.eslintignore index b5cb03ae6e..4704ea2e8e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -9,8 +9,10 @@ internal_exports.ts # output files animate/*.js -esing/*.js +easing/*.js +environment/*.js internal/*.js +interpolate/*.js motion/*.js store/*.js transition/*.js diff --git a/.gitignore b/.gitignore index 8d47cb279e..63d00d18aa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,32 +2,42 @@ .DS_Store .nyc_output .vscode + node_modules -*.map + /src/compiler/compile/internal_exports.ts -/compiler.d.ts -/compiler.*js -/index.*js -/internal + +/animate /dev -/store /easing +/environment +/internal /interpolate /motion +/store /transition -/animate + +/types + +*.map +/compiler.d.ts +/compiler.*js + +/index.*js + /scratch/ /coverage/ /coverage.lcov + +/yarn-error.log +_actual*.* +_output + /test/*/samples/_ /test/sourcemaps/samples/*/output.js /test/sourcemaps/samples/*/output.js.map /test/sourcemaps/samples/*/output.css /test/sourcemaps/samples/*/output.css.map -/yarn-error.log -_actual*.* -_output -/types /site/cypress/screenshots/ /site/__sapper__/ diff --git a/environment/index.js b/environment/index.js index 7f05d955cc..a404fa79f1 100644 --- a/environment/index.js +++ b/environment/index.js @@ -2,11 +2,13 @@ Object.defineProperty(exports, '__esModule', { value: true }); +function noop() {} + const is_browser = typeof window !== 'undefined'; -const is_iframe = is_browser && window.self !== window.top; +const is_iframe = /*#__PURE__*/ is_browser && window.self !== window.top; const is_cors = is_iframe && - (() => { + /*#__PURE__*/ (() => { try { if (window.parent) void window.parent.document; return false; @@ -16,9 +18,28 @@ const is_cors = })(); const has_Symbol = typeof Symbol === 'function'; const globals = is_browser ? window : typeof globalThis !== 'undefined' ? globalThis : global; +const resolved_promise = Promise.resolve(); + +exports.now = /*#__PURE__*/ is_browser ? performance.now.bind(performance) : Date.now.bind(Date); +exports.raf = /*#__PURE__*/ is_browser ? requestAnimationFrame : noop; +exports.framerate = 1000 / 60; +exports.raf((t1) => { + exports.raf((d) => { + const f24 = 1000 / 24, + f144 = 1000 / 144; + exports.framerate = (d = d - t1) > f144 ? f144 : d < f24 ? f24 : d; + }); +}); + +/* tests only */ +const test$set_now = (fn) => void (exports.now = fn); +const test$set_raf = (fn) => void (exports.raf = fn); exports.globals = globals; exports.has_Symbol = has_Symbol; exports.is_browser = is_browser; exports.is_cors = is_cors; exports.is_iframe = is_iframe; +exports.resolved_promise = resolved_promise; +exports.test$set_now = test$set_now; +exports.test$set_raf = test$set_raf; diff --git a/environment/index.mjs b/environment/index.mjs index 578e83c99e..ee31f602a1 100644 --- a/environment/index.mjs +++ b/environment/index.mjs @@ -1,8 +1,10 @@ +function noop() {} + const is_browser = typeof window !== 'undefined'; -const is_iframe = is_browser && window.self !== window.top; +const is_iframe = /*#__PURE__*/ is_browser && window.self !== window.top; const is_cors = is_iframe && - (() => { + /*#__PURE__*/ (() => { try { if (window.parent) void window.parent.document; return false; @@ -12,5 +14,21 @@ const is_cors = })(); const has_Symbol = typeof Symbol === 'function'; const globals = is_browser ? window : typeof globalThis !== 'undefined' ? globalThis : global; +const resolved_promise = Promise.resolve(); + +let now = /*#__PURE__*/ is_browser ? performance.now.bind(performance) : Date.now.bind(Date); +let raf = /*#__PURE__*/ is_browser ? requestAnimationFrame : noop; +let framerate = 1000 / 60; +raf((t1) => { + raf((d) => { + const f24 = 1000 / 24, + f144 = 1000 / 144; + framerate = (d = d - t1) > f144 ? f144 : d < f24 ? f24 : d; + }); +}); + +/* tests only */ +const test$set_now = (fn) => void (now = fn); +const test$set_raf = (fn) => void (raf = fn); -export { globals, has_Symbol, is_browser, is_cors, is_iframe }; +export { framerate, globals, has_Symbol, is_browser, is_cors, is_iframe, now, raf, resolved_promise, test$set_now, test$set_raf }; diff --git a/package.json b/package.json index 87885369dc..099a5a64f3 100644 --- a/package.json +++ b/package.json @@ -5,16 +5,19 @@ "module": "index.mjs", "main": "index", "files": [ + "animate", + "dev", + "easing", + "environment", + "internal", + "interpolate", + "motion", + "store", + "transition", "types", "compiler.*", "register.js", "index.*", - "internal", - "store", - "animate", - "transition", - "easing", - "motion", "svelte", "README.md" ], diff --git a/rollup.config.js b/rollup.config.js index 43d4331dd0..ef732cc9d5 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -15,14 +15,19 @@ const ts_plugin = is_publish // documented in src/ambient.ts const globals = (name) => - replace({ - 'var __DEV__: boolean': 'var rollup_removes_this', - '__DEV__': name === 'dev', - 'var __TEST__: boolean': 'var rollup_removes_this', - '__TEST__': name === 'test', - 'var __VERSION__: string': 'var rollup_removes_this', - '__VERSION__': `"${pkg.version}"`, - }); + name === 'compiler' + ? replace({ + 'var __VERSION__: string': 'var rollup_removes_this', + '__VERSION__': `"${pkg.version}"`, + }) + : replace({ + 'var __DEV__: boolean': 'var rollup_removes_this', + '__DEV__': name === 'dev', + 'var __TEST__: boolean': 'var rollup_removes_this', + '__TEST__': name === 'test', + 'var __VERSION__: string': 'var rollup_removes_this', + '__VERSION__': `"${pkg.version}"`, + }); /** * */ diff --git a/src/ambient.ts b/src/ambient.ts index 48b2439a92..c567d4577d 100644 --- a/src/ambient.ts +++ b/src/ambient.ts @@ -53,5 +53,3 @@ declare var __VERSION__: string; * instead of relying on hacks */ declare var __TEST__: boolean; - -declare var global: any; diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 72944eb179..49c60ccd6f 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -181,24 +181,29 @@ export default class Component { injected: true, referenced: true, }); - } else if (name[0] === '$') { - this.add_var({ - name, - injected: true, - referenced: true, - mutated: true, - writable: true, - }); + } else { + if (!name) { + console.log(name); + } + if (name[0] === '$') { + this.add_var({ + name, + injected: true, + referenced: true, + mutated: true, + writable: true, + }); - const subscribable_name = name.slice(1); + const subscribable_name = name.slice(1); - const variable = this.var_lookup.get(subscribable_name); - if (variable) { - variable.referenced = true; - variable.subscribable = true; + const variable = this.var_lookup.get(subscribable_name); + if (variable) { + variable.referenced = true; + variable.subscribable = true; + } + } else { + this.used_names.add(name); } - } else { - this.used_names.add(name); } } diff --git a/src/compiler/compile/create_module.ts b/src/compiler/compile/create_module.ts index 39c62033ed..63950d3d8e 100644 --- a/src/compiler/compile/create_module.ts +++ b/src/compiler/compile/create_module.ts @@ -36,14 +36,14 @@ export default function create_module( throw new Error(`options.format is invalid (must be ${list(Object.keys(wrappers))})`); } -function edit_source(source, sveltePath) { - return source === 'svelte' || source.startsWith('svelte/') ? source.replace('svelte', sveltePath) : source; -} +const edit_source = (source, sveltePath) => (/^svelte\/?/.test(source) ? source.replace('svelte', sveltePath) : source); function get_internal_globals( globals: Array<{ name: string; alias: Identifier }>, helpers: Array<{ name: string; alias: Identifier }> ) { + // TODO : internal_globals is too aggressive + // see output https://svelte.dev/repl/1623b8b2ff604d7ca6e794343d976ae6 return ( globals.length > 0 && { type: 'VariableDeclaration', diff --git a/src/compiler/compile/index.ts b/src/compiler/compile/index.ts index 003c26a82d..8f73475549 100644 --- a/src/compiler/compile/index.ts +++ b/src/compiler/compile/index.ts @@ -68,7 +68,7 @@ function validate_options(options: CompileOptions, warnings: Warning[]) { } export default function compile(source: string, options: CompileOptions = {}) { - options = { generate: 'dom', dev: false, ...options }; + options = { generate: 'dom', dev: null, ...options }; const stats = new Stats(); const warnings = []; diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 2f2541c720..98f4719d0e 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -30,7 +30,7 @@ export default class Expression { scope: Scope; scope_map: WeakMap; - declarations: Array<(Node | Node[])> = []; + declarations: Array = []; uses_context = false; manipulated: Node; @@ -40,8 +40,8 @@ export default class Expression { // TODO revert to direct property access in prod? Object.defineProperties(this, { component: { - value: component - } + value: component, + }, }); this.node = info; @@ -79,12 +79,13 @@ export default class Expression { if (name[0] === '$' && template_scope.names.has(name.slice(1))) { component.error(node, { code: `contextual-store`, - message: `Stores must be declared at the top level of the component (this may change in a future version of Svelte)` + message: `Stores must be declared at the top level of the component (this may change in a future version of Svelte)`, }); } if (template_scope.is_let(name)) { - if (!function_expression) { // TODO should this be `!lazy` ? + if (!function_expression) { + // TODO should this be `!lazy` ? contextual_dependencies.add(name); dependencies.add(name); } @@ -97,7 +98,7 @@ export default class Expression { const is_index = owner.type === 'EachBlock' && owner.key && name === owner.index; if (!lazy || is_index) { - template_scope.dependencies_for_name.get(name).forEach(name => dependencies.add(name)); + template_scope.dependencies_for_name.get(name).forEach((name) => dependencies.add(name)); } } else { if (!lazy) { @@ -118,9 +119,7 @@ export default class Expression { if (function_expression) { if (node.type === 'AssignmentExpression') { deep = node.left.type === 'MemberExpression'; - names = deep - ? [get_object(node.left).name] - : extract_names(node.left); + names = deep ? [get_object(node.left).name] : extract_names(node.left); } else if (node.type === 'UpdateExpression') { const { name } = get_object(node.argument); names = [name]; @@ -128,9 +127,10 @@ export default class Expression { } if (names) { - names.forEach(name => { + names.forEach((name) => { + if (!name) return; if (template_scope.names.has(name)) { - template_scope.dependencies_for_name.get(name).forEach(name => { + template_scope.dependencies_for_name.get(name).forEach((name) => { const variable = component.var_lookup.get(name); if (variable) variable[deep ? 'mutated' : 'reassigned'] = true; }); @@ -152,12 +152,12 @@ export default class Expression { if (node === function_expression) { function_expression = null; } - } + }, }); } dynamic_dependencies() { - return Array.from(this.dependencies).filter(name => { + return Array.from(this.dependencies).filter((name) => { if (this.template_scope.is_let(name)) return true; if (is_reserved_keyword(name)) return true; @@ -172,13 +172,7 @@ export default class Expression { // multiple times if (this.manipulated) return this.manipulated; - const { - component, - declarations, - scope_map: map, - template_scope, - owner - } = this; + const { component, declarations, scope_map: map, template_scope, owner } = this; let scope = this.scope; let function_expression; @@ -206,7 +200,7 @@ export default class Expression { if (template_scope.names.has(name)) { contextual_dependencies.add(name); - template_scope.dependencies_for_name.get(name).forEach(dependency => { + template_scope.dependencies_for_name.get(name).forEach((dependency) => { dependencies.add(dependency); }); } else { @@ -238,9 +232,7 @@ export default class Expression { if (map.has(node)) scope = scope.parent; if (node === function_expression) { - const id = component.get_unique_name( - sanitize(get_function_name(node, owner)) - ); + const id = component.get_unique_name(sanitize(get_function_name(node, owner))); const declaration = b`const ${id} = ${node}`; @@ -254,28 +246,24 @@ export default class Expression { name: id.name, internal: true, hoistable: true, - referenced: true + referenced: true, }); - } - - else if (contextual_dependencies.size === 0) { + } else if (contextual_dependencies.size === 0) { // function can be hoisted inside the component init component.partly_hoisted.push(declaration); block.renderer.add_to_context(id.name); this.replace(block.renderer.reference(id)); - } - - else { + } else { // we need a combo block/init recipe const deps = Array.from(contextual_dependencies); (node as FunctionExpression).params = [ - ...deps.map(name => ({ type: 'Identifier', name } as Identifier)), - ...(node as FunctionExpression).params + ...deps.map((name) => ({ type: 'Identifier', name } as Identifier)), + ...(node as FunctionExpression).params, ]; - const context_args = deps.map(name => block.renderer.reference(name)); + const context_args = deps.map((name) => block.renderer.reference(name)); component.partly_hoisted.push(declaration); @@ -318,10 +306,10 @@ export default class Expression { const names = new Set(extract_names(assignee)); const traced: Set = new Set(); - names.forEach(name => { + names.forEach((name) => { const dependencies = template_scope.dependencies_for_name.get(name); if (dependencies) { - dependencies.forEach(name => traced.add(name)); + dependencies.forEach((name) => traced.add(name)); } else { traced.add(name); } @@ -329,12 +317,12 @@ export default class Expression { this.replace(invalidate(block.renderer, scope, node, traced)); } - } + }, }); if (declarations.length > 0) { block.maintain_context = true; - declarations.forEach(declaration => { + declarations.forEach((declaration) => { block.chunks.init.push(declaration); }); } diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 4e5fd10f47..173fe09a34 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -230,6 +230,8 @@ export default class Block { get_contents(key?: any) { const { dev, version } = this.renderer.options; + let k; + for (k in this.chunks) this.chunks[k] = this.chunks[k].filter(Boolean); if (this.has_outros) { this.add_variable({ type: 'Identifier', name: '#current' }); @@ -420,17 +422,17 @@ export default class Block { } has_content(): boolean { - return ( - !!this.first || - this.event_listeners.length > 0 || - this.chunks.intro.length > 0 || - this.chunks.outro.length > 0 || - this.chunks.create.length > 0 || - this.chunks.hydrate.length > 0 || - this.chunks.claim.length > 0 || - this.chunks.mount.length > 0 || - this.chunks.update.length > 0 || - this.chunks.destroy.length > 0 || + return !!( + this.first || + this.event_listeners.length || + this.chunks.intro.length || + this.chunks.outro.length || + this.chunks.create.length || + this.chunks.hydrate.length || + this.chunks.claim.length || + this.chunks.mount.length || + this.chunks.update.length || + this.chunks.destroy.length || this.has_animation ); } @@ -472,13 +474,13 @@ export default class Block { this.chunks.destroy.push(b`${dispose}();`); } else { this.chunks.mount.push(b` - if (#remount) for(let #i=0;#i<${dispose}.length;#i++){ ${dispose}[#i];} + if (#remount) for(let #i=0;#i<${dispose}.length;#i++){ ${dispose}[#i](); } ${dispose} = [ ${this.event_listeners} ]; `); - this.chunks.destroy.push(b`for(let #i=0;#i<${dispose}.length;#i++){ ${dispose}[#i];}`); + this.chunks.destroy.push(b`for(let #i=0;#i<${dispose}.length;#i++){ ${dispose}[#i](); }`); } } } diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index e22e2fb670..a365148181 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -55,9 +55,6 @@ export default class EachBlockWrapper extends Wrapper { each_block_value: Identifier; get_each_context: Identifier; iterations: Identifier; - fixed_length: number; - data_length: string; - view_length: string; }; context_props: Array; @@ -92,7 +89,6 @@ export default class EachBlockWrapper extends Wrapper { type: 'each', // @ts-ignore todo: probably error key: node.key as string, - bindings: new Map(block.bindings), }); @@ -103,42 +99,16 @@ export default class EachBlockWrapper extends Wrapper { ? { type: 'Identifier', name: this.node.index } : renderer.component.get_unique_name(`${this.node.context}_index`); - const fixed_length = - node.expression.node.type === 'ArrayExpression' && - node.expression.node.elements.every((element) => element.type !== 'SpreadElement') - ? node.expression.node.elements.length - : null; - - // hack the sourcemap, so that if data is missing the bug - // is easy to find - let c = this.node.start + 2; - while (renderer.component.source[c] !== 'e') c += 1; - const start = renderer.component.locate(c); - const end = { line: start.line, column: start.column + 4 }; - const length = { - type: 'Identifier', - name: 'length', - loc: { start, end }, - }; - - const each_block_value = renderer.component.get_unique_name(`${this.var.name}_value`); - const iterations = block.get_unique_name(`${this.var.name}_blocks`); - - renderer.add_to_context(each_block_value.name, true); - renderer.add_to_context(this.index_name.name, true); - this.vars = { create_each_block: this.block.name, - each_block_value, + each_block_value: renderer.component.get_unique_name(`${this.var.name}_value`), get_each_context: renderer.component.get_unique_name(`get_${this.var.name}_context`), - iterations, - - // optimisation for array literal - fixed_length, - data_length: fixed_length === null ? x`${each_block_value}.${length}` : fixed_length, - view_length: fixed_length === null ? x`${iterations}.length` : fixed_length, + iterations: block.get_unique_name(`${this.var.name}_blocks`), }; + renderer.add_to_context(this.vars.each_block_value.name, true); + renderer.add_to_context(this.index_name.name, true); + const store = node.expression.node.type === 'Identifier' && node.expression.node.name[0] === '$' ? node.expression.node.name.slice(1) @@ -182,7 +152,8 @@ export default class EachBlockWrapper extends Wrapper { render(block: Block, parent_node: Identifier, parent_nodes: Identifier) { if (this.fragment.nodes.length === 0) return; - + const __DEV__ = this.renderer.options.dev; + const { each_block_value, iterations: each_block } = this.vars; const { renderer } = this; const { component } = renderer; @@ -193,20 +164,17 @@ export default class EachBlockWrapper extends Wrapper { ); if (this.node.has_binding) - this.context_props.push( - b`child_ctx[${renderer.context_lookup.get(this.vars.each_block_value.name).index}] = list;` - ); + this.context_props.push(b`child_ctx[${renderer.context_lookup.get(each_block_value.name).index}] = list;`); if (this.node.has_binding || this.node.index) this.context_props.push(b`child_ctx[${renderer.context_lookup.get(this.index_name.name).index}] = i;`); const snippet = this.node.expression.manipulate(block); - block.chunks.init.push(b`let ${this.vars.each_block_value} = ${snippet};`); - if (this.renderer.options.dev) { - block.chunks.init.push(b`@validate_each_argument(${this.vars.each_block_value});`); + block.chunks.init.push(b`let ${each_block_value} = ${snippet};`); + if (__DEV__) { + block.chunks.init.push(b`@validate_each_argument(${each_block_value});`); } - // TODO which is better — Object.create(array) or array.slice()? renderer.blocks.push(b` function ${this.vars.get_each_context}(#ctx, list, i) { const child_ctx = #ctx.slice(); @@ -246,11 +214,7 @@ export default class EachBlockWrapper extends Wrapper { } if (this.block.has_intro_method || this.block.has_outro_method) { - block.chunks.intro.push(b` - for (let #i = 0; #i < ${this.vars.data_length}; #i += 1) { - @transition_in(${this.vars.iterations}[#i]); - } - `); + block.chunks.intro.push(for_loop(each_block, (item) => b`@transition_in(${item});`)); } if (needs_anchor) { @@ -260,20 +224,18 @@ export default class EachBlockWrapper extends Wrapper { if (this.else) { const each_block_else = component.get_unique_name(`${this.var.name}_else`); - block.chunks.init.push(b`let ${each_block_else} = null;`); - // TODO neaten this up... will end up with an empty line in the block - block.chunks.init.push(b` - if (!${this.vars.data_length}) { - ${each_block_else} = ${this.else.block.name}(#ctx); - } - `); + block.chunks.init.push( + b`let ${each_block_else} = null;`, + b`if (!${each_block_value}.length) { + ${each_block_else} = ${this.else.block.name}(#ctx); + }` + ); block.chunks.create.push(b` if (${each_block_else}) { ${each_block_else}.c(); - } - `); + }`); if (this.renderer.options.hydratable) { block.chunks.claim.push(b` @@ -288,40 +250,37 @@ export default class EachBlockWrapper extends Wrapper { ${each_block_else}.m(${initial_mount_node}, ${initial_anchor_node}); } `); + const no_each_else = x`!${each_block_value}.length`; + const update_else = b`${each_block_else}.p(#ctx, #dirty);`; + const destroy_else = b`${each_block_else}.d(1);${each_block_else} = null;`; + const create_else = b` + ${each_block_else} = ${this.else.block.name}(#ctx); + ${each_block_else}.c(); + ${each_block_else}.m(${update_mount_node}, ${update_anchor_node});`; - if (this.else.block.has_update_method) { - this.updates.push(b` - if (!${this.vars.data_length} && ${each_block_else}) { - ${each_block_else}.p(#ctx, #dirty); - } else if (!${this.vars.data_length}) { - ${each_block_else} = ${this.else.block.name}(#ctx); - ${each_block_else}.c(); - ${each_block_else}.m(${update_mount_node}, ${update_anchor_node}); - } else if (${each_block_else}) { - ${each_block_else}.d(1); - ${each_block_else} = null; - } - `); - } else { - this.updates.push(b` - if (${this.vars.data_length}) { - if (${each_block_else}) { - ${each_block_else}.d(1); - ${each_block_else} = null; - } - } else if (!${each_block_else}) { - ${each_block_else} = ${this.else.block.name}(#ctx); - ${each_block_else}.c(); - ${each_block_else}.m(${update_mount_node}, ${update_anchor_node}); - } - `); - } + this.updates.push( + $if({ + if: each_block_else, + true: $if({ + if: no_each_else, + true: update_else, + false: destroy_else, + }), + false: $if({ + if: no_each_else, + true: create_else, + }), + }) + ); block.chunks.destroy.push(b` - if (${each_block_else}) ${each_block_else}.d(${parent_node ? '' : 'detaching'}); + if (${each_block_else}){ + ${each_block_else}.d(${parent_node ? '' : 'detaching'}); + } `); } + this.updates = this.updates.filter(Boolean); if (this.updates.length) { block.chunks.update.push(b` if (${block.renderer.dirty(Array.from(all_dependencies))}) { @@ -356,104 +315,76 @@ export default class EachBlockWrapper extends Wrapper { update_anchor_node: Identifier; update_mount_node: Identifier; }) { - const { create_each_block, iterations, data_length, view_length } = this.vars; + const __DEV__ = this.renderer.options.dev; + const { + create_each_block, + iterations: each_block, + each_block_value, + get_each_context: each_context_getter, + } = this.vars; - const get_key = block.get_unique_name('get_key'); + const for_each_block = (fn) => for_loop(each_block, fn); + + const key_getter = block.get_unique_name('get_key'); const lookup = block.get_unique_name(`${this.var.name}_lookup`); - block.add_variable(iterations, x`[]`); + block.add_variable(each_block, x`[]`); block.add_variable(lookup, x`new @_Map()`); - if (this.fragment.nodes[0].is_dom_node()) { - this.block.first = this.fragment.nodes[0].var; - } else { - this.block.first = this.block.get_unique_name('first'); - this.block.add_element(this.block.first, x`@empty()`, parent_nodes && x`@empty()`, null); - } - - block.chunks.init.push(b` - const ${get_key} = #ctx => ${this.node.key.manipulate(block)}; - - ${ - this.renderer.options.dev && - b`@validate_each_keys(#ctx, ${this.vars.each_block_value}, ${this.vars.get_each_context}, ${get_key});` - } - for (let #i = 0; #i < ${data_length}; #i += 1) { - let child_ctx = ${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i); - let key = ${get_key}(child_ctx); - ${lookup}.set(key, ${iterations}[#i] = ${create_each_block}(key, child_ctx)); - } - `); - - block.chunks.create.push(b` - for (let #i = 0; #i < ${view_length}; #i += 1) { - ${iterations}[#i].c(); - } - `); + if (this.fragment.nodes[0].is_dom_node()) this.block.first = this.fragment.nodes[0].var; + else + this.block.add_element( + (this.block.first = this.block.get_unique_name('first')), + x`@empty()`, + parent_nodes && x`@empty()`, + null + ); - if (parent_nodes && this.renderer.options.hydratable) { - block.chunks.claim.push(b` - for (let #i = 0; #i < ${view_length}; #i += 1) { - ${iterations}[#i].l(${parent_nodes}); - } - `); - } + const validate_each_keys = + __DEV__ && b`@validate_each_keys(#ctx, ${each_block_value}, ${each_context_getter}, ${key_getter});`; + + const validate_each_argument = __DEV__ && b`@validate_each_argument(${each_block_value});`; + + block.chunks.init.push( + b`const ${key_getter} = (#ctx) => ${this.node.key.manipulate(block)};`, + validate_each_keys, + for_loop( + each_block_value, + (_, index) => b` + const #child_ctx = ${each_context_getter}(#ctx, ${each_block_value}, ${index}); + const #key = ${key_getter}(#child_ctx); + ${lookup}.set(#key, (${each_block}[${index}] = ${create_each_block}(#key, #child_ctx)));` + ) + ); - block.chunks.mount.push(b` - for (let #i = 0; #i < ${view_length}; #i += 1) { - ${iterations}[#i].m(${initial_mount_node}, ${initial_anchor_node}); - } - `); + block.chunks.create.push(for_each_block((block) => b`${block}.c();`)); + if (parent_nodes && this.renderer.options.hydratable) + block.chunks.claim.push(for_each_block((block) => b`${block}.l(${parent_nodes});`)); + block.chunks.mount.push(for_each_block((block) => b`${block}.m(${initial_mount_node}, ${initial_anchor_node});`)); const dynamic = this.block.has_update_method; - - // const destroy = this.node.has_animation - // ? this.block.has_outros - // ? `@fix_and_outro_and_destroy_block` - // : `@fix_and_destroy_block` - // : this.block.has_outros - // ? `@outro_and_destroy_block` - // : `@destroy_block`; + const has_animation = this.node.has_animation || null; + const { has_outros } = this.block; if (this.dependencies.size) { + const transition_state = bit_state([dynamic, has_animation, has_outros]); + const update_keyed_each = (transition_out) => + b`${each_block} = @update_keyed_each(${each_block}, #dirty, #ctx, ${transition_state}, ${key_getter}, ${each_block_value}, ${lookup}, ${update_mount_node}, ${create_each_block}, ${update_anchor_node}, ${each_context_getter}, ${transition_out});`; + const measure_animations = has_animation && b`${for_each_block((block) => b`${block}.r();`)}`; + this.updates.push( - b` - const ${this.vars.each_block_value} = ${snippet}; - ${this.renderer.options.dev && b`@validate_each_argument(${this.vars.each_block_value});`}`, - this.block.group_transition_out( - (transition_out) => b` - ${this.node.has_animation && b`for (let #i = 0; #i < ${view_length}; #i += 1){ ${iterations}[#i].r();}`} - ${ - this.renderer.options.dev && - b`@validate_each_keys(#ctx, ${this.vars.each_block_value}, ${this.vars.get_each_context}, ${get_key});` - } - ${iterations} = @update_keyed_each(${iterations}, #dirty, #ctx, ${bit_state([ - dynamic, - this.node.has_animation, - this.block.has_outros, - ])}, ${get_key}, ${ - this.vars.each_block_value - }, ${lookup}, ${update_mount_node}, ${create_each_block}, ${update_anchor_node}, ${ - this.vars.get_each_context - }, ${transition_out}); - ${this.node.has_animation && b`for (let #i = 0; #i < ${view_length}; #i += 1){ ${iterations}[#i].a();}`}` - ) + b`const ${each_block_value} = ${snippet};`, + validate_each_keys, + validate_each_argument, + measure_animations, + this.block.group_transition_out((transition_out) => update_keyed_each(transition_out)), + has_animation && for_each_block((block) => b`${block}.a();`) ); } - if (this.block.has_outros) { - block.chunks.outro.push(b` - for (let #i = 0; #i < ${view_length}; #i += 1) { - @transition_out(${iterations}[#i]); - } - `); - } + if (has_outros) block.chunks.outro.push(for_each_block((block) => b`@transition_out(${block});`)); - block.chunks.destroy.push(b` - for (let #i = 0; #i < ${view_length}; #i += 1) { - ${iterations}[#i].d(${parent_node ? null : 'detaching'}); - } - `); + block.chunks.destroy.push(for_each_block((block) => b`${block}.d(${parent_node ? null : 'detaching'});`)); } render_unkeyed({ @@ -473,117 +404,109 @@ export default class EachBlockWrapper extends Wrapper { update_anchor_node: Identifier; update_mount_node: Identifier; }) { - const { create_each_block, iterations, fixed_length, data_length, view_length } = this.vars; - - block.chunks.init.push(b` - let ${iterations} = []; - for (let #i = 0; #i < ${data_length}; #i += 1) { - ${iterations}[#i] = ${create_each_block}(${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i)); - } - `); - - block.chunks.create.push(b` - for (let #i = 0; #i < ${view_length}; #i += 1) { - ${iterations}[#i].c(); - } - `); - - if (parent_nodes && this.renderer.options.hydratable) { - block.chunks.claim.push(b` - for (let #i = 0; #i < ${view_length}; #i += 1) { - ${iterations}[#i].l(${parent_nodes}); - } - `); - } + const __DEV__ = this.renderer.options.dev; + const { + create_each_block, + iterations: each_block, + each_block_value, + get_each_context: each_context_getter, + } = this.vars; + const for_each_block = (fn, opts?) => for_loop(each_block, fn, opts); + + block.chunks.init.push( + b`let ${each_block} = [];`, + for_loop( + each_block_value, + (_, index) => + b`${each_block}[${index}] = ${create_each_block}(${each_context_getter}(#ctx, ${each_block_value}, ${index}));` + ) + ); - block.chunks.mount.push(b` - for (let #i = 0; #i < ${view_length}; #i += 1) { - ${iterations}[#i].m(${initial_mount_node}, ${initial_anchor_node}); - } - `); + block.chunks.create.push(for_each_block((block) => b`${block}.c();`)); + if (parent_nodes && this.renderer.options.hydratable) + block.chunks.claim.push(for_each_block((block) => b`${block}.l(${parent_nodes});`)); + block.chunks.mount.push(for_each_block((block) => b`${block}.m(${initial_mount_node}, ${initial_anchor_node});`)); if (this.dependencies.size) { const has_transitions = !!(this.block.has_intro_method || this.block.has_outro_method); + const { has_update_method } = this.block; - const for_loop_body = this.block.has_update_method - ? b` - if (${iterations}[#i]) { - ${iterations}[#i].p(child_ctx, #dirty); - ${has_transitions && b`@transition_in(${this.vars.iterations}[#i], 1);`} - } else { - ${iterations}[#i] = ${create_each_block}(child_ctx); - ${iterations}[#i].c(); - ${has_transitions && b`@transition_in(${this.vars.iterations}[#i], 1);`} - ${iterations}[#i].m(${update_mount_node}, ${update_anchor_node}); - } - ` - : has_transitions - ? b` - if (${iterations}[#i]) { - @transition_in(${this.vars.iterations}[#i], 1); - } else { - ${iterations}[#i] = ${create_each_block}(child_ctx); - ${iterations}[#i].c(); - @transition_in(${this.vars.iterations}[#i], 1); - ${iterations}[#i].m(${update_mount_node}, ${update_anchor_node}); - } - ` - : b` - if (!${iterations}[#i]) { - ${iterations}[#i] = ${create_each_block}(child_ctx); - ${iterations}[#i].c(); - ${iterations}[#i].m(${update_mount_node}, ${update_anchor_node}); - } - `; - - const start = this.block.has_update_method ? 0 : `#old_length`; - - const remove_old_blocks = this.block.group_transition_out((transition_out) => - transition_out - ? b` - for (#i = ${data_length}; #i < ${view_length}; #i += 1) { - ${transition_out}(${iterations}[#i], () => { ${iterations}[#i] = null; }); - }` - : b` - for (${this.block.has_update_method ? null : x`#i = ${data_length}`}; - #i < ${this.block.has_update_method ? view_length : '#old_length'}; - #i += 1 ) { - ${iterations}[#i].d(1); - } - ${!fixed_length && b`${view_length} = ${data_length};`} - ` - ); + const start = has_update_method ? 0 : `#old_length`; // We declare `i` as block scoped here, as the `remove_old_blocks` code // may rely on continuing where this iteration stopped. - const update = b` - ${!this.block.has_update_method && b`const #old_length = ${this.vars.each_block_value}.length;`} - ${this.vars.each_block_value} = ${snippet}; - ${this.renderer.options.dev && b`@validate_each_argument(${this.vars.each_block_value});`} - + this.updates.push(b` + ${!has_update_method && b`const #old_length = ${each_block_value}.length;`} + ${each_block_value} = ${snippet}; + ${__DEV__ && b`@validate_each_argument(${each_block_value});`} let #i; - for (#i = ${start}; #i < ${data_length}; #i += 1) { - const child_ctx = ${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i); - - ${for_loop_body} - } - - ${remove_old_blocks} - `; - - this.updates.push(update); + ${for_each_block( + (block, index) => b` + const #child_ctx = ${each_context_getter}(#ctx, ${each_block_value}, ${index}); + ${$if({ + if: (has_update_method || has_transitions) && block, + true: b` + ${has_update_method && b`${block}.p(#child_ctx, #dirty);`} + ${has_transitions && b`@transition_in(${block}, 1);`} + `, + false: b` + ${block} = ${create_each_block}(#child_ctx); + ${block}.c(); + ${has_transitions && b`@transition_in(${block}, 1);`} + ${block}.m(${update_mount_node}, ${update_anchor_node}); + `, + })}`, + { i: start } + )} + ${this.block.group_transition_out((transition_out) => + for_each_block( + (block) => + transition_out ? b`${transition_out}(${block}, () => { ${block} = null; });` : b`${block}.d(1);`, + { + i: has_update_method && !transition_out ? null : x`#i = ${each_block_value}.length`, + length: has_update_method || transition_out ? x`${each_block}.length` : x`#old_length`, + } + ) + )} + ${each_block}.length = ${each_block_value}.length; + `); } if (this.block.has_outros) { block.chunks.outro.push(b` - ${iterations} = ${iterations}.filter(@_Boolean); - for (let #i = 0; #i < ${view_length}; #i += 1) { - @transition_out(${iterations}[#i]); - } - `); + ${each_block} = ${each_block}.filter(@_Boolean); + ${for_each_block((block) => b`@transition_out(${block})`)}`); } - block.chunks.destroy.push(b`@destroy_each(${iterations}, detaching);`); + block.chunks.destroy.push(b`@destroy_each(${each_block}, detaching);`); } } const bit_state = (arr) => arr.reduce((state, bool, index) => (bool ? (state |= 1 << index) : state), 0); + +const for_loop = ( + arr: T, + callback: (item: Node, index: Node, array: T) => Node[], + { length = x`${arr}.length`, i = undefined } = {} +) => + i || i === null + ? b`for (${i}; #i < ${length}; #i++) { ${callback(x`${arr}[#i]`, x`#i`, arr)} }` + : b`for (let #i = 0; #i < ${length}; #i++) { ${callback(x`${arr}[#i]`, x`#i`, arr)} }`; + +const $if = ({ if: condition, true: success, false: failure = null }) => { + if (condition) { + if (success) { + if (failure) { + return b`if(${condition}){ ${success} } else { ${failure} }`; + } else { + return b`if(${condition}){ ${success} }`; + } + } else if (failure) { + return b`if(!${condition}){ ${success} }`; + } + } else { + if (!failure) { + return failure; + } + } + throw new Error('Error in if_else'); +}; diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 2cd2701034..aa24bc181a 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -692,31 +692,28 @@ export default class ElementWrapper extends Wrapper { add_intro(block: Block, intro: Transition, outro: Transition) { if (outro) { const outro_var = block.alias(`${this.var.name}_outro`); - if (this.node.animation) { - const [unfreeze_var, rect_var, stop_animation_var, animationFn, params] = run_animation(this, block); - block.chunks.intro.push(b` + block.chunks.intro.push(b` if (${outro_var}){ ${outro_var}(1); - if (${unfreeze_var}) { - ${unfreeze_var}(), (unfreeze = undefined); - ${stop_animation_var} = @run_animation(${this.var}, ${rect_var}, ${animationFn}, ${params}); - } } `); - } else { - block.chunks.intro.push(b` - if (${outro_var}){ - ${outro_var}(1); - } - `); - } + } + if (this.node.animation) { + const [unfreeze_var, rect_var, stop_animation_var, animationFn, params] = run_animation(this, block); + block.chunks.intro.push(b` + if (${unfreeze_var}) { + ${unfreeze_var}(); + ${unfreeze_var} = void 0; + ${stop_animation_var} = @run_animation(${this.var}, ${rect_var}, ${animationFn}, ${params}); + } + `); } if (!intro) return; const [intro_var, node, transitionFn, params] = run_transition(this, block, intro, `intro`); block.add_variable(intro_var); - let start_intro = b`@add_render_callback(()=>{${intro_var} = @run_transition(${node}, ${transitionFn}, true, ${params});})`; + let start_intro = b`${intro_var} = @run_transition(${node}, ${transitionFn}, true, ${params});`; if (intro.is_local) start_intro = b`if (#local) ${start_intro};`; block.chunks.intro.push(start_intro); } @@ -750,23 +747,24 @@ export default class ElementWrapper extends Wrapper { block.add_variable(stop_animation_var, x`@noop`); block.chunks.measure.push(b` - ${rect_var} = ${this.var}.getBoundingClientRect(); + if(!${unfreeze_var}) ${rect_var} = ${this.var}.getBoundingClientRect(); ${intro && b`if(${intro_var}) ${intro_var}();`} `); block.chunks.fix.push(b` - ${unfreeze_var} = @fix_position(${this.var}); ${stop_animation_var}(); - ${outro && b`@add_transform(${this.var}, ${rect_var});`} + ${unfreeze_var} = @fix_position(${this.var}, ${rect_var}); `); block.chunks.animate.push(b` - if(${unfreeze_var}) return - ${stop_animation_var}(); - @add_render_callback(()=>{${stop_animation_var} = @run_animation(${this.var}, ${rect_var}, ${name_var}, ${params_var});}); + if (${unfreeze_var}) return + else { + ${stop_animation_var}(); + ${stop_animation_var} = @run_animation(${this.var}, ${rect_var}, ${name_var}, ${params_var}); + } `); - block.chunks.destroy.push(b`${unfreeze_var} = undefined;`); + block.chunks.destroy.push(b`${unfreeze_var} = void 0;`); } add_classes(block: Block) { @@ -882,7 +880,7 @@ function run_animation(element: ElementWrapper, block: Block) { block.alias('rect'), block.alias('stop_animation'), element.renderer.reference(element.node.animation.name), - element.node.animation.expression ? element.node.animation.expression.manipulate(block) : x`{}`, + element.node.animation.expression ? element.node.animation.expression.manipulate(block) : null, ]; } function run_transition(element: ElementWrapper, block: Block, transition: Transition, type: string) { @@ -890,6 +888,6 @@ function run_transition(element: ElementWrapper, block: Block, transition: Trans /* node_intro */ block.alias(`${element.var.name}_${type}`), /* node */ element.var, /* transitionFn */ element.renderer.reference(transition.name), - /* params */ transition.expression ? transition.expression.manipulate(block) : x`{}`, + /* params */ transition.expression ? transition.expression.manipulate(block) : null, ]; } diff --git a/src/compiler/utils/names.ts b/src/compiler/utils/names.ts index 3049186aef..25698305c8 100644 --- a/src/compiler/utils/names.ts +++ b/src/compiler/utils/names.ts @@ -1,64 +1,667 @@ import { isIdentifierStart, isIdentifierChar } from 'acorn'; import full_char_code_at from './full_char_code_at'; - +/** source : rollup */ export const globals = new Set([ + 'global', + '__proto__', + 'AbortController', + 'AbortSignal', + 'addEventListener', 'alert', + 'AnalyserNode', + 'Animation', + 'AnimationEvent', + 'applicationCache', + 'ApplicationCache', + 'ApplicationCacheErrorEvent', 'Array', + 'ArrayBuffer', + 'atob', + 'Atomics', + 'Attr', + 'Audio', + 'AudioBuffer', + 'AudioBufferSourceNode', + 'AudioContext', + 'AudioDestinationNode', + 'AudioListener', + 'AudioNode', + 'AudioParam', + 'AudioProcessingEvent', + 'AudioScheduledSourceNode', + 'AudioWorkletNode', + 'BarProp', + 'BaseAudioContext', + 'BatteryManager', + 'BeforeUnloadEvent', + 'BigInt', + 'BigInt64Array', + 'BigUint64Array', + 'BiquadFilterNode', + 'Blob', + 'BlobEvent', + 'blur', 'Boolean', + 'BroadcastChannel', + 'btoa', + 'ByteLengthQueuingStrategy', + 'Cache', + 'caches', + 'CacheStorage', + 'cancelAnimationFrame', + 'cancelIdleCallback', + 'CanvasCaptureMediaStreamTrack', + 'CanvasGradient', + 'CanvasPattern', + 'CanvasRenderingContext2D', + 'ChannelMergerNode', + 'ChannelSplitterNode', + 'CharacterData', 'clearInterval', 'clearTimeout', + 'clientInformation', + 'ClipboardEvent', + 'close', + 'closed', + 'CloseEvent', + 'Comment', + 'CompositionEvent', 'confirm', 'console', + 'ConstantSourceNode', + 'ConvolverNode', + 'CountQueuingStrategy', + 'createImageBitmap', + 'Credential', + 'CredentialsContainer', + 'crypto', + 'Crypto', + 'CryptoKey', + 'CSS', + 'CSSConditionRule', + 'CSSFontFaceRule', + 'CSSGroupingRule', + 'CSSImportRule', + 'CSSKeyframeRule', + 'CSSKeyframesRule', + 'CSSMediaRule', + 'CSSNamespaceRule', + 'CSSPageRule', + 'CSSRule', + 'CSSRuleList', + 'CSSStyleDeclaration', + 'CSSStyleRule', + 'CSSStyleSheet', + 'CSSSupportsRule', + 'CustomElementRegistry', + 'customElements', + 'CustomEvent', + 'DataTransfer', + 'DataTransferItem', + 'DataTransferItemList', + 'DataView', 'Date', 'decodeURI', 'decodeURIComponent', + 'defaultstatus', + 'defaultStatus', + 'DelayNode', + 'DeviceMotionEvent', + 'DeviceOrientationEvent', + 'devicePixelRatio', + 'dispatchEvent', 'document', + 'Document', + 'DocumentFragment', + 'DocumentType', + 'DOMError', + 'DOMException', + 'DOMImplementation', + 'DOMMatrix', + 'DOMMatrixReadOnly', + 'DOMParser', + 'DOMPoint', + 'DOMPointReadOnly', + 'DOMQuad', + 'DOMRect', + 'DOMRectReadOnly', + 'DOMStringList', + 'DOMStringMap', + 'DOMTokenList', + 'DragEvent', + 'DynamicsCompressorNode', + 'Element', 'encodeURI', 'encodeURIComponent', 'Error', + 'ErrorEvent', + 'escape', + 'eval', 'EvalError', 'Event', + 'EventSource', + 'EventTarget', + 'external', 'fetch', - 'global', + 'File', + 'FileList', + 'FileReader', + 'find', + 'Float32Array', + 'Float64Array', + 'focus', + 'FocusEvent', + 'FontFace', + 'FontFaceSetLoadEvent', + 'FormData', + 'frames', + 'Function', + 'GainNode', + 'Gamepad', + 'GamepadButton', + 'GamepadEvent', + 'getComputedStyle', + 'getSelection', 'globalThis', + 'HashChangeEvent', + 'hasOwnProperty', + 'Headers', 'history', + 'History', + 'HTMLAllCollection', + 'HTMLAnchorElement', + 'HTMLAreaElement', + 'HTMLAudioElement', + 'HTMLBaseElement', + 'HTMLBodyElement', + 'HTMLBRElement', + 'HTMLButtonElement', + 'HTMLCanvasElement', + 'HTMLCollection', + 'HTMLContentElement', + 'HTMLDataElement', + 'HTMLDataListElement', + 'HTMLDetailsElement', + 'HTMLDialogElement', + 'HTMLDirectoryElement', + 'HTMLDivElement', + 'HTMLDListElement', + 'HTMLDocument', + 'HTMLElement', + 'HTMLEmbedElement', + 'HTMLFieldSetElement', + 'HTMLFontElement', + 'HTMLFormControlsCollection', + 'HTMLFormElement', + 'HTMLFrameElement', + 'HTMLFrameSetElement', + 'HTMLHeadElement', + 'HTMLHeadingElement', + 'HTMLHRElement', + 'HTMLHtmlElement', + 'HTMLIFrameElement', + 'HTMLImageElement', + 'HTMLInputElement', + 'HTMLLabelElement', + 'HTMLLegendElement', + 'HTMLLIElement', + 'HTMLLinkElement', + 'HTMLMapElement', + 'HTMLMarqueeElement', + 'HTMLMediaElement', + 'HTMLMenuElement', + 'HTMLMetaElement', + 'HTMLMeterElement', + 'HTMLModElement', + 'HTMLObjectElement', + 'HTMLOListElement', + 'HTMLOptGroupElement', + 'HTMLOptionElement', + 'HTMLOptionsCollection', + 'HTMLOutputElement', + 'HTMLParagraphElement', + 'HTMLParamElement', + 'HTMLPictureElement', + 'HTMLPreElement', + 'HTMLProgressElement', + 'HTMLQuoteElement', + 'HTMLScriptElement', + 'HTMLSelectElement', + 'HTMLShadowElement', + 'HTMLSlotElement', + 'HTMLSourceElement', + 'HTMLSpanElement', + 'HTMLStyleElement', + 'HTMLTableCaptionElement', + 'HTMLTableCellElement', + 'HTMLTableColElement', + 'HTMLTableElement', + 'HTMLTableRowElement', + 'HTMLTableSectionElement', + 'HTMLTemplateElement', + 'HTMLTextAreaElement', + 'HTMLTimeElement', + 'HTMLTitleElement', + 'HTMLTrackElement', + 'HTMLUListElement', + 'HTMLUnknownElement', + 'HTMLVideoElement', + 'IDBCursor', + 'IDBCursorWithValue', + 'IDBDatabase', + 'IDBFactory', + 'IDBIndex', + 'IDBKeyRange', + 'IDBObjectStore', + 'IDBOpenDBRequest', + 'IDBRequest', + 'IDBTransaction', + 'IDBVersionChangeEvent', + 'IdleDeadline', + 'IIRFilterNode', + 'Image', + 'ImageBitmap', + 'ImageBitmapRenderingContext', + 'ImageCapture', + 'ImageData', + 'indexedDB', 'Infinity', - 'InternalError', + 'innerHeight', + 'innerWidth', + 'InputEvent', + 'Int16Array', + 'Int32Array', + 'Int8Array', + 'IntersectionObserver', + 'IntersectionObserverEntry', 'Intl', 'isFinite', 'isNaN', + 'isPrototypeOf', + 'isSecureContext', 'JSON', + 'KeyboardEvent', + 'KeyframeEffect', + 'length', 'localStorage', 'location', + 'Location', + 'locationbar', 'Map', + 'matchMedia', 'Math', + 'MediaDeviceInfo', + 'MediaDevices', + 'MediaElementAudioSourceNode', + 'MediaEncryptedEvent', + 'MediaError', + 'MediaKeyMessageEvent', + 'MediaKeySession', + 'MediaKeyStatusMap', + 'MediaKeySystemAccess', + 'MediaList', + 'MediaQueryList', + 'MediaQueryListEvent', + 'MediaRecorder', + 'MediaSettingsRange', + 'MediaSource', + 'MediaStream', + 'MediaStreamAudioDestinationNode', + 'MediaStreamAudioSourceNode', + 'MediaStreamEvent', + 'MediaStreamTrack', + 'MediaStreamTrackEvent', + 'menubar', + 'MessageChannel', + 'MessageEvent', + 'MessagePort', + 'MIDIAccess', + 'MIDIConnectionEvent', + 'MIDIInput', + 'MIDIInputMap', + 'MIDIMessageEvent', + 'MIDIOutput', + 'MIDIOutputMap', + 'MIDIPort', + 'MimeType', + 'MimeTypeArray', + 'MouseEvent', + 'moveBy', + 'moveTo', + 'MutationEvent', + 'MutationObserver', + 'MutationRecord', + 'name', + 'NamedNodeMap', 'NaN', + 'NavigationPreloadManager', 'navigator', + 'Navigator', + 'NetworkInformation', + 'Node', + 'NodeFilter', + 'NodeIterator', + 'NodeList', + 'Notification', 'Number', 'Object', + 'OfflineAudioCompletionEvent', + 'OfflineAudioContext', + 'offscreenBuffering', + 'OffscreenCanvas', + 'open', + 'openDatabase', + 'Option', + 'origin', + 'OscillatorNode', + 'outerHeight', + 'outerWidth', + 'PageTransitionEvent', + 'pageXOffset', + 'pageYOffset', + 'PannerNode', + 'parent', 'parseFloat', 'parseInt', - 'process', + 'Path2D', + 'PaymentAddress', + 'PaymentRequest', + 'PaymentRequestUpdateEvent', + 'PaymentResponse', + 'performance', + 'Performance', + 'PerformanceEntry', + 'PerformanceLongTaskTiming', + 'PerformanceMark', + 'PerformanceMeasure', + 'PerformanceNavigation', + 'PerformanceNavigationTiming', + 'PerformanceObserver', + 'PerformanceObserverEntryList', + 'PerformancePaintTiming', + 'PerformanceResourceTiming', + 'PerformanceTiming', + 'PeriodicWave', + 'Permissions', + 'PermissionStatus', + 'personalbar', + 'PhotoCapabilities', + 'Plugin', + 'PluginArray', + 'PointerEvent', + 'PopStateEvent', + 'postMessage', + 'Presentation', + 'PresentationAvailability', + 'PresentationConnection', + 'PresentationConnectionAvailableEvent', + 'PresentationConnectionCloseEvent', + 'PresentationConnectionList', + 'PresentationReceiver', + 'PresentationRequest', + 'print', + 'ProcessingInstruction', + 'ProgressEvent', 'Promise', + 'PromiseRejectionEvent', 'prompt', + 'propertyIsEnumerable', + 'Proxy', + 'PushManager', + 'PushSubscription', + 'PushSubscriptionOptions', + 'queueMicrotask', + 'RadioNodeList', + 'Range', 'RangeError', + 'ReadableStream', 'ReferenceError', + 'Reflect', 'RegExp', + 'RemotePlayback', + 'removeEventListener', + 'Request', + 'requestAnimationFrame', + 'requestIdleCallback', + 'resizeBy', + 'ResizeObserver', + 'ResizeObserverEntry', + 'resizeTo', + 'Response', + 'RTCCertificate', + 'RTCDataChannel', + 'RTCDataChannelEvent', + 'RTCDtlsTransport', + 'RTCIceCandidate', + 'RTCIceTransport', + 'RTCPeerConnection', + 'RTCPeerConnectionIceEvent', + 'RTCRtpReceiver', + 'RTCRtpSender', + 'RTCSctpTransport', + 'RTCSessionDescription', + 'RTCStatsReport', + 'RTCTrackEvent', + 'screen', + 'Screen', + 'screenLeft', + 'ScreenOrientation', + 'screenTop', + 'screenX', + 'screenY', + 'ScriptProcessorNode', + 'scroll', + 'scrollbars', + 'scrollBy', + 'scrollTo', + 'scrollX', + 'scrollY', + 'SecurityPolicyViolationEvent', + 'Selection', + 'self', + 'ServiceWorker', + 'ServiceWorkerContainer', + 'ServiceWorkerRegistration', 'sessionStorage', 'Set', 'setInterval', 'setTimeout', + 'ShadowRoot', + 'SharedArrayBuffer', + 'SharedWorker', + 'SourceBuffer', + 'SourceBufferList', + 'speechSynthesis', + 'SpeechSynthesisEvent', + 'SpeechSynthesisUtterance', + 'StaticRange', + 'status', + 'statusbar', + 'StereoPannerNode', + 'stop', + 'Storage', + 'StorageEvent', + 'StorageManager', 'String', + 'styleMedia', + 'StyleSheet', + 'StyleSheetList', + 'SubtleCrypto', + 'SVGAElement', + 'SVGAngle', + 'SVGAnimatedAngle', + 'SVGAnimatedBoolean', + 'SVGAnimatedEnumeration', + 'SVGAnimatedInteger', + 'SVGAnimatedLength', + 'SVGAnimatedLengthList', + 'SVGAnimatedNumber', + 'SVGAnimatedNumberList', + 'SVGAnimatedPreserveAspectRatio', + 'SVGAnimatedRect', + 'SVGAnimatedString', + 'SVGAnimatedTransformList', + 'SVGAnimateElement', + 'SVGAnimateMotionElement', + 'SVGAnimateTransformElement', + 'SVGAnimationElement', + 'SVGCircleElement', + 'SVGClipPathElement', + 'SVGComponentTransferFunctionElement', + 'SVGDefsElement', + 'SVGDescElement', + 'SVGDiscardElement', + 'SVGElement', + 'SVGEllipseElement', + 'SVGFEBlendElement', + 'SVGFEColorMatrixElement', + 'SVGFEComponentTransferElement', + 'SVGFECompositeElement', + 'SVGFEConvolveMatrixElement', + 'SVGFEDiffuseLightingElement', + 'SVGFEDisplacementMapElement', + 'SVGFEDistantLightElement', + 'SVGFEDropShadowElement', + 'SVGFEFloodElement', + 'SVGFEFuncAElement', + 'SVGFEFuncBElement', + 'SVGFEFuncGElement', + 'SVGFEFuncRElement', + 'SVGFEGaussianBlurElement', + 'SVGFEImageElement', + 'SVGFEMergeElement', + 'SVGFEMergeNodeElement', + 'SVGFEMorphologyElement', + 'SVGFEOffsetElement', + 'SVGFEPointLightElement', + 'SVGFESpecularLightingElement', + 'SVGFESpotLightElement', + 'SVGFETileElement', + 'SVGFETurbulenceElement', + 'SVGFilterElement', + 'SVGForeignObjectElement', + 'SVGGElement', + 'SVGGeometryElement', + 'SVGGradientElement', + 'SVGGraphicsElement', + 'SVGImageElement', + 'SVGLength', + 'SVGLengthList', + 'SVGLinearGradientElement', + 'SVGLineElement', + 'SVGMarkerElement', + 'SVGMaskElement', + 'SVGMatrix', + 'SVGMetadataElement', + 'SVGMPathElement', + 'SVGNumber', + 'SVGNumberList', + 'SVGPathElement', + 'SVGPatternElement', + 'SVGPoint', + 'SVGPointList', + 'SVGPolygonElement', + 'SVGPolylineElement', + 'SVGPreserveAspectRatio', + 'SVGRadialGradientElement', + 'SVGRect', + 'SVGRectElement', + 'SVGScriptElement', + 'SVGSetElement', + 'SVGStopElement', + 'SVGStringList', + 'SVGStyleElement', + 'SVGSVGElement', + 'SVGSwitchElement', + 'SVGSymbolElement', + 'SVGTextContentElement', + 'SVGTextElement', + 'SVGTextPathElement', + 'SVGTextPositioningElement', + 'SVGTitleElement', + 'SVGTransform', + 'SVGTransformList', + 'SVGTSpanElement', + 'SVGUnitTypes', + 'SVGUseElement', + 'SVGViewElement', + 'Symbol', 'SyntaxError', + 'TaskAttributionTiming', + 'Text', + 'TextDecoder', + 'TextEncoder', + 'TextEvent', + 'TextMetrics', + 'TextTrack', + 'TextTrackCue', + 'TextTrackCueList', + 'TextTrackList', + 'TimeRanges', + 'toLocaleString', + 'toolbar', + 'top', + 'toString', + 'Touch', + 'TouchEvent', + 'TouchList', + 'TrackEvent', + 'TransitionEvent', + 'TreeWalker', 'TypeError', - 'undefined', + 'UIEvent', + 'Uint16Array', + 'Uint32Array', + 'Uint8Array', + 'Uint8ClampedArray', + 'unescape', 'URIError', 'URL', + 'URLSearchParams', + 'ValidityState', + 'valueOf', + 'visualViewport', + 'VisualViewport', + 'VTTCue', + 'WaveShaperNode', + 'WeakMap', + 'WeakSet', + 'WebAssembly', + 'WebGL2RenderingContext', + 'WebGLActiveInfo', + 'WebGLBuffer', + 'WebGLContextEvent', + 'WebGLFramebuffer', + 'WebGLProgram', + 'WebGLQuery', + 'WebGLRenderbuffer', + 'WebGLRenderingContext', + 'WebGLSampler', + 'WebGLShader', + 'WebGLShaderPrecisionFormat', + 'WebGLSync', + 'WebGLTexture', + 'WebGLTransformFeedback', + 'WebGLUniformLocation', + 'WebGLVertexArrayObject', + 'WebSocket', + 'WheelEvent', 'window', + 'Window', + 'Worker', + 'WritableStream', + 'XMLDocument', + 'XMLHttpRequest', + 'XMLHttpRequestEventTarget', + 'XMLHttpRequestUpload', + 'XMLSerializer', + 'XPathEvaluator', + 'XPathExpression', + 'XPathResult', + 'XSLTProcessor', ]); export const reserved = new Set([ - 'arguments', 'await', 'break', 'case', @@ -72,10 +675,8 @@ export const reserved = new Set([ 'do', 'else', 'enum', - 'eval', 'export', 'extends', - 'false', 'finally', 'for', 'function', @@ -87,7 +688,6 @@ export const reserved = new Set([ 'interface', 'let', 'new', - 'null', 'package', 'private', 'protected', @@ -98,7 +698,6 @@ export const reserved = new Set([ 'switch', 'this', 'throw', - 'true', 'try', 'typeof', 'var', diff --git a/src/runtime/environment/index.ts b/src/runtime/environment/index.ts index d115e358f8..36183cf463 100644 --- a/src/runtime/environment/index.ts +++ b/src/runtime/environment/index.ts @@ -1,8 +1,9 @@ +import { noop } from '../internal/utils'; export const is_browser = typeof window !== 'undefined'; -export const is_iframe = is_browser && window.self !== window.top; +export const is_iframe = /*#__PURE__*/ is_browser && window.self !== window.top; export const is_cors = is_iframe && - (() => { + /*#__PURE__*/ (() => { try { if (window.parent) void window.parent.document; return false; @@ -12,3 +13,19 @@ export const is_cors = })(); export const has_Symbol = typeof Symbol === 'function'; export const globals = is_browser ? window : typeof globalThis !== 'undefined' ? globalThis : global; +export const resolved_promise = Promise.resolve(); + +export let now = /*#__PURE__*/ is_browser ? performance.now.bind(performance) : Date.now.bind(Date); +export let raf = /*#__PURE__*/ is_browser ? requestAnimationFrame : noop; +export let framerate = 1000 / 60; +raf((t1) => { + raf((d) => { + const f24 = 1000 / 24, + f144 = 1000 / 144; + framerate = (d = d - t1) > f144 ? f144 : d < f24 ? f24 : d; + }); +}); + +/* tests only */ +export const test$set_now = (fn) => void (now = fn); +export const test$set_raf = (fn) => void (raf = fn); diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 9d7286a8f8..e48e636897 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -59,7 +59,7 @@ export function destroy_component({ $$ }, detaching: 0 | 1) { if (null === $$.fragment) return; for (let i = 0, { on_destroy } = $$; i < on_destroy.length; i++) on_destroy[i](); - if ($$.fragment) $$.fragment.d(detaching); + if (false !== $$.fragment) $$.fragment.d(detaching); // TODO null out other refs, including component.$$ // (need to preserve final state?) diff --git a/src/runtime/internal/animations.ts b/src/runtime/internal/animations.ts index 962bfd601a..1870ef2ddf 100644 --- a/src/runtime/internal/animations.ts +++ b/src/runtime/internal/animations.ts @@ -9,31 +9,27 @@ export interface AnimationConfig { tick?: (t: number, u?: number) => void; } -//todo: documentation says it is DOMRect, but in IE it would be ClientRect -type PositionRect = DOMRect | ClientRect; +type AnimationFn = (node: Element, { from, to }: { from: DOMRect; to: DOMRect }, params: any) => AnimationConfig; -type AnimationFn = ( - node: Element, - { from, to }: { from: PositionRect; to: PositionRect }, - params: any -) => AnimationConfig; - -export function run_animation(node: HTMLElement, from: PositionRect, fn: AnimationFn, params) { +export function run_animation(node: HTMLElement, from: DOMRect, fn: AnimationFn, params) { if (!from) return noop; - const to = node.getBoundingClientRect(); - if (from.left === to.left && from.right === to.right && from.top === to.top && from.bottom === to.bottom) return noop; - return run_transition(node, (node, params) => fn(node, { from, to }, params), true, params); + return run_transition( + node, + (node, params) => fn(node, { from, to: node.getBoundingClientRect() }, params), + true, + params + ); } -export function fix_position(node: HTMLElement) { - const { position, width, height } = getComputedStyle(node); +export function fix_position(node: HTMLElement, { left, top }: DOMRect) { + const { position, width, height, transform } = 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, current_position); + const b = node.getBoundingClientRect(); + node.style.transform = `${transform === 'none' ? '' : transform} translate(${left - b.left}px, ${top - b.top}px)`; return () => { node.style.position = og_position; node.style.width = og_width; @@ -42,7 +38,7 @@ export function fix_position(node: HTMLElement) { }; } -export function add_transform(node: HTMLElement, a: PositionRect) { +export function add_transform(node: HTMLElement, a: DOMRect) { const b = node.getBoundingClientRect(); if (a.left !== b.left || a.top !== b.top) { const style = getComputedStyle(node); diff --git a/src/runtime/internal/dev.legacy.ts b/src/runtime/internal/dev.legacy.ts index a0282d7a1c..5626e7a45b 100644 --- a/src/runtime/internal/dev.legacy.ts +++ b/src/runtime/internal/dev.legacy.ts @@ -1,5 +1,5 @@ import { custom_event, append, insert, detach, listen, attr } from './dom'; -import { now } from './environment'; +import { now } from 'svelte/environment'; let inited; export function add_location_dev$legacy(element, file, line, column, char) { element.__svelte_meta = { diff --git a/src/runtime/internal/dev.utils.ts b/src/runtime/internal/dev.utils.ts index ee45146476..aef0d3749e 100644 --- a/src/runtime/internal/dev.utils.ts +++ b/src/runtime/internal/dev.utils.ts @@ -1,5 +1,5 @@ import { SvelteComponent } from './Component'; -import { now, has_Symbol } from './environment'; +import { now, has_Symbol } from 'svelte/environment'; import { dev$assert } from './dev.tools'; export const dev$is_array_like = (arg) => diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 9353085262..37512eb37a 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -1,5 +1,5 @@ import { dev$element, dev$block } from './dev.tools'; -import { is_client, is_cors } from './environment'; +import { is_cors } from 'svelte/environment'; export function append(target: Node, node: Node) { dev$element(node, `onMount`, { target }); @@ -341,18 +341,3 @@ export class HtmlTag { this.n.forEach(detach); } } - -export const hasOwnProperty = Object.prototype.hasOwnProperty; -const nodeProto = Node.prototype; -export const insertBefore = nodeProto.insertBefore; -export const removeChild = nodeProto.removeChild; -export const replaceChild = nodeProto.replaceChild; -export const cloneNode = nodeProto.cloneNode; -const elementProto = Element.prototype; -export const setAttribute = elementProto.setAttribute; -export const setAttributeNS = elementProto.setAttributeNS; -export const removeAttribute = elementProto.removeAttribute; -const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; -export const setClassName = getOwnPropertyDescriptor(elementProto, 'className').set; -export const getStyle = getOwnPropertyDescriptor(HTMLElement.prototype, 'style').get; -export const svg_getStyle = getOwnPropertyDescriptor(SVGElement.prototype, 'style').get; diff --git a/src/runtime/internal/environment.ts b/src/runtime/internal/environment.ts deleted file mode 100644 index 76232e1656..0000000000 --- a/src/runtime/internal/environment.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { noop } from './utils'; -export const resolved_promise = Promise.resolve(); -export const is_client = typeof window !== 'undefined'; -export const is_iframe = !is_client && window.self !== window.top; -export const is_cors = - is_iframe && - (() => { - try { - if (window.parent) void window.parent.document; - return false; - } catch (error) { - return true; - } - })(); - -export const globals = ((is_client - ? window - : typeof globalThis !== 'undefined' - ? globalThis - : global) as unknown) as typeof globalThis; - -export const has_Symbol = typeof Symbol === 'function'; -export let now = is_client ? performance.now.bind(performance) : Date.now.bind(Date); - -export let raf = is_client ? requestAnimationFrame : noop; - -/* tests only */ -export const set_now = (fn) => void (now = fn); - -export const set_raf = (fn) => void (raf = fn); diff --git a/src/runtime/internal/index.ts b/src/runtime/internal/index.ts index 835c058da5..b154e4cd3d 100644 --- a/src/runtime/internal/index.ts +++ b/src/runtime/internal/index.ts @@ -5,7 +5,6 @@ export * from './dev.legacy'; export * from './dev.utils'; export * from './dev.tools'; export * from './dom'; -export * from './environment'; export * from './keyed_each'; export * from './lifecycle'; export * from './loop'; @@ -16,3 +15,6 @@ export * from './stores'; // export * from './style_manager' export * from './transitions'; export * from './utils'; + +// todo; create_module.ts line 24; allow compiler to import non internal +export * from '../environment/index'; diff --git a/src/runtime/internal/keyed_each.ts b/src/runtime/internal/keyed_each.ts index b8a43440e8..4fa0c6b515 100644 --- a/src/runtime/internal/keyed_each.ts +++ b/src/runtime/internal/keyed_each.ts @@ -1,5 +1,5 @@ import { transition_in } from './transitions'; -export function update_keyed_each( +export const update_keyed_each = ( old_blocks, dirty, ctx, @@ -12,7 +12,7 @@ export function update_keyed_each( next, get_context, transition_out? -) { +) => { let o = old_blocks.length; let n = list.length; @@ -54,7 +54,7 @@ export function update_keyed_each( }; const destroy = (block) => { if (state & 2) block.f(); - if (state & 4) transition_out(block, () => lookup.delete(block.key)); + if (state & 4) transition_out(block, lookup.delete.bind(lookup, block.key)); else block.d(1), lookup.delete(block.key); }; @@ -94,7 +94,7 @@ export function update_keyed_each( while (n) insert(new_blocks[n - 1]); return new_blocks; -} +}; export function validate_each_keys(ctx, list, get_context, get_key) { const keys = new Set(); diff --git a/src/runtime/internal/loop.ts b/src/runtime/internal/loop.ts index d4aae2334d..2d845b208a 100644 --- a/src/runtime/internal/loop.ts +++ b/src/runtime/internal/loop.ts @@ -1,5 +1,4 @@ -import { now, raf } from './environment'; -import { calc_framerate, FRAME_RATE } from './style_manager'; +import { now, raf, framerate } from 'svelte/environment'; import { noop } from './utils'; type TaskCallback = (t: number) => boolean; type TaskCanceller = () => void; @@ -90,7 +89,7 @@ export const onEachFrame = ( on_stop?, max_skipped_frames = 4 ): TaskCanceller => { - max_skipped_frames *= FRAME_RATE || calc_framerate(); + max_skipped_frames *= framerate; let lastTime = now(); let running = true; const cancel = (t) => (on_stop && on_stop(t), false); diff --git a/src/runtime/internal/scheduler.ts b/src/runtime/internal/scheduler.ts index e3e4109dfd..b2fa55da08 100644 --- a/src/runtime/internal/scheduler.ts +++ b/src/runtime/internal/scheduler.ts @@ -1,5 +1,5 @@ import { set_current_component } from './lifecycle'; -import { resolved_promise } from './environment'; +import { resolved_promise } from 'svelte/environment'; import { T$$ } from './Component'; let update_scheduled = false; @@ -88,15 +88,15 @@ export const flush = () => { update_scheduled = false; // measurement callbacks for animations - for (i = 0; i < measure_callbacks.length; i++) { - flush_callbacks.push(measure_callbacks[i]()); + for (i = 0, j = flush_callbacks.length; i < measure_callbacks.length; i++) { + flush_callbacks[j++] = measure_callbacks[i](); } measure_callbacks.length = i = 0; // apply styles // todo : remove every non style callback from flush_callbacks - for (; i < flush_callbacks.length; i++) flush_callbacks[i](); - flush_callbacks.length = 0; + for (; i < j; i++) flush_callbacks[i](); + flush_callbacks.length = i = j = 0; is_flushing = false; }; diff --git a/src/runtime/internal/style_manager.ts b/src/runtime/internal/style_manager.ts index 679032ef78..3f7afcf877 100644 --- a/src/runtime/internal/style_manager.ts +++ b/src/runtime/internal/style_manager.ts @@ -1,23 +1,10 @@ import { element } from './dom'; -import { raf } from './environment'; -const enum SVELTE { +import { framerate } from 'svelte/environment'; +enum SVELTE { RULE = `__svelte_`, STYLESHEET = `__svelte_stylesheet`, RULESET = `__svelte_rules`, } - -export let FRAME_RATE; -export 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.RULESET]: Set; @@ -36,8 +23,9 @@ function add_rule(node): [CSSStyleSheet, Set] { } return [ownerDocument[SVELTE.STYLESHEET], ownerDocument[SVELTE.RULESET]]; } -// https://github.com/darkskyapp/string-hash/blob/master/index.js + function hash(str: string) { + // darkskyapp/string-hash let hash = 5381; let i = str.length; while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i); @@ -50,21 +38,23 @@ const gen = (step, css) => { const name = SVELTE.RULE + hash(rule); return [name, `@keyframes ${name} ${rule}`]; }; -export function animate_css(css: (t: number) => string, node: HTMLElement, duration: number, delay = 0) { - const [name, rule] = gen(Math.max(1 / 1000, (FRAME_RATE || calc_framerate()) / duration), css); - const [stylesheet, rules] = add_rule(node); +function animate(this: HTMLElement, css: (t: number) => string, duration: number, delay = 0) { + const [name, rule] = gen(Math.max(1 / 1000, framerate / duration), css); + const [stylesheet, rules] = add_rule(this); if (!rules.has(name)) { rules.add(name); stylesheet.insertRule(rule, stylesheet.cssRules.length); } - const previous = node.style.animation; - node.style.animation = - (previous ? previous + ', ' : '') + `${duration}ms linear ${delay}ms 1 normal both running ${name}`; + const previous = this.style.animation; + this.style.animation = `${ + previous ? `${previous}, ` : '' + } ${duration}ms linear ${delay}ms 1 normal both running ${name}`; + running_animations++; return () => { - const prev = (node.style.animation || '').split(', '); + const prev = (this.style.animation || '').split(', '); const next = prev.filter((anim) => !anim.includes(name)); - if (prev.length !== next.length) node.style.animation = next.join(', '); + if (prev.length !== next.length) this.style.animation = next.join(', '); if (--running_animations) return; active_documents.forEach(({ [SVELTE.STYLESHEET]: stylesheet, [SVELTE.RULESET]: ruleset }) => { let i = stylesheet.cssRules.length; @@ -74,17 +64,4 @@ export function animate_css(css: (t: number) => string, node: HTMLElement, durat active_documents.clear(); }; } -export function delete_rule(node: HTMLElement, name?: string) { - const previous = (node.style.animation || '').split(', '); - const next = previous.filter( - name - ? (anim) => anim.indexOf(name) < 0 // remove specific animation - : (anim) => anim.indexOf(SVELTE.RULE) === -1 // remove all Svelte animations - ); - const deleted = previous.length - next.length; - if (deleted) { - node.style.animation = next.join(', '); - running_animations -= deleted; - if (!active_documents) active_documents.clear(); - } -} +export const animate_css = Function.prototype.call.bind(animate); diff --git a/src/runtime/internal/transitions.ts b/src/runtime/internal/transitions.ts index 99dbde3754..d2c192bd1a 100644 --- a/src/runtime/internal/transitions.ts +++ b/src/runtime/internal/transitions.ts @@ -1,7 +1,7 @@ import { TransitionConfig } from '../transition'; import { Fragment } from './Component'; import { custom_event } from './dom'; -import { now } from './environment'; +import { now } from 'svelte/environment'; import { setFrameTimeout, setTweenTimeout } from './loop'; import { add_measure_callback } from './scheduler'; import { animate_css } from './style_manager'; @@ -99,17 +99,17 @@ export const run_transition = ( const solver = strategy === 'reverse' ? reversed : mirrored; const runner = (fn) => solver(fn, is_intro, easing, elapsed_ratio, 1); - if (solver === mirrored) { - delay -= elapsed_duration; - } else if (solver === reversed) { + if (solver === reversed) { duration -= elapsed_duration; + } else if (solver === mirrored) { + delay -= elapsed_duration; } end_time = (start_time = now() + delay) + duration; dispatch_end = startStopDispatcher(node, is_intro); - if (css) cancel_css = animate_css(runner(css), node, duration, delay); + if (css) cancel_css = animate_css(node, runner(css), duration, delay); cancel_raf = tick ? setTweenTimeout(stop, end_time, runner(tick), duration) : setFrameTimeout(stop, end_time); }; diff --git a/src/runtime/transition/index.ts b/src/runtime/transition/index.ts index 827b0aa3f2..f8dfcf2354 100644 --- a/src/runtime/transition/index.ts +++ b/src/runtime/transition/index.ts @@ -153,22 +153,30 @@ export function crossfade({ const dw = from.width / to.width; const dh = from.height / to.height; const { transform, opacity } = getComputedStyle(to_node); + const op = +opacity; const prev = transform === 'none' ? '' : transform; return { delay, easing, duration: run_duration(duration, Math.sqrt(dx * dx + dy * dy)), css: (t, u) => ` - opacity: ${t * +opacity}; + opacity: ${t * op}; transform-origin: top left; 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) => { - const key = params.key; - a.set(key, node); + const transition = (a: ElementMap, b: ElementMap, is_intro: boolean) => ( + node: Element, + params: MarkedCrossFadeConfig + ) => { + const key = params.key; + a.set(key, node); + if (b.has(key)) { + const from_node = b.get(key); + b.delete(key); + return crossfade(from_node, node, params); + } else { return () => { if (b.has(key)) { const from_node = b.get(key); @@ -179,8 +187,8 @@ export function crossfade({ return fallback && fallback(node, params, is_intro); } }; - }; - } + } + }; return [transition(to_send, to_receive, false), transition(to_receive, to_send, true)]; } diff --git a/tsconfig.json b/tsconfig.json index 39476f3dd1..3d17e92a66 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,17 +6,18 @@ // target node v8+ (https://node.green/) // the only missing feature is Array.prototype.values - "lib": ["es2017"], - "target": "es2017", + "lib": ["ESNext"], + "target": "ESNext", "declaration": true, "declarationDir": "types", + "strictBindCallApply": true, "noEmitOnError": true, "noErrorTruncation": true, // rollup takes care of these - "module": "esnext", + "module": "ESNext", "moduleResolution": "node", "resolveJsonModule": true, "allowSyntheticDefaultImports": true,