mirror of https://github.com/sveltejs/svelte
commit
af6419bd15
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
perf: reuse the cached value in the `<option>`/`<select>` value guard
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: prevent malformed AST output for `<select>` with static `value` attribute
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: apply ownership mutation ignores to binding assignments
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
perf: fold SSR block-open markers into the branch's first push
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: report `derived_invalid_export` for `export let x = $derived(...)` in runes mode
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: keep `defaultChecked` on hydrated radio inputs with spread attributes
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: measure nested transitions before applying their starting styles
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
perf: emit `$.only_child` for elements with a single child
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: more robust rendering of Svelte custom element slots
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: end a restored reaction context at the end of its synchronous segment
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: keep the dependencies of a reaction that throws, so deriveds it read are neither leaked nor stuck in their error
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
perf: use `$.comment()` for single-comment templates
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
perf: store setters cache as `Set` instead of `Array`
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: transform derived assignments and select function bindings correctly during server-side rendering
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: keep boolean attributes with an empty string value when rendering attribute objects on the server
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: sync `SvelteURL` port signal when the protocol setter clears the port
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': minor
|
||||
---
|
||||
|
||||
feat: support `defaultValue` on `<select>`
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: block declaration tags and `{@const}` on async values read inside closures
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: avoid css tree-shaking for exported Snippet
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
perf: treat `<img loading>` as a static element again
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: preserve line feed character references in attribute values
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: decode uppercase-`X` hex numeric character references (`&#X...;`)
|
||||
@ -0,0 +1,9 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
error: {
|
||||
code: 'derived_invalid_export',
|
||||
message:
|
||||
'Cannot export derived state from a module. To expose the current derived value, export a function returning its value'
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,4 @@
|
||||
<script>
|
||||
let count = $state(0);
|
||||
export let double = $derived(count * 2);
|
||||
</script>
|
||||
@ -0,0 +1,5 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
hasGlobal: true
|
||||
});
|
||||
@ -0,0 +1,4 @@
|
||||
|
||||
.inner.svelte-xyz {
|
||||
color: red;
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
<script module>
|
||||
export { outer };
|
||||
</script>
|
||||
|
||||
{#snippet outer()}
|
||||
<p class="inner"></p>
|
||||
{/snippet}
|
||||
|
||||
<style>
|
||||
.inner {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1 @@
|
||||
<p title="A
B">A
B</p>
|
||||
@ -0,0 +1,53 @@
|
||||
{
|
||||
"html": {
|
||||
"type": "Fragment",
|
||||
"start": 0,
|
||||
"end": 32,
|
||||
"children": [
|
||||
{
|
||||
"type": "Element",
|
||||
"start": 0,
|
||||
"end": 32,
|
||||
"name": "p",
|
||||
"attributes": [
|
||||
{
|
||||
"type": "Attribute",
|
||||
"start": 3,
|
||||
"end": 19,
|
||||
"name": "title",
|
||||
"name_loc": {
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 3,
|
||||
"character": 3
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 8,
|
||||
"character": 8
|
||||
}
|
||||
},
|
||||
"value": [
|
||||
{
|
||||
"start": 10,
|
||||
"end": 18,
|
||||
"type": "Text",
|
||||
"raw": "A
B",
|
||||
"data": "A\nB"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"type": "Text",
|
||||
"start": 20,
|
||||
"end": 28,
|
||||
"raw": "A
B",
|
||||
"data": "A B"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
import Nested from './Nested.svelte';
|
||||
import { slide } from 'svelte/transition';
|
||||
|
||||
let { depth } = $props();
|
||||
</script>
|
||||
|
||||
<div class="level-{depth}" in:slide|global={{ duration: 100 }}>
|
||||
{#if depth > 0}
|
||||
<Nested depth={depth - 1} />
|
||||
{:else}
|
||||
<div style="height: 100px">leaf</div>
|
||||
{/if}
|
||||
</div>
|
||||
@ -0,0 +1,36 @@
|
||||
import { test } from '../../assert';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
const button = target.querySelector('button');
|
||||
button?.click();
|
||||
|
||||
// wait for the transition's keyframes to be created
|
||||
const animation = await new Promise((resolve, reject) => {
|
||||
const start = performance.now();
|
||||
|
||||
function check() {
|
||||
const outer = target.querySelector('.level-2');
|
||||
const animation = outer
|
||||
?.getAnimations()
|
||||
.find((a) => a.effect?.getTiming().duration === 100);
|
||||
|
||||
if (animation) {
|
||||
resolve(animation);
|
||||
} else if (performance.now() - start > 2000) {
|
||||
reject(new Error('timed out waiting for the transition to start'));
|
||||
} else {
|
||||
requestAnimationFrame(check);
|
||||
}
|
||||
}
|
||||
|
||||
check();
|
||||
});
|
||||
|
||||
// the outermost `slide` must have measured the element with its
|
||||
// descendants at their natural size, not collapsed to zero by their
|
||||
// own starting styles (#18421)
|
||||
const keyframes = animation.effect?.getKeyframes() ?? [];
|
||||
assert.equal(keyframes[keyframes.length - 1].height, '100px');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
import Nested from './Nested.svelte';
|
||||
|
||||
let visible = $state(false);
|
||||
</script>
|
||||
|
||||
<button onclick={() => (visible = !visible)}>toggle</button>
|
||||
|
||||
{#if visible}
|
||||
<Nested depth={2} />
|
||||
{/if}
|
||||
@ -0,0 +1,10 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
// #18469 — a @const in a nested snippet reading an async declaration through a closure must block on it
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, '<p>true</p> <p>false</p>');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
async function getValue() {
|
||||
return new Set(['a', 'b', 'c']);
|
||||
}
|
||||
|
||||
const value = await getValue();
|
||||
</script>
|
||||
|
||||
{#each [['a', 'b'], ['a', 'x']] as keys}
|
||||
{@const all_present = keys.every((k) => value.has(k))}
|
||||
<p>{all_present}</p>
|
||||
{/each}
|
||||
@ -0,0 +1,11 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
// #18469 — a sync $derived in a nested snippet reading an async declaration through a closure must block on it
|
||||
export default test({
|
||||
ssrHtml: '<p>true</p> <p>false</p>',
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, '<p>true</p> <p>false</p>');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,17 @@
|
||||
<script>
|
||||
async function getValue() {
|
||||
return new Set(['a', 'b', 'c']);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#snippet outer()}
|
||||
{const value = $derived(await getValue())}
|
||||
{#snippet inner(keys)}
|
||||
{const all_present = $derived(keys.every((k) => value.has(k)))}
|
||||
<p>{all_present}</p>
|
||||
{/snippet}
|
||||
{@render inner(['a', 'b'])}
|
||||
{@render inner(['a', 'x'])}
|
||||
{/snippet}
|
||||
|
||||
{@render outer()}
|
||||
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
const { environment } = $props();
|
||||
|
||||
if (environment === 'client') {
|
||||
throw new Error('oops');
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,14 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
mode: ['hydrate'],
|
||||
server_props: { environment: 'server' },
|
||||
props: { environment: 'client' },
|
||||
ssrHtml: 'loading inner loading nested',
|
||||
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, 'inner failed: oops outer failed: oops');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,24 @@
|
||||
<script>
|
||||
import Child from './Child.svelte';
|
||||
|
||||
const { environment } = $props();
|
||||
</script>
|
||||
|
||||
<svelte:boundary>
|
||||
<Child {environment} />
|
||||
{await new Promise(() => {})}
|
||||
|
||||
{#snippet pending()}loading inner{/snippet}
|
||||
{#snippet failed(error)}inner failed: {error.message}{/snippet}
|
||||
</svelte:boundary>
|
||||
|
||||
<svelte:boundary>
|
||||
<svelte:boundary>
|
||||
<Child {environment} />
|
||||
{await new Promise(() => {})}
|
||||
|
||||
{#snippet pending()}loading nested{/snippet}
|
||||
</svelte:boundary>
|
||||
|
||||
{#snippet failed(error)}outer failed: {error.message}{/snippet}
|
||||
</svelte:boundary>
|
||||
@ -0,0 +1,20 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
compileOptions: {
|
||||
dev: true
|
||||
},
|
||||
|
||||
async test({ assert, target, errors }) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 20));
|
||||
await tick();
|
||||
|
||||
assert.deepEqual(
|
||||
errors.filter((error) => error.includes('state_unsafe_mutation')),
|
||||
[]
|
||||
);
|
||||
assert.htmlEqual(target.innerHTML, '<p>pending</p><p>1</p>');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
let foreign = $state(0);
|
||||
const input = Promise.resolve({ pending: new Promise(() => {}) });
|
||||
|
||||
setTimeout(() => {
|
||||
foreign += 1;
|
||||
});
|
||||
</script>
|
||||
|
||||
{#await (await input).pending}
|
||||
<p>pending</p>
|
||||
{/await}
|
||||
|
||||
<p>{foreign}</p>
|
||||
@ -0,0 +1,22 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
|
||||
compileOptions: {
|
||||
dev: false
|
||||
},
|
||||
|
||||
async test({ assert, target, errors }) {
|
||||
await tick();
|
||||
await tick();
|
||||
await tick();
|
||||
|
||||
assert.deepEqual(
|
||||
errors.filter((error) => error.includes('state_unsafe_mutation')),
|
||||
[]
|
||||
);
|
||||
assert.htmlEqual(target.innerHTML, '<p>4 1</p>');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,20 @@
|
||||
<script>
|
||||
let foreign = $state(0);
|
||||
|
||||
const items = Promise.resolve([1, 2, 3]);
|
||||
const one = Promise.resolve(1);
|
||||
|
||||
// lands the write while the derived is suspended on `await one`, after the
|
||||
// context restored for `.length` — in production that await has no dev hook
|
||||
items.then(() => {
|
||||
queueMicrotask(() => {
|
||||
queueMicrotask(() => {
|
||||
foreign += 1;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const total = $derived((await items).length + (await one));
|
||||
</script>
|
||||
|
||||
<p>{total} {foreign}</p>
|
||||
@ -0,0 +1,21 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
|
||||
compileOptions: {
|
||||
dev: true
|
||||
},
|
||||
|
||||
async test({ assert, target, errors }) {
|
||||
await tick();
|
||||
await tick();
|
||||
|
||||
assert.deepEqual(
|
||||
errors.filter((error) => error.includes('state_unsafe_mutation')),
|
||||
[]
|
||||
);
|
||||
assert.htmlEqual(target.innerHTML, '<p>3 1</p>');
|
||||
}
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue