diff --git a/packages/svelte/src/ambient.d.ts b/packages/svelte/src/ambient.d.ts index 5200d386e6..41fd7ab48b 100644 --- a/packages/svelte/src/ambient.d.ts +++ b/packages/svelte/src/ambient.d.ts @@ -144,8 +144,8 @@ declare namespace $state { * * @param initial The initial value */ - export function opaque(initial: T): [T, () => void]; - export function opaque(): [T | undefined, () => void]; + export function opaque(initial: T): [T, (mutate?: (value: T) => void) => void]; + export function opaque(): [T | undefined, (mutate?: (value: T) => void) => void]; /** * To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`: diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 331dff952e..c88db8b6d9 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -164,7 +164,13 @@ export function VariableDeclaration(node, context) { b.declarator(state_id, b.call('$.opaque_state', value)), b.declarator( invalidation_id, - b.thunk(b.call('$.set', state_id, b.member(state_id, b.id('v')))) + b.arrow( + [b.id('$$fn')], + b.sequence([ + b.call(b.id('$$fn'), b.member(state_id, b.id('v'))), + b.call('$.set', state_id, b.member(state_id, b.id('v'))) + ]) + ) ) ); continue; diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js index 889fffd31a..a70f2852b8 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js @@ -98,7 +98,7 @@ export function VariableDeclaration(node, context) { const invalidation_id = /** @type {Identifier} */ (pattern.elements[1]); declarations.push( b.declarator(state_id, value), - b.declarator(invalidation_id, b.thunk(b.block([]))) + b.declarator(invalidation_id, b.arrow([b.id('$$fn')], b.call(b.id('$$fn'), state_id))) ); continue; } diff --git a/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/Child.svelte b/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/Child.svelte new file mode 100644 index 0000000000..449f93e450 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/Child.svelte @@ -0,0 +1,13 @@ + + +

{obj.count}

diff --git a/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/_config.js b/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/_config.js new file mode 100644 index 0000000000..b5f7e88154 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/_config.js @@ -0,0 +1,18 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: `

0

`, + + test({ assert, target }) { + const button = target.querySelector('button'); + + button?.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, `

1

`); + + button?.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, `

2

`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/main.svelte b/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/main.svelte new file mode 100644 index 0000000000..8efd150aec --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/main.svelte @@ -0,0 +1,8 @@ + + + + diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 82a20ff9c5..f39299a08a 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -2691,8 +2691,8 @@ declare namespace $state { * * @param initial The initial value */ - export function opaque(initial: T): [T, () => void]; - export function opaque(): [T | undefined, () => void]; + export function opaque(initial: T): [T, (mutate?: (value: T) => void) => void]; + export function opaque(): [T | undefined, (mutate?: (value: T) => void) => void]; /** * To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`: