mirror of https://github.com/sveltejs/svelte
commit
b9ee487b58
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
fix: refine css `:global()` selector checks in a compound selector
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
breaking: warn on slots and event handlers in runes mode, error on `<slot>` + `{@render ...}` tag usage in same component
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
fix: fall back to component namespace when not statically determinable, add way to tell `<svelte:element>` the namespace at runtime
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
fix: remove memory leak from bind:this
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: take outroing elements out of the flow when animating siblings
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
fix: remove memory leak from retaining old DOM elements
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
feat: add warning when using `$bindable` rune without calling it
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
feat: allow inspect reactivity map, set, date
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
fix: widen ownership when sub state is assigned to new state
|
||||
@ -0,0 +1,10 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
error: {
|
||||
code: 'conflicting-slot-usage',
|
||||
message:
|
||||
'Cannot use <slot> syntax and {@render ...} tags in the same component. Migrate towards {@render ...} tags completely.',
|
||||
position: [71, 84]
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,6 @@
|
||||
<script>
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
{@render children()}
|
||||
<slot></slot>
|
||||
@ -0,0 +1,9 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
test({ assert, target }) {
|
||||
const path = target.querySelector('path');
|
||||
|
||||
assert.equal(path?.namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,11 @@
|
||||
<svelte:options namespace="svg" />
|
||||
|
||||
<script>
|
||||
import Svg from "./svg.svelte";
|
||||
|
||||
let tag = "path";
|
||||
</script>
|
||||
|
||||
<Svg>
|
||||
<svelte:element this="{tag}" d="M21 12a9 9 0 1 1-6.219-8.56"/>
|
||||
</Svg>
|
||||
|
After Width: | Height: | Size: 24 B |
@ -0,0 +1,10 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
assert.equal(target.querySelector('path')?.namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
|
||||
await target.querySelector('button')?.click();
|
||||
assert.equal(target.querySelector('div')?.namespaceURI, 'http://www.w3.org/1999/xhtml');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
let tag = $state('path');
|
||||
let xmlns = $state('http://www.w3.org/2000/svg');
|
||||
</script>
|
||||
|
||||
<button onclick={() => {
|
||||
tag = 'div';
|
||||
xmlns = null;
|
||||
}}>change</button>
|
||||
|
||||
<!-- wrapper necessary or else jsdom says this is always an xhtml namespace -->
|
||||
<svg>
|
||||
<svelte:element this={tag} xmlns={xmlns} />
|
||||
</svg>
|
||||
@ -0,0 +1,39 @@
|
||||
import { flushSync } from '../../../../src/index-client';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `<button>add item</button><button>make span</button><button>reverse</button>`,
|
||||
|
||||
async test({ assert, target }) {
|
||||
const [btn1, btn2, btn3] = target.querySelectorAll('button');
|
||||
|
||||
flushSync(() => {
|
||||
btn1?.click();
|
||||
btn1?.click();
|
||||
btn1?.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<button>add item</button><button>make span</button><button>reverse</button><div>Item 1</div><div>Item 2</div><div>Item 3</div>`
|
||||
);
|
||||
|
||||
flushSync(() => {
|
||||
btn2?.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<button>add item</button><button>make span</button><button>reverse</button><span>Item 1</span><span>Item 2</span><span>Item 3</span>`
|
||||
);
|
||||
|
||||
flushSync(() => {
|
||||
btn3?.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<button>add item</button><button>make span</button><button>reverse</button><span>Item 3</span><span>Item 2</span><span>Item 1</span>`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,30 @@
|
||||
<script>
|
||||
let items = $state([]);
|
||||
|
||||
function add_item() {
|
||||
items.push({
|
||||
id: items.length,
|
||||
text: 'Item ' + (items.length + 1),
|
||||
html: '<div>Item ' + (items.length + 1) + '</div>',
|
||||
dom: null,
|
||||
})
|
||||
}
|
||||
|
||||
function make_span() {
|
||||
items.forEach(item => {
|
||||
item.html = item.html.replace(/div/g, 'span')
|
||||
})
|
||||
}
|
||||
|
||||
function reverse() {
|
||||
items.reverse();
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={add_item}>add item</button>
|
||||
<button on:click={make_span}>make span</button>
|
||||
<button on:click={reverse}>reverse</button>
|
||||
|
||||
{#each items as item (item.id)}
|
||||
{@html item.html}
|
||||
{/each}
|
||||
@ -0,0 +1,81 @@
|
||||
import { test } from '../../test';
|
||||
import { flushSync } from 'svelte';
|
||||
import { log } from './log';
|
||||
|
||||
export default test({
|
||||
compileOptions: {
|
||||
dev: true
|
||||
},
|
||||
before_test() {
|
||||
log.length = 0;
|
||||
},
|
||||
async test({ assert, target }) {
|
||||
const [in1, in2] = target.querySelectorAll('input');
|
||||
const [b1, b2, b3] = target.querySelectorAll('button');
|
||||
|
||||
assert.deepEqual(log, [
|
||||
{ label: 'map', type: 'init', values: [] },
|
||||
{ label: 'set', type: 'init', values: [] },
|
||||
{ label: 'date', type: 'init', values: 1712966400000 }
|
||||
]);
|
||||
log.length = 0;
|
||||
|
||||
flushSync(() => b1.click()); // map.set('key', 'value')
|
||||
|
||||
in1.value = 'name';
|
||||
in2.value = 'Svelte';
|
||||
in1.dispatchEvent(new window.Event('input', { bubbles: true }));
|
||||
in2.dispatchEvent(new window.Event('input', { bubbles: true }));
|
||||
flushSync(() => b1.click()); // map.set('name', 'Svelte')
|
||||
|
||||
in2.value = 'World';
|
||||
in2.dispatchEvent(new window.Event('input', { bubbles: true }));
|
||||
flushSync(() => b1.click()); // map.set('name', 'World')
|
||||
flushSync(() => b1.click()); // map.set('name', 'World')
|
||||
|
||||
assert.deepEqual(log, [
|
||||
{ label: 'map', type: 'update', values: [['key', 'value']] },
|
||||
{
|
||||
label: 'map',
|
||||
type: 'update',
|
||||
values: [
|
||||
['key', 'value'],
|
||||
['name', 'Svelte']
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'map',
|
||||
type: 'update',
|
||||
values: [
|
||||
['key', 'value'],
|
||||
['name', 'World']
|
||||
]
|
||||
}
|
||||
]);
|
||||
log.length = 0;
|
||||
|
||||
flushSync(() => b2.click()); // set.add('name');
|
||||
|
||||
in1.value = 'Svelte';
|
||||
in1.dispatchEvent(new window.Event('input', { bubbles: true }));
|
||||
flushSync(() => b2.click()); // set.add('Svelte');
|
||||
|
||||
flushSync(() => b2.click()); // set.add('Svelte');
|
||||
|
||||
assert.deepEqual(log, [
|
||||
{ label: 'set', type: 'update', values: ['name'] },
|
||||
{ label: 'set', type: 'update', values: ['name', 'Svelte'] }
|
||||
]);
|
||||
log.length = 0;
|
||||
|
||||
flushSync(() => b3.click()); // date.minutes++
|
||||
flushSync(() => b3.click()); // date.minutes++
|
||||
flushSync(() => b3.click()); // date.minutes++
|
||||
|
||||
assert.deepEqual(log, [
|
||||
{ label: 'date', type: 'update', values: 1712966460000 },
|
||||
{ label: 'date', type: 'update', values: 1712966520000 },
|
||||
{ label: 'date', type: 'update', values: 1712966580000 }
|
||||
]);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,2 @@
|
||||
/** @type {any[]} */
|
||||
export const log = [];
|
||||
@ -0,0 +1,27 @@
|
||||
<script>
|
||||
import { Map, Set, Date } from 'svelte/reactivity';
|
||||
import { log } from './log';
|
||||
|
||||
const map = new Map();
|
||||
const set = new Set();
|
||||
const date = new Date('2024-04-13 00:00:00+0000');
|
||||
let key = $state('key');
|
||||
let value = $state('value');
|
||||
|
||||
$inspect(map).with((type, map) => {
|
||||
log.push({ label: 'map', type, values: [...map] });
|
||||
});
|
||||
$inspect(set).with((type, set) => {
|
||||
log.push({ label: 'set', type, values: [...set] });
|
||||
});
|
||||
$inspect(date).with((type, date) => {
|
||||
log.push({ label: 'date', type, values: date.getTime() });
|
||||
});
|
||||
</script>
|
||||
|
||||
<input bind:value={key} />
|
||||
<input bind:value={value} />
|
||||
|
||||
<button on:click={() => map.set(key, value)}>map</button>
|
||||
<button on:click={() => set.add(key)}>set</button>
|
||||
<button on:click={() => date.setMinutes(date.getMinutes() + 1)}>date</button>
|
||||
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
let { item } = $props();
|
||||
|
||||
function onclick() {
|
||||
item.name = `${item.name} edited`
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>{item?.name}</div>
|
||||
<button {onclick}>Then click here</button>
|
||||
@ -0,0 +1,41 @@
|
||||
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 [btn1, btn2] = target.querySelectorAll('button');
|
||||
|
||||
btn1.click();
|
||||
await tick();
|
||||
|
||||
assert.deepEqual(warnings.length, 0);
|
||||
|
||||
btn2.click();
|
||||
await tick();
|
||||
|
||||
assert.deepEqual(warnings.length, 1);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,13 @@
|
||||
<script>
|
||||
import Child from './Child.svelte';
|
||||
|
||||
let items = $state([{ id: "test", name: "this is a test"}, { id:"test2", name: "this is a second test"}]);
|
||||
let found = $state();
|
||||
|
||||
function onclick() {
|
||||
found = items.find(c => c.id === 'test2');
|
||||
}
|
||||
</script>
|
||||
|
||||
<button {onclick}>First click here</button>
|
||||
<Child item={found} />
|
||||
@ -0,0 +1,14 @@
|
||||
[
|
||||
{
|
||||
"code": "invalid-css-global-selector-list",
|
||||
"message": ":global(...) must not contain type or universal selectors when used in a compound selector",
|
||||
"start": {
|
||||
"line": 20,
|
||||
"column": 6
|
||||
},
|
||||
"end": {
|
||||
"line": 20,
|
||||
"column": 17
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,27 @@
|
||||
<style>
|
||||
::foo:global([data-state='checked']) {
|
||||
color: red;
|
||||
}
|
||||
::foo:global(.foo) {
|
||||
color: red;
|
||||
}
|
||||
::foo:global(#foo) {
|
||||
color: red;
|
||||
}
|
||||
::foo:global(::foo) {
|
||||
color: red;
|
||||
}
|
||||
::foo:global(:foo) {
|
||||
color: red;
|
||||
}
|
||||
:global(h1) {
|
||||
color: red;
|
||||
}
|
||||
::foo:global(h1) {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div>
|
||||
<h1>hello world</h1>
|
||||
</div>
|
||||
@ -0,0 +1,14 @@
|
||||
[
|
||||
{
|
||||
"code": "invalid-css-type-selector-placement",
|
||||
"message": ":global(...) must not be followed with a type selector",
|
||||
"start": {
|
||||
"line": 17,
|
||||
"column": 14
|
||||
},
|
||||
"end": {
|
||||
"line": 17,
|
||||
"column": 16
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,24 @@
|
||||
<style>
|
||||
:global(.foo):foo {
|
||||
color: red;
|
||||
}
|
||||
:global(.foo)::foo {
|
||||
color: red;
|
||||
}
|
||||
:global(.foo).bar {
|
||||
color: red;
|
||||
}
|
||||
:global(.foo)#baz {
|
||||
color: red;
|
||||
}
|
||||
:global(.foo)[id] {
|
||||
color: red;
|
||||
}
|
||||
:global(.foo)h1 {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div>
|
||||
<h1 class="bar" id="baz">hello world</h1>
|
||||
</div>
|
||||
@ -0,0 +1,16 @@
|
||||
<script>
|
||||
function test() {
|
||||
try {
|
||||
throw new TypeError("oops1");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
try {
|
||||
throw new TypeError("oops2");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
test();
|
||||
</script>
|
||||
@ -0,0 +1,3 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({});
|
||||
@ -0,0 +1,3 @@
|
||||
<script>
|
||||
let { a = $bindable } = $props();
|
||||
</script>
|
||||
@ -0,0 +1,14 @@
|
||||
[
|
||||
{
|
||||
"code": "invalid-bindable-declaration",
|
||||
"message": "Bindable component properties are declared using $bindable() in runes mode. Did you forget to call the function?",
|
||||
"start": {
|
||||
"column": 7,
|
||||
"line": 2
|
||||
},
|
||||
"end": {
|
||||
"column": 20,
|
||||
"line": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,13 @@
|
||||
<script>
|
||||
let { foo } = $props();
|
||||
</script>
|
||||
|
||||
<!-- ok -->
|
||||
<button onclick={foo}>click me</button>
|
||||
<Button onclick={foo}>click me</Button>
|
||||
<Button on:click={foo}>click me</Button>
|
||||
|
||||
<!-- warn -->
|
||||
<slot></slot>
|
||||
<slot name="foo"></slot>
|
||||
<button on:click={foo}>click me</button>
|
||||
@ -0,0 +1,38 @@
|
||||
[
|
||||
{
|
||||
"code": "deprecated-slot-element",
|
||||
"end": {
|
||||
"column": 13,
|
||||
"line": 11
|
||||
},
|
||||
"message": "Using <slot> to render parent content is deprecated. Use {@render ...} tags instead.",
|
||||
"start": {
|
||||
"column": 0,
|
||||
"line": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "deprecated-slot-element",
|
||||
"end": {
|
||||
"column": 24,
|
||||
"line": 12
|
||||
},
|
||||
"message": "Using <slot> to render parent content is deprecated. Use {@render ...} tags instead.",
|
||||
"start": {
|
||||
"column": 0,
|
||||
"line": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "deprecated-event-handler",
|
||||
"end": {
|
||||
"column": 22,
|
||||
"line": 13
|
||||
},
|
||||
"message": "Using on:click to listen to the click event is is deprecated. Use the event attribute onclick instead.",
|
||||
"start": {
|
||||
"column": 8,
|
||||
"line": 13
|
||||
}
|
||||
}
|
||||
]
|
||||
Loading…
Reference in new issue