Handle a scroll event. Writes reactive fields (`scroll_offset`, `is_scrolling`) which trigger component re-renders. Returns an optional correction to apply when scrolling stops.
(
state: &Store<VirtualizerState>,
measurements: &[VirtualItem],
offset: u32,
is_scrolling: bool,
)
| 86 | /// |
| 87 | /// Returns an optional correction to apply when scrolling stops. |
| 88 | pub fn set_scroll_offset( |
| 89 | state: &Store<VirtualizerState>, |
| 90 | measurements: &[VirtualItem], |
| 91 | offset: u32, |
| 92 | is_scrolling: bool, |
| 93 | ) -> Option<i32> { |
| 94 | let was_scrolling = *state.is_scrolling().peek(); |
| 95 | let mut correction = None; |
| 96 | |
| 97 | // Reset adjustments when user starts a new scroll |
| 98 | if is_scrolling && !was_scrolling { |
| 99 | state.scroll_adjustments().set(0); |
| 100 | state.deferred_adjustments().set(0); |
| 101 | // Freeze total size when scrolling starts to prevent scrollbar drift |
| 102 | let total = calculate_total_size(measurements); |
| 103 | state.stable_total_size().set(Some(total)); |
| 104 | state |
| 105 | .stable_measurement_count() |
| 106 | .set(Some(measurements.len())); |
| 107 | } |
| 108 | |
| 109 | // When scrolling stops, apply accumulated deferred adjustments |
| 110 | if !is_scrolling && was_scrolling { |
| 111 | state.stable_total_size().set(None); |
| 112 | state.stable_measurement_count().set(None); |
| 113 | |
| 114 | let deferred = *state.deferred_adjustments().peek(); |
| 115 | if deferred != 0 { |
| 116 | correction = Some(deferred); |
| 117 | state.deferred_adjustments().set(0); |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | // Reactive writes – these trigger re-renders. |
| 122 | state.scroll_offset().set(offset); |
| 123 | state.is_scrolling().set(is_scrolling); |
| 124 | |
| 125 | correction |
| 126 | } |
| 127 | |
| 128 | /// Set the viewport size. Reactive write. |
| 129 | pub fn set_viewport_size(state: &Store<VirtualizerState>, size: u32) { |