@xhub-reels/sdk 0.1.19 → 0.1.20

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/index.cjs CHANGED
@@ -1723,8 +1723,8 @@ function DefaultPauseAction() {
1723
1723
  }
1724
1724
  );
1725
1725
  }
1726
- var PLAY_AHEAD_MAX_CONCURRENT = 3;
1727
- var PLAY_AHEAD_STAGGER_MS = 50;
1726
+ var PLAY_AHEAD_MAX_CONCURRENT = 2;
1727
+ var PLAY_AHEAD_STAGGER_MS = 80;
1728
1728
  var _playAheadActive = 0;
1729
1729
  var _playAheadQueue = [];
1730
1730
  function acquirePlayAhead() {
@@ -1733,9 +1733,8 @@ function acquirePlayAhead() {
1733
1733
  return Promise.resolve();
1734
1734
  }
1735
1735
  return new Promise((resolve) => {
1736
- const queuePosition = _playAheadQueue.length;
1737
1736
  _playAheadQueue.push(() => {
1738
- setTimeout(resolve, PLAY_AHEAD_STAGGER_MS * queuePosition);
1737
+ setTimeout(resolve, PLAY_AHEAD_STAGGER_MS);
1739
1738
  });
1740
1739
  });
1741
1740
  }
@@ -2270,7 +2269,6 @@ function ReelsFeed({
2270
2269
  const slotCacheRef = react.useRef(/* @__PURE__ */ new Map());
2271
2270
  const activeIndexRef = react.useRef(0);
2272
2271
  activeIndexRef.current = focusedIndex;
2273
- const [isSnapping, setIsSnapping] = react.useState(false);
2274
2272
  const { animateSnap, animateBounceBack, cancelAnimation } = useSnapAnimation({
2275
2273
  duration: snapConfig?.duration ?? 260,
2276
2274
  easing: snapConfig?.easing ?? "cubic-bezier(0.25, 0.46, 0.45, 0.94)"
@@ -2376,13 +2374,7 @@ function ReelsFeed({
2376
2374
  return;
2377
2375
  }
2378
2376
  cancelAnimation();
2379
- setIsSnapping(true);
2380
2377
  setPrefetchIndex(null);
2381
- setFocusedIndexImmediate(next);
2382
- const nextItem = items[next];
2383
- if (nextItem) {
2384
- onSlotChange?.(next, nextItem, current);
2385
- }
2386
2378
  const h = containerHeight.current;
2387
2379
  const targets = [];
2388
2380
  for (const [idx, el] of slotCacheRef.current) {
@@ -2393,7 +2385,13 @@ function ReelsFeed({
2393
2385
  });
2394
2386
  }
2395
2387
  animateSnap(targets);
2396
- setTimeout(() => setIsSnapping(false), 300);
2388
+ requestAnimationFrame(() => {
2389
+ setFocusedIndexImmediate(next);
2390
+ const nextItem = items[next];
2391
+ if (nextItem) {
2392
+ onSlotChange?.(next, nextItem, current);
2393
+ }
2394
+ });
2397
2395
  },
2398
2396
  [items, animateSnap, animateBounceBack, cancelAnimation, setFocusedIndexImmediate, setPrefetchIndex, onSlotChange]
2399
2397
  );
@@ -2415,13 +2413,13 @@ function ReelsFeed({
2415
2413
  setIsDragMuted(true);
2416
2414
  }, []);
2417
2415
  const handleDragEnd = react.useCallback(() => {
2418
- setTimeout(() => setIsDragMuted(false), 50);
2416
+ setTimeout(() => setIsDragMuted(false), 300);
2419
2417
  }, []);
2420
2418
  const { bind } = usePointerGesture({
2421
2419
  axis: "y",
2422
2420
  velocityThreshold: gestureConfig?.velocityThreshold ?? 0.3,
2423
2421
  distanceThreshold: gestureConfig?.distanceThreshold ?? 80,
2424
- disabled: isSnapping,
2422
+ disabled: false,
2425
2423
  containerSize: containerHeight.current,
2426
2424
  dragThresholdRatio: gestureConfig?.dragThresholdRatio ?? 0.5,
2427
2425
  onDragOffset: (offset) => {
@@ -2495,7 +2493,13 @@ function ReelsFeed({
2495
2493
  const wrapperStyle = {
2496
2494
  position: "absolute",
2497
2495
  inset: 0,
2498
- contain: "layout style paint",
2496
+ // Fix 4: 'strict' = layout + style + paint + size containment.
2497
+ // Tells browser this slot is fully self-contained — no layout
2498
+ // escapes to parent. Eliminates layout thrash during animation.
2499
+ contain: "strict",
2500
+ // Fix 4: willChange only on active ±1 (3 slots max).
2501
+ // Previously ±1 already, keep it. Avoids unnecessary GPU layers
2502
+ // on warm/cold slots that are never animated directly.
2499
2503
  willChange: distFromFocus <= 1 ? "transform" : "auto",
2500
2504
  transform: getInitialTransformPx(index)
2501
2505
  };
package/dist/index.js CHANGED
@@ -1717,8 +1717,8 @@ function DefaultPauseAction() {
1717
1717
  }
1718
1718
  );
1719
1719
  }
1720
- var PLAY_AHEAD_MAX_CONCURRENT = 3;
1721
- var PLAY_AHEAD_STAGGER_MS = 50;
1720
+ var PLAY_AHEAD_MAX_CONCURRENT = 2;
1721
+ var PLAY_AHEAD_STAGGER_MS = 80;
1722
1722
  var _playAheadActive = 0;
1723
1723
  var _playAheadQueue = [];
1724
1724
  function acquirePlayAhead() {
@@ -1727,9 +1727,8 @@ function acquirePlayAhead() {
1727
1727
  return Promise.resolve();
1728
1728
  }
1729
1729
  return new Promise((resolve) => {
1730
- const queuePosition = _playAheadQueue.length;
1731
1730
  _playAheadQueue.push(() => {
1732
- setTimeout(resolve, PLAY_AHEAD_STAGGER_MS * queuePosition);
1731
+ setTimeout(resolve, PLAY_AHEAD_STAGGER_MS);
1733
1732
  });
1734
1733
  });
1735
1734
  }
@@ -2264,7 +2263,6 @@ function ReelsFeed({
2264
2263
  const slotCacheRef = useRef(/* @__PURE__ */ new Map());
2265
2264
  const activeIndexRef = useRef(0);
2266
2265
  activeIndexRef.current = focusedIndex;
2267
- const [isSnapping, setIsSnapping] = useState(false);
2268
2266
  const { animateSnap, animateBounceBack, cancelAnimation } = useSnapAnimation({
2269
2267
  duration: snapConfig?.duration ?? 260,
2270
2268
  easing: snapConfig?.easing ?? "cubic-bezier(0.25, 0.46, 0.45, 0.94)"
@@ -2370,13 +2368,7 @@ function ReelsFeed({
2370
2368
  return;
2371
2369
  }
2372
2370
  cancelAnimation();
2373
- setIsSnapping(true);
2374
2371
  setPrefetchIndex(null);
2375
- setFocusedIndexImmediate(next);
2376
- const nextItem = items[next];
2377
- if (nextItem) {
2378
- onSlotChange?.(next, nextItem, current);
2379
- }
2380
2372
  const h = containerHeight.current;
2381
2373
  const targets = [];
2382
2374
  for (const [idx, el] of slotCacheRef.current) {
@@ -2387,7 +2379,13 @@ function ReelsFeed({
2387
2379
  });
2388
2380
  }
2389
2381
  animateSnap(targets);
2390
- setTimeout(() => setIsSnapping(false), 300);
2382
+ requestAnimationFrame(() => {
2383
+ setFocusedIndexImmediate(next);
2384
+ const nextItem = items[next];
2385
+ if (nextItem) {
2386
+ onSlotChange?.(next, nextItem, current);
2387
+ }
2388
+ });
2391
2389
  },
2392
2390
  [items, animateSnap, animateBounceBack, cancelAnimation, setFocusedIndexImmediate, setPrefetchIndex, onSlotChange]
2393
2391
  );
@@ -2409,13 +2407,13 @@ function ReelsFeed({
2409
2407
  setIsDragMuted(true);
2410
2408
  }, []);
2411
2409
  const handleDragEnd = useCallback(() => {
2412
- setTimeout(() => setIsDragMuted(false), 50);
2410
+ setTimeout(() => setIsDragMuted(false), 300);
2413
2411
  }, []);
2414
2412
  const { bind } = usePointerGesture({
2415
2413
  axis: "y",
2416
2414
  velocityThreshold: gestureConfig?.velocityThreshold ?? 0.3,
2417
2415
  distanceThreshold: gestureConfig?.distanceThreshold ?? 80,
2418
- disabled: isSnapping,
2416
+ disabled: false,
2419
2417
  containerSize: containerHeight.current,
2420
2418
  dragThresholdRatio: gestureConfig?.dragThresholdRatio ?? 0.5,
2421
2419
  onDragOffset: (offset) => {
@@ -2489,7 +2487,13 @@ function ReelsFeed({
2489
2487
  const wrapperStyle = {
2490
2488
  position: "absolute",
2491
2489
  inset: 0,
2492
- contain: "layout style paint",
2490
+ // Fix 4: 'strict' = layout + style + paint + size containment.
2491
+ // Tells browser this slot is fully self-contained — no layout
2492
+ // escapes to parent. Eliminates layout thrash during animation.
2493
+ contain: "strict",
2494
+ // Fix 4: willChange only on active ±1 (3 slots max).
2495
+ // Previously ±1 already, keep it. Avoids unnecessary GPU layers
2496
+ // on warm/cold slots that are never animated directly.
2493
2497
  willChange: distFromFocus <= 1 ? "transform" : "auto",
2494
2498
  transform: getInitialTransformPx(index)
2495
2499
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xhub-reels/sdk",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "High-performance Short Video / Reels SDK for React — optimized for Flutter WebView",
5
5
  "license": "MIT",
6
6
  "type": "module",