@video-lab/react-frame 4.0.0 → 4.1.0

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/README.md CHANGED
@@ -121,6 +121,7 @@ MIT
121
121
  ## 完整事件与命令失败
122
122
 
123
123
  `onPlayerEvent` 交付完整 `PlayerEvent`,其顶层 `delivery` 包含生产端排序、去重与迟到事件证据。
124
+ `PlayerEvent` 用 `event` 字段区分类型(如 `e.event === 'ready'`),数据在 `payload`;它没有 `type` 字段。
124
125
  旧 iframe 的事件可缺少该字段。宿主主动调用的每次可失败命令都应处理 rejection,可在业务封装层
125
126
  集中处理,不必在每个按钮里重复写 `catch`。命令 rejection 不保证产生 `error`,播放期 `error`
126
127
  也不保证对应某个命令 rejection。`void ref.current?.play()` 不会处理 Promise rejection。
package/dist/index.cjs CHANGED
@@ -168,6 +168,10 @@ function useFrameConnection(props, hasCustomPoster = false, hasCustomPause = fal
168
168
  pauseIntentPendingRef.current = false;
169
169
  setHostPauseVisible(false);
170
170
  awaitingNewSourceRef.current = "switching";
171
+ setLoadingOverlay({
172
+ phase: firstFrameSeenRef.current ? "runtime" : "initial",
173
+ reason: "source_switching"
174
+ });
171
175
  handleRef.current?.setSourceSwitching(true).catch(() => {});
172
176
  forwardWithDelivery({
173
177
  event: "playablechange",
@@ -242,6 +246,7 @@ function useFrameConnection(props, hasCustomPoster = false, hasCustomPause = fal
242
246
  let cancelled = false;
243
247
  const container = containerRef.current;
244
248
  if (!container) return;
249
+ const handshake = new AbortController();
245
250
  const p = propsRef.current;
246
251
  setHostOwnsOverlays(false);
247
252
  (0, _video_lab_frame_core.createPlayerFrame)({
@@ -249,6 +254,7 @@ function useFrameConnection(props, hasCustomPoster = false, hasCustomPause = fal
249
254
  source: activeSourceRef.current,
250
255
  config: toConfig(p, hasCustomPoster, hasCustomPause),
251
256
  renderDefaultFallback: false,
257
+ signal: handshake.signal,
252
258
  onHostOverlayOwnershipChange: (owned) => setHostOwnsOverlays(owned),
253
259
  sourceSwitching: sourceSwitchRef.current !== null,
254
260
  pageFullscreen: p.pageFullscreen,
@@ -310,17 +316,18 @@ function useFrameConnection(props, hasCustomPoster = false, hasCustomPause = fal
310
316
  }
311
317
  }
312
318
  if (event.event === "firstframe" || event.event === "timeupdate") if (awaitingNewSourceRef.current === "switching") {} else {
313
- if (awaitingNewSourceRef.current === "new-source") awaitingNewSourceRef.current = false;
319
+ const newSourceArrived = awaitingNewSourceRef.current === "new-source";
320
+ if (newSourceArrived) awaitingNewSourceRef.current = false;
314
321
  firstFrameSeenRef.current = true;
315
322
  setHostPosterVisible(false);
316
- setLoadingOverlay(null);
323
+ setLoadingOverlay((prev) => newSourceArrived || prev?.phase !== "runtime" ? null : prev);
317
324
  }
318
325
  else if (event.event === "playablechange") {
319
326
  const { playable, recoverable, reason, action = "none" } = event.payload;
320
327
  const terminalError = !playable && !recoverable && reason === "error";
321
328
  const blockingAction = !playable && !recoverable && action !== "none";
322
329
  if (terminalError) setHostPosterVisible(false);
323
- setLoadingOverlay(!firstFrameSeenRef.current ? terminalError || blockingAction ? null : {
330
+ if (!(awaitingNewSourceRef.current !== false && (reason === "initializing" || reason === "ok"))) setLoadingOverlay(!firstFrameSeenRef.current ? terminalError || blockingAction ? null : {
324
331
  phase: "initial",
325
332
  reason
326
333
  } : !playable && recoverable && reason !== "initializing" ? {
@@ -350,6 +357,7 @@ function useFrameConnection(props, hasCustomPoster = false, hasCustomPause = fal
350
357
  });
351
358
  return () => {
352
359
  cancelled = true;
360
+ handshake.abort();
353
361
  handleRef.current?.destroy();
354
362
  handleRef.current = null;
355
363
  };
package/dist/index.d.cts CHANGED
@@ -301,4 +301,3 @@ interface VideoPlayerFrameHandle {
301
301
  declare const VideoPlayerFrame: import("react").ForwardRefExoticComponent<VideoPlayerFrameProps & import("react").RefAttributes<VideoPlayerFrameHandle>>;
302
302
  //#endregion
303
303
  export { type DanmakuConfig, type DanmakuItem, type LoadingOverlayContext, type MediaSource, type PageFullscreenAdapter, type PageFullscreenState, type PlayerError, type PlayerHandle, PlayerProvider, type PlayerProviderProps, type QualityLevel, type ResolveSource, type SubtitleTrackInfo, VideoPlayerFrame, type VideoPlayerFrameHandle, type VideoPlayerFrameProps, usePlayerI18n };
304
- //# sourceMappingURL=index.d.cts.map
package/dist/index.d.mts CHANGED
@@ -301,4 +301,3 @@ interface VideoPlayerFrameHandle {
301
301
  declare const VideoPlayerFrame: import("react").ForwardRefExoticComponent<VideoPlayerFrameProps & import("react").RefAttributes<VideoPlayerFrameHandle>>;
302
302
  //#endregion
303
303
  export { type DanmakuConfig, type DanmakuItem, type LoadingOverlayContext, type MediaSource, type PageFullscreenAdapter, type PageFullscreenState, type PlayerError, type PlayerHandle, PlayerProvider, type PlayerProviderProps, type QualityLevel, type ResolveSource, type SubtitleTrackInfo, VideoPlayerFrame, type VideoPlayerFrameHandle, type VideoPlayerFrameProps, usePlayerI18n };
304
- //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -167,6 +167,10 @@ function useFrameConnection(props, hasCustomPoster = false, hasCustomPause = fal
167
167
  pauseIntentPendingRef.current = false;
168
168
  setHostPauseVisible(false);
169
169
  awaitingNewSourceRef.current = "switching";
170
+ setLoadingOverlay({
171
+ phase: firstFrameSeenRef.current ? "runtime" : "initial",
172
+ reason: "source_switching"
173
+ });
170
174
  handleRef.current?.setSourceSwitching(true).catch(() => {});
171
175
  forwardWithDelivery({
172
176
  event: "playablechange",
@@ -241,6 +245,7 @@ function useFrameConnection(props, hasCustomPoster = false, hasCustomPause = fal
241
245
  let cancelled = false;
242
246
  const container = containerRef.current;
243
247
  if (!container) return;
248
+ const handshake = new AbortController();
244
249
  const p = propsRef.current;
245
250
  setHostOwnsOverlays(false);
246
251
  createPlayerFrame({
@@ -248,6 +253,7 @@ function useFrameConnection(props, hasCustomPoster = false, hasCustomPause = fal
248
253
  source: activeSourceRef.current,
249
254
  config: toConfig(p, hasCustomPoster, hasCustomPause),
250
255
  renderDefaultFallback: false,
256
+ signal: handshake.signal,
251
257
  onHostOverlayOwnershipChange: (owned) => setHostOwnsOverlays(owned),
252
258
  sourceSwitching: sourceSwitchRef.current !== null,
253
259
  pageFullscreen: p.pageFullscreen,
@@ -309,17 +315,18 @@ function useFrameConnection(props, hasCustomPoster = false, hasCustomPause = fal
309
315
  }
310
316
  }
311
317
  if (event.event === "firstframe" || event.event === "timeupdate") if (awaitingNewSourceRef.current === "switching") {} else {
312
- if (awaitingNewSourceRef.current === "new-source") awaitingNewSourceRef.current = false;
318
+ const newSourceArrived = awaitingNewSourceRef.current === "new-source";
319
+ if (newSourceArrived) awaitingNewSourceRef.current = false;
313
320
  firstFrameSeenRef.current = true;
314
321
  setHostPosterVisible(false);
315
- setLoadingOverlay(null);
322
+ setLoadingOverlay((prev) => newSourceArrived || prev?.phase !== "runtime" ? null : prev);
316
323
  }
317
324
  else if (event.event === "playablechange") {
318
325
  const { playable, recoverable, reason, action = "none" } = event.payload;
319
326
  const terminalError = !playable && !recoverable && reason === "error";
320
327
  const blockingAction = !playable && !recoverable && action !== "none";
321
328
  if (terminalError) setHostPosterVisible(false);
322
- setLoadingOverlay(!firstFrameSeenRef.current ? terminalError || blockingAction ? null : {
329
+ if (!(awaitingNewSourceRef.current !== false && (reason === "initializing" || reason === "ok"))) setLoadingOverlay(!firstFrameSeenRef.current ? terminalError || blockingAction ? null : {
323
330
  phase: "initial",
324
331
  reason
325
332
  } : !playable && recoverable && reason !== "initializing" ? {
@@ -349,6 +356,7 @@ function useFrameConnection(props, hasCustomPoster = false, hasCustomPause = fal
349
356
  });
350
357
  return () => {
351
358
  cancelled = true;
359
+ handshake.abort();
352
360
  handleRef.current?.destroy();
353
361
  handleRef.current = null;
354
362
  };
@@ -826,4 +834,3 @@ const VideoPlayerFrame = forwardRef(function VideoPlayerFrame(rawProps, ref) {
826
834
  //#endregion
827
835
  export { PlayerProvider, VideoPlayerFrame, usePlayerI18n };
828
836
 
829
- //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@video-lab/react-frame",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -34,9 +34,9 @@
34
34
  "react-dom": ">=19.0.0"
35
35
  },
36
36
  "dependencies": {
37
- "@video-lab/protocol": "4.0.0",
38
- "@video-lab/react-config": "4.0.0",
39
- "@video-lab/frame-core": "4.0.0"
37
+ "@video-lab/protocol": "4.1.0",
38
+ "@video-lab/react-config": "4.1.0",
39
+ "@video-lab/frame-core": "4.1.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@testing-library/jest-dom": "^6.0.0",
@@ -3,8 +3,8 @@ name: video-lab-host-integration
3
3
  skillVersion: 1
4
4
  sdkMajor: 4
5
5
  supportedPackages:
6
- - '@video-lab/react-frame@4.0.0'
7
- - '@video-lab/vue-frame@4.0.0'
6
+ - '@video-lab/react-frame@4.1.0'
7
+ - '@video-lab/vue-frame@4.1.0'
8
8
  description: >-
9
9
  在业务宿主项目中接入 Video Lab Player 时使用。选择五种接入面之一,完成可验证 demo,
10
10
  并交接 SDK、宿主与服务端责任;不用于修改 SDK 契约或设计品牌 UI。