From 98b46cb8a0ee21fa1f872e6e10133834777063e2 Mon Sep 17 00:00:00 2001 From: adiguba Date: Sat, 26 Oct 2024 13:26:16 +0200 Subject: [PATCH 1/2] make use:action reactive --- .../client/visitors/UseDirective.js | 27 +++++++------------ .../internal/client/dom/elements/actions.js | 8 ++++-- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/UseDirective.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/UseDirective.js index 311ba3649763..43310f79fa61 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/UseDirective.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/UseDirective.js @@ -9,26 +9,19 @@ import { parse_directive_name } from './shared/utils.js'; * @param {ComponentContext} context */ export function UseDirective(node, context) { - const params = [b.id('$$node')]; - - if (node.expression) { - params.push(b.id('$$action_arg')); + let action = /** @type {Expression} */ (context.visit(parse_directive_name(node.name))); + if (action.type === 'MemberExpression') { + action = b.maybe_call(b.member(action, 'bind', false, true), /** @type {Expression} */ (action.object)); } - /** @type {Expression[]} */ - const args = [ - context.state.node, - b.arrow( - params, - b.call(/** @type {Expression} */ (context.visit(parse_directive_name(node.name))), ...params) - ) - ]; - - if (node.expression) { - args.push(b.thunk(/** @type {Expression} */ (context.visit(node.expression)))); - } + const get_action = b.arrow([], action); + const get_value = node.expression + ? b.thunk(/** @type {Expression} */ (context.visit(node.expression))) + : undefined; // actions need to run after attribute updates in order with bindings/events - context.state.after_update.push(b.stmt(b.call('$.action', ...args))); + context.state.after_update.push( + b.stmt(b.call('$.action', context.state.node, get_action, get_value)) + ); context.next(); } diff --git a/packages/svelte/src/internal/client/dom/elements/actions.js b/packages/svelte/src/internal/client/dom/elements/actions.js index dad3ce6fef5d..4a8ff45d77c3 100644 --- a/packages/svelte/src/internal/client/dom/elements/actions.js +++ b/packages/svelte/src/internal/client/dom/elements/actions.js @@ -6,12 +6,16 @@ import { deep_read_state, untrack } from '../../runtime.js'; /** * @template P * @param {Element} dom - * @param {(dom: Element, value?: P) => ActionPayload

} action + * @param {() => (((dom: Element, value?: P) => ActionPayload

) | null | undefined)} get_action * @param {() => P} [get_value] * @returns {void} */ -export function action(dom, action, get_value) { +export function action(dom, get_action, get_value) { effect(() => { + const action = get_action(); + if (action == null) { + return; + } var payload = untrack(() => action(dom, get_value?.()) || {}); if (get_value && payload?.update) { From e9b27371ad52aed3cda7d9daa570ffa98871299c Mon Sep 17 00:00:00 2001 From: adiguba Date: Sat, 26 Oct 2024 15:26:28 +0200 Subject: [PATCH 2/2] lint + test --- .../client/visitors/UseDirective.js | 5 +- .../samples/action-reactive/Child.svelte | 4 ++ .../samples/action-reactive/_config.js | 49 +++++++++++++++++++ .../samples/action-reactive/main.svelte | 36 ++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 packages/svelte/tests/runtime-runes/samples/action-reactive/Child.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/action-reactive/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/action-reactive/main.svelte diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/UseDirective.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/UseDirective.js index 43310f79fa61..46284436c3f2 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/UseDirective.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/UseDirective.js @@ -11,7 +11,10 @@ import { parse_directive_name } from './shared/utils.js'; export function UseDirective(node, context) { let action = /** @type {Expression} */ (context.visit(parse_directive_name(node.name))); if (action.type === 'MemberExpression') { - action = b.maybe_call(b.member(action, 'bind', false, true), /** @type {Expression} */ (action.object)); + action = b.maybe_call( + b.member(action, 'bind', false, true), + /** @type {Expression} */ (action.object) + ); } const get_action = b.arrow([], action); diff --git a/packages/svelte/tests/runtime-runes/samples/action-reactive/Child.svelte b/packages/svelte/tests/runtime-runes/samples/action-reactive/Child.svelte new file mode 100644 index 000000000000..cc79512368bb --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/action-reactive/Child.svelte @@ -0,0 +1,4 @@ + +

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/action-reactive/_config.js b/packages/svelte/tests/runtime-runes/samples/action-reactive/_config.js new file mode 100644 index 000000000000..bda5e019be93 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/action-reactive/_config.js @@ -0,0 +1,49 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: `
`, + + async test({ assert, target }) { + const [div] = target.querySelectorAll('div'); + const [set_action1, set_action2, set_null, increment] = target.querySelectorAll('button'); + + assert.equal(div.innerText, undefined); + + flushSync(() => set_action1.click()); + assert.equal(div.innerText, 'action1 value=0'); + + flushSync(() => increment.click()); + assert.equal(div.innerText, 'action1 updated=1'); + + flushSync(() => set_null.click()); + assert.equal(div.innerText, 'action1 destroyed'); + + flushSync(() => set_action2.click()); + assert.equal(div.innerText, '1'); + + flushSync(() => increment.click()); + assert.equal(div.innerText, '2'); + + flushSync(() => set_null.click()); + assert.equal(div.innerText, ''); + + flushSync(() => increment.click()); + assert.equal(div.innerText, ''); + + flushSync(() => set_action1.click()); + assert.equal(div.innerText, 'action1 value=3'); + + flushSync(() => increment.click()); + assert.equal(div.innerText, 'action1 updated=4'); + + flushSync(() => set_action1.click()); + assert.equal(div.innerText, 'action1 updated=4'); + + flushSync(() => increment.click()); + assert.equal(div.innerText, 'action1 updated=5'); + + flushSync(() => set_action2.click()); + assert.equal(div.innerText, '5'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/action-reactive/main.svelte b/packages/svelte/tests/runtime-runes/samples/action-reactive/main.svelte new file mode 100644 index 000000000000..090f157133b9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/action-reactive/main.svelte @@ -0,0 +1,36 @@ + + + + + + +