Merge branch 'master' into pr/4634

pull/4699/head
Conduitry 6 years ago
commit a0d86dcfe3

@ -2,6 +2,9 @@
## Unreleased ## Unreleased
* Support dimension bindings in cross-origin environments ([#2147](https://github.com/sveltejs/svelte/issues/2147))
* Try using `globalThis` rather than `globals` for the benefit of non-Node servers and web workers ([#3561](https://github.com/sveltejs/svelte/issues/3561), [#4545](https://github.com/sveltejs/svelte/issues/4545))
* Support `{#await ... catch ...}` syntax shorthand ([#3623](https://github.com/sveltejs/svelte/issues/3623))
* Fix attaching of JS debugging comments to HTML comments ([#4565](https://github.com/sveltejs/svelte/issues/4565)) * Fix attaching of JS debugging comments to HTML comments ([#4565](https://github.com/sveltejs/svelte/issues/4565))
## 3.20.1 ## 3.20.1

@ -893,7 +893,7 @@ A custom transition function can also return a `tick` function, which is called
function typewriter(node, { speed = 50 }) { function typewriter(node, { speed = 50 }) {
const valid = ( const valid = (
node.childNodes.length === 1 && node.childNodes.length === 1 &&
node.childNodes[0].nodeType === 3 node.childNodes[0].nodeType === Node.TEXT_NODE
); );
if (!valid) return {}; if (!valid) return {};

@ -804,7 +804,7 @@ You can see a full example on the [animations tutorial](tutorial/animate)
### `svelte/easing` ### `svelte/easing`
Easing functions specificy the rate of change over time and are useful when working with Svelte's built-in transitions and animations as well as the tweened and spring utilities. `svelte/easing` contains 31 named exports, a `linear` ease and 3 variants of 10 different easing functions: `in`, `out` and `inOut`. Easing functions specify the rate of change over time and are useful when working with Svelte's built-in transitions and animations as well as the tweened and spring utilities. `svelte/easing` contains 31 named exports, a `linear` ease and 3 variants of 10 different easing functions: `in`, `out` and `inOut`.
You can explore the various eases using the [ease visualiser](examples#easing) in the [examples section](examples). You can explore the various eases using the [ease visualiser](examples#easing) in the [examples section](examples).

@ -18,7 +18,7 @@
Remove first thing Remove first thing
</button> </button>
<div style="display: grid; grid-template-columns: 1fr 1fr; grip-gap: 1em"> <div style="display: grid; grid-template-columns: 1fr 1fr; grid-gap: 1em">
<div> <div>
<h2>Keyed</h2> <h2>Keyed</h2>
{#each things as thing (thing.id)} {#each things as thing (thing.id)}

@ -4,7 +4,7 @@
function typewriter(node, { speed = 50 }) { function typewriter(node, { speed = 50 }) {
const valid = ( const valid = (
node.childNodes.length === 1 && node.childNodes.length === 1 &&
node.childNodes[0].nodeType === 3 node.childNodes[0].nodeType === Node.TEXT_NODE
); );
if (!valid) { if (!valid) {

@ -3,6 +3,8 @@
export let item; export let item;
export let returnTo; export let returnTo;
$: url = !item.domain ? `https://news.ycombinator.com/${item.url}` : item.url;
</script> </script>
<style> <style>
@ -24,9 +26,11 @@
<a href={returnTo}>&laquo; back</a> <a href={returnTo}>&laquo; back</a>
<article> <article>
<a href="{item.url}"> <a href="{url}">
<h1>{item.title}</h1> <h1>{item.title}</h1>
{#if item.domain}
<small>{item.domain}</small> <small>{item.domain}</small>
{/if}
</a> </a>
<p class="meta">submitted by {item.user} {item.time_ago} <p class="meta">submitted by {item.user} {item.time_ago}

@ -7,6 +7,8 @@
const c = item.comments_count; const c = item.comments_count;
return `${c} ${c === 1 ? 'comment' : 'comments'}`; return `${c} ${c === 1 ? 'comment' : 'comments'}`;
} }
$: url = item.type === "ask" ? `https://news.ycombinator.com/${item.url}` : item.url;
</script> </script>
<style> <style>
@ -33,6 +35,6 @@
<article> <article>
<span>{i + offset + 1}</span> <span>{i + offset + 1}</span>
<h2><a target="_blank" href={item.url}>{item.title}</a></h2> <h2><a target="_blank" href={url}>{item.title}</a></h2>
<p class="meta"><a href="#/item/{item.id}">{comment_text()}</a> by {item.user} {item.time_ago}</p> <p class="meta"><a href="#/item/{item.id}">{comment_text()}</a> by {item.user} {item.time_ago}</p>
</article> </article>

@ -20,3 +20,5 @@ Add a `<script>` tag that imports `Nested.svelte`...
``` ```
Notice that even though `Nested.svelte` has a `<p>` element, the styles from `App.svelte` don't leak in. Notice that even though `Nested.svelte` has a `<p>` element, the styles from `App.svelte` don't leak in.
Also notice that the component name `Nested` is capitalised. This convention has been adopted to allow us to differentiate between user-defined components and regular HTML tags.

@ -4,7 +4,7 @@
function typewriter(node, { speed = 50 }) { function typewriter(node, { speed = 50 }) {
const valid = ( const valid = (
node.childNodes.length === 1 && node.childNodes.length === 1 &&
node.childNodes[0].nodeType === 3 node.childNodes[0].nodeType === Node.TEXT_NODE
); );
if (!valid) { if (!valid) {

@ -8,7 +8,7 @@ While you should generally use CSS for transitions as much as possible, there ar
function typewriter(node, { speed = 50 }) { function typewriter(node, { speed = 50 }) {
const valid = ( const valid = (
node.childNodes.length === 1 && node.childNodes.length === 1 &&
node.childNodes[0].nodeType === 3 node.childNodes[0].nodeType === Node.TEXT_NODE
); );
if (!valid) { if (!valid) {

@ -1291,13 +1291,14 @@
} }
}, },
"@sveltejs/svelte-repl": { "@sveltejs/svelte-repl": {
"version": "0.1.17", "version": "0.1.18",
"resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.1.17.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.1.18.tgz",
"integrity": "sha512-rM0DC+pZnqwH6PiuxXUmFRwYZ9XNkexxTNt+prR91Qs7ssxGgf0QkH6kGivSNLbrOtOvcgJbt1nUDybWra5HKA==", "integrity": "sha512-b1psPdlJ9qRqn28l+sPSma6OSfilue0dGK4BcS75MOsfdjZjSvsc0AIAoriQ3q1mB/frCoyUri6nxFGgEKv0iQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"codemirror": "^5.49.2", "codemirror": "^5.49.2",
"estree-walker": "^0.9.0", "estree-walker": "^0.9.0",
"marked": "^0.8.2",
"sourcemap-codec": "^1.4.6", "sourcemap-codec": "^1.4.6",
"svelte-json-tree": "0.0.5", "svelte-json-tree": "0.0.5",
"yootils": "0.0.16" "yootils": "0.0.16"
@ -1309,10 +1310,16 @@
"integrity": "sha512-12U47o7XHUX329+x3FzNVjCx3SHEzMF0nkDv7r/HnBzX/xNTKxajBk6gyygaxrAFtLj39219oMfbtxv4KpaOiA==", "integrity": "sha512-12U47o7XHUX329+x3FzNVjCx3SHEzMF0nkDv7r/HnBzX/xNTKxajBk6gyygaxrAFtLj39219oMfbtxv4KpaOiA==",
"dev": true "dev": true
}, },
"marked": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz",
"integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==",
"dev": true
},
"sourcemap-codec": { "sourcemap-codec": {
"version": "1.4.6", "version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==", "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"dev": true "dev": true
} }
} }
@ -1594,9 +1601,9 @@
"dev": true "dev": true
}, },
"codemirror": { "codemirror": {
"version": "5.49.2", "version": "5.52.2",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.49.2.tgz", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.52.2.tgz",
"integrity": "sha512-dwJ2HRPHm8w51WB5YTF9J7m6Z5dtkqbU9ntMZ1dqXyFB9IpjoUFDj80ahRVEoVanfIp6pfASJbOlbWdEf8FOzQ==", "integrity": "sha512-WCGCixNUck2HGvY8/ZNI1jYfxPG5cRHv0VjmWuNzbtCLz8qYA5d+je4QhSSCtCaagyeOwMi/HmmPTjBgiTm2lQ==",
"dev": true "dev": true
}, },
"color-convert": { "color-convert": {

@ -36,7 +36,7 @@
"@babel/runtime": "^7.6.0", "@babel/runtime": "^7.6.0",
"@sindresorhus/slugify": "^0.9.1", "@sindresorhus/slugify": "^0.9.1",
"@sveltejs/site-kit": "^1.1.4", "@sveltejs/site-kit": "^1.1.4",
"@sveltejs/svelte-repl": "^0.1.17", "@sveltejs/svelte-repl": "^0.1.18",
"degit": "^2.1.4", "degit": "^2.1.4",
"dotenv": "^8.1.0", "dotenv": "^8.1.0",
"esm": "^3.2.25", "esm": "^3.2.25",

@ -1216,7 +1216,6 @@ export default class Component {
}); });
const lookup = new Map(); const lookup = new Map();
let seen;
unsorted_reactive_declarations.forEach(declaration => { unsorted_reactive_declarations.forEach(declaration => {
declaration.assignees.forEach(name => { declaration.assignees.forEach(name => {
@ -1251,28 +1250,19 @@ export default class Component {
} }
const add_declaration = declaration => { const add_declaration = declaration => {
if (this.reactive_declarations.indexOf(declaration) !== -1) { if (this.reactive_declarations.includes(declaration)) return;
return;
}
seen.add(declaration);
declaration.dependencies.forEach(name => { declaration.dependencies.forEach(name => {
if (declaration.assignees.has(name)) return; if (declaration.assignees.has(name)) return;
const earlier_declarations = lookup.get(name); const earlier_declarations = lookup.get(name);
if (earlier_declarations) if (earlier_declarations)
earlier_declarations.forEach(declaration => { earlier_declarations.forEach(add_declaration);
add_declaration(declaration);
});
}); });
this.reactive_declarations.push(declaration); this.reactive_declarations.push(declaration);
}; };
unsorted_reactive_declarations.forEach(declaration => { unsorted_reactive_declarations.forEach(add_declaration);
seen = new Set();
add_declaration(declaration);
});
} }
warn_if_undefined(name: string, node, template_scope: TemplateScope) { warn_if_undefined(name: string, node, template_scope: TemplateScope) {

@ -586,7 +586,7 @@ export default class ElementWrapper extends Wrapper {
); );
block.chunks.destroy.push( block.chunks.destroy.push(
b`${resize_listener}.cancel();` b`${resize_listener}();`
); );
} else { } else {
block.event_listeners.push( block.event_listeners.push(

@ -309,6 +309,13 @@ export default function mustache(parser: Parser) {
parser.allow_whitespace(); parser.allow_whitespace();
} }
const await_block_catch_shorthand = !await_block_shorthand && type === 'AwaitBlock' && parser.eat('catch');
if (await_block_catch_shorthand) {
parser.require_whitespace();
block.error = parser.read_destructure_pattern();
parser.allow_whitespace();
}
parser.eat('}', true); parser.eat('}', true);
parser.current().children.push(block); parser.current().children.push(block);
@ -319,6 +326,9 @@ export default function mustache(parser: Parser) {
if (await_block_shorthand) { if (await_block_shorthand) {
block.then.skip = false; block.then.skip = false;
child_block = block.then; child_block = block.then;
} else if (await_block_catch_shorthand) {
block.catch.skip = false;
child_block = block.catch;
} else { } else {
block.pending.skip = false; block.pending.skip = false;
child_block = block.pending; child_block = block.pending;

@ -57,7 +57,7 @@ export function empty() {
return text(''); return text('');
} }
export function listen(node: Node, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | EventListenerOptions) { export function listen(node: EventTarget, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | EventListenerOptions) {
node.addEventListener(event, handler, options); node.addEventListener(event, handler, options);
return () => node.removeEventListener(event, handler, options); return () => node.removeEventListener(event, handler, options);
} }
@ -234,37 +234,61 @@ export function select_multiple_value(select) {
return [].map.call(select.querySelectorAll(':checked'), option => option.__value); return [].map.call(select.querySelectorAll(':checked'), option => option.__value);
} }
export function add_resize_listener(element, fn) { // unfortunately this can't be a constant as that wouldn't be tree-shakeable
if (getComputedStyle(element).position === 'static') { // so we cache the result instead
element.style.position = 'relative'; let crossorigin: boolean;
export function is_crossorigin() {
if (crossorigin === undefined) {
crossorigin = false;
try {
if (typeof window !== 'undefined' && window.parent) {
void window.parent.document;
}
} catch (error) {
crossorigin = true;
}
} }
const object = document.createElement('object'); return crossorigin;
object.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;'); }
object.setAttribute('aria-hidden', 'true');
object.type = 'text/html';
object.tabIndex = -1;
let win; export function add_resize_listener(node: HTMLElement, fn: () => void) {
const computed_style = getComputedStyle(node);
const z_index = (parseInt(computed_style.zIndex) || 0) - 1;
object.onload = () => { if (computed_style.position === 'static') {
win = object.contentDocument.defaultView; node.style.position = 'relative';
win.addEventListener('resize', fn); }
};
if (/Trident/.test(navigator.userAgent)) { const iframe = element('iframe');
element.appendChild(object); iframe.setAttribute('style',
object.data = 'about:blank'; `display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; ` +
`overflow: hidden; border: 0; opacity: 0; pointer-events: none; z-index: ${z_index};`
);
iframe.setAttribute('aria-hidden', 'true');
iframe.tabIndex = -1;
let unsubscribe: () => void;
if (is_crossorigin()) {
iframe.src = `data:text/html,<script>onresize=function(){parent.postMessage(0,'*')}</script>`;
unsubscribe = listen(window, 'message', (event: MessageEvent) => {
if (event.source === iframe.contentWindow) fn();
});
} else { } else {
object.data = 'about:blank'; iframe.src = 'about:blank';
element.appendChild(object); iframe.onload = () => {
unsubscribe = listen(iframe.contentWindow, 'resize', fn);
};
} }
return { append(node, iframe);
cancel: () => {
win && win.removeEventListener && win.removeEventListener('resize', fn); return () => {
element.removeChild(object); detach(iframe);
} if (unsubscribe) unsubscribe();
}; };
} }

@ -1,3 +1,7 @@
declare const global: any; declare const global: any;
export const globals = (typeof window !== 'undefined' ? window : global) as unknown as typeof globalThis; export const globals = (typeof window !== 'undefined'
? window
: typeof globalThis !== 'undefined'
? globalThis
: global) as unknown as typeof globalThis;

@ -30,7 +30,7 @@ function create_fragment(ctx) {
o: noop, o: noop,
d(detaching) { d(detaching) {
if (detaching) detach(div); if (detaching) detach(div);
div_resize_listener.cancel(); div_resize_listener();
} }
}; };
} }

@ -59,7 +59,7 @@ function create_fragment(ctx) {
o: noop, o: noop,
d(detaching) { d(detaching) {
if (detaching) detach(video); if (detaching) detach(video);
video_resize_listener.cancel(); video_resize_listener();
run_all(dispose); run_all(dispose);
} }
}; };

@ -0,0 +1,41 @@
let fulfil;
let thePromise = new Promise(f => {
fulfil = f;
});
export default {
props: {
thePromise
},
html: ``,
test({ assert, component, target }) {
fulfil(42);
return thePromise
.then(() => {
assert.htmlEqual(target.innerHTML, ``);
let reject;
thePromise = new Promise((f, r) => {
reject = r;
});
component.thePromise = thePromise;
assert.htmlEqual(target.innerHTML, ``);
reject(new Error('something broke'));
return thePromise.catch(() => {});
})
.then(() => {
assert.htmlEqual(target.innerHTML, `
<p>oh no! something broke</p>
`);
});
}
};

@ -0,0 +1,7 @@
<script>
export let thePromise;
</script>
{#await thePromise catch theError}
<p>oh no! {theError.message}</p>
{/await}

@ -1,8 +1,8 @@
export default { export default {
async test({ assert, target }) { async test({ assert, target }) {
const object = target.querySelector('object'); const iframe = target.querySelector('iframe');
assert.equal(object.getAttribute('aria-hidden'), "true"); assert.equal(iframe.getAttribute('aria-hidden'), "true");
assert.equal(object.getAttribute('tabindex'), "-1"); assert.equal(iframe.getAttribute('tabindex'), "-1");
} }
}; };

@ -0,0 +1,7 @@
<script>
let promise;
</script>
{#await promise catch error}
<p>Error: {error}</p>
{/await}
Loading…
Cancel
Save