mirror of https://github.com/sveltejs/svelte
commit
c4509b2de8
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: deeply unstate objects passed to inspect
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: handle delegated events of elements moved outside the container
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: improve text node output
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: improve style parser whitespace handling
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: allow input elements within button elements
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: improve script `lang` attribute detection
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: support TypeScript's `satisfies` operator
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: improve pseudo class parsing
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: provide `unstate` in server environment
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: improve key block reactivity detection
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: add types for popover attributes and events
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: skip generating $.proxy() calls for unary and binary expressions
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: always treat spread attributes as reactive and separate them if needed
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: allow pseudo classes after `:global(..)`
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: bail-out event handler referencing each index
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: parse `:nth-of-type(xn+y)` correctly
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: ensure if block is executed in correct order
|
@ -0,0 +1,4 @@
|
||||
<!--should not error out-->
|
||||
<script lang="ts">
|
||||
let count: number;
|
||||
</script>
|
@ -0,0 +1,132 @@
|
||||
{
|
||||
"css": null,
|
||||
"js": [],
|
||||
"start": 0,
|
||||
"end": 27,
|
||||
"type": "Root",
|
||||
"fragment": {
|
||||
"type": "Fragment",
|
||||
"nodes": [
|
||||
{
|
||||
"type": "Comment",
|
||||
"start": 0,
|
||||
"end": 27,
|
||||
"data": "should not error out",
|
||||
"ignores": []
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"start": 27,
|
||||
"end": 28,
|
||||
"raw": "\n",
|
||||
"data": "\n"
|
||||
}
|
||||
],
|
||||
"transparent": false
|
||||
},
|
||||
"options": null,
|
||||
"instance": {
|
||||
"type": "Script",
|
||||
"start": 28,
|
||||
"end": 76,
|
||||
"context": "default",
|
||||
"content": {
|
||||
"type": "Program",
|
||||
"start": 46,
|
||||
"end": 67,
|
||||
"loc": {
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 0
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "VariableDeclaration",
|
||||
"start": 48,
|
||||
"end": 66,
|
||||
"loc": {
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 19
|
||||
}
|
||||
},
|
||||
"declarations": [
|
||||
{
|
||||
"type": "VariableDeclarator",
|
||||
"start": 52,
|
||||
"end": 65,
|
||||
"loc": {
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 5
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"start": 52,
|
||||
"end": 18,
|
||||
"loc": {
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 5
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
}
|
||||
},
|
||||
"name": "count",
|
||||
"typeAnnotation": {
|
||||
"type": "TSTypeAnnotation",
|
||||
"start": 57,
|
||||
"end": 65,
|
||||
"loc": {
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
}
|
||||
},
|
||||
"typeAnnotation": {
|
||||
"type": "TSNumberKeyword",
|
||||
"start": 59,
|
||||
"end": 65,
|
||||
"loc": {
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 12
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"init": null
|
||||
}
|
||||
],
|
||||
"kind": "let"
|
||||
}
|
||||
],
|
||||
"sourceType": "module"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<style>
|
||||
/* test that all these are parsed correctly */
|
||||
::view-transition-old(x-y) {
|
||||
color: red;
|
||||
}
|
||||
:global(::view-transition-old(x-y)) {
|
||||
color: red;
|
||||
}
|
||||
::highlight(rainbow-color-1) {
|
||||
color: red;
|
||||
}
|
||||
custom-element::part(foo) {
|
||||
color: red;
|
||||
}
|
||||
::slotted(.content) {
|
||||
color: red;
|
||||
}
|
||||
:is( /*button*/
|
||||
button, /*p after h1*/
|
||||
h1 + p
|
||||
){
|
||||
color: red;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,330 @@
|
||||
{
|
||||
"css": {
|
||||
"type": "Style",
|
||||
"start": 0,
|
||||
"end": 386,
|
||||
"attributes": [],
|
||||
"children": [
|
||||
{
|
||||
"type": "Rule",
|
||||
"prelude": {
|
||||
"type": "SelectorList",
|
||||
"start": 60,
|
||||
"end": 86,
|
||||
"children": [
|
||||
{
|
||||
"type": "Selector",
|
||||
"start": 60,
|
||||
"end": 86,
|
||||
"children": [
|
||||
{
|
||||
"type": "PseudoElementSelector",
|
||||
"name": "view-transition-old",
|
||||
"start": 60,
|
||||
"end": 81
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"block": {
|
||||
"type": "Block",
|
||||
"start": 88,
|
||||
"end": 109,
|
||||
"children": [
|
||||
{
|
||||
"type": "Declaration",
|
||||
"start": 92,
|
||||
"end": 102,
|
||||
"property": "color",
|
||||
"value": "red"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start": 60,
|
||||
"end": 109
|
||||
},
|
||||
{
|
||||
"type": "Rule",
|
||||
"prelude": {
|
||||
"type": "SelectorList",
|
||||
"start": 111,
|
||||
"end": 146,
|
||||
"children": [
|
||||
{
|
||||
"type": "Selector",
|
||||
"start": 111,
|
||||
"end": 146,
|
||||
"children": [
|
||||
{
|
||||
"type": "PseudoClassSelector",
|
||||
"name": "global",
|
||||
"args": {
|
||||
"type": "SelectorList",
|
||||
"start": 119,
|
||||
"end": 145,
|
||||
"children": [
|
||||
{
|
||||
"type": "Selector",
|
||||
"start": 119,
|
||||
"end": 145,
|
||||
"children": [
|
||||
{
|
||||
"type": "PseudoElementSelector",
|
||||
"name": "view-transition-old",
|
||||
"start": 119,
|
||||
"end": 140
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"start": 111,
|
||||
"end": 146
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"block": {
|
||||
"type": "Block",
|
||||
"start": 148,
|
||||
"end": 169,
|
||||
"children": [
|
||||
{
|
||||
"type": "Declaration",
|
||||
"start": 152,
|
||||
"end": 162,
|
||||
"property": "color",
|
||||
"value": "red"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start": 111,
|
||||
"end": 169
|
||||
},
|
||||
{
|
||||
"type": "Rule",
|
||||
"prelude": {
|
||||
"type": "SelectorList",
|
||||
"start": 171,
|
||||
"end": 199,
|
||||
"children": [
|
||||
{
|
||||
"type": "Selector",
|
||||
"start": 171,
|
||||
"end": 199,
|
||||
"children": [
|
||||
{
|
||||
"type": "PseudoElementSelector",
|
||||
"name": "highlight",
|
||||
"start": 171,
|
||||
"end": 182
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"block": {
|
||||
"type": "Block",
|
||||
"start": 200,
|
||||
"end": 218,
|
||||
"children": [
|
||||
{
|
||||
"type": "Declaration",
|
||||
"start": 204,
|
||||
"end": 214,
|
||||
"property": "color",
|
||||
"value": "red"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start": 171,
|
||||
"end": 218
|
||||
},
|
||||
{
|
||||
"type": "Rule",
|
||||
"prelude": {
|
||||
"type": "SelectorList",
|
||||
"start": 220,
|
||||
"end": 245,
|
||||
"children": [
|
||||
{
|
||||
"type": "Selector",
|
||||
"start": 220,
|
||||
"end": 245,
|
||||
"children": [
|
||||
{
|
||||
"type": "TypeSelector",
|
||||
"name": "custom-element",
|
||||
"start": 220,
|
||||
"end": 234
|
||||
},
|
||||
{
|
||||
"type": "PseudoElementSelector",
|
||||
"name": "part",
|
||||
"start": 234,
|
||||
"end": 240
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"block": {
|
||||
"type": "Block",
|
||||
"start": 246,
|
||||
"end": 264,
|
||||
"children": [
|
||||
{
|
||||
"type": "Declaration",
|
||||
"start": 250,
|
||||
"end": 260,
|
||||
"property": "color",
|
||||
"value": "red"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start": 220,
|
||||
"end": 264
|
||||
},
|
||||
{
|
||||
"type": "Rule",
|
||||
"prelude": {
|
||||
"type": "SelectorList",
|
||||
"start": 266,
|
||||
"end": 285,
|
||||
"children": [
|
||||
{
|
||||
"type": "Selector",
|
||||
"start": 266,
|
||||
"end": 285,
|
||||
"children": [
|
||||
{
|
||||
"type": "PseudoElementSelector",
|
||||
"name": "slotted",
|
||||
"start": 266,
|
||||
"end": 275
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"block": {
|
||||
"type": "Block",
|
||||
"start": 286,
|
||||
"end": 304,
|
||||
"children": [
|
||||
{
|
||||
"type": "Declaration",
|
||||
"start": 290,
|
||||
"end": 300,
|
||||
"property": "color",
|
||||
"value": "red"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start": 266,
|
||||
"end": 304
|
||||
},
|
||||
{
|
||||
"type": "Rule",
|
||||
"prelude": {
|
||||
"type": "SelectorList",
|
||||
"start": 306,
|
||||
"end": 359,
|
||||
"children": [
|
||||
{
|
||||
"type": "Selector",
|
||||
"start": 306,
|
||||
"end": 359,
|
||||
"children": [
|
||||
{
|
||||
"type": "PseudoClassSelector",
|
||||
"name": "is",
|
||||
"args": {
|
||||
"type": "SelectorList",
|
||||
"start": 324,
|
||||
"end": 355,
|
||||
"children": [
|
||||
{
|
||||
"type": "Selector",
|
||||
"start": 324,
|
||||
"end": 330,
|
||||
"children": [
|
||||
{
|
||||
"type": "TypeSelector",
|
||||
"name": "button",
|
||||
"start": 324,
|
||||
"end": 330
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Selector",
|
||||
"start": 349,
|
||||
"end": 355,
|
||||
"children": [
|
||||
{
|
||||
"type": "TypeSelector",
|
||||
"name": "h1",
|
||||
"start": 349,
|
||||
"end": 351
|
||||
},
|
||||
{
|
||||
"type": "Combinator",
|
||||
"name": "+",
|
||||
"start": 352,
|
||||
"end": 353
|
||||
},
|
||||
{
|
||||
"type": "TypeSelector",
|
||||
"name": "p",
|
||||
"start": 354,
|
||||
"end": 355
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"start": 306,
|
||||
"end": 359
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"block": {
|
||||
"type": "Block",
|
||||
"start": 359,
|
||||
"end": 377,
|
||||
"children": [
|
||||
{
|
||||
"type": "Declaration",
|
||||
"start": 363,
|
||||
"end": 373,
|
||||
"property": "color",
|
||||
"value": "red"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start": 306,
|
||||
"end": 377
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"start": 7,
|
||||
"end": 378,
|
||||
"styles": "\n /* test that all these are parsed correctly */\n\t::view-transition-old(x-y) {\n\t\tcolor: red;\n }\n\t:global(::view-transition-old(x-y)) {\n\t\tcolor: red;\n }\n\t::highlight(rainbow-color-1) {\n\t\tcolor: red;\n\t}\n\tcustom-element::part(foo) {\n\t\tcolor: red;\n\t}\n\t::slotted(.content) {\n\t\tcolor: red;\n\t}\n\t:is( /*button*/\n\t\tbutton, /*p after h1*/\n\t\th1 + p\n\t\t){\n\t\tcolor: red;\n\t}\n"
|
||||
}
|
||||
},
|
||||
"js": [],
|
||||
"start": null,
|
||||
"end": null,
|
||||
"type": "Root",
|
||||
"fragment": {
|
||||
"type": "Fragment",
|
||||
"nodes": [],
|
||||
"transparent": false
|
||||
},
|
||||
"options": null
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `
|
||||
<button class="red">red</button>
|
||||
<button class="red">red</button>
|
||||
<button class="red">red</button>
|
||||
<button class="red">red</button>
|
||||
`,
|
||||
|
||||
async test({ assert, target }) {
|
||||
const [b1, b2, b3, b4] = target.querySelectorAll('button');
|
||||
|
||||
b1?.click();
|
||||
await Promise.resolve();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button class="blue">blue</button>
|
||||
<button class="red">red</button>
|
||||
<button class="red">red</button>
|
||||
<button class="red">red</button>
|
||||
`
|
||||
);
|
||||
|
||||
b2?.click();
|
||||
await Promise.resolve();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button class="blue">blue</button>
|
||||
<button class="blue">blue</button>
|
||||
<button class="red">red</button>
|
||||
<button class="red">red</button>
|
||||
`
|
||||
);
|
||||
|
||||
b3?.click();
|
||||
await Promise.resolve();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button class="blue">blue</button>
|
||||
<button class="blue">blue</button>
|
||||
<button class="blue">blue</button>
|
||||
<button class="red">red</button>
|
||||
`
|
||||
);
|
||||
|
||||
b4?.click();
|
||||
await Promise.resolve();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button class="blue">blue</button>
|
||||
<button class="blue">blue</button>
|
||||
<button class="blue">blue</button>
|
||||
<button class="blue">blue</button>
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
@ -0,0 +1,24 @@
|
||||
<script>
|
||||
let tag = $state('button');
|
||||
let values = $state({ a: 'red', b: 'red', c: 'red', d: 'red' });
|
||||
|
||||
let count = 0;
|
||||
const factory = (name) => {
|
||||
count++;
|
||||
// check that spread effects are isolated from each other
|
||||
if (count > 8) throw new Error('too many calls');
|
||||
|
||||
return {
|
||||
class: values[name],
|
||||
onclick: () => {
|
||||
values[name] = 'blue';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<button {...factory('a')}>{values.a}</button>
|
||||
<button {...factory('b')}>{values.b}</button>
|
||||
|
||||
<svelte:element this={tag} {...factory('c')}>{values.c}</svelte:element>
|
||||
<svelte:element this={tag} {...factory('d')}>{values.d}</svelte:element>
|
@ -0,0 +1,24 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `
|
||||
<div style="color: red;"></div><div class="red"></div><div class="red"></div>
|
||||
<div style="color: red;"></div><div class="red"></div><div class="red"></div>
|
||||
<button>toggle</button
|
||||
`,
|
||||
|
||||
async test({ assert, target }) {
|
||||
const [b1] = target.querySelectorAll('button');
|
||||
|
||||
b1?.click();
|
||||
await Promise.resolve();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<div class="blue" style="color: blue;"></div><div class="blue"></div><div class="blue"></div>
|
||||
<div class="blue" style="color: blue;"></div><div class="blue"></div><div class="blue"></div>
|
||||
<button>toggle</button
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
const { item } = $props();
|
||||
</script>
|
||||
|
||||
<div>
|
||||
{#if item}
|
||||
{item.length}
|
||||
{/if}
|
||||
</div>
|
@ -0,0 +1,26 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target, component }) {
|
||||
const [b1, b2] = target.querySelectorAll('button');
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
'<div>5</div><div>5</div><div>3</div><button>set null</button><button>set object</button'
|
||||
);
|
||||
flushSync(() => {
|
||||
b2.click();
|
||||
});
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
'<div>5</div><div>5</div><div>3</div><button>set null</button><button>set object</button'
|
||||
);
|
||||
flushSync(() => {
|
||||
b1.click();
|
||||
});
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
'<div>5</div><div></div><div>3</div><button>set null</button><button>set object</button'
|
||||
);
|
||||
}
|
||||
});
|
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
import Component from './Component.svelte';
|
||||
|
||||
let items = $state(['hello', 'world', 'bye']);
|
||||
</script>
|
||||
|
||||
{#each items as item}
|
||||
<Component {item} />
|
||||
{/each}
|
||||
|
||||
<button onclick={() => (items[1] = null)}> set null </button>
|
||||
<button onclick={() => (items[1] = 'hello')}> set object </button>
|
@ -0,0 +1,5 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `<p>A<br>B<br>C<br></p>`
|
||||
});
|
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
let array = $state(['A', 'B', 'C']);
|
||||
</script>
|
||||
|
||||
<p>
|
||||
{#each array as a}
|
||||
{a}<br/>
|
||||
{/each}
|
||||
</p>
|
@ -0,0 +1,39 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `<p>test costs $1</p><p>test 2 costs $2</p><p>test costs $1</p><p>test 2 costs $2</p><button>add</button><button>change</button><button>reload</button>`,
|
||||
skip_if_ssr: 'permanent',
|
||||
skip_if_hydrate: 'permanent',
|
||||
|
||||
async test({ assert, target }) {
|
||||
const [btn1, btn2, btn3] = target.querySelectorAll('button');
|
||||
|
||||
flushSync(() => {
|
||||
btn2.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<p>test costs $1</p><p>test 2 costs $2000</p><p>test costs $1</p><p>test 2 costs $2000</p><button>add</button><button>change</button><button>reload</button>`
|
||||
);
|
||||
|
||||
flushSync(() => {
|
||||
btn1.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<p>test costs $1</p><p>test 2 costs $2000</p><p>test 3 costs $3</p><p>test costs $1</p><p>test 2 costs $2000</p><p>test 3 costs $3</p><button>add</button><button>change</button><button>reload</button>`
|
||||
);
|
||||
|
||||
flushSync(() => {
|
||||
btn3.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<p>test costs $1</p><p>test 2 costs $2000</p><p>test costs $1</p><p>test 2 costs $2000</p><button>add</button><button>change</button><button>reload</button>`
|
||||
);
|
||||
}
|
||||
});
|
@ -0,0 +1,54 @@
|
||||
<script>
|
||||
let data = $state({ items: [] });
|
||||
|
||||
function fetchData() {
|
||||
data = {
|
||||
items: [{
|
||||
id: 1,
|
||||
price: 1,
|
||||
name: 'test'
|
||||
}, {
|
||||
id: 2,
|
||||
price: 2,
|
||||
name: 'test 2'
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
fetchData();
|
||||
|
||||
function copyItems(original) {
|
||||
return [...original.map((item) => ({ ...item }))];
|
||||
}
|
||||
|
||||
let items = $state();
|
||||
|
||||
$effect(() => {
|
||||
items = copyItems(data.items);
|
||||
});
|
||||
</script>
|
||||
|
||||
{#each items as item}
|
||||
<p>{item.name} costs ${item.price}</p>
|
||||
{/each}
|
||||
|
||||
{#each items as item (item.id)}
|
||||
<p>{item.name} costs ${item.price}</p>
|
||||
{/each}
|
||||
|
||||
|
||||
<button onclick={() => {
|
||||
items.push({
|
||||
id: 3,
|
||||
price: 3,
|
||||
name: 'test 3'
|
||||
})
|
||||
}}>add</button>
|
||||
|
||||
<button onclick={() => {
|
||||
data.items[1].price = 2000
|
||||
}}>change</button>
|
||||
|
||||
<button onclick={() => {
|
||||
fetchData();
|
||||
}}>reload</button>
|
@ -1,16 +0,0 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `<div style="color: red;"></div><div class="red"></div><button>toggle</button`,
|
||||
|
||||
async test({ assert, target }) {
|
||||
const [b1] = target.querySelectorAll('button');
|
||||
|
||||
b1?.click();
|
||||
await Promise.resolve();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
'<div class="blue" style="color: blue;"></div><div class="blue"></div><button>toggle</button>'
|
||||
);
|
||||
}
|
||||
});
|
@ -0,0 +1,23 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
// Tests that event delegation still works when the element with the event listener is moved outside the container
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
const btn1 = target.parentElement?.querySelector('button');
|
||||
const btn2 = target.querySelector('button');
|
||||
|
||||
btn1?.click();
|
||||
await Promise.resolve();
|
||||
assert.htmlEqual(
|
||||
target.parentElement?.innerHTML ?? '',
|
||||
'<main><div><button>clicks: 1</button></div></main><button>clicks: 1</button>'
|
||||
);
|
||||
|
||||
btn2?.click();
|
||||
await Promise.resolve();
|
||||
assert.htmlEqual(
|
||||
target.parentElement?.innerHTML ?? '',
|
||||
'<main><div><button>clicks: 2</button></div></main><button>clicks: 2</button>'
|
||||
);
|
||||
}
|
||||
});
|
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
let count = $state(0);
|
||||
let el;
|
||||
$effect(() => {
|
||||
document.getElementsByTagName('body')[0].appendChild(el);
|
||||
})
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<button bind:this={el} onclick={() => count++}>clicks: {count}</button>
|
||||
<button onclick={() => count++}>clicks: {count}</button>
|
||||
</div>
|
@ -0,0 +1,40 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
/**
|
||||
* @type {any[]}
|
||||
*/
|
||||
let log;
|
||||
/**
|
||||
* @type {typeof console.log}}
|
||||
*/
|
||||
let original_log;
|
||||
|
||||
export default test({
|
||||
compileOptions: {
|
||||
dev: true
|
||||
},
|
||||
before_test() {
|
||||
log = [];
|
||||
original_log = console.log;
|
||||
console.log = (...v) => {
|
||||
log.push(...v);
|
||||
};
|
||||
},
|
||||
after_test() {
|
||||
console.log = original_log;
|
||||
},
|
||||
async test({ assert, target }) {
|
||||
const [b1] = target.querySelectorAll('button');
|
||||
b1.click();
|
||||
await Promise.resolve();
|
||||
|
||||
assert.deepEqual(log, [
|
||||
'init',
|
||||
{ x: { count: 0 } },
|
||||
[{ count: 0 }],
|
||||
'update',
|
||||
{ x: { count: 1 } },
|
||||
[{ count: 1 }]
|
||||
]);
|
||||
}
|
||||
});
|
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
let x = $state({count: 0});
|
||||
|
||||
$inspect({x}, [x]);
|
||||
</script>
|
||||
|
||||
<button on:click={() => x.count++}>{x.count}</button>
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue