mirror of https://github.com/sveltejs/svelte
fix: don't throw state_unsafe_mutation when the focused element is removed with bind:activeElement (#18921)
Fixes #15742 With `<svelte:document bind:activeElement />`, clicking a button that removes itself throws `state_unsafe_mutation`. Removing the focused element makes the browser fire `focusout` while the `{#if}` block effect is running, and the binding's listener sets the state from inside that effect. `bind_active_element` now calls `update` inside `without_reactive_context`, like event handlers created with `create_event` and `bind_window_scroll` already do.pull/18896/merge
parent
fe4fb460b1
commit
3f885e3016
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: don't throw `state_unsafe_mutation` when the focused element is removed while `bind:activeElement` is used
|
||||
@ -0,0 +1,27 @@
|
||||
import { test, ok } from '../../assert';
|
||||
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
async test({ assert, target }) {
|
||||
/** @type {string[]} */
|
||||
const errors = [];
|
||||
/** @param {ErrorEvent} event */
|
||||
const on_error = (event) => {
|
||||
errors.push(event.message);
|
||||
event.preventDefault();
|
||||
};
|
||||
window.addEventListener('error', on_error);
|
||||
|
||||
const button = target.querySelector('button');
|
||||
ok(button);
|
||||
|
||||
button.focus();
|
||||
button.click();
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
window.removeEventListener('error', on_error);
|
||||
|
||||
assert.equal(errors.length, 0, errors.join('\n'));
|
||||
assert.equal(target.querySelector('button'), null);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
let activeElement = $state();
|
||||
let show = $state(true);
|
||||
</script>
|
||||
|
||||
<svelte:document bind:activeElement />
|
||||
|
||||
{#if show}
|
||||
<button onclick={() => (show = false)}>hide</button>
|
||||
{/if}
|
||||
Loading…
Reference in new issue