mirror of https://github.com/sveltejs/svelte
commit
f13056783d
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: support contenteditable binding undefined fallback
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
fix(types): export CompileResult and Warning
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: ensure element dir properties persist with text changes
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
breaking: rename `svelte/reactivity` helpers to include `Svelte` prefix
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: disallow accessing internal Svelte props
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: avoid duplicate signal dependencies
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: make media bindings more robust
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
feat: allow `let props = $props()` and optimize prop read access
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: ensure HMR doesn't mess with anchor nodes
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
feat: improve type arguments for Snippet and $bindable
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: deconflict multiple snippets of the same name
|
||||
@ -1,4 +1,29 @@
|
||||
export { ReactiveDate as Date } from './date.js';
|
||||
export { ReactiveSet as Set } from './set.js';
|
||||
export { ReactiveMap as Map } from './map.js';
|
||||
export { ReactiveURL as URL, ReactiveURLSearchParams as URLSearchParams } from './url.js';
|
||||
export { SvelteDate } from './date.js';
|
||||
export { SvelteSet } from './set.js';
|
||||
export { SvelteMap } from './map.js';
|
||||
export { SvelteURL, SvelteURLSearchParams } from './url.js';
|
||||
|
||||
/** @deprecated Use `SvelteDate` instead */
|
||||
export function Date() {
|
||||
throw new Error('Date has been removed, use SvelteDate instead.');
|
||||
}
|
||||
|
||||
/** @deprecated Use `SvelteSet` instead */
|
||||
export function Set() {
|
||||
throw new Error('Set has been removed, use SvelteSet instead.');
|
||||
}
|
||||
|
||||
/** @deprecated Use `SvelteMap` instead */
|
||||
export function Map() {
|
||||
throw new Error('Map has been removed, use SvelteMap instead.');
|
||||
}
|
||||
|
||||
/** @deprecated Use `SvelteURL` instead */
|
||||
export function URL() {
|
||||
throw new Error('URL has been removed, use SvelteURL instead.');
|
||||
}
|
||||
|
||||
/** @deprecated Use `SvelteURLSearchParams` instead */
|
||||
export function URLSearchParams() {
|
||||
throw new Error('URLSearchParams has been removed, use SvelteURLSearchParams instead.');
|
||||
}
|
||||
|
||||
@ -1,5 +1,30 @@
|
||||
export const Date = globalThis.Date;
|
||||
export const Set = globalThis.Set;
|
||||
export const Map = globalThis.Map;
|
||||
export const URL = globalThis.URL;
|
||||
export const URLSearchParams = globalThis.URLSearchParams;
|
||||
export const SvelteDate = globalThis.Date;
|
||||
export const SvelteSet = globalThis.Set;
|
||||
export const SvelteMap = globalThis.Map;
|
||||
export const SvelteURL = globalThis.URL;
|
||||
export const SvelteURLSearchParams = globalThis.URLSearchParams;
|
||||
|
||||
/** @deprecated Use `SvelteDate` instead */
|
||||
export function Date() {
|
||||
throw new Error('Date has been removed, use SvelteDate instead.');
|
||||
}
|
||||
|
||||
/** @deprecated Use `SvelteSet` instead */
|
||||
export function Set() {
|
||||
throw new Error('Set has been removed, use SvelteSet instead.');
|
||||
}
|
||||
|
||||
/** @deprecated Use `SvelteMap` instead */
|
||||
export function Map() {
|
||||
throw new Error('Map has been removed, use SvelteMap instead.');
|
||||
}
|
||||
|
||||
/** @deprecated Use `SvelteURL` instead */
|
||||
export function URL() {
|
||||
throw new Error('URL has been removed, use SvelteURL instead.');
|
||||
}
|
||||
|
||||
/** @deprecated Use `SvelteURLSearchParams` instead */
|
||||
export function URLSearchParams() {
|
||||
throw new Error('URLSearchParams has been removed, use SvelteURLSearchParams instead.');
|
||||
}
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
error: {
|
||||
code: 'props_illegal_name',
|
||||
message:
|
||||
'Declaring or accessing a prop starting with `$$` is illegal (they are reserved for Svelte internals)'
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,3 @@
|
||||
<script>
|
||||
let { $$slots: a } = $props();
|
||||
</script>
|
||||
@ -0,0 +1,9 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
error: {
|
||||
code: 'props_illegal_name',
|
||||
message:
|
||||
'Declaring or accessing a prop starting with `$$` is illegal (they are reserved for Svelte internals)'
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,4 @@
|
||||
<script>
|
||||
let props = $props();
|
||||
props.$$slots;
|
||||
</script>
|
||||
@ -0,0 +1,29 @@
|
||||
import { test, ok } from '../../assert';
|
||||
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
async test({ assert, target }) {
|
||||
const audio = target.querySelector('audio');
|
||||
const button = target.querySelector('button');
|
||||
ok(audio);
|
||||
|
||||
assert.equal(audio.muted, false);
|
||||
|
||||
audio.muted = true;
|
||||
audio.dispatchEvent(new CustomEvent('volumechange'));
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.muted, true, 'event');
|
||||
|
||||
button?.click();
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.muted, false, 'click 1');
|
||||
|
||||
button?.click();
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.muted, true, 'click 2');
|
||||
|
||||
button?.click();
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.muted, false, 'click 3');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,6 @@
|
||||
<script>
|
||||
let muted = $state(false);
|
||||
</script>
|
||||
|
||||
<audio bind:muted></audio>
|
||||
<button onclick={() => (muted = !muted)}>toggle</button>
|
||||
@ -0,0 +1,29 @@
|
||||
import { test, ok } from '../../assert';
|
||||
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
async test({ assert, target }) {
|
||||
const audio = target.querySelector('audio');
|
||||
const button = target.querySelector('button');
|
||||
ok(audio);
|
||||
|
||||
assert.equal(audio.playbackRate, 0.5);
|
||||
|
||||
audio.playbackRate = 1.0;
|
||||
audio.dispatchEvent(new CustomEvent('ratechange'));
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.playbackRate, 1.0);
|
||||
|
||||
button?.click();
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.playbackRate, 2);
|
||||
|
||||
button?.click();
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.playbackRate, 3);
|
||||
|
||||
button?.click();
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.playbackRate, 4);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,6 @@
|
||||
<script>
|
||||
let playbackRate = $state(0.5);
|
||||
</script>
|
||||
|
||||
<audio bind:playbackRate></audio>
|
||||
<button onclick={() => (playbackRate += 1)}>increment</button>
|
||||
@ -0,0 +1,29 @@
|
||||
import { test, ok } from '../../assert';
|
||||
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
async test({ assert, target }) {
|
||||
const audio = target.querySelector('audio');
|
||||
const button = target.querySelector('button');
|
||||
ok(audio);
|
||||
|
||||
assert.equal(audio.volume, 0.1);
|
||||
|
||||
audio.volume = 0.2;
|
||||
audio.dispatchEvent(new CustomEvent('volumechange'));
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.volume, 0.2);
|
||||
|
||||
button?.click();
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.volume, 0.2 + 0.1); // JavaScript can't add floating point numbers correctly
|
||||
|
||||
button?.click();
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.volume, 0.2 + 0.1 + 0.1);
|
||||
|
||||
button?.click();
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.equal(audio.volume, 0.2 + 0.1 + 0.1 + 0.1);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,6 @@
|
||||
<script>
|
||||
let volume = $state(0.1);
|
||||
</script>
|
||||
|
||||
<audio bind:volume></audio>
|
||||
<button onclick={() => (volume += 0.1)}>increment</button>
|
||||
@ -1,27 +0,0 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
test({ assert, target, variant }) {
|
||||
// if created on client side, should not build noscript
|
||||
if (variant === 'dom') {
|
||||
assert.equal(target.querySelectorAll('noscript').length, 0);
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<div>foo</div>
|
||||
<div>foo<div>foo</div></div>
|
||||
`
|
||||
);
|
||||
} else {
|
||||
assert.equal(target.querySelectorAll('noscript').length, 3);
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<noscript>foo</noscript>
|
||||
<div>foo<noscript>foo</noscript></div>
|
||||
<div>foo<div>foo<noscript>foo</noscript></div></div>
|
||||
`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,5 +0,0 @@
|
||||
<noscript>foo</noscript>
|
||||
|
||||
<div>foo<noscript>foo</noscript></div>
|
||||
|
||||
<div>foo<div>foo<noscript>foo</noscript></div></div>
|
||||
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
let {children} = $props()
|
||||
let innerText = $state()
|
||||
$inspect(innerText);
|
||||
</script>
|
||||
|
||||
<div contenteditable="true" bind:innerHTML={innerText}>
|
||||
{@render children()}
|
||||
</div>
|
||||
@ -0,0 +1,5 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `<div contenteditable="true">Test</div>`
|
||||
});
|
||||
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
import Test from './Test.svelte'
|
||||
</script>
|
||||
|
||||
<Test>
|
||||
Test
|
||||
</Test>
|
||||
@ -0,0 +1,23 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
let [btn1, btn2] = target.querySelectorAll('button');
|
||||
|
||||
flushSync(() => {
|
||||
btn1?.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `<button>hide</button><button>show</button`);
|
||||
|
||||
flushSync(() => {
|
||||
btn2?.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<h1>John Doe</h1><p>Body</p><button>hide</button><button>show</button>`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,27 @@
|
||||
<script>
|
||||
let data = $state({
|
||||
event: {
|
||||
author: 'John Doe',
|
||||
body: 'Body'
|
||||
}
|
||||
});
|
||||
const { event } = $derived(data);
|
||||
</script>
|
||||
|
||||
{#if event}
|
||||
<h1>{event.author}</h1>
|
||||
<p>{event.body}</p>
|
||||
{/if}
|
||||
|
||||
<button onclick={() => {
|
||||
data = {}
|
||||
}}>hide</button>
|
||||
|
||||
<button onclick={() => {
|
||||
data = {
|
||||
event: {
|
||||
author: 'John Doe',
|
||||
body: 'Body'
|
||||
}
|
||||
}
|
||||
}}>show</button>
|
||||
@ -0,0 +1,27 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `<ul><li>test (1) <span style="background-color: red; width: 20px; height: 20px; display: inline-block;"></span></li><li>test 2 (2)</li><li>test 3 (3)</li></ul><button>Swap items 1 & 3</button>`,
|
||||
|
||||
async test({ assert, target }) {
|
||||
const [btn1] = target.querySelectorAll('button');
|
||||
|
||||
flushSync(() => {
|
||||
btn1.click();
|
||||
});
|
||||
|
||||
flushSync(() => {
|
||||
btn1.click();
|
||||
});
|
||||
|
||||
flushSync(() => {
|
||||
btn1.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<ul><li>test (1) <span style="background-color: red; width: 20px; height: 20px; display: inline-block;"></span></li><li>test 2 (2)</li><li>test 3 (3)</li></ul><button>Swap items 1 & 3</button>`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
const items = $state([
|
||||
{ name: 'test', id: 1, color: 'red' },
|
||||
{ name: 'test 2', id: 2 },
|
||||
{ name: 'test 3', id: 3 },
|
||||
]);
|
||||
const onclick = () => {
|
||||
const from = 0;
|
||||
const to = 2;
|
||||
items.splice(to, 0, items.splice(from, 1)[0]);
|
||||
};
|
||||
</script>
|
||||
|
||||
{#snippet renderItem(item)}
|
||||
<li>
|
||||
{item.name} ({item.id})
|
||||
{#if item.color}<span style="background-color: {item.color}; width: 20px; height: 20px; display: inline-block;"></span>{/if}
|
||||
</li>
|
||||
{/snippet}
|
||||
|
||||
<ul>
|
||||
{#each items as item (item.id)}
|
||||
{@render renderItem(item)}
|
||||
{/each}
|
||||
</ul>
|
||||
<button {onclick}>Swap items 1 & 3</button>
|
||||
@ -0,0 +1,27 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `<ul><li>test (1)</li> <span style="background-color: red; width: 20px; height: 20px; display: inline-block;"></span><li>test 2 (2)</li><li>test 3 (3)</li></ul><button>Swap items 1 & 3</button>`,
|
||||
|
||||
async test({ assert, target }) {
|
||||
const [btn1] = target.querySelectorAll('button');
|
||||
|
||||
flushSync(() => {
|
||||
btn1.click();
|
||||
});
|
||||
|
||||
flushSync(() => {
|
||||
btn1.click();
|
||||
});
|
||||
|
||||
flushSync(() => {
|
||||
btn1.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<ul><li>test (1)</li><span style="background-color: red; width: 20px; height: 20px; display: inline-block;"></span><li>test 2 (2)</li><li>test 3 (3)</li></ul><button>Swap items 1 & 3</button>`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
const items = $state([
|
||||
{ name: 'test', id: 1, color: 'red' },
|
||||
{ name: 'test 2', id: 2 },
|
||||
{ name: 'test 3', id: 3 },
|
||||
]);
|
||||
const onclick = () => {
|
||||
const from = 0;
|
||||
const to = 2;
|
||||
items.splice(to, 0, items.splice(from, 1)[0]);
|
||||
};
|
||||
</script>
|
||||
|
||||
{#snippet renderItem(item)}
|
||||
<li>
|
||||
{item.name} ({item.id})
|
||||
</li>
|
||||
{#if item.color}<span style="background-color: {item.color}; width: 20px; height: 20px; display: inline-block;"></span>{/if}
|
||||
{/snippet}
|
||||
|
||||
<ul>
|
||||
{#each items as item (item.id)}
|
||||
{@render renderItem(item)}
|
||||
{/each}
|
||||
</ul>
|
||||
<button {onclick}>Swap items 1 & 3</button>
|
||||
@ -0,0 +1,42 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
html: `<button>Add new message</button><p>first</p><p>message 1</p>`,
|
||||
|
||||
async test({ assert, target }) {
|
||||
/**
|
||||
* @type {{ click: () => void; }}
|
||||
*/
|
||||
let btn1;
|
||||
|
||||
[btn1] = target.querySelectorAll('button');
|
||||
|
||||
flushSync(() => {
|
||||
btn1.click();
|
||||
});
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<button>Add new message</button><p>first</p><p>message 1</p><p>message 2</p>`
|
||||
);
|
||||
|
||||
await Promise.resolve();
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<button>Add new message</button><p>first</p><p>message 1</p><p>message 2</p>`
|
||||
);
|
||||
|
||||
flushSync(() => {
|
||||
btn1.click();
|
||||
});
|
||||
|
||||
await Promise.resolve();
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<button>Add new message</button><p>first</p><p>message 1</p><p>message 2</p><p>message 3</p>`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
let messages = $state([{id: 1, content: "message 1"}]);
|
||||
|
||||
function add() {
|
||||
const newId = messages.length + 1
|
||||
messages.push({id: 0, tmpId: newId, content: `message ${newId}`})
|
||||
|
||||
queueMicrotask(() => {
|
||||
const msg = messages.find((m) => m.tmpId === newId && m.id === 0)
|
||||
msg.tmpId = ""
|
||||
msg.id = newId
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={add}>Add new message</button>
|
||||
|
||||
{#each messages as msg, i (`${msg.id}_${msg.tmpId ?? ""}`)}
|
||||
{#if i === 0}
|
||||
<p>first</p>
|
||||
{/if}
|
||||
<p>{msg.content}</p>
|
||||
{/each}
|
||||
@ -0,0 +1 @@
|
||||
<p>hello</p>
|
||||
@ -0,0 +1,21 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
compileOptions: {
|
||||
dev: true,
|
||||
hmr: true
|
||||
},
|
||||
|
||||
html: `<button>toggle</button>`,
|
||||
|
||||
test({ assert, target }) {
|
||||
const button = target.querySelector('button');
|
||||
|
||||
flushSync(() => button?.click());
|
||||
assert.htmlEqual(target.innerHTML, `<button>toggle</button><p>hello</p>`);
|
||||
|
||||
flushSync(() => button?.click());
|
||||
assert.htmlEqual(target.innerHTML, `<button>toggle</button>`);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
import Child from './Child.svelte';
|
||||
|
||||
let open = $state(false);
|
||||
</script>
|
||||
|
||||
<button onclick={() => (open = !open)}>toggle</button>
|
||||
|
||||
{#if open}
|
||||
<Child />
|
||||
{/if}
|
||||
@ -1,13 +1,13 @@
|
||||
<script>
|
||||
import { Set as ReactiveSet, Map as ReactiveMap } from 'svelte/reactivity';
|
||||
import { SvelteSet, SvelteMap } from 'svelte/reactivity';
|
||||
|
||||
let map = new Map();
|
||||
let set = new Set();
|
||||
let rmap = new ReactiveMap();
|
||||
let rset = new ReactiveSet();
|
||||
let rmap = new SvelteMap();
|
||||
let rset = new SvelteSet();
|
||||
</script>
|
||||
|
||||
<div>{rset.entries()} {rset.keys()} {rset.values()}</div>
|
||||
<div>{set.entries()} {set.keys()} {set.values()}</div>
|
||||
<div>{rmap.entries()} {rmap.keys()} {rmap.values()}</div>
|
||||
<div>{map.entries()} {map.keys()} {map.values()}</div>
|
||||
<div>{map.entries()} {map.keys()} {map.values()}</div>
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
|
||||
test({ assert, target }) {
|
||||
const btn = target.querySelector('button');
|
||||
|
||||
btn?.click();
|
||||
btn?.click();
|
||||
btn?.click();
|
||||
flushSync();
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>push</button><div style="display: grid; grid-template-columns: 1fr 1fr"><div><p style="color: red">1</p><p style="color: red">2</p><p style="color: red">3</p>
|
||||
<p style="color: red">4</p><p style="color: red">5</p><p style="color: red">6</p></div><div><p style="color: blue">1</p><p style="color: blue">2</p><p style="color: blue">3</p>
|
||||
<p style="color: blue">4</p><p style="color: blue">5</p><p style="color: blue">6</p></div></div>
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,29 @@
|
||||
<script>
|
||||
let numbers = $state([1, 2, 3]);
|
||||
</script>
|
||||
|
||||
<button onclick={() => numbers.push(numbers.length + 1)}>
|
||||
push
|
||||
</button>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr">
|
||||
<div>
|
||||
{#snippet x(n)}
|
||||
<p style="color: red">{n}</p>
|
||||
{/snippet}
|
||||
|
||||
{#each numbers as n}
|
||||
{@render x(n)}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{#snippet x(n)}
|
||||
<p style="color: blue">{n}</p>
|
||||
{/snippet}
|
||||
|
||||
{#each numbers as n}
|
||||
{@render x(n)}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1 @@
|
||||
A
|
||||
@ -0,0 +1 @@
|
||||
B
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue