@player-ui/react 0.12.0 → 0.12.1-next.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/dist/cjs/index.cjs +61 -15
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.legacy-esm.js +61 -15
- package/dist/index.mjs +61 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -5
- package/src/manager/__tests__/managed-player.test.tsx +507 -360
- package/src/manager/managed-player.tsx +89 -22
- package/types/manager/managed-player.d.ts +1 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { useSyncExternalStore } from "use-sync-external-store/shim";
|
|
2
3
|
import type {
|
|
3
4
|
FlowManager,
|
|
4
5
|
ManagedPlayerProps,
|
|
@@ -20,10 +21,7 @@ interface ManagedPlayerStateKey {
|
|
|
20
21
|
_key: symbol;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
export
|
|
24
|
-
/** Trigger for state changes */
|
|
25
|
-
onState: (s: ManagedPlayerState) => void;
|
|
26
|
-
}
|
|
24
|
+
export type StateChangeCallback = (state?: ManagedPlayerState) => void;
|
|
27
25
|
|
|
28
26
|
/**
|
|
29
27
|
* An object to store the state of the managed player
|
|
@@ -106,7 +104,9 @@ class ManagedState {
|
|
|
106
104
|
private async setState(state: ManagedPlayerState) {
|
|
107
105
|
this.state = state;
|
|
108
106
|
this.callbacks.forEach((c) => {
|
|
109
|
-
c
|
|
107
|
+
if (c && typeof c === "function") {
|
|
108
|
+
c(this.state);
|
|
109
|
+
}
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
const { manager, reactPlayer, playerConfig } = state.context;
|
|
@@ -208,6 +208,12 @@ const managedPlayerStateMachines = new WeakMap<
|
|
|
208
208
|
ManagedState
|
|
209
209
|
>();
|
|
210
210
|
|
|
211
|
+
function createKey(): ManagedPlayerStateKey {
|
|
212
|
+
return {
|
|
213
|
+
_key: Symbol("managed-player"),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
211
217
|
/** Creates an x-state state machine that persists when this component is no longer renders (due to Suspense) */
|
|
212
218
|
export const usePersistentStateMachine = (options: {
|
|
213
219
|
/** the flow manager to use */
|
|
@@ -219,29 +225,90 @@ export const usePersistentStateMachine = (options: {
|
|
|
219
225
|
/** Any middleware for the manager */
|
|
220
226
|
middleware?: ManagerMiddleware;
|
|
221
227
|
}): { managedState: ManagedState; state?: ManagedPlayerState } => {
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
228
|
+
const mounted = React.useRef(false);
|
|
229
|
+
const previousManager = React.useRef(options.manager);
|
|
230
|
+
const keyRef = React.useRef<ManagedPlayerStateKey>(createKey());
|
|
231
|
+
const managedStateRef = React.useRef(
|
|
232
|
+
new ManagedState({ middleware: options.middleware }),
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
if (!mounted.current) {
|
|
236
|
+
managedPlayerStateMachines.set(keyRef.current, managedStateRef.current);
|
|
237
|
+
mounted.current = true;
|
|
238
|
+
}
|
|
225
239
|
|
|
226
|
-
|
|
227
|
-
managedPlayerStateMachines.get(keyRef.current)
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
240
|
+
if (previousManager.current !== options.manager) {
|
|
241
|
+
const oldManagedState = managedPlayerStateMachines.get(keyRef.current);
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* We have to handle terminate here as well as the useEffect in the
|
|
245
|
+
* ManagedPlayer since it won't have the instance of the previous manager
|
|
246
|
+
*/
|
|
247
|
+
if (oldManagedState) {
|
|
248
|
+
const playerState =
|
|
249
|
+
oldManagedState.state?.context.reactPlayer.player.getState();
|
|
250
|
+
|
|
251
|
+
if (
|
|
252
|
+
oldManagedState.state?.value === "running" &&
|
|
253
|
+
playerState?.status === "in-progress"
|
|
254
|
+
) {
|
|
255
|
+
previousManager.current.terminate?.(
|
|
256
|
+
playerState.controllers.data.serialize(),
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
231
260
|
|
|
232
|
-
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
setState(s);
|
|
236
|
-
},
|
|
261
|
+
const newKey = createKey();
|
|
262
|
+
const newManagedState = new ManagedState({
|
|
263
|
+
middleware: options.middleware,
|
|
237
264
|
});
|
|
238
265
|
|
|
239
|
-
|
|
240
|
-
|
|
266
|
+
managedPlayerStateMachines.set(newKey, newManagedState);
|
|
267
|
+
keyRef.current = newKey;
|
|
268
|
+
managedStateRef.current = newManagedState;
|
|
269
|
+
previousManager.current = options.manager;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const managedState =
|
|
273
|
+
managedPlayerStateMachines.get(keyRef.current) ?? managedStateRef.current;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* There are times where the managedState the external store references no
|
|
277
|
+
* longer exists, so we have to wrap instead of calling addListener directly.
|
|
278
|
+
*/
|
|
279
|
+
function subscription(callback: (val?: ManagedPlayerState) => void) {
|
|
280
|
+
if (managedState) {
|
|
281
|
+
const unsub = managedState.addListener((s) => {
|
|
282
|
+
callback(s);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
return () => {
|
|
286
|
+
if (managedState) {
|
|
287
|
+
unsub();
|
|
288
|
+
}
|
|
289
|
+
};
|
|
241
290
|
}
|
|
242
291
|
|
|
243
|
-
return
|
|
244
|
-
}
|
|
292
|
+
return () => {};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function getSnapshot() {
|
|
296
|
+
return managedState.state;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const state = useSyncExternalStore(
|
|
300
|
+
subscription,
|
|
301
|
+
getSnapshot,
|
|
302
|
+
() => undefined,
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* This needs to come after useSyncExternalStore, otherwise it causes
|
|
307
|
+
* a weird state update and none of the refs in this hook persist
|
|
308
|
+
*/
|
|
309
|
+
if (managedState.state === undefined) {
|
|
310
|
+
managedState.start(options);
|
|
311
|
+
}
|
|
245
312
|
|
|
246
313
|
return { managedState, state };
|
|
247
314
|
};
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { FlowManager, ManagedPlayerProps, ManagedPlayerState, ManagerMiddleware } from "./types";
|
|
3
3
|
import type { ReactPlayerOptions } from "../player";
|
|
4
|
-
export
|
|
5
|
-
/** Trigger for state changes */
|
|
6
|
-
onState: (s: ManagedPlayerState) => void;
|
|
7
|
-
}
|
|
4
|
+
export type StateChangeCallback = (state?: ManagedPlayerState) => void;
|
|
8
5
|
/**
|
|
9
6
|
* An object to store the state of the managed player
|
|
10
7
|
*/
|