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