add changeset and tests

bind-get-set
Dominic Gannaway 23 hours ago
parent f75a781a64
commit d5638844e7

@ -0,0 +1,5 @@
---
'svelte': patch
---
feat: add support for bind getters/setters

@ -42,7 +42,7 @@ export function build_component(node, component_name, context, anchor = context.
/** @type {Property[]} */ /** @type {Property[]} */
const custom_css_props = []; const custom_css_props = [];
/** @type {Identifier | MemberExpression | null} */ /** @type {Identifier | MemberExpression | [Expression, Expression] | null} */
let bind_this = null; let bind_this = null;
/** @type {ExpressionStatement[]} */ /** @type {ExpressionStatement[]} */
@ -162,6 +162,9 @@ export function build_component(node, component_name, context, anchor = context.
} }
} else if (attribute.type === 'BindDirective') { } else if (attribute.type === 'BindDirective') {
if (Array.isArray(attribute.expression)) { if (Array.isArray(attribute.expression)) {
if (attribute.name === 'this') {
bind_this = attribute.expression;
} else {
const [get_expression, set_expression] = attribute.expression; const [get_expression, set_expression] = attribute.expression;
const get = /** @type {Expression} */ (context.visit(get_expression)); const get = /** @type {Expression} */ (context.visit(get_expression));
const set = /** @type {Expression} */ (context.visit(set_expression)); const set = /** @type {Expression} */ (context.visit(set_expression));
@ -173,6 +176,7 @@ export function build_component(node, component_name, context, anchor = context.
push_prop(b.get(attribute.name, [b.return(b.call(get_id))])); push_prop(b.get(attribute.name, [b.return(b.call(get_id))]));
push_prop(b.set(attribute.name, [b.stmt(b.call(set_id, b.id('$$value')))])); push_prop(b.set(attribute.name, [b.stmt(b.call(set_id, b.id('$$value')))]));
}
} else { } else {
const expression = /** @type {Expression} */ (context.visit(attribute.expression)); const expression = /** @type {Expression} */ (context.visit(attribute.expression));

@ -171,7 +171,7 @@ export function build_bind_this(expression, value, { state, visit }) {
const get = /** @type {Expression} */ (visit(get_expression)); const get = /** @type {Expression} */ (visit(get_expression));
const set = /** @type {Expression} */ (visit(set_expression)); const set = /** @type {Expression} */ (visit(set_expression));
return b.call('$.bind_this', value, get, set); return b.call('$.bind_this', value, set, get);
} }
/** @type {Identifier[]} */ /** @type {Identifier[]} */

@ -0,0 +1,11 @@
<script>
let div = $state();
$effect(() => {
console.log(div?.textContent);
})
export const someData = '123';
</script>
<div bind:this={() => div, v => div = v}>123</div>

@ -0,0 +1,9 @@
import { test } from '../../test';
export default test({
async test({ assert, target, logs }) {
assert.htmlEqual(target.innerHTML, `<div>123</div>`);
assert.deepEqual(logs, ['123', '123']);
}
});

@ -0,0 +1,11 @@
<script>
import Child from './Child.svelte';
let child = $state();
$effect(() => {
console.log(child.someData);
});
</script>
<Child bind:this={() => child, v => child = v} />

@ -0,0 +1,12 @@
<script>
let { a = $bindable() } = $props();
</script>
<input
type="value"
bind:value={() => a,
(v) => {
console.log('b', v);
a = v;
}}
/>

@ -0,0 +1,20 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
import { assert_ok } from '../../../suite';
export default test({
async test({ assert, target, logs }) {
const input = target.querySelector('input');
assert_ok(input);
input.value = '2';
input.dispatchEvent(new window.Event('input'));
flushSync();
assert.htmlEqual(target.innerHTML, `<button>a: 2</button><input type="value">`);
assert.deepEqual(logs, ['b', '2', 'a', '2']);
}
});

@ -0,0 +1,16 @@
<script>
import Child from './Child.svelte';
let a = $state(0);
</script>
<button onclick={() => a++}>a: {a}</button>
<Child
bind:a={() => a,
(v) => {
console.log('a', v);
a = v;
}}
/>
Loading…
Cancel
Save