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