mirror of https://github.com/sveltejs/svelte
commit
dd3cfda172
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
perf: reuse the cached value in the `<option>`/`<select>` value guard
|
||||
@ -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: omit `bind:focused` from SSR output (it has no HTML attribute)
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: more robust rendering of Svelte custom element slots
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: properly apply static textarea value attribute during CSR
|
||||
@ -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
|
||||
---
|
||||
|
||||
chore: move `@types/trusted-types` to devDependencies
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': minor
|
||||
---
|
||||
|
||||
feat: add `has` function to `createContext`
|
||||
@ -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': minor
|
||||
---
|
||||
|
||||
feat: add getOrInsert/getOrInsertComputed to SvelteMap
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: block declaration tags and `{@const}` on async values read inside closures
|
||||
@ -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 @@
|
||||
<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>
|
||||
@ -1,7 +1,13 @@
|
||||
<script>
|
||||
import { get } from './main.svelte';
|
||||
import { get, has, has_unset } from './main.svelte';
|
||||
|
||||
const message = get();
|
||||
</script>
|
||||
|
||||
<h1>{message}</h1>
|
||||
{#if has()}
|
||||
<h2>it's me</h2>
|
||||
{/if}
|
||||
{#if !has_unset()}
|
||||
<h2>or not</h2>
|
||||
{/if}
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
<script>
|
||||
import { get } from './main.svelte';
|
||||
import { get, has, has_unset } from './main.svelte';
|
||||
|
||||
const message = get();
|
||||
</script>
|
||||
|
||||
<h1>{message}</h1>
|
||||
{#if has()}
|
||||
<h2>it's me</h2>
|
||||
{/if}
|
||||
{#if !has_unset()}
|
||||
<h2>or not</h2>
|
||||
{/if}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `<h1>hello</h1>`
|
||||
html: `<h1>hello</h1><h2>it's me</h2><h2>or not</h2>`
|
||||
});
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
ssrHtml: '<p>LATER</p> <input value="LATER">',
|
||||
html: '<p>LATER</p> <input>'
|
||||
});
|
||||
@ -0,0 +1,6 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
ssrHtml: '<p>y:y</p> <p>LATER</p> <input value="LATER">',
|
||||
html: '<p>y:y</p> <p>LATER</p> <input>'
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
mode: ['hydrate'],
|
||||
|
||||
async test({ assert, target }) {
|
||||
const [a, b, reset] = target.querySelectorAll('input');
|
||||
|
||||
// let the deferred hydration cleanup run
|
||||
await Promise.resolve();
|
||||
flushSync();
|
||||
|
||||
b.checked = true;
|
||||
reset.click();
|
||||
await Promise.resolve();
|
||||
flushSync();
|
||||
|
||||
assert.equal(a.defaultChecked, true);
|
||||
assert.equal(a.checked, true);
|
||||
assert.equal(b.checked, false);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
let spread = { defaultChecked: true, checked: true };
|
||||
</script>
|
||||
|
||||
<form>
|
||||
<input type="radio" name="option" value="a" {...spread} />
|
||||
<input type="radio" name="option" value="b" />
|
||||
<input type="reset" value="Reset" />
|
||||
</form>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue