bunnyquery 1.8.14 → 1.8.15

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,8 @@ 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;
2583
2585
  var UNKNOWN_ROW_POS = "\0?";
2584
2586
  function createScrollAnchor(options) {
2585
2587
  var held = null;
@@ -2590,6 +2592,7 @@ function createScrollAnchor(options) {
2590
2592
  var boxTop = box.getBoundingClientRect().top;
2591
2593
  var kids = box.children;
2592
2594
  var fallback = null;
2595
+ var fallbackAt = -1;
2593
2596
  for (var i = 0; i < kids.length; i++) {
2594
2597
  var el = kids[i];
2595
2598
  if (!el || typeof el.getAttribute !== "function") continue;
@@ -2608,10 +2611,20 @@ function createScrollAnchor(options) {
2608
2611
  scrollHeight: box.scrollHeight,
2609
2612
  el
2610
2613
  };
2611
- if (rawPos === null) return cand;
2612
- if (!fallback) fallback = cand;
2614
+ if (rawPos === null) {
2615
+ cand.alts = collectAlts(box, boxTop, i + 1);
2616
+ return cand;
2617
+ }
2618
+ if (!fallback) {
2619
+ fallback = cand;
2620
+ fallbackAt = i;
2621
+ }
2622
+ }
2623
+ if (fallback) {
2624
+ fallback.alts = collectAlts(box, boxTop, fallbackAt + 1, true);
2625
+ return fallback;
2613
2626
  }
2614
- return fallback || {
2627
+ return {
2615
2628
  key: null,
2616
2629
  top: 0,
2617
2630
  pos: null,
@@ -2620,6 +2633,26 @@ function createScrollAnchor(options) {
2620
2633
  el: null
2621
2634
  };
2622
2635
  }
2636
+ function collectAlts(box, boxTop, from, ordinaryOnly) {
2637
+ var out = [];
2638
+ var kids = box.children;
2639
+ var stop = Math.min(kids.length, from + ALT_SCAN_LIMIT);
2640
+ for (var i = from; i < stop && out.length < MAX_ALTS; i++) {
2641
+ var el = kids[i];
2642
+ if (!el || typeof el.getAttribute !== "function") continue;
2643
+ var key = el.getAttribute(ROW_KEY_ATTR);
2644
+ if (!key) continue;
2645
+ var rawPos = el.getAttribute(ROW_POS_ATTR);
2646
+ if (ordinaryOnly && rawPos !== null) continue;
2647
+ out.push({
2648
+ key,
2649
+ top: el.getBoundingClientRect().top - boxTop,
2650
+ pos: rawPos === null ? null : rawPos || UNKNOWN_ROW_POS,
2651
+ el
2652
+ });
2653
+ }
2654
+ return out.length ? out : void 0;
2655
+ }
2623
2656
  function findRow(box, anchor) {
2624
2657
  var el = anchor.el;
2625
2658
  if (el && el.parentNode === box) return el;
@@ -2632,31 +2665,79 @@ function createScrollAnchor(options) {
2632
2665
  }
2633
2666
  return null;
2634
2667
  }
2635
- function restore(anchor) {
2668
+ var sawFrozen = false;
2669
+ var parked = null;
2670
+ var parkedStuck = false;
2671
+ var returning = false;
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;
2636
2682
  var box = options.getBox();
2637
2683
  if (!box || !anchor || options.isStuck()) return;
2638
2684
  var el = findRow(box, anchor);
2639
2685
  if (el) {
2640
2686
  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
- }
2687
+ if (anchor.pos !== null && anchor.pos !== UNKNOWN_ROW_POS && livePos !== UNKNOWN_ROW_POS && livePos !== anchor.pos) el = null;
2688
+ }
2689
+ if (el) {
2645
2690
  var boxTop = box.getBoundingClientRect().top;
2646
2691
  var delta = el.getBoundingClientRect().top - boxTop - anchor.top;
2647
2692
  var slack = Math.abs(box.scrollHeight - anchor.scrollHeight) + box.clientHeight;
2648
- if (delta > slack || delta < -slack) {
2693
+ if (!unbounded && (delta > slack || delta < -slack)) {
2649
2694
  lost(box, anchor);
2650
2695
  return;
2651
2696
  }
2697
+ var want = box.scrollTop + delta;
2652
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;
2653
2702
  held = {
2654
2703
  key: anchor.key,
2655
2704
  top: anchor.top,
2656
2705
  pos: anchor.pos,
2657
2706
  scrollTop: box.scrollTop,
2658
2707
  scrollHeight: box.scrollHeight,
2659
- el
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
+ }
2715
+ var alts = anchor.alts;
2716
+ for (var ai = 0; alts && ai < alts.length; ai++) {
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 });
2719
+ if (!ael) continue;
2720
+ if (alt.pos !== null && alt.pos !== UNKNOWN_ROW_POS) {
2721
+ var altLive = ael.getAttribute(ROW_POS_ATTR) || UNKNOWN_ROW_POS;
2722
+ if (altLive !== UNKNOWN_ROW_POS && altLive !== alt.pos) continue;
2723
+ }
2724
+ var aboxTop = box.getBoundingClientRect().top;
2725
+ var adelta = ael.getBoundingClientRect().top - aboxTop - alt.top;
2726
+ var aslack = Math.abs(box.scrollHeight - anchor.scrollHeight) + box.clientHeight;
2727
+ if (!unbounded && (adelta > aslack || adelta < -aslack)) continue;
2728
+ var awant = box.scrollTop + adelta;
2729
+ 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
+ held = {
2734
+ key: alt.key,
2735
+ top: alt.top,
2736
+ pos: alt.pos,
2737
+ scrollTop: box.scrollTop,
2738
+ scrollHeight: box.scrollHeight,
2739
+ el: ael,
2740
+ alts: alts.slice(ai + 1)
2660
2741
  };
2661
2742
  return;
2662
2743
  }
@@ -2667,9 +2748,13 @@ function createScrollAnchor(options) {
2667
2748
  var grew = box.scrollHeight - anchor.scrollHeight;
2668
2749
  if (grew > 0) {
2669
2750
  box.scrollTop = anchor.scrollTop + grew;
2751
+ wroteTop = box.scrollTop;
2670
2752
  return;
2671
2753
  }
2672
- if (options.rawFallback) box.scrollTop = anchor.scrollTop;
2754
+ if (options.rawFallback) {
2755
+ box.scrollTop = anchor.scrollTop;
2756
+ wroteTop = box.scrollTop;
2757
+ }
2673
2758
  }
2674
2759
  function preserve(mutate) {
2675
2760
  var anchor = capture();
@@ -2678,9 +2763,21 @@ function createScrollAnchor(options) {
2678
2763
  return result;
2679
2764
  }
2680
2765
  function remember() {
2766
+ var b0 = options.getBox();
2767
+ if (returning && b0 && b0.scrollTop !== wroteTop) {
2768
+ parked = null;
2769
+ parkedStuck = false;
2770
+ returning = false;
2771
+ }
2772
+ if (frozen()) return;
2681
2773
  held = capture();
2682
2774
  }
2683
2775
  function hold() {
2776
+ if (frozen()) return;
2777
+ if (sawFrozen || returning) {
2778
+ settleReturn();
2779
+ return;
2780
+ }
2684
2781
  var box = options.getBox();
2685
2782
  if (!box || options.isStuck()) {
2686
2783
  held = null;
@@ -2707,12 +2804,67 @@ function createScrollAnchor(options) {
2707
2804
  if (prev === void 0) prev = 0;
2708
2805
  var delta = h - prev;
2709
2806
  if (delta === 0) return;
2807
+ if (frozen()) {
2808
+ foldFrozenGrowth(box, el, delta);
2809
+ return;
2810
+ }
2710
2811
  if (el.getBoundingClientRect().top >= box.getBoundingClientRect().top) return;
2711
2812
  box.scrollTop += delta;
2813
+ wroteTop = box.scrollTop;
2712
2814
  if (held) held = capture();
2713
2815
  }
2816
+ function park() {
2817
+ parked = capture();
2818
+ parkedStuck = !!options.isStuck();
2819
+ returning = true;
2820
+ }
2821
+ function pinBottom() {
2822
+ var box = options.getBox();
2823
+ if (!box) return;
2824
+ box.scrollTop = box.scrollHeight;
2825
+ wroteTop = box.scrollTop;
2826
+ }
2827
+ function settleReturn() {
2828
+ if (frozen()) return false;
2829
+ sawFrozen = false;
2830
+ if (parkedStuck) {
2831
+ pinBottom();
2832
+ return true;
2833
+ }
2834
+ var target = parked || held;
2835
+ restoreExact = true;
2836
+ restorePinned = false;
2837
+ restore(target, true);
2838
+ parked = !restorePinned || !restoreExact ? target : null;
2839
+ returning = !!parked;
2840
+ return false;
2841
+ }
2842
+ function isReturning() {
2843
+ return returning;
2844
+ }
2845
+ function thaw() {
2846
+ settleReturn();
2847
+ }
2848
+ function foldFrozenGrowth(box, el, delta) {
2849
+ var elTop = el.getBoundingClientRect().top;
2850
+ foldInto(box, held, elTop, delta);
2851
+ foldInto(box, parked, elTop, delta);
2852
+ }
2853
+ function foldInto(box, a, elTop, delta) {
2854
+ if (!a || a.top >= 0) return;
2855
+ var rowEl = findRow(box, a);
2856
+ if (!rowEl) return;
2857
+ var within = elTop - rowEl.getBoundingClientRect().top;
2858
+ if (within < 0 || within >= rowEl.offsetHeight) return;
2859
+ if (within >= -a.top) return;
2860
+ a.top -= delta;
2861
+ a.scrollHeight += delta;
2862
+ }
2714
2863
  function forget() {
2715
2864
  held = null;
2865
+ parked = null;
2866
+ parkedStuck = false;
2867
+ returning = false;
2716
2868
  }
2717
2869
  return {
2718
2870
  capture,
@@ -2720,6 +2872,12 @@ function createScrollAnchor(options) {
2720
2872
  preserve,
2721
2873
  remember,
2722
2874
  hold,
2875
+ park,
2876
+ settleReturn,
2877
+ isReturning,
2878
+ pinBottom,
2879
+ isFrozen: frozen,
2880
+ thaw,
2723
2881
  absorb,
2724
2882
  forget
2725
2883
  };
@@ -5822,6 +5980,7 @@ var ChatSession = class {
5822
5980
  releaseBgFlag();
5823
5981
  self.updateHistoryCache();
5824
5982
  self.host.notify();
5983
+ if (self.host.settleScroll) self.host.settleScroll();
5825
5984
  }, function() {
5826
5985
  releaseBgFlag();
5827
5986
  self.host.notify();
@@ -5903,7 +6062,7 @@ var ChatSession = class {
5903
6062
  self.drainBgTaskQueue();
5904
6063
  }
5905
6064
  if (!fetchMore) self.refreshLiveIndexState();
5906
- if (!fetchMore) return self.host.scrollToBottomIfSticky();
6065
+ if (!fetchMore) return self.host.settleScroll ? self.host.settleScroll() : self.host.scrollToBottomIfSticky();
5907
6066
  }).catch(function(err) {
5908
6067
  console.warn("[chat-engine] getChatHistory failed", err);
5909
6068
  }).then(function() {