@xhub-reels/sdk 0.2.11 → 0.2.12

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
@@ -444,6 +444,13 @@ var FeedManager = class {
444
444
  // ═══════════════════════════════════════════
445
445
  // PUBLIC API — Prefetch
446
446
  // ═══════════════════════════════════════════
447
+ setInitialItems(items) {
448
+ this.prefetchCache = {
449
+ items,
450
+ nextCursor: null,
451
+ timestamp: Date.now()
452
+ };
453
+ }
447
454
  async prefetch(ttlMs) {
448
455
  if (this.prefetchCache) {
449
456
  const ttl = ttlMs ?? this.config.staleTTL;
@@ -1137,7 +1144,12 @@ function useSnapAnimation(config = {}) {
1137
1144
  return { animateSnap, animateBounceBack, cancelAnimation };
1138
1145
  }
1139
1146
  var SDKContext = react.createContext(null);
1140
- function ReelsProvider({ children, adapters, debug = false }) {
1147
+ function ReelsProvider({
1148
+ children,
1149
+ adapters,
1150
+ initialItems,
1151
+ debug = false
1152
+ }) {
1141
1153
  const logger = adapters.logger;
1142
1154
  const sdkRef = react.useRef(null);
1143
1155
  const value = react.useMemo(() => {
@@ -1148,6 +1160,9 @@ function ReelsProvider({ children, adapters, debug = false }) {
1148
1160
  sdkRef.current.optimisticManager.destroy();
1149
1161
  }
1150
1162
  const feedManager = new FeedManager(adapters.dataSource, {}, logger);
1163
+ if (initialItems && initialItems.length > 0) {
1164
+ feedManager.setInitialItems(initialItems);
1165
+ }
1151
1166
  const playerEngine = new PlayerEngine(
1152
1167
  {},
1153
1168
  adapters.analytics,
@@ -1336,10 +1351,11 @@ var ACTIVE_HLS_DEFAULTS = {
1336
1351
  maxMaxBufferLength: 15,
1337
1352
  capLevelToPlayerSize: true,
1338
1353
  startLevel: 0,
1339
- abrEwmaDefaultEstimate: 5e5,
1354
+ abrEwmaDefaultEstimate: 2e6,
1340
1355
  lowLatencyMode: false,
1341
1356
  backBufferLength: 5,
1342
- enableWorker: true
1357
+ enableWorker: true,
1358
+ startFragPrefetch: true
1343
1359
  };
1344
1360
  var HOT_HLS_DEFAULTS = {
1345
1361
  maxBufferLength: 2,
@@ -1833,6 +1849,20 @@ function VideoSlotInner({
1833
1849
  }
1834
1850
  }, [mp4Src, isActive, isPrefetch, isPreloaded, isHlsSource]);
1835
1851
  const isReady = isHlsSource ? hlsReady : mp4Ready;
1852
+ const [isVideoPlaying, setIsVideoPlaying] = react.useState(false);
1853
+ react.useEffect(() => {
1854
+ const video = videoRef.current;
1855
+ if (!video || !isActive) {
1856
+ setIsVideoPlaying(false);
1857
+ return;
1858
+ }
1859
+ const onPlaying = () => setIsVideoPlaying(true);
1860
+ video.addEventListener("playing", onPlaying);
1861
+ return () => {
1862
+ video.removeEventListener("playing", onPlaying);
1863
+ setIsVideoPlaying(false);
1864
+ };
1865
+ }, [isActive]);
1836
1866
  const [hasPlayedAhead, setHasPlayedAhead] = react.useState(false);
1837
1867
  react.useEffect(() => {
1838
1868
  const video = videoRef.current;
@@ -1872,6 +1902,7 @@ function VideoSlotInner({
1872
1902
  }, [isActive, isReady, hasPlayedAhead]);
1873
1903
  react.useEffect(() => {
1874
1904
  setHasPlayedAhead(false);
1905
+ setIsVideoPlaying(false);
1875
1906
  }, [src]);
1876
1907
  const wasActiveRef = react.useRef(false);
1877
1908
  const [isManuallyPaused, setIsManuallyPaused] = react.useState(false);
@@ -1948,7 +1979,7 @@ function VideoSlotInner({
1948
1979
  if (!video) return;
1949
1980
  video.muted = isActive ? isMuted : true;
1950
1981
  }, [isMuted, isActive]);
1951
- const showPosterOverlay = !isReady && !hasPlayedAhead;
1982
+ const showPosterOverlay = isActive ? !isVideoPlaying : !isReady && !hasPlayedAhead;
1952
1983
  const isPreDecoded = hasPlayedAhead;
1953
1984
  const [showMuteIndicator, setShowMuteIndicator] = react.useState(false);
1954
1985
  const muteIndicatorTimer = react.useRef(null);
@@ -2066,9 +2097,9 @@ function VideoSlotInner({
2066
2097
  height: "100%",
2067
2098
  objectFit: "cover",
2068
2099
  // Hide video until ready to avoid black frame flash.
2069
- // When pre-decoded, skip transition — first frame is already on canvas.
2100
+ // When pre-decoded or active, skip transition — first frame is already on canvas or playing.
2070
2101
  opacity: showPosterOverlay ? 0 : 1,
2071
- transition: isPreDecoded ? "none" : "opacity 0.15s ease"
2102
+ transition: isActive ? "none" : isPreDecoded ? "none" : "opacity 0.15s ease"
2072
2103
  }
2073
2104
  }
2074
2105
  ),
@@ -2082,7 +2113,7 @@ function VideoSlotInner({
2082
2113
  backgroundSize: "cover",
2083
2114
  backgroundPosition: "center",
2084
2115
  opacity: showPosterOverlay ? 1 : 0,
2085
- transition: "opacity 0.15s ease",
2116
+ transition: isActive ? "none" : "opacity 0.15s ease",
2086
2117
  pointerEvents: "none"
2087
2118
  }
2088
2119
  }
package/dist/index.d.cts CHANGED
@@ -503,6 +503,7 @@ declare class FeedManager {
503
503
  constructor(dataSource: IDataSource, config?: FeedConfig, logger?: ILogger);
504
504
  getDataSource(): IDataSource;
505
505
  setDataSource(dataSource: IDataSource, reset?: boolean): void;
506
+ setInitialItems(items: ContentItem[]): void;
506
507
  prefetch(ttlMs?: number): Promise<void>;
507
508
  hasPrefetchCache(): boolean;
508
509
  clearPrefetchCache(): void;
@@ -781,10 +782,12 @@ interface SDKContextValue {
781
782
  interface ReelsProviderProps {
782
783
  children: ReactNode;
783
784
  adapters: SDKAdapters;
785
+ /** Seed initial items into feedManager */
786
+ initialItems?: ContentItem[];
784
787
  /** Enable verbose logging (default: false) */
785
788
  debug?: boolean;
786
789
  }
787
- declare function ReelsProvider({ children, adapters, debug }: ReelsProviderProps): react_jsx_runtime.JSX.Element;
790
+ declare function ReelsProvider({ children, adapters, initialItems, debug, }: ReelsProviderProps): react_jsx_runtime.JSX.Element;
788
791
  declare function useSDK(): SDKContextValue;
789
792
 
790
793
  declare function ReelsFeed({ renderOverlay, renderActions, renderPauseAction, renderLoading, renderEmpty, renderError: _renderError, showFps, loadMoreThreshold, onSlotChange, gestureConfig, snapConfig, initialMuted, onAutoplayBlocked, }: ReelsFeedProps): string | number | bigint | boolean | Iterable<react.ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<react.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
package/dist/index.d.ts CHANGED
@@ -503,6 +503,7 @@ declare class FeedManager {
503
503
  constructor(dataSource: IDataSource, config?: FeedConfig, logger?: ILogger);
504
504
  getDataSource(): IDataSource;
505
505
  setDataSource(dataSource: IDataSource, reset?: boolean): void;
506
+ setInitialItems(items: ContentItem[]): void;
506
507
  prefetch(ttlMs?: number): Promise<void>;
507
508
  hasPrefetchCache(): boolean;
508
509
  clearPrefetchCache(): void;
@@ -781,10 +782,12 @@ interface SDKContextValue {
781
782
  interface ReelsProviderProps {
782
783
  children: ReactNode;
783
784
  adapters: SDKAdapters;
785
+ /** Seed initial items into feedManager */
786
+ initialItems?: ContentItem[];
784
787
  /** Enable verbose logging (default: false) */
785
788
  debug?: boolean;
786
789
  }
787
- declare function ReelsProvider({ children, adapters, debug }: ReelsProviderProps): react_jsx_runtime.JSX.Element;
790
+ declare function ReelsProvider({ children, adapters, initialItems, debug, }: ReelsProviderProps): react_jsx_runtime.JSX.Element;
788
791
  declare function useSDK(): SDKContextValue;
789
792
 
790
793
  declare function ReelsFeed({ renderOverlay, renderActions, renderPauseAction, renderLoading, renderEmpty, renderError: _renderError, showFps, loadMoreThreshold, onSlotChange, gestureConfig, snapConfig, initialMuted, onAutoplayBlocked, }: ReelsFeedProps): string | number | bigint | boolean | Iterable<react.ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<react.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
package/dist/index.js CHANGED
@@ -438,6 +438,13 @@ var FeedManager = class {
438
438
  // ═══════════════════════════════════════════
439
439
  // PUBLIC API — Prefetch
440
440
  // ═══════════════════════════════════════════
441
+ setInitialItems(items) {
442
+ this.prefetchCache = {
443
+ items,
444
+ nextCursor: null,
445
+ timestamp: Date.now()
446
+ };
447
+ }
441
448
  async prefetch(ttlMs) {
442
449
  if (this.prefetchCache) {
443
450
  const ttl = ttlMs ?? this.config.staleTTL;
@@ -1131,7 +1138,12 @@ function useSnapAnimation(config = {}) {
1131
1138
  return { animateSnap, animateBounceBack, cancelAnimation };
1132
1139
  }
1133
1140
  var SDKContext = createContext(null);
1134
- function ReelsProvider({ children, adapters, debug = false }) {
1141
+ function ReelsProvider({
1142
+ children,
1143
+ adapters,
1144
+ initialItems,
1145
+ debug = false
1146
+ }) {
1135
1147
  const logger = adapters.logger;
1136
1148
  const sdkRef = useRef(null);
1137
1149
  const value = useMemo(() => {
@@ -1142,6 +1154,9 @@ function ReelsProvider({ children, adapters, debug = false }) {
1142
1154
  sdkRef.current.optimisticManager.destroy();
1143
1155
  }
1144
1156
  const feedManager = new FeedManager(adapters.dataSource, {}, logger);
1157
+ if (initialItems && initialItems.length > 0) {
1158
+ feedManager.setInitialItems(initialItems);
1159
+ }
1145
1160
  const playerEngine = new PlayerEngine(
1146
1161
  {},
1147
1162
  adapters.analytics,
@@ -1330,10 +1345,11 @@ var ACTIVE_HLS_DEFAULTS = {
1330
1345
  maxMaxBufferLength: 15,
1331
1346
  capLevelToPlayerSize: true,
1332
1347
  startLevel: 0,
1333
- abrEwmaDefaultEstimate: 5e5,
1348
+ abrEwmaDefaultEstimate: 2e6,
1334
1349
  lowLatencyMode: false,
1335
1350
  backBufferLength: 5,
1336
- enableWorker: true
1351
+ enableWorker: true,
1352
+ startFragPrefetch: true
1337
1353
  };
1338
1354
  var HOT_HLS_DEFAULTS = {
1339
1355
  maxBufferLength: 2,
@@ -1827,6 +1843,20 @@ function VideoSlotInner({
1827
1843
  }
1828
1844
  }, [mp4Src, isActive, isPrefetch, isPreloaded, isHlsSource]);
1829
1845
  const isReady = isHlsSource ? hlsReady : mp4Ready;
1846
+ const [isVideoPlaying, setIsVideoPlaying] = useState(false);
1847
+ useEffect(() => {
1848
+ const video = videoRef.current;
1849
+ if (!video || !isActive) {
1850
+ setIsVideoPlaying(false);
1851
+ return;
1852
+ }
1853
+ const onPlaying = () => setIsVideoPlaying(true);
1854
+ video.addEventListener("playing", onPlaying);
1855
+ return () => {
1856
+ video.removeEventListener("playing", onPlaying);
1857
+ setIsVideoPlaying(false);
1858
+ };
1859
+ }, [isActive]);
1830
1860
  const [hasPlayedAhead, setHasPlayedAhead] = useState(false);
1831
1861
  useEffect(() => {
1832
1862
  const video = videoRef.current;
@@ -1866,6 +1896,7 @@ function VideoSlotInner({
1866
1896
  }, [isActive, isReady, hasPlayedAhead]);
1867
1897
  useEffect(() => {
1868
1898
  setHasPlayedAhead(false);
1899
+ setIsVideoPlaying(false);
1869
1900
  }, [src]);
1870
1901
  const wasActiveRef = useRef(false);
1871
1902
  const [isManuallyPaused, setIsManuallyPaused] = useState(false);
@@ -1942,7 +1973,7 @@ function VideoSlotInner({
1942
1973
  if (!video) return;
1943
1974
  video.muted = isActive ? isMuted : true;
1944
1975
  }, [isMuted, isActive]);
1945
- const showPosterOverlay = !isReady && !hasPlayedAhead;
1976
+ const showPosterOverlay = isActive ? !isVideoPlaying : !isReady && !hasPlayedAhead;
1946
1977
  const isPreDecoded = hasPlayedAhead;
1947
1978
  const [showMuteIndicator, setShowMuteIndicator] = useState(false);
1948
1979
  const muteIndicatorTimer = useRef(null);
@@ -2060,9 +2091,9 @@ function VideoSlotInner({
2060
2091
  height: "100%",
2061
2092
  objectFit: "cover",
2062
2093
  // Hide video until ready to avoid black frame flash.
2063
- // When pre-decoded, skip transition — first frame is already on canvas.
2094
+ // When pre-decoded or active, skip transition — first frame is already on canvas or playing.
2064
2095
  opacity: showPosterOverlay ? 0 : 1,
2065
- transition: isPreDecoded ? "none" : "opacity 0.15s ease"
2096
+ transition: isActive ? "none" : isPreDecoded ? "none" : "opacity 0.15s ease"
2066
2097
  }
2067
2098
  }
2068
2099
  ),
@@ -2076,7 +2107,7 @@ function VideoSlotInner({
2076
2107
  backgroundSize: "cover",
2077
2108
  backgroundPosition: "center",
2078
2109
  opacity: showPosterOverlay ? 1 : 0,
2079
- transition: "opacity 0.15s ease",
2110
+ transition: isActive ? "none" : "opacity 0.15s ease",
2080
2111
  pointerEvents: "none"
2081
2112
  }
2082
2113
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xhub-reels/sdk",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "description": "High-performance Short Video / Reels SDK for React — optimized for Flutter WebView",
5
5
  "license": "MIT",
6
6
  "type": "module",