Skip to content

Commit e26d8ff

Browse files
paoloricciutijhwz
andcommitted
fix: muted reactive without bind and select/autofocus attributes working with function calls
Co-authored-by: Joel Howse <[email protected]>
1 parent 575900d commit e26d8ff

File tree

8 files changed

+82
-10
lines changed

8 files changed

+82
-10
lines changed

.changeset/silver-ties-itch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: `muted` reactive without `bind` and select/autofocus attributes working with function calls

packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ import {
2929
build_render_statement,
3030
build_template_chunk,
3131
build_update_assignment,
32-
get_expression_id
32+
get_expression_id,
33+
memoize_expression
3334
} from './shared/utils.js';
3435
import { visit_event_attribute } from './shared/events.js';
3536

@@ -532,18 +533,28 @@ function build_element_attribute_update_assignment(
532533
const is_svg = context.state.metadata.namespace === 'svg' || element.name === 'svg';
533534
const is_mathml = context.state.metadata.namespace === 'mathml';
534535

536+
const is_autofocus = name === 'autofocus';
537+
535538
let { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) =>
536-
metadata.has_call ? get_expression_id(state, value) : value
539+
metadata.has_call
540+
? is_autofocus
541+
? memoize_expression(state, value)
542+
: get_expression_id(state, value)
543+
: value
537544
);
538545

539-
if (name === 'autofocus') {
546+
if (is_autofocus) {
540547
state.init.push(b.stmt(b.call('$.autofocus', node_id, value)));
541548
return false;
542549
}
543550

544551
// Special case for Firefox who needs it set as a property in order to work
545552
if (name === 'muted') {
546-
state.init.push(b.stmt(b.assignment('=', b.member(node_id, b.id('muted')), value)));
553+
if (!has_state) {
554+
state.init.push(b.stmt(b.assignment('=', b.member(node_id, b.id('muted')), value)));
555+
return false;
556+
}
557+
state.update.push(b.stmt(b.assignment('=', b.member(node_id, b.id('muted')), value)));
547558
return false;
548559
}
549560

@@ -660,8 +671,17 @@ function build_custom_element_attribute_update_assignment(node_id, attribute, co
660671
*/
661672
function build_element_special_value_attribute(element, node_id, attribute, context) {
662673
const state = context.state;
674+
const is_select_with_value =
675+
// attribute.metadata.dynamic would give false negatives because even if the value does not change,
676+
// the inner options could still change, so we need to always treat it as reactive
677+
element === 'select' && attribute.value !== true && !is_text_attribute(attribute);
678+
663679
const { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) =>
664-
metadata.has_call ? get_expression_id(state, value) : value
680+
metadata.has_call
681+
? is_select_with_value
682+
? memoize_expression(context.state, value)
683+
: get_expression_id(state, value)
684+
: value
665685
);
666686

667687
const inner_assignment = b.assignment(
@@ -674,11 +694,6 @@ function build_element_special_value_attribute(element, node_id, attribute, cont
674694
)
675695
);
676696

677-
const is_select_with_value =
678-
// attribute.metadata.dynamic would give false negatives because even if the value does not change,
679-
// the inner options could still change, so we need to always treat it as reactive
680-
element === 'select' && attribute.value !== true && !is_text_attribute(attribute);
681-
682697
const update = b.stmt(
683698
is_select_with_value
684699
? b.sequence([
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
async test({ assert, errors }) {
5+
assert.deepEqual(errors, []);
6+
}
7+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<svelte:options runes />
2+
<script>
3+
function test(){}
4+
</script>
5+
6+
<input autofocus={test()} />
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { flushSync } from 'svelte';
2+
import { ok, test } from '../../test';
3+
4+
export default test({
5+
async test({ assert, target, logs }) {
6+
const btn = target.querySelector('button');
7+
ok(btn);
8+
flushSync(() => {
9+
btn.click();
10+
});
11+
assert.deepEqual(logs, [true]);
12+
}
13+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
let muted = $state(false);
3+
4+
function volume_change(node){
5+
node.addEventListener("volumechange", () => {
6+
console.log(node.muted);
7+
});
8+
}
9+
</script>
10+
11+
<audio use:volume_change {muted}></audio>
12+
<button onclick={() => (muted = !muted)}></button>
13+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
async test({ assert, errors }) {
5+
assert.deepEqual(errors, []);
6+
}
7+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<svelte:options runes />
2+
<script>
3+
function test(){}
4+
</script>
5+
6+
<select value={test()}></select>

0 commit comments

Comments
 (0)