diff --git a/packages/svelte/src/internal/client/dom/elements/bindings/input.js b/packages/svelte/src/internal/client/dom/elements/bindings/input.js index 7c099a47e2..203f911ac5 100644 --- a/packages/svelte/src/internal/client/dom/elements/bindings/input.js +++ b/packages/svelte/src/internal/client/dom/elements/bindings/input.js @@ -4,7 +4,7 @@ import { stringify } from '../../../render.js'; import { listen_to_event_and_reset_event } from './shared.js'; import * as e from '../../../errors.js'; import { get_proxied_value, is } from '../../../proxy.js'; -import { yield_updates } from '../../../runtime.js'; +import { yield_event_updates } from '../../../runtime.js'; /** * @param {HTMLInputElement} input @@ -19,7 +19,9 @@ export function bind_value(input, get_value, update) { e.bind_invalid_checkbox_value(); } - yield_updates(() => update(is_numberlike_input(input) ? to_number(input.value) : input.value)); + yield_event_updates(() => + update(is_numberlike_input(input) ? to_number(input.value) : input.value) + ); }); render_effect(() => { @@ -85,10 +87,10 @@ export function bind_group(inputs, group_index, input, get_value, update) { value = get_binding_group_value(binding_group, value, input.checked); } - yield_updates(() => update(value)); + yield_event_updates(() => update(value)); }, // TODO better default value handling - () => yield_updates(() => update(is_checkbox ? [] : null)) + () => yield_event_updates(() => update(is_checkbox ? [] : null)) ); render_effect(() => { @@ -129,7 +131,7 @@ export function bind_group(inputs, group_index, input, get_value, update) { export function bind_checked(input, get_value, update) { listen_to_event_and_reset_event(input, 'change', () => { var value = input.checked; - yield_updates(() => update(value)); + yield_event_updates(() => update(value)); }); if (get_value() == undefined) { @@ -188,7 +190,7 @@ function to_number(value) { */ export function bind_files(input, get_value, update) { listen_to_event_and_reset_event(input, 'change', () => { - yield_updates(() => update(input.files)); + yield_event_updates(() => update(input.files)); }); render_effect(() => { input.files = get_value(); diff --git a/packages/svelte/src/internal/client/dom/elements/bindings/media.js b/packages/svelte/src/internal/client/dom/elements/bindings/media.js index c47ee7a99c..000443763b 100644 --- a/packages/svelte/src/internal/client/dom/elements/bindings/media.js +++ b/packages/svelte/src/internal/client/dom/elements/bindings/media.js @@ -1,7 +1,7 @@ import { hydrating } from '../../hydration.js'; import { render_effect, effect } from '../../../reactivity/effects.js'; import { listen } from './shared.js'; -import { yield_updates } from '../../../runtime.js'; +import { yield_event_updates } from '../../../runtime.js'; /** @param {TimeRanges} ranges */ function time_ranges_to_array(ranges) { @@ -36,7 +36,7 @@ export function bind_current_time(media, get_value, update) { } updating = true; - yield_updates(() => update(media.currentTime)); + yield_event_updates(() => update(media.currentTime)); }; raf_id = requestAnimationFrame(callback); @@ -62,7 +62,7 @@ export function bind_current_time(media, get_value, update) { */ export function bind_buffered(media, update) { listen(media, ['loadedmetadata', 'progress'], () => - yield_updates(() => update(time_ranges_to_array(media.buffered))) + yield_event_updates(() => update(time_ranges_to_array(media.buffered))) ); } @@ -80,7 +80,7 @@ export function bind_seekable(media, update) { */ export function bind_played(media, update) { listen(media, ['timeupdate'], () => - yield_updates(() => update(time_ranges_to_array(media.played))) + yield_event_updates(() => update(time_ranges_to_array(media.played))) ); } @@ -89,7 +89,7 @@ export function bind_played(media, update) { * @param {(seeking: boolean) => void} update */ export function bind_seeking(media, update) { - listen(media, ['seeking', 'seeked'], () => yield_updates(() => update(media.seeking))); + listen(media, ['seeking', 'seeked'], () => yield_event_updates(() => update(media.seeking))); } /** @@ -97,7 +97,7 @@ export function bind_seeking(media, update) { * @param {(seeking: boolean) => void} update */ export function bind_ended(media, update) { - listen(media, ['timeupdate', 'ended'], () => yield_updates(() => update(media.ended))); + listen(media, ['timeupdate', 'ended'], () => yield_event_updates(() => update(media.ended))); } /** @@ -108,7 +108,7 @@ export function bind_ready_state(media, update) { listen( media, ['loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'emptied'], - () => yield_updates(() => update(media.readyState)) + () => yield_event_updates(() => update(media.readyState)) ); } @@ -132,7 +132,7 @@ export function bind_playback_rate(media, get_value, update) { } listen(media, ['ratechange'], () => { - if (!updating) yield_updates(() => update(media.playbackRate)); + if (!updating) yield_event_updates(() => update(media.playbackRate)); updating = false; }); }); @@ -150,7 +150,7 @@ export function bind_paused(media, get_value, update) { var callback = () => { if (paused !== media.paused) { paused = media.paused; - yield_updates(() => update((paused = media.paused))); + yield_event_updates(() => update((paused = media.paused))); } }; @@ -175,7 +175,7 @@ export function bind_paused(media, get_value, update) { media.pause(); } else { media.play().catch(() => { - yield_updates(() => update((paused = true))); + yield_event_updates(() => update((paused = true))); }); } }; @@ -239,7 +239,7 @@ export function bind_muted(media, get_value, update) { var callback = () => { updating = true; - yield_updates(() => update(media.muted)); + yield_event_updates(() => update(media.muted)); }; if (get_value() == null) { diff --git a/packages/svelte/src/internal/client/dom/elements/bindings/navigator.js b/packages/svelte/src/internal/client/dom/elements/bindings/navigator.js index 28d6bf9926..39a7e60527 100644 --- a/packages/svelte/src/internal/client/dom/elements/bindings/navigator.js +++ b/packages/svelte/src/internal/client/dom/elements/bindings/navigator.js @@ -1,4 +1,4 @@ -import { yield_updates } from '../../../runtime.js'; +import { yield_event_updates } from '../../../runtime.js'; import { listen } from './shared.js'; /** @@ -7,6 +7,6 @@ import { listen } from './shared.js'; */ export function bind_online(update) { listen(window, ['online', 'offline'], () => { - yield_updates(() => update(navigator.onLine)); + yield_event_updates(() => update(navigator.onLine)); }); } diff --git a/packages/svelte/src/internal/client/dom/elements/bindings/select.js b/packages/svelte/src/internal/client/dom/elements/bindings/select.js index 624c77abb0..5891aa5f81 100644 --- a/packages/svelte/src/internal/client/dom/elements/bindings/select.js +++ b/packages/svelte/src/internal/client/dom/elements/bindings/select.js @@ -1,6 +1,6 @@ import { effect } from '../../../reactivity/effects.js'; import { listen_to_event_and_reset_event } from './shared.js'; -import { untrack, yield_updates } from '../../../runtime.js'; +import { untrack, yield_event_updates } from '../../../runtime.js'; import { is } from '../../../proxy.js'; /** @@ -90,7 +90,7 @@ export function bind_select_value(select, get_value, update) { value = selected_option && get_option_value(selected_option); } - yield_updates(() => update(value)); + yield_event_updates(() => update(value)); }); // Needs to be an effect, not a render_effect, so that in case of each loops the logic runs after the each block has updated diff --git a/packages/svelte/src/internal/client/dom/elements/bindings/size.js b/packages/svelte/src/internal/client/dom/elements/bindings/size.js index 771975d7a3..5ade7d5a7e 100644 --- a/packages/svelte/src/internal/client/dom/elements/bindings/size.js +++ b/packages/svelte/src/internal/client/dom/elements/bindings/size.js @@ -1,5 +1,5 @@ import { effect, render_effect } from '../../../reactivity/effects.js'; -import { untrack, yield_updates } from '../../../runtime.js'; +import { untrack, yield_event_updates } from '../../../runtime.js'; /** * Resize observer singleton. @@ -90,7 +90,7 @@ export function bind_resize_observer(element, type, update) { var unsub = observer.observe( element, - /** @param {any} entry */ (entry) => yield_updates(() => update(entry[type])) + /** @param {any} entry */ (entry) => yield_event_updates(() => update(entry[type])) ); render_effect(() => unsub); } @@ -104,7 +104,7 @@ export function bind_element_size(element, type, update) { var unsub = resize_observer_border_box.observe(element, () => update(element[type])); effect(() => { - yield_updates(() => untrack(() => update(element[type]))); + yield_event_updates(() => untrack(() => update(element[type]))); return unsub; }); } diff --git a/packages/svelte/src/internal/client/dom/elements/bindings/this.js b/packages/svelte/src/internal/client/dom/elements/bindings/this.js index 125ead6cd2..df06c46f2f 100644 --- a/packages/svelte/src/internal/client/dom/elements/bindings/this.js +++ b/packages/svelte/src/internal/client/dom/elements/bindings/this.js @@ -1,6 +1,6 @@ import { STATE_SYMBOL } from '../../../constants.js'; import { effect, render_effect } from '../../../reactivity/effects.js'; -import { untrack, yield_updates } from '../../../runtime.js'; +import { untrack, yield_event_updates } from '../../../runtime.js'; import { queue_micro_task } from '../../task.js'; /** @@ -37,7 +37,7 @@ export function bind_this(element_or_component, update, get_value, get_parts) { untrack(() => { if (element_or_component !== get_value(...parts)) { - yield_updates(() => { + yield_event_updates(() => { update(element_or_component, ...parts); // If this is an effect rerun (cause: each block context changes), then nullfiy the binding at // the previous position if it isn't already taken over by a different effect. diff --git a/packages/svelte/src/internal/client/dom/elements/bindings/window.js b/packages/svelte/src/internal/client/dom/elements/bindings/window.js index 13fa9d4225..511f2d5666 100644 --- a/packages/svelte/src/internal/client/dom/elements/bindings/window.js +++ b/packages/svelte/src/internal/client/dom/elements/bindings/window.js @@ -1,5 +1,5 @@ import { effect, render_effect } from '../../../reactivity/effects.js'; -import { yield_updates } from '../../../runtime.js'; +import { yield_event_updates } from '../../../runtime.js'; import { listen } from './shared.js'; /** @@ -16,7 +16,7 @@ export function bind_window_scroll(type, get_value, update) { clearTimeout(timeout); timeout = setTimeout(clear, 100); // TODO use scrollend event if supported (or when supported everywhere?) - yield_updates(() => update(window[is_scrolling_x ? 'scrollX' : 'scrollY'])); + yield_event_updates(() => update(window[is_scrolling_x ? 'scrollX' : 'scrollY'])); }; addEventListener('scroll', target_handler, { @@ -64,5 +64,5 @@ export function bind_window_scroll(type, get_value, update) { * @param {(size: number) => void} update */ export function bind_window_size(type, update) { - listen(window, ['resize'], () => yield_updates(() => update(window[type]))); + listen(window, ['resize'], () => yield_event_updates(() => update(window[type]))); } diff --git a/packages/svelte/src/internal/client/dom/elements/events.js b/packages/svelte/src/internal/client/dom/elements/events.js index fb2cf88c37..1f94162064 100644 --- a/packages/svelte/src/internal/client/dom/elements/events.js +++ b/packages/svelte/src/internal/client/dom/elements/events.js @@ -1,6 +1,6 @@ import { render_effect } from '../../reactivity/effects.js'; import { all_registered_events, root_event_handles } from '../../render.js'; -import { yield_updates } from '../../runtime.js'; +import { yield_event_updates } from '../../runtime.js'; import { define_property, is_array } from '../../utils.js'; import { hydrating } from '../hydration.js'; import { queue_micro_task } from '../task.js'; @@ -48,7 +48,7 @@ export function create_event(event_name, dom, handler, options) { handle_event_propagation(dom, event); } if (!event.cancelBubble) { - return yield_updates(() => handler.call(this, event)); + return yield_event_updates(() => handler.call(this, event)); } } @@ -204,7 +204,7 @@ export function handle_event_propagation(handler_element, event) { } try { - yield_updates(() => next(/** @type {Element} */ (current_target))); + yield_event_updates(() => next(/** @type {Element} */ (current_target))); } finally { // @ts-expect-error is used above event.__root = handler_element; diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 4c341e5cfc..1f0a0bfdab 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -738,7 +738,7 @@ function process_effects(effect, collected_effects) { /** * @param {{ (): void; (): any; }} fn */ -export function yield_updates(fn) { +export function yield_event_updates(fn) { const previous_scheduler_mode = current_scheduler_mode; try { current_scheduler_mode = FLUSH_YIELD; @@ -767,6 +767,8 @@ export function flush_sync(fn, flush_previous = true) { current_scheduler_mode = FLUSH_SYNC; current_queued_root_effects = root_effects; + is_yield_task_queued = false; + is_micro_task_queued = false; if (flush_previous) { flush_queued_root_effects(previous_queued_root_effects); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-7/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-7/_config.js index d3737b0a2a..f51154ef00 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-7/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-7/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ @@ -22,15 +23,15 @@ export default test({ `, - async test({ assert, target, window }) { + test({ assert, target, window }) { const inputs = target.querySelectorAll('input'); const checked = new Set(); /** @param {number} i */ - const checkInbox = async (i) => { + const checkInbox = (i) => { checked.add(i); inputs[i].checked = true; - await inputs[i].dispatchEvent(event); + inputs[i].dispatchEvent(event); }; for (let i = 0; i < 18; i++) { @@ -39,17 +40,20 @@ export default test({ const event = new window.Event('change'); - await checkInbox(2); + checkInbox(2); + flushSync(); for (let i = 0; i < 18; i++) { assert.equal(inputs[i].checked, checked.has(i)); } - await checkInbox(12); + checkInbox(12); + flushSync(); for (let i = 0; i < 18; i++) { assert.equal(inputs[i].checked, checked.has(i)); } - await checkInbox(8); + checkInbox(8); + flushSync(); for (let i = 0; i < 18; i++) { assert.equal(inputs[i].checked, checked.has(i)); } diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-number-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-number-2/_config.js index 264982c365..e6b235676d 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-input-number-2/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-number-2/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { ok, test } from '../../test'; export default test({ @@ -16,6 +17,7 @@ export default test({ input.value = '5.'; input.dispatchEvent(inputEvent); + flushSync(); // input type number has value === "" if ends with dot/comma assert.equal(component.value, undefined); @@ -23,12 +25,14 @@ export default test({ input.value = '5.5'; input.dispatchEvent(inputEvent); + flushSync(); assert.equal(component.value, 5.5); assert.equal(input.value, '5.5'); input.value = '5.50'; input.dispatchEvent(inputEvent); + flushSync(); assert.equal(component.value, 5.5); assert.equal(input.value, '5.50');