bunnyquery 1.8.14 → 1.8.16

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.cjs CHANGED
@@ -2580,6 +2580,9 @@ function shouldRescueInFlightMessage(m, ctx) {
2580
2580
  // src/engine/scroll_anchor.ts
2581
2581
  var ROW_KEY_ATTR = "data-row-key";
2582
2582
  var ROW_POS_ATTR = "data-row-pos";
2583
+ var MAX_ALTS = 2;
2584
+ var ALT_SCAN_LIMIT = 64;
2585
+ var MAX_RETURN_SETTLES = 3;
2583
2586
  var UNKNOWN_ROW_POS = "\0?";
2584
2587
  function createScrollAnchor(options) {
2585
2588
  var held = null;
@@ -2590,6 +2593,7 @@ function createScrollAnchor(options) {
2590
2593
  var boxTop = box.getBoundingClientRect().top;
2591
2594
  var kids = box.children;
2592
2595
  var fallback = null;
2596
+ var fallbackAt = -1;
2593
2597
  for (var i = 0; i < kids.length; i++) {
2594
2598
  var el = kids[i];
2595
2599
  if (!el || typeof el.getAttribute !== "function") continue;
@@ -2608,10 +2612,20 @@ function createScrollAnchor(options) {
2608
2612
  scrollHeight: box.scrollHeight,
2609
2613
  el
2610
2614
  };
2611
- if (rawPos === null) return cand;
2612
- if (!fallback) fallback = cand;
2615
+ if (rawPos === null) {
2616
+ cand.alts = collectAlts(box, boxTop, i + 1);
2617
+ return cand;
2618
+ }
2619
+ if (!fallback) {
2620
+ fallback = cand;
2621
+ fallbackAt = i;
2622
+ }
2623
+ }
2624
+ if (fallback) {
2625
+ fallback.alts = collectAlts(box, boxTop, fallbackAt + 1, true);
2626
+ return fallback;
2613
2627
  }
2614
- return fallback || {
2628
+ return {
2615
2629
  key: null,
2616
2630
  top: 0,
2617
2631
  pos: null,
@@ -2620,6 +2634,26 @@ function createScrollAnchor(options) {
2620
2634
  el: null
2621
2635
  };
2622
2636
  }
2637
+ function collectAlts(box, boxTop, from, ordinaryOnly) {
2638
+ var out = [];
2639
+ var kids = box.children;
2640
+ var stop = Math.min(kids.length, from + ALT_SCAN_LIMIT);
2641
+ for (var i = from; i < stop && out.length < MAX_ALTS; i++) {
2642
+ var el = kids[i];
2643
+ if (!el || typeof el.getAttribute !== "function") continue;
2644
+ var key = el.getAttribute(ROW_KEY_ATTR);
2645
+ if (!key) continue;
2646
+ var rawPos = el.getAttribute(ROW_POS_ATTR);
2647
+ if (ordinaryOnly && rawPos !== null) continue;
2648
+ out.push({
2649
+ key,
2650
+ top: el.getBoundingClientRect().top - boxTop,
2651
+ pos: rawPos === null ? null : rawPos || UNKNOWN_ROW_POS,
2652
+ el
2653
+ });
2654
+ }
2655
+ return out.length ? out : void 0;
2656
+ }
2623
2657
  function findRow(box, anchor) {
2624
2658
  var el = anchor.el;
2625
2659
  if (el && el.parentNode === box) return el;
@@ -2632,31 +2666,80 @@ function createScrollAnchor(options) {
2632
2666
  }
2633
2667
  return null;
2634
2668
  }
2635
- function restore(anchor) {
2669
+ var sawFrozen = false;
2670
+ var parked = null;
2671
+ var parkedStuck = false;
2672
+ var returning = false;
2673
+ var returnBudget = 0;
2674
+ var wroteTop = -1;
2675
+ var restoreExact = true;
2676
+ var restorePinned = false;
2677
+ function frozen() {
2678
+ var f = !!options.isFrozen && options.isFrozen();
2679
+ if (f) sawFrozen = true;
2680
+ return f;
2681
+ }
2682
+ function restore(anchor, unbounded) {
2683
+ if (frozen()) return;
2636
2684
  var box = options.getBox();
2637
2685
  if (!box || !anchor || options.isStuck()) return;
2638
2686
  var el = findRow(box, anchor);
2639
2687
  if (el) {
2640
2688
  var livePos = el.getAttribute(ROW_POS_ATTR) || UNKNOWN_ROW_POS;
2641
- if (anchor.pos !== null && anchor.pos !== UNKNOWN_ROW_POS && livePos !== UNKNOWN_ROW_POS && livePos !== anchor.pos) {
2642
- lost(box, anchor);
2643
- return;
2644
- }
2689
+ if (anchor.pos !== null && anchor.pos !== UNKNOWN_ROW_POS && livePos !== UNKNOWN_ROW_POS && livePos !== anchor.pos) el = null;
2690
+ }
2691
+ if (el) {
2645
2692
  var boxTop = box.getBoundingClientRect().top;
2646
2693
  var delta = el.getBoundingClientRect().top - boxTop - anchor.top;
2647
2694
  var slack = Math.abs(box.scrollHeight - anchor.scrollHeight) + box.clientHeight;
2648
- if (delta > slack || delta < -slack) {
2695
+ if (!unbounded && (delta > slack || delta < -slack)) {
2649
2696
  lost(box, anchor);
2650
2697
  return;
2651
2698
  }
2699
+ var want = box.scrollTop + delta;
2652
2700
  if (delta >= 1 || delta <= -1) box.scrollTop += delta;
2701
+ wroteTop = box.scrollTop;
2702
+ restorePinned = true;
2703
+ restoreExact = box.scrollTop >= want - 1 && box.scrollTop <= want + 1;
2653
2704
  held = {
2654
2705
  key: anchor.key,
2655
2706
  top: anchor.top,
2656
2707
  pos: anchor.pos,
2657
2708
  scrollTop: box.scrollTop,
2658
2709
  scrollHeight: box.scrollHeight,
2659
- el
2710
+ el,
2711
+ // Carried, not dropped: one successful restore used to disarm the
2712
+ // standbys for every later hold.
2713
+ alts: anchor.alts
2714
+ };
2715
+ return;
2716
+ }
2717
+ var alts = anchor.alts;
2718
+ for (var ai = 0; alts && ai < alts.length; ai++) {
2719
+ var alt = alts[ai];
2720
+ var ael = findRow(box, { key: alt.key, top: alt.top, pos: alt.pos, scrollTop: anchor.scrollTop, scrollHeight: anchor.scrollHeight, el: alt.el });
2721
+ if (!ael) continue;
2722
+ if (alt.pos !== null && alt.pos !== UNKNOWN_ROW_POS) {
2723
+ var altLive = ael.getAttribute(ROW_POS_ATTR) || UNKNOWN_ROW_POS;
2724
+ if (altLive !== UNKNOWN_ROW_POS && altLive !== alt.pos) continue;
2725
+ }
2726
+ var aboxTop = box.getBoundingClientRect().top;
2727
+ var adelta = ael.getBoundingClientRect().top - aboxTop - alt.top;
2728
+ var aslack = Math.abs(box.scrollHeight - anchor.scrollHeight) + box.clientHeight;
2729
+ if (!unbounded && (adelta > aslack || adelta < -aslack)) continue;
2730
+ var awant = box.scrollTop + adelta;
2731
+ if (adelta >= 1 || adelta <= -1) box.scrollTop += adelta;
2732
+ wroteTop = box.scrollTop;
2733
+ restorePinned = true;
2734
+ restoreExact = box.scrollTop >= awant - 1 && box.scrollTop <= awant + 1;
2735
+ held = {
2736
+ key: alt.key,
2737
+ top: alt.top,
2738
+ pos: alt.pos,
2739
+ scrollTop: box.scrollTop,
2740
+ scrollHeight: box.scrollHeight,
2741
+ el: ael,
2742
+ alts: alts.slice(ai + 1)
2660
2743
  };
2661
2744
  return;
2662
2745
  }
@@ -2667,9 +2750,13 @@ function createScrollAnchor(options) {
2667
2750
  var grew = box.scrollHeight - anchor.scrollHeight;
2668
2751
  if (grew > 0) {
2669
2752
  box.scrollTop = anchor.scrollTop + grew;
2753
+ wroteTop = box.scrollTop;
2670
2754
  return;
2671
2755
  }
2672
- if (options.rawFallback) box.scrollTop = anchor.scrollTop;
2756
+ if (options.rawFallback) {
2757
+ box.scrollTop = anchor.scrollTop;
2758
+ wroteTop = box.scrollTop;
2759
+ }
2673
2760
  }
2674
2761
  function preserve(mutate) {
2675
2762
  var anchor = capture();
@@ -2678,9 +2765,17 @@ function createScrollAnchor(options) {
2678
2765
  return result;
2679
2766
  }
2680
2767
  function remember() {
2768
+ var b0 = options.getBox();
2769
+ if (returning && b0 && b0.scrollTop !== wroteTop) release();
2770
+ if (frozen()) return;
2681
2771
  held = capture();
2682
2772
  }
2683
2773
  function hold() {
2774
+ if (frozen()) return;
2775
+ if (sawFrozen) {
2776
+ settleReturn();
2777
+ return;
2778
+ }
2684
2779
  var box = options.getBox();
2685
2780
  if (!box || options.isStuck()) {
2686
2781
  held = null;
@@ -2707,12 +2802,86 @@ function createScrollAnchor(options) {
2707
2802
  if (prev === void 0) prev = 0;
2708
2803
  var delta = h - prev;
2709
2804
  if (delta === 0) return;
2805
+ if (frozen()) {
2806
+ foldFrozenGrowth(box, el, delta);
2807
+ return;
2808
+ }
2710
2809
  if (el.getBoundingClientRect().top >= box.getBoundingClientRect().top) return;
2711
2810
  box.scrollTop += delta;
2811
+ wroteTop = box.scrollTop;
2712
2812
  if (held) held = capture();
2713
2813
  }
2814
+ function park() {
2815
+ parked = capture();
2816
+ parkedStuck = !!options.isStuck();
2817
+ returning = true;
2818
+ returnBudget = MAX_RETURN_SETTLES;
2819
+ }
2820
+ function release() {
2821
+ parked = null;
2822
+ parkedStuck = false;
2823
+ returning = false;
2824
+ returnBudget = 0;
2825
+ }
2826
+ function pinBottom() {
2827
+ var box = options.getBox();
2828
+ if (!box) return;
2829
+ box.scrollTop = box.scrollHeight;
2830
+ wroteTop = box.scrollTop;
2831
+ }
2832
+ function settleReturn() {
2833
+ if (frozen()) return false;
2834
+ var wasFrozen = sawFrozen;
2835
+ sawFrozen = false;
2836
+ if (!returning && !wasFrozen) return false;
2837
+ if (returning) {
2838
+ if (returnBudget <= 0) {
2839
+ release();
2840
+ return false;
2841
+ }
2842
+ returnBudget--;
2843
+ }
2844
+ if (parkedStuck) {
2845
+ pinBottom();
2846
+ return true;
2847
+ }
2848
+ var target = parked || held;
2849
+ restoreExact = true;
2850
+ restorePinned = false;
2851
+ restore(target, true);
2852
+ parked = !restorePinned || !restoreExact ? target : null;
2853
+ returning = !!parked && returnBudget > 0;
2854
+ if (!returning) {
2855
+ parked = null;
2856
+ parkedStuck = false;
2857
+ returnBudget = 0;
2858
+ }
2859
+ return false;
2860
+ }
2861
+ function isReturning() {
2862
+ return returning;
2863
+ }
2864
+ function thaw() {
2865
+ settleReturn();
2866
+ }
2867
+ function foldFrozenGrowth(box, el, delta) {
2868
+ var elTop = el.getBoundingClientRect().top;
2869
+ foldInto(box, held, elTop, delta);
2870
+ foldInto(box, parked, elTop, delta);
2871
+ }
2872
+ function foldInto(box, a, elTop, delta) {
2873
+ if (!a || a.top >= 0) return;
2874
+ var rowEl = findRow(box, a);
2875
+ if (!rowEl) return;
2876
+ var within = elTop - rowEl.getBoundingClientRect().top;
2877
+ if (within < 0 || within >= rowEl.offsetHeight) return;
2878
+ if (within >= -a.top) return;
2879
+ a.top -= delta;
2880
+ a.scrollHeight += delta;
2881
+ }
2714
2882
  function forget() {
2715
2883
  held = null;
2884
+ release();
2716
2885
  }
2717
2886
  return {
2718
2887
  capture,
@@ -2720,6 +2889,13 @@ function createScrollAnchor(options) {
2720
2889
  preserve,
2721
2890
  remember,
2722
2891
  hold,
2892
+ park,
2893
+ settleReturn,
2894
+ isReturning,
2895
+ release,
2896
+ pinBottom,
2897
+ isFrozen: frozen,
2898
+ thaw,
2723
2899
  absorb,
2724
2900
  forget
2725
2901
  };
@@ -5822,6 +5998,7 @@ var ChatSession = class {
5822
5998
  releaseBgFlag();
5823
5999
  self.updateHistoryCache();
5824
6000
  self.host.notify();
6001
+ if (self.host.settleScroll) self.host.settleScroll();
5825
6002
  }, function() {
5826
6003
  releaseBgFlag();
5827
6004
  self.host.notify();
@@ -5903,7 +6080,7 @@ var ChatSession = class {
5903
6080
  self.drainBgTaskQueue();
5904
6081
  }
5905
6082
  if (!fetchMore) self.refreshLiveIndexState();
5906
- if (!fetchMore) return self.host.scrollToBottomIfSticky();
6083
+ if (!fetchMore) return self.host.settleScroll ? self.host.settleScroll() : self.host.scrollToBottomIfSticky();
5907
6084
  }).catch(function(err) {
5908
6085
  console.warn("[chat-engine] getChatHistory failed", err);
5909
6086
  }).then(function() {