mirror of https://github.com/sveltejs/svelte
parent
0fd39219d3
commit
8bb4083b67
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: link top-level `using` declarations in components to lifecycle
|
@ -0,0 +1,26 @@
|
|||||||
|
import { teardown } from '../reactivity/effects.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {...any} disposables
|
||||||
|
*/
|
||||||
|
export function dispose(...disposables) {
|
||||||
|
teardown(() => {
|
||||||
|
for (const disposable of disposables) {
|
||||||
|
disposable?.[Symbol.dispose]();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In dev, check that a value used with `using` is in fact disposable. We need this
|
||||||
|
* because we're replacing `using foo = ...` with `const foo = ...` if the
|
||||||
|
* declaration is at the top level of a component
|
||||||
|
* @param {any} value
|
||||||
|
*/
|
||||||
|
export function disposable(value) {
|
||||||
|
if (value != null && !value[Symbol.dispose]) {
|
||||||
|
throw new TypeError('Symbol(Symbol.dispose) is not a function');
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
let { message } = $props();
|
||||||
|
|
||||||
|
using x = {
|
||||||
|
message,
|
||||||
|
[Symbol.dispose]() {
|
||||||
|
console.log(`disposing ${message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>{x.message}</p>
|
@ -0,0 +1,18 @@
|
|||||||
|
import { flushSync } from 'svelte';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
// TODO unskip this for applicable node versions, once supported
|
||||||
|
skip: true,
|
||||||
|
|
||||||
|
html: `<button>toggle</button><p>hello</p>`,
|
||||||
|
|
||||||
|
test({ assert, target, logs }) {
|
||||||
|
const [button] = target.querySelectorAll('button');
|
||||||
|
|
||||||
|
flushSync(() => button.click());
|
||||||
|
assert.htmlEqual(target.innerHTML, `<button>toggle</button>`);
|
||||||
|
|
||||||
|
assert.deepEqual(logs, ['disposing hello']);
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,13 @@
|
|||||||
|
<script>
|
||||||
|
import Child from './Child.svelte';
|
||||||
|
|
||||||
|
let message = $state('hello');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button onclick={() => message = message ? null : 'hello'}>
|
||||||
|
toggle
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#if message}
|
||||||
|
<Child {message} />
|
||||||
|
{/if}
|
@ -0,0 +1,7 @@
|
|||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
compileOptions: {
|
||||||
|
dev: true
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,28 @@
|
|||||||
|
import 'svelte/internal/disclose-version';
|
||||||
|
|
||||||
|
Using_top_level[$.FILENAME] = 'packages/svelte/tests/snapshot/samples/using-top-level/index.svelte';
|
||||||
|
|
||||||
|
import * as $ from 'svelte/internal/client';
|
||||||
|
|
||||||
|
var root = $.add_locations($.from_html(`<p> </p>`), Using_top_level[$.FILENAME], [[12, 0]]);
|
||||||
|
|
||||||
|
export default function Using_top_level($$anchor, $$props) {
|
||||||
|
$.check_target(new.target);
|
||||||
|
$.push($$props, true, Using_top_level);
|
||||||
|
|
||||||
|
const x = $.disposable({
|
||||||
|
message: $$props.message,
|
||||||
|
[Symbol.dispose]() {
|
||||||
|
console.log(...$.log_if_contains_state('log', `disposing ${$$props.message}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var p = root();
|
||||||
|
var text = $.child(p, true);
|
||||||
|
|
||||||
|
$.reset(p);
|
||||||
|
$.template_effect(() => $.set_text(text, x.message));
|
||||||
|
$.append($$anchor, p);
|
||||||
|
$.dispose(x);
|
||||||
|
return $.pop({ ...$.legacy_api() });
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
Using_top_level[$.FILENAME] = 'packages/svelte/tests/snapshot/samples/using-top-level/index.svelte';
|
||||||
|
|
||||||
|
import * as $ from 'svelte/internal/server';
|
||||||
|
|
||||||
|
function Using_top_level($$payload, $$props) {
|
||||||
|
$.push(Using_top_level);
|
||||||
|
|
||||||
|
let { message } = $$props;
|
||||||
|
|
||||||
|
using x = {
|
||||||
|
message,
|
||||||
|
[Symbol.dispose]() {
|
||||||
|
console.log(`disposing ${message}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$$payload.out += `<p>`;
|
||||||
|
$.push_element($$payload, 'p', 12, 0);
|
||||||
|
$$payload.out += `${$.escape(x.message)}</p>`;
|
||||||
|
$.pop_element();
|
||||||
|
$.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Using_top_level.render = function () {
|
||||||
|
throw new Error('Component.render(...) is no longer valid in Svelte 5. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information');
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Using_top_level;
|
@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
let { message } = $props();
|
||||||
|
|
||||||
|
using x = {
|
||||||
|
message,
|
||||||
|
[Symbol.dispose]() {
|
||||||
|
console.log(`disposing ${message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>{x.message}</p>
|
Loading…
Reference in new issue