bunnyquery 1.8.16 → 1.8.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/engine.d.mts CHANGED
@@ -1815,32 +1815,54 @@ declare function shouldRescueInFlightMessage(m: ChatMessage, ctx: RescueDecision
1815
1815
  * prepends, a poll resolves, an indexing row splices in or changes label, a link
1816
1816
  * chip goes grey, an image preview finishes decoding, the "Fetching history..."
1817
1817
  * bar appears and disappears. Every one of those changes the height of something
1818
- * that may sit ABOVE the viewport, and the browser answers by keeping scrollTop —
1819
- * which slides the sentence the user was reading out from under them.
1820
- *
1821
- * Both clients had their own copy of a row anchor for the ONE case each could
1822
- * bracket (agent.vue watched its row-key list, the widget bracketed its full
1823
- * re-render). Everything else — anything that changed a height without changing
1824
- * the row SET, and everything asynchronous — was uncovered in both. This is the
1825
- * single implementation, and it covers both shapes:
1818
+ * that may sit ABOVE the viewport, and the browser answers by keeping scrollTop,
1819
+ * which slides the sentence the reader was on out from under them.
1820
+ *
1821
+ * THE ONE RULE: nothing here stores a position to be applied later. Every method
1822
+ * acts at the moment it is called, against the box as it is at that moment, and
1823
+ * is finished when it returns.
1824
+ *
1825
+ * That rule is the whole design, and it was learned the hard way. An earlier
1826
+ * version of this module also had a "park the place they left, put them back when
1827
+ * they return" half — parked/parkedStuck/returning/returnBudget/sawFrozen, a
1828
+ * frozen mode, a retry budget. Every one of those was a stored instruction that
1829
+ * some later event would carry out, and the reader's experience of a stored
1830
+ * instruction is that the chat throws them somewhere for no reason they can see:
1831
+ * they came back from another app, tapped the composer, the on-screen keyboard
1832
+ * fired a resize, the resize triggered a fetch, the fetch settled, and the settle
1833
+ * dutifully executed an instruction recorded before they ever left. Compensating
1834
+ * at the moment of the change needs no such instruction, and a return then needs
1835
+ * no handling at all, because nothing moved the reader in the first place.
1836
+ *
1837
+ * Two shapes, both immediate:
1826
1838
  *
1827
1839
  * preserve(fn) / capture() + restore(a)
1828
1840
  * A mutation you can bracket. Measures immediately before and immediately
1829
1841
  * after, so it is exact even when the mutation tears the list down.
1830
1842
  *
1831
1843
  * remember() + hold()
1832
- * A layout change you CANNOT bracket — an image decoding, a font arriving,
1833
- * a re-parse triggered from a promise. `remember()` runs from the view's
1834
- * scroll handler, so the anchor is always the reader's own last position;
1835
- * `hold()` puts that position back whenever something settles.
1836
- *
1837
- * The staleness rule is what makes the unbracketed half safe. A layout change
1838
- * above the viewport does NOT change scrollTop — the browser preserves it, which
1839
- * is precisely why the content appears to jump. So a remembered anchor is still
1840
- * valid exactly while `box.scrollTop` equals the value it was captured at. If it
1841
- * differs, something moved the box on purpose (the user scrolled, a clamp fired,
1842
- * or the browser's own scroll anchoring already compensated), and `hold()`
1843
- * re-captures rather than dragging the reader back to a position they left.
1844
+ * A layout change you CANNOT bracket: an image decoding, a font arriving, a
1845
+ * re-parse from a promise. remember() runs from the view's scroll handler,
1846
+ * so the anchor is always the reader's own last position.
1847
+ *
1848
+ * hold() is not an exception to the rule, and the staleness check is why. A height
1849
+ * change above the viewport does NOT change scrollTop; the browser preserves it,
1850
+ * which is precisely why the content appears to jump. So the remembered anchor is
1851
+ * valid exactly while `box.scrollTop` still equals the value it was captured at,
1852
+ * i.e. while nothing at all has moved the box. The instant that stops being true
1853
+ * it is re-measured, never replayed. hold() can therefore only ever undo a height
1854
+ * change that just happened, and can never carry out an old intention.
1855
+ *
1856
+ * Two more consequences worth stating, because both were once done the other way:
1857
+ *
1858
+ * NO FREEZE. Compensation runs whether or not the tab is visible. Layout and
1859
+ * getBoundingClientRect are live in a hidden tab; only painting and rAF stop.
1860
+ * Suspending compensation while hidden is what created the need to restore
1861
+ * something afterwards.
1862
+ *
1863
+ * A CLAMP IS ACCEPTED. If the content below the reader shrank, their line is
1864
+ * genuinely unreachable and the browser truncates the correction. Retrying that
1865
+ * later is how a correction turns into an ambush.
1844
1866
  *
1845
1867
  * DOM-free like the rest of the engine: the element shapes below are structural,
1846
1868
  * so real DOM nodes satisfy them while this file imports nothing from lib.dom.
@@ -1914,21 +1936,6 @@ interface ScrollAnchorOptions {
1914
1936
  * scrollToBottom* paths own the position, so every method here no-ops.
1915
1937
  */
1916
1938
  isStuck: () => boolean;
1917
- /**
1918
- * The reader cannot see this box right now (the tab is hidden), so FREEZE:
1919
- * remember where they were and refuse to move them.
1920
- *
1921
- * A hidden tab still runs everything that mutates the list — a resumed poll, a
1922
- * head refresh and its deferred background batch, a settling request — and each
1923
- * of those would otherwise write scrollTop against a layout nobody is looking at
1924
- * and re-stamp the remembered position on the way through. The reader then comes
1925
- * back to wherever the last of those writes happened to land, which is the
1926
- * "somehow placed in the middle" they see, and only the NEXT correction puts
1927
- * them right. So while frozen, reads still happen but nothing writes and nothing
1928
- * re-stamps: the anchor holds the last position the reader actually had, and one
1929
- * hold() on return puts them back on it.
1930
- */
1931
- isFrozen?: () => boolean;
1932
1939
  /**
1933
1940
  * Fall back to the raw scrollTop when the anchored row cannot be found again.
1934
1941
  *
@@ -1951,33 +1958,8 @@ interface ScrollAnchor {
1951
1958
  remember: () => void;
1952
1959
  /** Put the remembered place back, if it is still the reader's own. */
1953
1960
  hold: () => void;
1954
- /** The reader is going away: park the exact place they are leaving. */
1955
- park: () => void;
1956
- /**
1957
- * They are back. Puts them on the parked place, and STAYS ARMED until it has
1958
- * actually landed. Returns true when the host must pin to the bottom instead
1959
- * (the reader left pinned), which only the host can do meaningfully.
1960
- */
1961
- settleReturn: () => boolean;
1962
- /** A return is armed: its position, not the host's, decides scrollTop. */
1963
- isReturning: () => boolean;
1964
- /**
1965
- * The reader is driving. Retire any armed return, at once.
1966
- *
1967
- * Call from the raw gesture handlers (wheel, touchstart, touchmove, keydown),
1968
- * which fire synchronously on a real user action and never for a programmatic
1969
- * scroll. Waiting for the scroll EVENT is not good enough: a background refresh
1970
- * can settle in between, and a settle with a return still armed puts the reader
1971
- * back where they were before they left, which lands as "I touched the scroll
1972
- * and it threw me somewhere else".
1973
- */
1974
- release: () => void;
1975
1961
  /** Pin to the bottom, instantly, recording the write. The ONLY way to pin. */
1976
1962
  pinBottom: () => void;
1977
- /** The box is not being painted (hidden tab). Shared so hosts agree. */
1978
- isFrozen: () => boolean;
1979
- /** Deprecated alias of settleReturn, kept so a stale dist does not break. */
1980
- thaw: () => void;
1981
1963
  /** Absorb one element's own resize. See below. */
1982
1964
  absorb: (el: AnchorGrowableEl | null | undefined) => void;
1983
1965
  /** Drop the remembered place (chat switch, unmount). */
package/dist/engine.d.ts CHANGED
@@ -1815,32 +1815,54 @@ declare function shouldRescueInFlightMessage(m: ChatMessage, ctx: RescueDecision
1815
1815
  * prepends, a poll resolves, an indexing row splices in or changes label, a link
1816
1816
  * chip goes grey, an image preview finishes decoding, the "Fetching history..."
1817
1817
  * bar appears and disappears. Every one of those changes the height of something
1818
- * that may sit ABOVE the viewport, and the browser answers by keeping scrollTop —
1819
- * which slides the sentence the user was reading out from under them.
1820
- *
1821
- * Both clients had their own copy of a row anchor for the ONE case each could
1822
- * bracket (agent.vue watched its row-key list, the widget bracketed its full
1823
- * re-render). Everything else — anything that changed a height without changing
1824
- * the row SET, and everything asynchronous — was uncovered in both. This is the
1825
- * single implementation, and it covers both shapes:
1818
+ * that may sit ABOVE the viewport, and the browser answers by keeping scrollTop,
1819
+ * which slides the sentence the reader was on out from under them.
1820
+ *
1821
+ * THE ONE RULE: nothing here stores a position to be applied later. Every method
1822
+ * acts at the moment it is called, against the box as it is at that moment, and
1823
+ * is finished when it returns.
1824
+ *
1825
+ * That rule is the whole design, and it was learned the hard way. An earlier
1826
+ * version of this module also had a "park the place they left, put them back when
1827
+ * they return" half — parked/parkedStuck/returning/returnBudget/sawFrozen, a
1828
+ * frozen mode, a retry budget. Every one of those was a stored instruction that
1829
+ * some later event would carry out, and the reader's experience of a stored
1830
+ * instruction is that the chat throws them somewhere for no reason they can see:
1831
+ * they came back from another app, tapped the composer, the on-screen keyboard
1832
+ * fired a resize, the resize triggered a fetch, the fetch settled, and the settle
1833
+ * dutifully executed an instruction recorded before they ever left. Compensating
1834
+ * at the moment of the change needs no such instruction, and a return then needs
1835
+ * no handling at all, because nothing moved the reader in the first place.
1836
+ *
1837
+ * Two shapes, both immediate:
1826
1838
  *
1827
1839
  * preserve(fn) / capture() + restore(a)
1828
1840
  * A mutation you can bracket. Measures immediately before and immediately
1829
1841
  * after, so it is exact even when the mutation tears the list down.
1830
1842
  *
1831
1843
  * remember() + hold()
1832
- * A layout change you CANNOT bracket — an image decoding, a font arriving,
1833
- * a re-parse triggered from a promise. `remember()` runs from the view's
1834
- * scroll handler, so the anchor is always the reader's own last position;
1835
- * `hold()` puts that position back whenever something settles.
1836
- *
1837
- * The staleness rule is what makes the unbracketed half safe. A layout change
1838
- * above the viewport does NOT change scrollTop — the browser preserves it, which
1839
- * is precisely why the content appears to jump. So a remembered anchor is still
1840
- * valid exactly while `box.scrollTop` equals the value it was captured at. If it
1841
- * differs, something moved the box on purpose (the user scrolled, a clamp fired,
1842
- * or the browser's own scroll anchoring already compensated), and `hold()`
1843
- * re-captures rather than dragging the reader back to a position they left.
1844
+ * A layout change you CANNOT bracket: an image decoding, a font arriving, a
1845
+ * re-parse from a promise. remember() runs from the view's scroll handler,
1846
+ * so the anchor is always the reader's own last position.
1847
+ *
1848
+ * hold() is not an exception to the rule, and the staleness check is why. A height
1849
+ * change above the viewport does NOT change scrollTop; the browser preserves it,
1850
+ * which is precisely why the content appears to jump. So the remembered anchor is
1851
+ * valid exactly while `box.scrollTop` still equals the value it was captured at,
1852
+ * i.e. while nothing at all has moved the box. The instant that stops being true
1853
+ * it is re-measured, never replayed. hold() can therefore only ever undo a height
1854
+ * change that just happened, and can never carry out an old intention.
1855
+ *
1856
+ * Two more consequences worth stating, because both were once done the other way:
1857
+ *
1858
+ * NO FREEZE. Compensation runs whether or not the tab is visible. Layout and
1859
+ * getBoundingClientRect are live in a hidden tab; only painting and rAF stop.
1860
+ * Suspending compensation while hidden is what created the need to restore
1861
+ * something afterwards.
1862
+ *
1863
+ * A CLAMP IS ACCEPTED. If the content below the reader shrank, their line is
1864
+ * genuinely unreachable and the browser truncates the correction. Retrying that
1865
+ * later is how a correction turns into an ambush.
1844
1866
  *
1845
1867
  * DOM-free like the rest of the engine: the element shapes below are structural,
1846
1868
  * so real DOM nodes satisfy them while this file imports nothing from lib.dom.
@@ -1914,21 +1936,6 @@ interface ScrollAnchorOptions {
1914
1936
  * scrollToBottom* paths own the position, so every method here no-ops.
1915
1937
  */
1916
1938
  isStuck: () => boolean;
1917
- /**
1918
- * The reader cannot see this box right now (the tab is hidden), so FREEZE:
1919
- * remember where they were and refuse to move them.
1920
- *
1921
- * A hidden tab still runs everything that mutates the list — a resumed poll, a
1922
- * head refresh and its deferred background batch, a settling request — and each
1923
- * of those would otherwise write scrollTop against a layout nobody is looking at
1924
- * and re-stamp the remembered position on the way through. The reader then comes
1925
- * back to wherever the last of those writes happened to land, which is the
1926
- * "somehow placed in the middle" they see, and only the NEXT correction puts
1927
- * them right. So while frozen, reads still happen but nothing writes and nothing
1928
- * re-stamps: the anchor holds the last position the reader actually had, and one
1929
- * hold() on return puts them back on it.
1930
- */
1931
- isFrozen?: () => boolean;
1932
1939
  /**
1933
1940
  * Fall back to the raw scrollTop when the anchored row cannot be found again.
1934
1941
  *
@@ -1951,33 +1958,8 @@ interface ScrollAnchor {
1951
1958
  remember: () => void;
1952
1959
  /** Put the remembered place back, if it is still the reader's own. */
1953
1960
  hold: () => void;
1954
- /** The reader is going away: park the exact place they are leaving. */
1955
- park: () => void;
1956
- /**
1957
- * They are back. Puts them on the parked place, and STAYS ARMED until it has
1958
- * actually landed. Returns true when the host must pin to the bottom instead
1959
- * (the reader left pinned), which only the host can do meaningfully.
1960
- */
1961
- settleReturn: () => boolean;
1962
- /** A return is armed: its position, not the host's, decides scrollTop. */
1963
- isReturning: () => boolean;
1964
- /**
1965
- * The reader is driving. Retire any armed return, at once.
1966
- *
1967
- * Call from the raw gesture handlers (wheel, touchstart, touchmove, keydown),
1968
- * which fire synchronously on a real user action and never for a programmatic
1969
- * scroll. Waiting for the scroll EVENT is not good enough: a background refresh
1970
- * can settle in between, and a settle with a return still armed puts the reader
1971
- * back where they were before they left, which lands as "I touched the scroll
1972
- * and it threw me somewhere else".
1973
- */
1974
- release: () => void;
1975
1961
  /** Pin to the bottom, instantly, recording the write. The ONLY way to pin. */
1976
1962
  pinBottom: () => void;
1977
- /** The box is not being painted (hidden tab). Shared so hosts agree. */
1978
- isFrozen: () => boolean;
1979
- /** Deprecated alias of settleReturn, kept so a stale dist does not break. */
1980
- thaw: () => void;
1981
1963
  /** Absorb one element's own resize. See below. */
1982
1964
  absorb: (el: AnchorGrowableEl | null | undefined) => void;
1983
1965
  /** Drop the remembered place (chat switch, unmount). */
package/dist/engine.mjs CHANGED
@@ -2580,7 +2580,6 @@ var ROW_KEY_ATTR = "data-row-key";
2580
2580
  var ROW_POS_ATTR = "data-row-pos";
2581
2581
  var MAX_ALTS = 2;
2582
2582
  var ALT_SCAN_LIMIT = 64;
2583
- var MAX_RETURN_SETTLES = 3;
2584
2583
  var UNKNOWN_ROW_POS = "\0?";
2585
2584
  function createScrollAnchor(options) {
2586
2585
  var held = null;
@@ -2592,13 +2591,24 @@ function createScrollAnchor(options) {
2592
2591
  var kids = box.children;
2593
2592
  var fallback = null;
2594
2593
  var fallbackAt = -1;
2594
+ var behind = [];
2595
2595
  for (var i = 0; i < kids.length; i++) {
2596
2596
  var el = kids[i];
2597
2597
  if (!el || typeof el.getAttribute !== "function") continue;
2598
2598
  var key = el.getAttribute(ROW_KEY_ATTR);
2599
2599
  if (!key) continue;
2600
2600
  var top = el.getBoundingClientRect().top - boxTop;
2601
- if (top + el.offsetHeight <= 0) continue;
2601
+ if (top + el.offsetHeight <= 0) {
2602
+ var bpos = el.getAttribute(ROW_POS_ATTR);
2603
+ behind.push({
2604
+ key,
2605
+ top,
2606
+ pos: bpos === null ? null : bpos || UNKNOWN_ROW_POS,
2607
+ el
2608
+ });
2609
+ if (behind.length > MAX_ALTS) behind.shift();
2610
+ continue;
2611
+ }
2602
2612
  if (top >= box.clientHeight) break;
2603
2613
  var rawPos = el.getAttribute(ROW_POS_ATTR);
2604
2614
  var pos = rawPos === null ? null : rawPos || UNKNOWN_ROW_POS;
@@ -2611,7 +2621,7 @@ function createScrollAnchor(options) {
2611
2621
  el
2612
2622
  };
2613
2623
  if (rawPos === null) {
2614
- cand.alts = collectAlts(box, boxTop, i + 1);
2624
+ cand.alts = withBehind(collectAlts(box, boxTop, i + 1), behind);
2615
2625
  return cand;
2616
2626
  }
2617
2627
  if (!fallback) {
@@ -2620,7 +2630,10 @@ function createScrollAnchor(options) {
2620
2630
  }
2621
2631
  }
2622
2632
  if (fallback) {
2623
- fallback.alts = collectAlts(box, boxTop, fallbackAt + 1, true);
2633
+ fallback.alts = withBehind(
2634
+ collectAlts(box, boxTop, fallbackAt + 1, true) || collectAlts(box, boxTop, fallbackAt + 1),
2635
+ behind
2636
+ );
2624
2637
  return fallback;
2625
2638
  }
2626
2639
  return {
@@ -2652,6 +2665,10 @@ function createScrollAnchor(options) {
2652
2665
  }
2653
2666
  return out.length ? out : void 0;
2654
2667
  }
2668
+ function withBehind(forward, behind) {
2669
+ var out = (forward || []).concat(behind.slice().reverse());
2670
+ return out.length ? out : void 0;
2671
+ }
2655
2672
  function findRow(box, anchor) {
2656
2673
  var el = anchor.el;
2657
2674
  if (el && el.parentNode === box) return el;
@@ -2664,21 +2681,7 @@ function createScrollAnchor(options) {
2664
2681
  }
2665
2682
  return null;
2666
2683
  }
2667
- var sawFrozen = false;
2668
- var parked = null;
2669
- var parkedStuck = false;
2670
- var returning = false;
2671
- var returnBudget = 0;
2672
- var wroteTop = -1;
2673
- var restoreExact = true;
2674
- var restorePinned = false;
2675
- function frozen() {
2676
- var f = !!options.isFrozen && options.isFrozen();
2677
- if (f) sawFrozen = true;
2678
- return f;
2679
- }
2680
- function restore(anchor, unbounded) {
2681
- if (frozen()) return;
2684
+ function restore(anchor) {
2682
2685
  var box = options.getBox();
2683
2686
  if (!box || !anchor || options.isStuck()) return;
2684
2687
  var el = findRow(box, anchor);
@@ -2690,32 +2693,36 @@ function createScrollAnchor(options) {
2690
2693
  var boxTop = box.getBoundingClientRect().top;
2691
2694
  var delta = el.getBoundingClientRect().top - boxTop - anchor.top;
2692
2695
  var slack = Math.abs(box.scrollHeight - anchor.scrollHeight) + box.clientHeight;
2693
- if (!unbounded && (delta > slack || delta < -slack)) {
2694
- lost(box, anchor);
2696
+ var moved = delta - (anchor.scrollTop - box.scrollTop);
2697
+ if (moved > slack || moved < -slack) {
2698
+ el = null;
2699
+ } else {
2700
+ if (delta >= 1 || delta <= -1) box.scrollTop += delta;
2701
+ held = {
2702
+ key: anchor.key,
2703
+ top: anchor.top,
2704
+ pos: anchor.pos,
2705
+ scrollTop: box.scrollTop,
2706
+ scrollHeight: box.scrollHeight,
2707
+ el,
2708
+ // Carried, not dropped: one successful restore used to disarm the
2709
+ // standbys for every later hold.
2710
+ alts: anchor.alts
2711
+ };
2695
2712
  return;
2696
2713
  }
2697
- var want = box.scrollTop + delta;
2698
- if (delta >= 1 || delta <= -1) box.scrollTop += delta;
2699
- wroteTop = box.scrollTop;
2700
- restorePinned = true;
2701
- restoreExact = box.scrollTop >= want - 1 && box.scrollTop <= want + 1;
2702
- held = {
2703
- key: anchor.key,
2704
- top: anchor.top,
2705
- pos: anchor.pos,
2706
- scrollTop: box.scrollTop,
2707
- scrollHeight: box.scrollHeight,
2708
- el,
2709
- // Carried, not dropped: one successful restore used to disarm the
2710
- // standbys for every later hold.
2711
- alts: anchor.alts
2712
- };
2713
- return;
2714
2714
  }
2715
2715
  var alts = anchor.alts;
2716
2716
  for (var ai = 0; alts && ai < alts.length; ai++) {
2717
2717
  var alt = alts[ai];
2718
- var ael = findRow(box, { key: alt.key, top: alt.top, pos: alt.pos, scrollTop: anchor.scrollTop, scrollHeight: anchor.scrollHeight, el: alt.el });
2718
+ var ael = findRow(box, {
2719
+ key: alt.key,
2720
+ top: alt.top,
2721
+ pos: alt.pos,
2722
+ scrollTop: anchor.scrollTop,
2723
+ scrollHeight: anchor.scrollHeight,
2724
+ el: alt.el
2725
+ });
2719
2726
  if (!ael) continue;
2720
2727
  if (alt.pos !== null && alt.pos !== UNKNOWN_ROW_POS) {
2721
2728
  var altLive = ael.getAttribute(ROW_POS_ATTR) || UNKNOWN_ROW_POS;
@@ -2724,12 +2731,9 @@ function createScrollAnchor(options) {
2724
2731
  var aboxTop = box.getBoundingClientRect().top;
2725
2732
  var adelta = ael.getBoundingClientRect().top - aboxTop - alt.top;
2726
2733
  var aslack = Math.abs(box.scrollHeight - anchor.scrollHeight) + box.clientHeight;
2727
- if (!unbounded && (adelta > aslack || adelta < -aslack)) continue;
2728
- var awant = box.scrollTop + adelta;
2734
+ var amoved = adelta - (anchor.scrollTop - box.scrollTop);
2735
+ if (amoved > aslack || amoved < -aslack) continue;
2729
2736
  if (adelta >= 1 || adelta <= -1) box.scrollTop += adelta;
2730
- wroteTop = box.scrollTop;
2731
- restorePinned = true;
2732
- restoreExact = box.scrollTop >= awant - 1 && box.scrollTop <= awant + 1;
2733
2737
  held = {
2734
2738
  key: alt.key,
2735
2739
  top: alt.top,
@@ -2748,13 +2752,9 @@ function createScrollAnchor(options) {
2748
2752
  var grew = box.scrollHeight - anchor.scrollHeight;
2749
2753
  if (grew > 0) {
2750
2754
  box.scrollTop = anchor.scrollTop + grew;
2751
- wroteTop = box.scrollTop;
2752
2755
  return;
2753
2756
  }
2754
- if (options.rawFallback) {
2755
- box.scrollTop = anchor.scrollTop;
2756
- wroteTop = box.scrollTop;
2757
- }
2757
+ if (options.rawFallback) box.scrollTop = anchor.scrollTop;
2758
2758
  }
2759
2759
  function preserve(mutate) {
2760
2760
  var anchor = capture();
@@ -2763,17 +2763,9 @@ function createScrollAnchor(options) {
2763
2763
  return result;
2764
2764
  }
2765
2765
  function remember() {
2766
- var b0 = options.getBox();
2767
- if (returning && b0 && b0.scrollTop !== wroteTop) release();
2768
- if (frozen()) return;
2769
2766
  held = capture();
2770
2767
  }
2771
2768
  function hold() {
2772
- if (frozen()) return;
2773
- if (sawFrozen) {
2774
- settleReturn();
2775
- return;
2776
- }
2777
2769
  var box = options.getBox();
2778
2770
  if (!box || options.isStuck()) {
2779
2771
  held = null;
@@ -2800,86 +2792,17 @@ function createScrollAnchor(options) {
2800
2792
  if (prev === void 0) prev = 0;
2801
2793
  var delta = h - prev;
2802
2794
  if (delta === 0) return;
2803
- if (frozen()) {
2804
- foldFrozenGrowth(box, el, delta);
2805
- return;
2806
- }
2807
2795
  if (el.getBoundingClientRect().top >= box.getBoundingClientRect().top) return;
2808
2796
  box.scrollTop += delta;
2809
- wroteTop = box.scrollTop;
2810
2797
  if (held) held = capture();
2811
2798
  }
2812
- function park() {
2813
- parked = capture();
2814
- parkedStuck = !!options.isStuck();
2815
- returning = true;
2816
- returnBudget = MAX_RETURN_SETTLES;
2817
- }
2818
- function release() {
2819
- parked = null;
2820
- parkedStuck = false;
2821
- returning = false;
2822
- returnBudget = 0;
2823
- }
2824
2799
  function pinBottom() {
2825
2800
  var box = options.getBox();
2826
2801
  if (!box) return;
2827
2802
  box.scrollTop = box.scrollHeight;
2828
- wroteTop = box.scrollTop;
2829
- }
2830
- function settleReturn() {
2831
- if (frozen()) return false;
2832
- var wasFrozen = sawFrozen;
2833
- sawFrozen = false;
2834
- if (!returning && !wasFrozen) return false;
2835
- if (returning) {
2836
- if (returnBudget <= 0) {
2837
- release();
2838
- return false;
2839
- }
2840
- returnBudget--;
2841
- }
2842
- if (parkedStuck) {
2843
- pinBottom();
2844
- return true;
2845
- }
2846
- var target = parked || held;
2847
- restoreExact = true;
2848
- restorePinned = false;
2849
- restore(target, true);
2850
- parked = !restorePinned || !restoreExact ? target : null;
2851
- returning = !!parked && returnBudget > 0;
2852
- if (!returning) {
2853
- parked = null;
2854
- parkedStuck = false;
2855
- returnBudget = 0;
2856
- }
2857
- return false;
2858
- }
2859
- function isReturning() {
2860
- return returning;
2861
- }
2862
- function thaw() {
2863
- settleReturn();
2864
- }
2865
- function foldFrozenGrowth(box, el, delta) {
2866
- var elTop = el.getBoundingClientRect().top;
2867
- foldInto(box, held, elTop, delta);
2868
- foldInto(box, parked, elTop, delta);
2869
- }
2870
- function foldInto(box, a, elTop, delta) {
2871
- if (!a || a.top >= 0) return;
2872
- var rowEl = findRow(box, a);
2873
- if (!rowEl) return;
2874
- var within = elTop - rowEl.getBoundingClientRect().top;
2875
- if (within < 0 || within >= rowEl.offsetHeight) return;
2876
- if (within >= -a.top) return;
2877
- a.top -= delta;
2878
- a.scrollHeight += delta;
2879
2803
  }
2880
2804
  function forget() {
2881
2805
  held = null;
2882
- release();
2883
2806
  }
2884
2807
  return {
2885
2808
  capture,
@@ -2887,13 +2810,7 @@ function createScrollAnchor(options) {
2887
2810
  preserve,
2888
2811
  remember,
2889
2812
  hold,
2890
- park,
2891
- settleReturn,
2892
- isReturning,
2893
- release,
2894
2813
  pinBottom,
2895
- isFrozen: frozen,
2896
- thaw,
2897
2814
  absorb,
2898
2815
  forget
2899
2816
  };