Merge branch 'master' into pr/5059

pull/5059/head
Conduitry 5 years ago
commit d4b0999c38

@ -2,10 +2,13 @@
## Unreleased ## Unreleased
* Fix placement of `{@html}` when used at the root of a slot or the root of a component ([#5012](https://github.com/sveltejs/svelte/issues/5012))
* Fix handling of `import`ed value that is used as a store and is also mutated ([#5019](https://github.com/sveltejs/svelte/issues/5019)) * Fix handling of `import`ed value that is used as a store and is also mutated ([#5019](https://github.com/sveltejs/svelte/issues/5019))
* Do not display `a11y-missing-content` warning on elements with `contenteditable` bindings ([#5020](https://github.com/sveltejs/svelte/issues/5020)) * Do not display `a11y-missing-content` warning on elements with `contenteditable` bindings ([#5020](https://github.com/sveltejs/svelte/issues/5020))
* Fix handling of `this` in inline function expressions in the template ([#5033](https://github.com/sveltejs/svelte/issues/5033)) * Fix handling of `this` in inline function expressions in the template ([#5033](https://github.com/sveltejs/svelte/issues/5033))
* Update `<select>` with one-way `value` binding when the available `<option>`s change ([#5051](https://github.com/sveltejs/svelte/issues/5051)) * Update `<select>` with one-way `value` binding when the available `<option>`s change ([#5051](https://github.com/sveltejs/svelte/issues/5051))
* Fix published `tweened` types so the `.set()` and `.update()` options are optional ([#5062](https://github.com/sveltejs/svelte/issues/5062))
* Fix contextual `bind:this` inside `{#each}` block ([#5067](https://github.com/sveltejs/svelte/issues/5067))
## 3.23.2 ## 3.23.2

@ -13,6 +13,10 @@ const mode = process.env.NODE_ENV;
const dev = mode === 'development'; const dev = mode === 'development';
const legacy = !!process.env.SAPPER_LEGACY_BUILD; const legacy = !!process.env.SAPPER_LEGACY_BUILD;
if (!dev && !process.env.MAPBOX_ACCESS_TOKEN) {
throw new Error('MAPBOX_ACCESS_TOKEN is missing. Please add the token in the .env file before generating the production build.');
}
const onwarn = (warning, onwarn) => (warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) || onwarn(warning); const onwarn = (warning, onwarn) => (warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) || onwarn(warning);
const dedupe = importee => importee === 'svelte' || importee.startsWith('svelte/'); const dedupe = importee => importee === 'svelte' || importee.startsWith('svelte/');

@ -39,7 +39,7 @@ export default class RawMustacheTagWrapper extends Tag {
} }
else { else {
const needs_anchor = in_head || (this.next && !this.next.is_dom_node()); const needs_anchor = in_head || (this.next ? !this.next.is_dom_node() : (!this.parent || !this.parent.is_dom_node()));
const html_tag = block.get_unique_name('html_tag'); const html_tag = block.get_unique_name('html_tag');
const html_anchor = needs_anchor && block.get_unique_name('html_anchor'); const html_anchor = needs_anchor && block.get_unique_name('html_anchor');

@ -11,7 +11,7 @@ export default function bind_this(component: Component, block: Block, binding: B
block.renderer.add_to_context(fn.name); block.renderer.add_to_context(fn.name);
const callee = block.renderer.reference(fn.name); const callee = block.renderer.reference(fn.name);
const { contextual_dependencies, mutation, lhs } = binding.handler; const { contextual_dependencies, mutation } = binding.handler;
const dependencies = binding.get_dependencies(); const dependencies = binding.get_dependencies();
const body = b` const body = b`
@ -29,7 +29,6 @@ export default function bind_this(component: Component, block: Block, binding: B
})); }));
component.partly_hoisted.push(b` component.partly_hoisted.push(b`
function ${fn}($$value, ${params}) { function ${fn}($$value, ${params}) {
if (${lhs} === $$value) return;
@binding_callbacks[$$value ? 'unshift' : 'push'](() => { @binding_callbacks[$$value ? 'unshift' : 'push'](() => {
${body} ${body}
}); });

@ -64,9 +64,9 @@ interface Options<T> {
type Updater<T> = (target_value: T, value: T) => T; type Updater<T> = (target_value: T, value: T) => T;
interface Tweened<T> extends Readable<T> { interface Tweened<T> extends Readable<T> {
set(value: T, opts: Options<T>): Promise<void>; set(value: T, opts?: Options<T>): Promise<void>;
update(updater: Updater<T>, opts: Options<T>): Promise<void>; update(updater: Updater<T>, opts?: Options<T>): Promise<void>;
} }
export function tweened<T>(value?: T, defaults: Options<T> = {}): Tweened<T> { export function tweened<T>(value?: T, defaults: Options<T> = {}): Tweened<T> {
@ -75,7 +75,7 @@ export function tweened<T>(value?: T, defaults: Options<T> = {}): Tweened<T> {
let task: Task; let task: Task;
let target_value = value; let target_value = value;
function set(new_value: T, opts: Options<T>) { function set(new_value: T, opts?: Options<T>) {
if (value == null) { if (value == null) {
store.set(value = new_value); store.set(value = new_value);
return Promise.resolve(); return Promise.resolve();
@ -137,7 +137,7 @@ export function tweened<T>(value?: T, defaults: Options<T> = {}): Tweened<T> {
return { return {
set, set,
update: (fn, opts: Options<T>) => set(fn(target_value, value), opts), update: (fn, opts?: Options<T>) => set(fn(target_value, value), opts),
subscribe: store.subscribe subscribe: store.subscribe
}; };
} }

@ -0,0 +1,53 @@
let calls = [];
function callback(refs) {
calls.push(refs.map(({ ref }) => ({ ref })));
}
export default {
html: ``,
props: {
callback,
},
after_test() {
calls = [];
},
async test({ assert, component, target }) {
assert.equal(calls.length, 1);
assert.equal(calls[0].length, 0);
await component.addItem();
let divs = target.querySelectorAll("div");
assert.equal(calls.length, 3);
assert.equal(calls[1].length, 1);
assert.equal(calls[1][0].ref, null);
assert.equal(calls[2].length, 1);
assert.equal(calls[2][0].ref, divs[0]);
await component.addItem();
divs = target.querySelectorAll("div");
assert.equal(calls.length, 5);
assert.equal(calls[3].length, 2);
assert.equal(calls[3][0].ref, divs[0]);
assert.equal(calls[3][1].ref, null);
assert.equal(calls[4].length, 2);
assert.equal(calls[4][0].ref, divs[0]);
assert.equal(calls[4][1].ref, divs[1]);
await component.addItem();
divs = target.querySelectorAll("div");
assert.equal(calls.length, 7);
assert.equal(calls[5].length, 3);
assert.equal(calls[5][0].ref, divs[0]);
assert.equal(calls[5][1].ref, divs[1]);
assert.equal(calls[5][2].ref, null);
assert.equal(calls[6].length, 3);
assert.equal(calls[6][0].ref, divs[0]);
assert.equal(calls[6][1].ref, divs[1]);
assert.equal(calls[6][2].ref, divs[2]);
},
};

@ -0,0 +1,17 @@
<script>
import { tick } from 'svelte';
let refs = [];
export function addItem() {
refs = refs.concat({ ref: null });
return tick();
}
export let callback;
$: callback(refs);
</script>
{#each refs as xxx}
<div bind:this={xxx.ref} />
{/each}

@ -0,0 +1,5 @@
<script>
export let content;
</script>
{@html content}

@ -0,0 +1,33 @@
export default {
html: `
<button>Switch</button>
<p>Another first line</p>
<p>This line should be last.</p>
`,
async test({ assert, target, window }) {
const btn = target.querySelector("button");
const clickEvent = new window.MouseEvent("click");
await btn.dispatchEvent(clickEvent);
assert.htmlEqual(
target.innerHTML,
`
<button>Switch</button>
<p>First line</p>
<p>This line should be last.</p>
`
);
await btn.dispatchEvent(clickEvent);
assert.htmlEqual(
target.innerHTML,
`
<button>Switch</button>
<p>Another first line</p>
<p>This line should be last.</p>
`
);
},
};

@ -0,0 +1,17 @@
<script>
import RawMustache from './RawMustache.svelte';
let content1 = `<p>First line</p>`;
let content2 = `<p>Another first line</p>`;
let show = false;
$: content = show ? content1 : content2;
</script>
<button on:click={() => show = !show}>
Switch
</button>
<RawMustache {content} />
<p>This line should be last.</p>

@ -0,0 +1,2 @@
<slot />
<p>This line should be last.</p>

@ -1,3 +1,33 @@
export default { export default {
html: `<p>x<span>baz</span></p>` html: `
<button>Switch</button>
<p>Another first line</p>
<p>This line should be last.</p>
`,
async test({ assert, target, window }) {
const btn = target.querySelector("button");
const clickEvent = new window.MouseEvent("click");
await btn.dispatchEvent(clickEvent);
assert.htmlEqual(
target.innerHTML,
`
<button>Switch</button>
<p>First line</p>
<p>This line should be last.</p>
`
);
await btn.dispatchEvent(clickEvent);
assert.htmlEqual(
target.innerHTML,
`
<button>Switch</button>
<p>Another first line</p>
<p>This line should be last.</p>
`
);
},
}; };

@ -1 +1,17 @@
<p>{@html 'x'}<span>baz</span></p> <script>
import Component from './Component.svelte';
let content1 = `<p>First line</p>`;
let content2 = `<p>Another first line</p>`
let show = false;
$: content = show ? content1 : content2;
</script>
<button on:click={() => show = !show}>
Switch
</button>
<Component>
{@html content}
</Component>

@ -0,0 +1,3 @@
export default {
html: `<p>x<span>baz</span></p>`
};

@ -0,0 +1 @@
<p>{@html 'x'}<span>baz</span></p>
Loading…
Cancel
Save