diff --git a/.gitignore b/.gitignore index 1499a0e697..2c8e89efc2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ node_modules /index.js /internal.* /store.js +/easing.js +/transition.js /scratch/ /coverage/ /coverage.lcov/ @@ -21,4 +23,6 @@ _actual*.* /site/cypress/screenshots/ /site/__sapper__/ /site/.env -/site/.sessions \ No newline at end of file +/site/.sessions +/site/static/svelte-app.json +/site/scripts/svelte-app \ No newline at end of file diff --git a/easing.mjs b/easing.mjs new file mode 100644 index 0000000000..855713b03d --- /dev/null +++ b/easing.mjs @@ -0,0 +1,173 @@ +/* +Adapted from https://github.com/mattdesl +Distributed under MIT License https://github.com/mattdesl/eases/blob/master/LICENSE.md +*/ + +export function backInOut(t) { + var s = 1.70158 * 1.525; + if ((t *= 2) < 1) return 0.5 * (t * t * ((s + 1) * t - s)); + return 0.5 * ((t -= 2) * t * ((s + 1) * t + s) + 2); +} + +export function backIn(t) { + var s = 1.70158; + return t * t * ((s + 1) * t - s); +} + +export function backOut(t) { + var s = 1.70158; + return --t * t * ((s + 1) * t + s) + 1; +} + +export function bounceOut(t) { + var a = 4.0 / 11.0; + var b = 8.0 / 11.0; + var c = 9.0 / 10.0; + + var ca = 4356.0 / 361.0; + var cb = 35442.0 / 1805.0; + var cc = 16061.0 / 1805.0; + + var t2 = t * t; + + return t < a + ? 7.5625 * t2 + : t < b + ? 9.075 * t2 - 9.9 * t + 3.4 + : t < c + ? ca * t2 - cb * t + cc + : 10.8 * t * t - 20.52 * t + 10.72; +} + +export function bounceInOut(t) { + return t < 0.5 + ? 0.5 * (1.0 - bounceOut(1.0 - t * 2.0)) + : 0.5 * bounceOut(t * 2.0 - 1.0) + 0.5; +} + +export function bounceIn(t) { + return 1.0 - bounceOut(1.0 - t); +} + +export function circInOut(t) { + if ((t *= 2) < 1) return -0.5 * (Math.sqrt(1 - t * t) - 1); + return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1); +} + +export function circIn(t) { + return 1.0 - Math.sqrt(1.0 - t * t); +} + +export function circOut(t) { + return Math.sqrt(1 - --t * t); +} + +export function cubicInOut(t) { + return t < 0.5 ? 4.0 * t * t * t : 0.5 * Math.pow(2.0 * t - 2.0, 3.0) + 1.0; +} + +export function cubicIn(t) { + return t * t * t; +} + +export function cubicOut(t) { + var f = t - 1.0; + return f * f * f + 1.0; +} + +export function elasticInOut(t) { + return t < 0.5 + ? 0.5 * + Math.sin(((+13.0 * Math.PI) / 2) * 2.0 * t) * + Math.pow(2.0, 10.0 * (2.0 * t - 1.0)) + : 0.5 * + Math.sin(((-13.0 * Math.PI) / 2) * (2.0 * t - 1.0 + 1.0)) * + Math.pow(2.0, -10.0 * (2.0 * t - 1.0)) + + 1.0; +} + +export function elasticIn(t) { + return Math.sin((13.0 * t * Math.PI) / 2) * Math.pow(2.0, 10.0 * (t - 1.0)); +} + +export function elasticOut(t) { + return ( + Math.sin((-13.0 * (t + 1.0) * Math.PI) / 2) * Math.pow(2.0, -10.0 * t) + 1.0 + ); +} + +export function expoInOut(t) { + return t === 0.0 || t === 1.0 + ? t + : t < 0.5 + ? +0.5 * Math.pow(2.0, 20.0 * t - 10.0) + : -0.5 * Math.pow(2.0, 10.0 - t * 20.0) + 1.0; +} + +export function expoIn(t) { + return t === 0.0 ? t : Math.pow(2.0, 10.0 * (t - 1.0)); +} + +export function expoOut(t) { + return t === 1.0 ? t : 1.0 - Math.pow(2.0, -10.0 * t); +} + +export function linear(t) { + return t; +} + +export function quadInOut(t) { + t /= 0.5; + if (t < 1) return 0.5 * t * t; + t--; + return -0.5 * (t * (t - 2) - 1); +} + +export function quadIn(t) { + return t * t; +} + +export function quadOut(t) { + return -t * (t - 2.0); +} + +export function quartInOut(t) { + return t < 0.5 + ? +8.0 * Math.pow(t, 4.0) + : -8.0 * Math.pow(t - 1.0, 4.0) + 1.0; +} + +export function quartIn(t) { + return Math.pow(t, 4.0); +} + +export function quartOut(t) { + return Math.pow(t - 1.0, 3.0) * (1.0 - t) + 1.0; +} + +export function quintInOut(t) { + if ((t *= 2) < 1) return 0.5 * t * t * t * t * t; + return 0.5 * ((t -= 2) * t * t * t * t + 2); +} + +export function quintIn(t) { + return t * t * t * t * t; +} + +export function quintOut(t) { + return --t * t * t * t * t + 1; +} + +export function sineInOut(t) { + return -0.5 * (Math.cos(Math.PI * t) - 1); +} + +export function sineIn(t) { + var v = Math.cos(t * Math.PI * 0.5); + if (Math.abs(v) < 1e-14) return 1; + else return 1 - v; +} + +export function sineOut(t) { + return Math.sin((t * Math.PI) / 2); +} diff --git a/package.json b/package.json index 0f43ed0019..21234501f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.0.0-alpha8", + "version": "3.0.0-alpha12", "description": "The magical disappearing UI framework", "module": "index.mjs", "main": "index.js", @@ -14,6 +14,8 @@ "index.*", "internal.*", "store.*", + "transition.*", + "easing.*", "svelte", "README.md" ], diff --git a/rollup.config.js b/rollup.config.js index 1bb01c9282..7e1947ec4e 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -52,16 +52,6 @@ export default [ experimentalCodeSplitting: true }, - /* index.js */ - { - input: 'index.mjs', - output: { - file: 'index.js', - format: 'cjs' - }, - external: name => name !== 'index.mjs' - }, - /* internal.[m]js */ { input: 'src/internal/index.js', @@ -77,13 +67,13 @@ export default [ ] }, - /* store.js */ - { - input: 'store.mjs', + // runtime API + ...['index', 'store', 'easing', 'transition'].map(name => ({ + input: `${name}.mjs`, output: { - file: 'store.js', + file: `${name}.js`, format: 'cjs' }, - external: name => name !== 'store.mjs' - }, + external: id => id !== `${name}.mjs` + })) ]; diff --git a/site/package-lock.json b/site/package-lock.json index 27bb28b6b0..653489dcaf 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -3804,13 +3804,13 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sapper": { - "version": "0.25.0-alpha1", - "resolved": "https://registry.npmjs.org/sapper/-/sapper-0.25.0-alpha1.tgz", - "integrity": "sha512-zVD/9T0JRC9HveX06OfC04NLIbM3J834evccRGXhOqB3cI9wJeCESnwu2toYVCKPbS2qRNZIdOtKlKc0BhTXAw==", + "version": "0.25.0-alpha2", + "resolved": "https://registry.npmjs.org/sapper/-/sapper-0.25.0-alpha2.tgz", + "integrity": "sha512-GAYdwyDLo6XYJxJDFtpY1BcHPVjibYY/x/DvUEpH9rsH0fLF67SWAf0RokGs1lvhOMd1O6nxtR7KztwIeNIkZA==", "dev": true, "requires": { "html-minifier": "^3.5.20", - "shimport": "0.0.11", + "shimport": "0.0.14", "source-map-support": "^0.5.9", "sourcemap-codec": "^1.4.3", "string-hash": "^1.1.3", @@ -3935,9 +3935,9 @@ } }, "shimport": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/shimport/-/shimport-0.0.11.tgz", - "integrity": "sha512-wRlG/wMuV/czrzJEWBUPjydU/Ve0kTrTH8wHLRjuY6S2BDB+qDDXkTY/WrNc/7t5jnd0LPVO1sRIE7Ga6uXTpw==", + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/shimport/-/shimport-0.0.14.tgz", + "integrity": "sha512-JfzpHhyZ6CYuPYUSitFNw2/IxWEABLN1chs9xDHnn4tPXXCmfIn1METCmIl8Vwvm2FZGW7b8WB4zMCKaJEhY6A==", "dev": true }, "sirv": { @@ -4220,9 +4220,9 @@ } }, "svelte": { - "version": "3.0.0-alpha7", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.0.0-alpha7.tgz", - "integrity": "sha512-AIEeZlVKqw7rRss0+1YDJlPJW7uQpHMB3ys730D1AuuPQkZVFoW+KuCi+1HiE9D5AUr1pIAUxc3vD66RYGqoyw==", + "version": "3.0.0-alpha10", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.0.0-alpha10.tgz", + "integrity": "sha512-SmEI9Heks28DeBF26GZuViYXBwkqVXiqGbpH1CZ/HowGzTDVib2peWBpwaGjKHg1nX9zicNFTRa9E2Ebb/sWoQ==", "dev": true }, "terser": { diff --git a/site/package.json b/site/package.json index 62f2537530..5f0a1332e0 100644 --- a/site/package.json +++ b/site/package.json @@ -5,13 +5,13 @@ "scripts": { "dev": "sapper dev", "sapper": "sapper build --legacy", - "export": "sapper export --legacy", + "update_template": "sh ./scripts/update_template.sh", "start": "node __sapper__/build", "cy:run": "cypress run", "cy:open": "cypress open", "test": "run-p --race dev cy:run", "deploy": "npm run stage && now alias", - "prestage": "npm run sapper", + "prestage": "npm run update_template && npm run sapper", "stage": "now" }, "dependencies": { @@ -50,7 +50,7 @@ "rollup-plugin-replace": "^2.0.0", "rollup-plugin-svelte": "^4.2.1", "rollup-plugin-terser": "^1.0.1", - "sapper": "^0.25.0-alpha1", - "svelte": "^3.0.0-alpha7" + "sapper": "^0.25.0-alpha2", + "svelte": "^3.0.0-alpha10" } } diff --git a/site/scripts/build-svelte-app-json.js b/site/scripts/build-svelte-app-json.js new file mode 100644 index 0000000000..59a4b4a07b --- /dev/null +++ b/site/scripts/build-svelte-app-json.js @@ -0,0 +1,11 @@ +const fs = require('fs'); + +const files = []; + +for (const path of process.argv.slice(2)) { + if (!path.includes('/.')) { + files.push({ path: path.slice(19), data: fs.readFileSync(path).toString() }); + } +} + +fs.writeFileSync('static/svelte-app.json', JSON.stringify(files)); diff --git a/site/scripts/update_template.sh b/site/scripts/update_template.sh new file mode 100755 index 0000000000..59ab3cb0cd --- /dev/null +++ b/site/scripts/update_template.sh @@ -0,0 +1,15 @@ +cd `dirname $0`/.. + +# fetch svelte-app +rm -rf scripts/svelte-app +node_modules/.bin/degit sveltejs/template scripts/svelte-app + +# update repl-viewer.css based on template +cp scripts/svelte-app/public/global.css static/repl-viewer.css + +# remove src (will be recreated client-side) and node_modules +rm -rf scripts/svelte-app/src +rm -rf scripts/svelte-app/node_modules + +# build svelte-app.json +node scripts/build-svelte-app-json.js `find scripts/svelte-app -type f` diff --git a/site/src/routes/guide/index.html b/site/src/routes/guide/index.html index ff8bc20d73..09c3603f27 100644 --- a/site/src/routes/guide/index.html +++ b/site/src/routes/guide/index.html @@ -83,6 +83,17 @@ overflow: hidden; } + aside::after { + content: ''; + position: absolute; + left: 0; + bottom: 0; + width: 100%; + height: var(--top-offset); + background: linear-gradient(to bottom, rgba(255,255,255,0) 0%, rgba(255,255,255,0.7) 50%, rgba(255,255,255,1) 100%); + pointer-events: none; + } + .sidebar { padding: var(--top-offset) 3.2rem var(--top-offset) 0; font-family: var(--font-ui); diff --git a/site/src/routes/repl/_components/AppControls/index.html b/site/src/routes/repl/_components/AppControls/index.html index 381cc93f75..ab439251ac 100644 --- a/site/src/routes/repl/_components/AppControls/index.html +++ b/site/src/routes/repl/_components/AppControls/index.html @@ -171,13 +171,15 @@ async function download() { downloading = true; + const { components, imports, values } = repl.toJSON(); + const files = await (await fetch('/svelte-app.json')).json(); - if (bundle.imports.length > 0) { + if (imports.length > 0) { const idx = files.findIndex(({ path }) => path === 'package.json'); const pkg = JSON.parse(files[idx].data); const deps = {}; - bundle.imports.forEach(mod => { + imports.forEach(mod => { const match = /^(@[^\/]+\/)?[^@\/]+/.exec(mod); deps[match[0]] = 'latest'; }); @@ -191,7 +193,7 @@ var app = new App({ target: document.body, - props: ${JSON.stringify(data, null, '\t').replace(/\n/g, '\n\t')} + props: ${JSON.stringify(values, null, '\t').replace(/\n/g, '\n\t')} }); export default app;` }); diff --git a/site/src/routes/repl/_components/Repl.html b/site/src/routes/repl/_components/Repl.html index 2f03a8e002..862b584f78 100644 --- a/site/src/routes/repl/_components/Repl.html +++ b/site/src/routes/repl/_components/Repl.html @@ -18,6 +18,7 @@ version; // workaround return { + imports: bundle.imports, components: $component_store, values: $values_store }; diff --git a/site/src/user.js b/site/src/user.js index 665db40bae..0ba4e7716f 100644 --- a/site/src/user.js +++ b/site/src/user.js @@ -1,4 +1,4 @@ -import { writable } from 'svelte/store.js'; +import { writable } from 'svelte/store'; export const user = writable(null); diff --git a/src/compile/render-dom/Block.ts b/src/compile/render-dom/Block.ts index 8a205e25fd..573a9863d8 100644 --- a/src/compile/render-dom/Block.ts +++ b/src/compile/render-dom/Block.ts @@ -409,12 +409,10 @@ export default class Block { const localKey = this.key && this.getUniqueName('key'); return deindent` - ${this.comment && `// ${escape(this.comment)}`} - function ${this.name}(#component, ${this.key ? `${localKey}, ` : ''}ctx) { + ${this.comment && `// ${this.comment}`} + function ${this.name}(${this.alias('component')}, ${this.key ? `${localKey}, ` : ''}ctx) { ${this.getContents(localKey)} } - `.replace(/(#+)(\w*)/g, (match: string, sigil: string, name: string) => { - return sigil === '#' ? this.alias(name) : sigil.slice(1) + name; - }); + `; } } diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index ee5344869a..64a219ea6a 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -131,10 +131,10 @@ export default function dom( if (expected.length) { dev_props_check = deindent` const { ctx } = this.$$; + const props = ${options.customElement ? `this.attributes` : `options.props || {}`}; ${expected.map(name => deindent` - - if (ctx.${name} === undefined${options.customElement && ` && !('${name}' in this.attributes)`}) { - console.warn("<${component.tag}> was created without expected data property '${name}'"); + if (ctx.${name} === undefined && !('${name}' in props)) { + console.warn("<${component.tag}> was created without expected prop '${name}'"); }`)} `; } diff --git a/src/compile/render-dom/wrappers/Element/index.ts b/src/compile/render-dom/wrappers/Element/index.ts index f5092cab88..5f6f94f38b 100644 --- a/src/compile/render-dom/wrappers/Element/index.ts +++ b/src/compile/render-dom/wrappers/Element/index.ts @@ -403,7 +403,9 @@ export default class ElementWrapper extends Wrapper { const groups = events .map(event => ({ events: event.eventNames, - bindings: mungedBindings.filter(binding => event.filter(this.node, binding.name)) + bindings: mungedBindings + .filter(binding => binding.name !== 'this') + .filter(binding => event.filter(this.node, binding.name)) })) .filter(group => group.bindings.length); @@ -494,7 +496,7 @@ export default class ElementWrapper extends Wrapper { block.addVariable(resize_listener); block.builders.mount.addLine( - `${resize_listener} = @addResizeListener(${this.var}, ${callee});` + `${resize_listener} = @addResizeListener(${this.var}, ${callee}.bind(${this.var}));` ); block.builders.destroy.addLine( @@ -632,7 +634,7 @@ export default class ElementWrapper extends Wrapper { const fn = component.qualify(intro.name); - block.builders.intro.addConditional(`@intro.enabled`, deindent` + block.builders.intro.addConditional(`@intros.enabled`, deindent` if (${name}) ${name}.invalidate(); @add_render_callback(() => { @@ -669,7 +671,7 @@ export default class ElementWrapper extends Wrapper { `); } - block.builders.intro.addConditional(`@intro.enabled`, deindent` + block.builders.intro.addConditional(`@intros.enabled`, deindent` @add_render_callback(() => { ${introName} = @wrapTransition(#component, ${this.var}, ${fn}, ${snippet}, true); ${introName}.run(1); diff --git a/src/internal/Component.js b/src/internal/Component.js index e7d3d23d05..5ee644c714 100644 --- a/src/internal/Component.js +++ b/src/internal/Component.js @@ -1,4 +1,4 @@ -import { add_render_callback, flush, intro, schedule_update } from './scheduler.js'; +import { add_render_callback, flush, intros, schedule_update } from './scheduler.js'; import { current_component, set_current_component } from './lifecycle.js' import { is_function, run, run_all, noop } from './utils.js'; import { blankObject } from './utils.js'; @@ -101,7 +101,7 @@ export function init(component, options, instance, create_fragment, not_equal) { $$.fragment = create_fragment(component, $$.ctx); if (options.target) { - intro.enabled = !!options.intro; + intros.enabled = !!options.intro; if (options.hydrate) { $$.fragment.l(children(options.target)); @@ -111,7 +111,7 @@ export function init(component, options, instance, create_fragment, not_equal) { mount_component(component, options.target, options.anchor); flush(); - intro.enabled = true; + intros.enabled = true; } set_current_component(previous_component); diff --git a/src/internal/scheduler.js b/src/internal/scheduler.js index 9f1d5feffc..962c321fd6 100644 --- a/src/internal/scheduler.js +++ b/src/internal/scheduler.js @@ -6,7 +6,7 @@ let dirty_components = []; const binding_callbacks = []; const render_callbacks = []; -export const intro = { enabled: false }; +export const intros = { enabled: false }; export function schedule_update(component) { dirty_components.push(component); diff --git a/test/custom-elements/samples/no-missing-prop-warnings/test.js b/test/custom-elements/samples/no-missing-prop-warnings/test.js index 675fa66485..9430e97f3a 100644 --- a/test/custom-elements/samples/no-missing-prop-warnings/test.js +++ b/test/custom-elements/samples/no-missing-prop-warnings/test.js @@ -12,7 +12,7 @@ export default function (target) { target.innerHTML = ''; assert.equal(warnings.length, 1); - assert.equal(warnings[0], ` was created without expected data property 'bar'`); + assert.equal(warnings[0], ` was created without expected prop 'bar'`); console.warn = warn; } \ No newline at end of file diff --git a/test/js/samples/bind-width-height/expected.js b/test/js/samples/bind-width-height/expected.js index f97a6d81e5..d1396fe895 100644 --- a/test/js/samples/bind-width-height/expected.js +++ b/test/js/samples/bind-width-height/expected.js @@ -13,7 +13,7 @@ function create_fragment(component, ctx) { m(target, anchor) { insert(target, div, anchor); - div_resize_listener = addResizeListener(div, ctx.div_resize_handler); + div_resize_listener = addResizeListener(div, ctx.div_resize_handler.bind(div)); current = true; }, diff --git a/test/js/samples/debug-empty/expected.js b/test/js/samples/debug-empty/expected.js index 424221040a..9d7d110ca3 100644 --- a/test/js/samples/debug-empty/expected.js +++ b/test/js/samples/debug-empty/expected.js @@ -70,8 +70,9 @@ class SvelteComponent extends SvelteComponentDev { init(this, options, instance, create_fragment, safe_not_equal); const { ctx } = this.$$; - if (ctx.name === undefined) { - console.warn(" was created without expected data property 'name'"); + const props = options.props || {}; + if (ctx.name === undefined && !('name' in props)) { + console.warn(" was created without expected prop 'name'"); } } diff --git a/test/js/samples/debug-foo-bar-baz-things/expected.js b/test/js/samples/debug-foo-bar-baz-things/expected.js index c53273146e..3a1d6265e3 100644 --- a/test/js/samples/debug-foo-bar-baz-things/expected.js +++ b/test/js/samples/debug-foo-bar-baz-things/expected.js @@ -158,17 +158,18 @@ class SvelteComponent extends SvelteComponentDev { init(this, options, instance, create_fragment, safe_not_equal); const { ctx } = this.$$; - if (ctx.things === undefined) { - console.warn(" was created without expected data property 'things'"); + const props = options.props || {}; + if (ctx.things === undefined && !('things' in props)) { + console.warn(" was created without expected prop 'things'"); } - if (ctx.foo === undefined) { - console.warn(" was created without expected data property 'foo'"); + if (ctx.foo === undefined && !('foo' in props)) { + console.warn(" was created without expected prop 'foo'"); } - if (ctx.bar === undefined) { - console.warn(" was created without expected data property 'bar'"); + if (ctx.bar === undefined && !('bar' in props)) { + console.warn(" was created without expected prop 'bar'"); } - if (ctx.baz === undefined) { - console.warn(" was created without expected data property 'baz'"); + if (ctx.baz === undefined && !('baz' in props)) { + console.warn(" was created without expected prop 'baz'"); } } diff --git a/test/js/samples/debug-foo/expected.js b/test/js/samples/debug-foo/expected.js index 82df828323..92ca5ab9e1 100644 --- a/test/js/samples/debug-foo/expected.js +++ b/test/js/samples/debug-foo/expected.js @@ -156,11 +156,12 @@ class SvelteComponent extends SvelteComponentDev { init(this, options, instance, create_fragment, safe_not_equal); const { ctx } = this.$$; - if (ctx.things === undefined) { - console.warn(" was created without expected data property 'things'"); + const props = options.props || {}; + if (ctx.things === undefined && !('things' in props)) { + console.warn(" was created without expected prop 'things'"); } - if (ctx.foo === undefined) { - console.warn(" was created without expected data property 'foo'"); + if (ctx.foo === undefined && !('foo' in props)) { + console.warn(" was created without expected prop 'foo'"); } } diff --git a/test/js/samples/dev-warning-missing-data-computed/expected.js b/test/js/samples/dev-warning-missing-data-computed/expected.js index c77cac7174..95e85df1c1 100644 --- a/test/js/samples/dev-warning-missing-data-computed/expected.js +++ b/test/js/samples/dev-warning-missing-data-computed/expected.js @@ -76,8 +76,9 @@ class SvelteComponent extends SvelteComponentDev { init(this, options, instance, create_fragment, safe_not_equal); const { ctx } = this.$$; - if (ctx.foo === undefined) { - console.warn(" was created without expected data property 'foo'"); + const props = options.props || {}; + if (ctx.foo === undefined && !('foo' in props)) { + console.warn(" was created without expected prop 'foo'"); } } diff --git a/test/runtime/samples/binding-this-and-value/_config.js b/test/runtime/samples/binding-this-and-value/_config.js new file mode 100644 index 0000000000..70cc8d4110 --- /dev/null +++ b/test/runtime/samples/binding-this-and-value/_config.js @@ -0,0 +1,24 @@ +export default { + html: ` + +

value: initial

+ `, + + ssrHtml: ` + +

value: initial

+ `, + + async test({ assert, target, window }) { + const input = target.querySelector('input'); + const event = new window.Event('input'); + + input.value = 'changed'; + await input.dispatchEvent(event); + + assert.htmlEqual(target.innerHTML, ` + +

value: changed

+ `); + } +}; diff --git a/test/runtime/samples/binding-this-and-value/main.html b/test/runtime/samples/binding-this-and-value/main.html new file mode 100644 index 0000000000..c56509eb7a --- /dev/null +++ b/test/runtime/samples/binding-this-and-value/main.html @@ -0,0 +1,7 @@ + + + +

value: {value}

diff --git a/test/runtime/samples/dev-warning-missing-data-binding/_config.js b/test/runtime/samples/dev-warning-missing-data-binding/_config.js index e85ee3fbb6..ffe62384a1 100644 --- a/test/runtime/samples/dev-warning-missing-data-binding/_config.js +++ b/test/runtime/samples/dev-warning-missing-data-binding/_config.js @@ -4,6 +4,6 @@ export default { }, warnings: [ - ` was created without expected data property 'value'` + ` was created without expected prop 'value'` ] }; diff --git a/test/runtime/samples/dev-warning-missing-data-component/Foo.html b/test/runtime/samples/dev-warning-missing-data-component/Foo.html new file mode 100644 index 0000000000..8f26d21baf --- /dev/null +++ b/test/runtime/samples/dev-warning-missing-data-component/Foo.html @@ -0,0 +1 @@ +
{x} {y}
\ No newline at end of file diff --git a/test/runtime/samples/dev-warning-missing-data-component/_config.js b/test/runtime/samples/dev-warning-missing-data-component/_config.js new file mode 100644 index 0000000000..f3fc130528 --- /dev/null +++ b/test/runtime/samples/dev-warning-missing-data-component/_config.js @@ -0,0 +1,9 @@ +export default { + compileOptions: { + dev: true + }, + + warnings: [ + ` was created without expected prop 'y'` + ] +}; diff --git a/test/runtime/samples/dev-warning-missing-data-component/main.html b/test/runtime/samples/dev-warning-missing-data-component/main.html new file mode 100644 index 0000000000..2bda6e2937 --- /dev/null +++ b/test/runtime/samples/dev-warning-missing-data-component/main.html @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/dev-warning-missing-data/_config.js b/test/runtime/samples/dev-warning-missing-data/_config.js index aef14fd572..5bc6c8be1f 100644 --- a/test/runtime/samples/dev-warning-missing-data/_config.js +++ b/test/runtime/samples/dev-warning-missing-data/_config.js @@ -4,7 +4,7 @@ export default { }, warnings: [ - ` was created without expected data property 'foo'`, - ` was created without expected data property 'bar'` + ` was created without expected prop 'foo'`, + ` was created without expected prop 'bar'` ] }; diff --git a/test/runtime/samples/hash-in-attribute/_config.js b/test/runtime/samples/hash-in-attribute/_config.js new file mode 100644 index 0000000000..5e5726c48f --- /dev/null +++ b/test/runtime/samples/hash-in-attribute/_config.js @@ -0,0 +1,26 @@ +export default { + preserveIdentifiers: true, + + props: { + links: ['a', 'b', 'c'] + }, + + html: ` + x#a + x#b + x#c + `, + + test({ assert, component, target }) { + component.links = ['d', 'e', 'f']; + + const links = [...target.querySelectorAll('a')]; + assert.deepEqual(links.map(l => l.href), ['x#d', 'x#e', 'x#f']); + + assert.htmlEqual(target.innerHTML, ` + x#d + x#e + x#f + `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/hash-in-attribute/main.html b/test/runtime/samples/hash-in-attribute/main.html new file mode 100644 index 0000000000..0d1455b066 --- /dev/null +++ b/test/runtime/samples/hash-in-attribute/main.html @@ -0,0 +1,3 @@ +{#each links as link} + x#{link} +{/each} \ No newline at end of file diff --git a/transition.mjs b/transition.mjs new file mode 100644 index 0000000000..1b6fbec605 --- /dev/null +++ b/transition.mjs @@ -0,0 +1,82 @@ +import { cubicOut, cubicInOut } from './easing'; + +export function fade(node, { + delay = 0, + duration = 400 +}) { + const o = +getComputedStyle(node).opacity; + + return { + delay, + duration, + css: t => `opacity: ${t * o}` + }; +} + +export function fly(node, { + delay = 0, + duration = 400, + easing = cubicOut, + x = 0, + y = 0 +}) { + const style = getComputedStyle(node); + const opacity = +style.opacity; + const transform = style.transform === 'none' ? '' : style.transform; + + return { + delay, + duration, + easing, + css: t => ` + transform: ${transform} translate(${(1 - t) * x}px, ${(1 - t) * y}px); + opacity: ${t * opacity}` + }; +} + +export function slide(node, { + delay = 0, + duration = 400, + easing = cubicOut +}) { + const style = getComputedStyle(node); + const opacity = +style.opacity; + const height = parseFloat(style.height); + const padding_top = parseFloat(style.paddingTop); + const padding_bottom = parseFloat(style.paddingBottom); + const margin_top = parseFloat(style.marginTop); + const margin_bottom = parseFloat(style.marginBottom); + const border_top_width = parseFloat(style.borderTopWidth); + const border_bottom_width = parseFloat(style.borderBottomWidth); + + return { + delay, + duration, + easing, + css: t => + `overflow: hidden;` + + `opacity: ${Math.min(t * 20, 1) * opacity};` + + `height: ${t * height}px;` + + `padding-top: ${t * padding_top}px;` + + `padding-bottom: ${t * padding_bottom}px;` + + `margin-top: ${t * margin_top}px;` + + `margin-bottom: ${t * margin_bottom}px;` + + `border-top-width: ${t * border_top_width}px;` + + `border-bottom-width: ${t * border_bottom_width}px;` + }; +} + +export function draw(node, { + delay = 0, + duration = 800, + easing = cubicInOut +}) { + const len = node.getTotalLength(); + + return { + delay, + duration, + easing, + css: (t, u) => `stroke-dasharray: ${t * len} ${u * len}` + }; +} \ No newline at end of file