mirror of https://github.com/sveltejs/svelte
commit
0a07f95f9d
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
feat: use state proxy ancestry for ownership validation
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: make snippet effects transparent for transitions
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
fix: ensure bind:this unmount behavior for members is conditional
|
||||
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
let { item = $bindable() } = $props();
|
||||
</script>
|
||||
|
||||
<div bind:this={item.dom}>
|
||||
{item.text}
|
||||
</div>
|
||||
@ -0,0 +1,25 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target, component }) {
|
||||
const [b1, b2] = target.querySelectorAll('button');
|
||||
|
||||
flushSync(() => {
|
||||
b1.click();
|
||||
b1.click();
|
||||
b1.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<button>add item</button><button>clear</button><div>Item 1</div><div>Item 2</div><div>Item 3</div>`
|
||||
);
|
||||
|
||||
flushSync(() => {
|
||||
b2.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `<button>add item</button><button>clear</button>`);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
import Child from './Child.svelte';
|
||||
let items = $state([]);
|
||||
|
||||
function add_item() {
|
||||
items.push({
|
||||
id: items.length,
|
||||
text: 'Item ' + (items.length + 1),
|
||||
dom: null,
|
||||
})
|
||||
}
|
||||
|
||||
function clear() {
|
||||
items = [];
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={add_item}>add item</button>
|
||||
<button on:click={clear}>clear</button>
|
||||
|
||||
{#each items as item, index (item.id)}
|
||||
<Child bind:item={items[index]} />
|
||||
{/each}
|
||||
@ -0,0 +1,39 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
/** @type {typeof console.warn} */
|
||||
let warn;
|
||||
|
||||
/** @type {any[]} */
|
||||
let warnings = [];
|
||||
|
||||
export default test({
|
||||
html: `<button>clicks: 0</button>`,
|
||||
|
||||
compileOptions: {
|
||||
dev: true
|
||||
},
|
||||
|
||||
before_test: () => {
|
||||
warn = console.warn;
|
||||
|
||||
console.warn = (...args) => {
|
||||
warnings.push(...args);
|
||||
};
|
||||
},
|
||||
|
||||
after_test: () => {
|
||||
console.warn = warn;
|
||||
warnings = [];
|
||||
},
|
||||
|
||||
async test({ assert, target }) {
|
||||
const btn = target.querySelector('button');
|
||||
btn?.click();
|
||||
await tick();
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `<button>clicks: 1</button>`);
|
||||
|
||||
assert.deepEqual(warnings, []);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,3 @@
|
||||
<script>
|
||||
let { a = $bindable() } = $props();
|
||||
</script>
|
||||
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
import Child from './child.svelte';
|
||||
import { global } from './state.svelte.js';
|
||||
global.value.count = 0;
|
||||
</script>
|
||||
|
||||
<!-- binding shouldn't accidentally narrow ownership when it's already global -->
|
||||
<Child bind:a={global.value} />
|
||||
|
||||
<button onclick={() => global.value.count++}>
|
||||
clicks: {global.value.count}
|
||||
</button>
|
||||
@ -0,0 +1 @@
|
||||
export const global = $state({ value: { count: 0 } });
|
||||
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { getContext } from 'svelte';
|
||||
|
||||
const foo = getContext('foo')
|
||||
</script>
|
||||
|
||||
<button onclick={() => {
|
||||
foo.person.name.last = 'T';
|
||||
}}>mutate</button>
|
||||
@ -0,0 +1,35 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
/** @type {typeof console.warn} */
|
||||
let warn;
|
||||
|
||||
/** @type {any[]} */
|
||||
let warnings = [];
|
||||
|
||||
export default test({
|
||||
compileOptions: {
|
||||
dev: true
|
||||
},
|
||||
|
||||
before_test: () => {
|
||||
warn = console.warn;
|
||||
|
||||
console.warn = (...args) => {
|
||||
warnings.push(...args);
|
||||
};
|
||||
},
|
||||
|
||||
after_test: () => {
|
||||
console.warn = warn;
|
||||
warnings = [];
|
||||
},
|
||||
|
||||
async test({ assert, target }) {
|
||||
const btn = target.querySelector('button');
|
||||
|
||||
await btn?.click();
|
||||
await tick();
|
||||
assert.deepEqual(warnings.length, 0);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,17 @@
|
||||
<script>
|
||||
import { setContext } from 'svelte';
|
||||
import Child from './Child.svelte';
|
||||
|
||||
class Person {
|
||||
name = $state({
|
||||
first: 'Mr',
|
||||
last: 'Bean'
|
||||
});
|
||||
}
|
||||
|
||||
setContext('foo', {
|
||||
person: new Person()
|
||||
});
|
||||
</script>
|
||||
|
||||
<Child />
|
||||
@ -0,0 +1,8 @@
|
||||
<script>
|
||||
/** @type {{ object: { count: number }}} */
|
||||
let { object = $bindable() } = $props();
|
||||
</script>
|
||||
|
||||
<button onclick={() => object.count += 1}>
|
||||
clicks: {object.count}
|
||||
</button>
|
||||
@ -0,0 +1,8 @@
|
||||
<script>
|
||||
import Counter from './Counter.svelte';
|
||||
|
||||
/** @type {{ object: { count: number }}} */
|
||||
let { object } = $props();
|
||||
</script>
|
||||
|
||||
<Counter bind:object={object} />
|
||||
@ -0,0 +1,13 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `<button>clicks: 0</button>`,
|
||||
|
||||
compileOptions: {
|
||||
dev: true
|
||||
},
|
||||
|
||||
warnings: [
|
||||
'.../samples/non-local-mutation-with-binding-2/Intermediate.svelte passed a value to .../samples/non-local-mutation-with-binding-2/Counter.svelte with `bind:`, but the value is owned by .../samples/non-local-mutation-with-binding-2/main.svelte. Consider creating a binding between .../samples/non-local-mutation-with-binding-2/main.svelte and .../samples/non-local-mutation-with-binding-2/Intermediate.svelte'
|
||||
]
|
||||
});
|
||||
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
import Intermediate from './Intermediate.svelte';
|
||||
|
||||
let object = $state({ count: 0 });
|
||||
</script>
|
||||
|
||||
<Intermediate object={object} />
|
||||
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
/** @type {{ shared: { count: number }, notshared: { count: number } }} */
|
||||
let { shared = $bindable(), notshared } = $props();
|
||||
</script>
|
||||
|
||||
<button onclick={() => shared.count += 1}>
|
||||
clicks: {shared.count}
|
||||
</button>
|
||||
|
||||
<button onclick={() => notshared.count += 1}>
|
||||
clicks: {notshared.count}
|
||||
</button>
|
||||
@ -0,0 +1,53 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
/** @type {typeof console.warn} */
|
||||
let warn;
|
||||
|
||||
/** @type {typeof console.trace} */
|
||||
let trace;
|
||||
|
||||
/** @type {any[]} */
|
||||
let warnings = [];
|
||||
|
||||
export default test({
|
||||
html: `<button>clicks: 0</button><button>clicks: 0</button>`,
|
||||
|
||||
compileOptions: {
|
||||
dev: true
|
||||
},
|
||||
|
||||
before_test: () => {
|
||||
warn = console.warn;
|
||||
trace = console.trace;
|
||||
|
||||
console.warn = (...args) => {
|
||||
warnings.push(...args);
|
||||
};
|
||||
|
||||
console.trace = () => {};
|
||||
},
|
||||
|
||||
after_test: () => {
|
||||
console.warn = warn;
|
||||
console.trace = trace;
|
||||
|
||||
warnings = [];
|
||||
},
|
||||
|
||||
async test({ assert, target }) {
|
||||
const [btn1, btn2] = target.querySelectorAll('button');
|
||||
|
||||
flushSync(() => btn1.click());
|
||||
assert.htmlEqual(target.innerHTML, `<button>clicks: 1</button><button>clicks: 0</button>`);
|
||||
|
||||
assert.deepEqual(warnings, []);
|
||||
|
||||
flushSync(() => btn2.click());
|
||||
assert.htmlEqual(target.innerHTML, `<button>clicks: 1</button><button>clicks: 1</button>`);
|
||||
|
||||
assert.deepEqual(warnings, [
|
||||
'.../samples/non-local-mutation-with-binding-3/Counter.svelte mutated a value owned by .../samples/non-local-mutation-with-binding-3/main.svelte. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead.'
|
||||
]);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,13 @@
|
||||
<script>
|
||||
import Counter from './Counter.svelte';
|
||||
|
||||
let object = $state({
|
||||
shared: { count: 0 },
|
||||
notshared: { count: 0 }
|
||||
});
|
||||
</script>
|
||||
|
||||
<Counter
|
||||
bind:shared={object.shared}
|
||||
notshared={object.notshared}
|
||||
/>
|
||||
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
/** @type {{ children: import('svelte').Snippet }} */
|
||||
let { children } = $props();
|
||||
|
||||
let visible = $state(false);
|
||||
</script>
|
||||
|
||||
<button onclick={() => visible = !visible}>toggle</button>
|
||||
|
||||
{#if visible}
|
||||
{@render children()}
|
||||
{/if}
|
||||
@ -0,0 +1,20 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { ok, test } from '../../test';
|
||||
|
||||
export default test({
|
||||
test({ assert, target, raf }) {
|
||||
const button = target.querySelector('button');
|
||||
ok(button);
|
||||
|
||||
flushSync(() => button.click());
|
||||
raf.tick(50);
|
||||
assert.htmlEqual(target.innerHTML, '<button>toggle</button><p style="opacity: 0.5;">hello</p>');
|
||||
|
||||
flushSync(() => button.click());
|
||||
raf.tick(75);
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
'<button>toggle</button><p style="opacity: 0.25;">hello</p>'
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { fade } from 'svelte/transition';
|
||||
import { linear } from 'svelte/easing';
|
||||
import Container from './Container.svelte';
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<p style="opacity: 1" transition:fade={{ duration: 100, easing: linear }}>hello</p>
|
||||
</Container>
|
||||
Loading…
Reference in new issue