@clockworkdog/cogs-client-react 3.0.0-alpha.15 → 3.0.0-alpha.16

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.
@@ -1,2 +1 @@
1
- import { CogsAudioPlayer } from '@clockworkdog/cogs-client';
2
- export default function useIsAudioPlaying(customAudioPlayer?: CogsAudioPlayer | null): boolean;
1
+ export declare function useIsAudioPlaying(): boolean;
@@ -1,12 +1,21 @@
1
1
  import { useEffect, useState } from 'react';
2
- import { useAudioPlayer } from '../providers/CogsConnectionProvider';
3
- export default function useIsAudioPlaying(customAudioPlayer) {
2
+ import { useCogsConnection } from '../providers/CogsConnectionProvider';
3
+ import { getStateAtTime } from '@clockworkdog/cogs-client';
4
+ export function useIsAudioPlaying() {
4
5
  const [isAudioPlaying, setAudioPlaying] = useState(false);
5
- const audioPlayer = useAudioPlayer(customAudioPlayer ?? undefined);
6
+ const cogsConnection = useCogsConnection();
7
+ // Listen to messages
6
8
  useEffect(() => {
7
- const listener = (event) => setAudioPlaying(event.detail.isPlaying);
8
- audioPlayer?.addEventListener('state', listener);
9
- return () => audioPlayer?.removeEventListener('state', listener);
10
- }, [audioPlayer]);
9
+ function handleMessages({ message }) {
10
+ if (message.type === 'media_state' && message.media_strategy === 'state') {
11
+ const audioPlaybackRates = Object.values(message.state)
12
+ .filter((clip) => clip.type === 'audio')
13
+ .map((clip) => getStateAtTime(clip, Date.now())?.rate);
14
+ setAudioPlaying(audioPlaybackRates.some((rate) => rate !== 0));
15
+ }
16
+ }
17
+ cogsConnection.addEventListener('message', handleMessages);
18
+ return () => cogsConnection.removeEventListener('message', handleMessages);
19
+ }, [cogsConnection]);
11
20
  return isAudioPlaying;
12
21
  }
@@ -0,0 +1 @@
1
+ export declare function useIsVideoPlaying(): boolean;
@@ -0,0 +1,21 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { getStateAtTime } from '@clockworkdog/cogs-client';
3
+ import { useCogsConnection } from '..';
4
+ export function useIsVideoPlaying() {
5
+ const [isVideoPlaying, setVideoPlaying] = useState(false);
6
+ const cogsConnection = useCogsConnection();
7
+ // Listen to messages
8
+ useEffect(() => {
9
+ function handleMessages({ message }) {
10
+ if (message.type === 'media_state' && message.media_strategy === 'state') {
11
+ const videoPlaybackRates = Object.values(message.state)
12
+ .filter((clip) => clip.type === 'video')
13
+ .map((clip) => getStateAtTime(clip, Date.now())?.rate);
14
+ setVideoPlaying(videoPlaybackRates.some((rate) => rate !== 0));
15
+ }
16
+ }
17
+ cogsConnection.addEventListener('message', handleMessages);
18
+ return () => cogsConnection.removeEventListener('message', handleMessages);
19
+ }, [cogsConnection]);
20
+ return isVideoPlaying;
21
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { default as CogsConnectionProvider, useCogsConnection, useAudioPlayer, useVideoPlayer } from './providers/CogsConnectionProvider';
1
+ export { default as CogsConnectionProvider, useCogsConnection } from './providers/CogsConnectionProvider';
2
2
  export { MediaSurface, MediaSurfaceProps } from './components/MediaSurface';
3
3
  export { default as useIsConnected } from './hooks/useIsConnected';
4
4
  export { default as useCogsConfig } from './hooks/useCogsConfig';
@@ -12,11 +12,8 @@ export { default as usePreloadedUrl } from './hooks/usePreloadedUrl';
12
12
  export { default as useShowPhase } from './hooks/useShowPhase';
13
13
  export { default as useWhenShowReset } from './hooks/useWhenShowReset';
14
14
  export * from './utils/types';
15
- export { default as useAudioClips } from './hooks/useAudioClips';
16
- export { default as useIsAudioPlaying } from './hooks/useIsAudioPlaying';
17
- export { default as VideoContainer } from './components/VideoContainer';
15
+ export { useIsAudioPlaying } from './hooks/useIsAudioPlaying';
16
+ export { useIsVideoPlaying } from './hooks/useIsVideoPlaying';
18
17
  export { default as useHint } from './hooks/useHint';
19
18
  export { default as Hint } from './components/Hint';
20
19
  export { default as Timer } from './components/Timer';
21
- export { default as useImages, Image } from './hooks/useImages';
22
- export { default as Images } from './components/Images';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Utilities
2
- export { default as CogsConnectionProvider, useCogsConnection, useAudioPlayer, useVideoPlayer } from './providers/CogsConnectionProvider';
2
+ export { default as CogsConnectionProvider, useCogsConnection } from './providers/CogsConnectionProvider';
3
3
  export { MediaSurface } from './components/MediaSurface';
4
4
  export { default as useIsConnected } from './hooks/useIsConnected';
5
5
  export { default as useCogsConfig } from './hooks/useCogsConfig';
@@ -13,16 +13,10 @@ export { default as usePreloadedUrl } from './hooks/usePreloadedUrl';
13
13
  export { default as useShowPhase } from './hooks/useShowPhase';
14
14
  export { default as useWhenShowReset } from './hooks/useWhenShowReset';
15
15
  export * from './utils/types';
16
- // Audio
17
- export { default as useAudioClips } from './hooks/useAudioClips';
18
- export { default as useIsAudioPlaying } from './hooks/useIsAudioPlaying';
19
- // Video
20
- export { default as VideoContainer } from './components/VideoContainer';
16
+ export { useIsAudioPlaying } from './hooks/useIsAudioPlaying';
17
+ export { useIsVideoPlaying } from './hooks/useIsVideoPlaying';
21
18
  // Hints
22
19
  export { default as useHint } from './hooks/useHint';
23
20
  export { default as Hint } from './components/Hint';
24
21
  // Timer
25
22
  export { default as Timer } from './components/Timer';
26
- // Images
27
- export { default as useImages } from './hooks/useImages';
28
- export { default as Images } from './components/Images';
@@ -1,14 +1,7 @@
1
- import { CogsAudioPlayer, CogsConnection, CogsPluginManifest, CogsVideoPlayer, ManifestTypes } from '@clockworkdog/cogs-client';
1
+ import { CogsConnection, CogsPluginManifest, ManifestTypes } from '@clockworkdog/cogs-client';
2
2
  import React, { ReactNode } from 'react';
3
3
  /**
4
4
  * Create a persistent connection to COGS which can be accessed with `useCogsConnection()`
5
- * @param audioPlayer Creates a `CogsAudioPlayer` than can be accessed with `useAudioPlayer()`
6
- *
7
- * Note: If unset, the audio player will remain active.
8
- *
9
- * @param videoPlayer Creates a `CogsVideoPlayer` than can be accessed with `useVideoPlayer()`
10
- *
11
- * Note: If unset, the video player will remain active.
12
5
  *
13
6
  * *Example:*
14
7
  *
@@ -23,7 +16,7 @@ import React, { ReactNode } from 'react';
23
16
  * }
24
17
  *
25
18
  * function App() {
26
- * return <CogsConnectionProvider manifest={manifest} audioPlayer videoPlayer>
19
+ * return <CogsConnectionProvider manifest={manifest}>
27
20
  * <MyComponent />
28
21
  * <CogsConnectionProvider/>;
29
22
  * }
@@ -42,7 +35,7 @@ import React, { ReactNode } from 'react';
42
35
  * }
43
36
  *
44
37
  * function App() {
45
- * return <CogsConnectionProvider manifest={manifest} audioPlayer videoPlayer>
38
+ * return <CogsConnectionProvider manifest={manifest}>
46
39
  * <MyComponent />
47
40
  * <CogsConnectionProvider/>;
48
41
  * }
@@ -52,13 +45,11 @@ export default function CogsConnectionProvider<Manifest extends CogsPluginManife
52
45
  [key: string]: unknown;
53
46
  } = {
54
47
  [key: string]: unknown;
55
- }>({ manifest, hostname, port, children, audioPlayer, videoPlayer, initialClientState, initialDataStoreData, }: {
48
+ }>({ manifest, hostname, port, children, initialClientState, initialDataStoreData, }: {
56
49
  manifest: Manifest;
57
50
  hostname?: string;
58
51
  port?: number;
59
52
  children: React.ReactNode;
60
- audioPlayer?: boolean;
61
- videoPlayer?: boolean;
62
53
  initialClientState?: Partial<ManifestTypes.StateAsObject<Manifest, {
63
54
  writableFromClient: true;
64
55
  }>>;
@@ -68,11 +59,3 @@ export default function CogsConnectionProvider<Manifest extends CogsPluginManife
68
59
  * Get the connection from `<CogsConnectionProvider>`
69
60
  */
70
61
  export declare function useCogsConnection<Manifest extends CogsPluginManifest>(customConnection?: CogsConnection<Manifest>): CogsConnection<Manifest>;
71
- /**
72
- * Get the audio player from `<CogsConnectionProvider audioPlayer>`
73
- */
74
- export declare function useAudioPlayer<Manifest extends CogsPluginManifest>(customAudioPlayer?: CogsAudioPlayer): CogsAudioPlayer | null;
75
- /**
76
- * Get the video player from `<CogsConnectionProvider videoPlayer>`
77
- */
78
- export declare function useVideoPlayer<Manifest extends CogsPluginManifest>(customVideoPlayer?: CogsVideoPlayer): CogsVideoPlayer | null;
@@ -1,4 +1,4 @@
1
- import { CogsAudioPlayer, CogsConnection, CogsVideoPlayer } from '@clockworkdog/cogs-client';
1
+ import { CogsConnection } from '@clockworkdog/cogs-client';
2
2
  import React, { useContext, useEffect, useRef, useState } from 'react';
3
3
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
4
  const CogsConnectionContext = React.createContext({
@@ -8,28 +8,9 @@ const CogsConnectionContext = React.createContext({
8
8
  }
9
9
  return customConnection;
10
10
  },
11
- useAudioPlayer: (customAudioPlayer) => {
12
- if (!customAudioPlayer) {
13
- throw new Error('Ensure <CogsConnectionProvider> has been added to your React app');
14
- }
15
- return customAudioPlayer;
16
- },
17
- useVideoPlayer: (customVideoPlayer) => {
18
- if (!customVideoPlayer) {
19
- throw new Error('Ensure <CogsConnectionProvider> has been added to your React app');
20
- }
21
- return customVideoPlayer;
22
- },
23
11
  });
24
12
  /**
25
13
  * Create a persistent connection to COGS which can be accessed with `useCogsConnection()`
26
- * @param audioPlayer Creates a `CogsAudioPlayer` than can be accessed with `useAudioPlayer()`
27
- *
28
- * Note: If unset, the audio player will remain active.
29
- *
30
- * @param videoPlayer Creates a `CogsVideoPlayer` than can be accessed with `useVideoPlayer()`
31
- *
32
- * Note: If unset, the video player will remain active.
33
14
  *
34
15
  * *Example:*
35
16
  *
@@ -44,7 +25,7 @@ const CogsConnectionContext = React.createContext({
44
25
  * }
45
26
  *
46
27
  * function App() {
47
- * return <CogsConnectionProvider manifest={manifest} audioPlayer videoPlayer>
28
+ * return <CogsConnectionProvider manifest={manifest}>
48
29
  * <MyComponent />
49
30
  * <CogsConnectionProvider/>;
50
31
  * }
@@ -63,13 +44,13 @@ const CogsConnectionContext = React.createContext({
63
44
  * }
64
45
  *
65
46
  * function App() {
66
- * return <CogsConnectionProvider manifest={manifest} audioPlayer videoPlayer>
47
+ * return <CogsConnectionProvider manifest={manifest}>
67
48
  * <MyComponent />
68
49
  * <CogsConnectionProvider/>;
69
50
  * }
70
51
  * ```
71
52
  */
72
- export default function CogsConnectionProvider({ manifest, hostname, port, children, audioPlayer, videoPlayer, initialClientState, initialDataStoreData, }) {
53
+ export default function CogsConnectionProvider({ manifest, hostname, port, children, initialClientState, initialDataStoreData, }) {
73
54
  const connectionRef = useRef(undefined);
74
55
  const [, forceRender] = useState({});
75
56
  useEffect(() => {
@@ -81,26 +62,12 @@ export default function CogsConnectionProvider({ manifest, hostname, port, child
81
62
  connection.close();
82
63
  };
83
64
  }, [manifest, hostname, port, initialClientState, initialDataStoreData]);
84
- const audioPlayerRef = useRef(undefined);
85
- useEffect(() => {
86
- if (audioPlayer && !audioPlayerRef.current && connectionRef.current) {
87
- audioPlayerRef.current = new CogsAudioPlayer(connectionRef.current);
88
- }
89
- }, [audioPlayer]);
90
- const videoPlayerRef = useRef(undefined);
91
- useEffect(() => {
92
- if (videoPlayer && !videoPlayerRef.current && connectionRef.current) {
93
- videoPlayerRef.current = new CogsVideoPlayer(connectionRef.current);
94
- }
95
- }, [videoPlayer]);
96
65
  if (!connectionRef.current) {
97
66
  // Do not render if the `useEffect`s above have not run
98
67
  return null;
99
68
  }
100
69
  const value = {
101
70
  useCogsConnection: (customConnection) => customConnection ?? connectionRef.current,
102
- useAudioPlayer: (customAudioPlayer) => customAudioPlayer ?? audioPlayerRef.current ?? null,
103
- useVideoPlayer: (customVideoPlayer) => customVideoPlayer ?? videoPlayerRef.current ?? null,
104
71
  };
105
72
  return React.createElement(CogsConnectionContext.Provider, { value: value }, children);
106
73
  }
@@ -110,15 +77,3 @@ export default function CogsConnectionProvider({ manifest, hostname, port, child
110
77
  export function useCogsConnection(customConnection) {
111
78
  return useContext(CogsConnectionContext).useCogsConnection(customConnection);
112
79
  }
113
- /**
114
- * Get the audio player from `<CogsConnectionProvider audioPlayer>`
115
- */
116
- export function useAudioPlayer(customAudioPlayer) {
117
- return useContext(CogsConnectionContext).useAudioPlayer(customAudioPlayer);
118
- }
119
- /**
120
- * Get the video player from `<CogsConnectionProvider videoPlayer>`
121
- */
122
- export function useVideoPlayer(customVideoPlayer) {
123
- return useContext(CogsConnectionContext).useVideoPlayer(customVideoPlayer);
124
- }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "React components and hooks to connect to COGS to build a custom Media Master",
4
4
  "author": "Clockwork Dog <info@clockwork.dog>",
5
5
  "homepage": "https://github.com/clockwork-dog/cogs-sdk/tree/main/packages/react",
6
- "version": "3.0.0-alpha.15",
6
+ "version": "3.0.0-alpha.16",
7
7
  "keywords": [],
8
8
  "license": "MIT",
9
9
  "repository": {
@@ -28,7 +28,7 @@
28
28
  "prerelease": "yarn npm publish --access public --tag=next"
29
29
  },
30
30
  "dependencies": {
31
- "@clockworkdog/cogs-client": "^3.0.0-alpha.15"
31
+ "@clockworkdog/cogs-client": "^3.0.0-alpha.16"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "react": "^18.0.0 || ^19.0.0",
@@ -1,10 +0,0 @@
1
- import { CogsConnection } from '@clockworkdog/cogs-client';
2
- import React, { ReactNode } from 'react';
3
- export default function Images({ className, style, connection: customConnection, fullscreen, }: {
4
- className?: string;
5
- style?: React.CSSProperties;
6
- connection?: CogsConnection<any>;
7
- fullscreen?: boolean | {
8
- style: React.CSSProperties;
9
- };
10
- }): ReactNode;
@@ -1,14 +0,0 @@
1
- import React from 'react';
2
- import useImages from '../hooks/useImages';
3
- import { useCogsConnection } from '../providers/CogsConnectionProvider';
4
- export default function Images({ className, style, connection: customConnection, fullscreen, }) {
5
- const connection = useCogsConnection(customConnection);
6
- const images = useImages(connection);
7
- const fullscreenCustomStyle = typeof fullscreen === 'object' ? fullscreen.style : undefined;
8
- const imageElements = images.map((image, index) => (React.createElement("img", { className: className, key: index, src: connection.getAssetUrl?.(image.file), alt: image.file, style: {
9
- objectFit: image.fit,
10
- ...(fullscreen ? { width: '100%', height: '100%', position: 'absolute', top: 0, left: 0 } : {}),
11
- ...style,
12
- } })));
13
- return (React.createElement(React.Fragment, null, fullscreen ? (React.createElement("div", { style: { position: 'absolute', zIndex: 2, top: 0, left: 0, width: '100vw', height: '100vh', ...fullscreenCustomStyle } }, imageElements)) : (imageElements)));
14
- }
@@ -1,10 +0,0 @@
1
- import { CogsVideoPlayer } from '@clockworkdog/cogs-client';
2
- import React, { ReactNode } from 'react';
3
- export default function VideoContainer({ className, style, videoPlayer: customVideoPlayer, fullscreen, }: {
4
- className?: string;
5
- style?: React.CSSProperties;
6
- videoPlayer?: CogsVideoPlayer | null;
7
- fullscreen?: boolean | {
8
- style: React.CSSProperties;
9
- };
10
- }): ReactNode;
@@ -1,16 +0,0 @@
1
- import React, { useEffect, useRef } from 'react';
2
- import { useVideoPlayer } from '../providers/CogsConnectionProvider';
3
- export default function VideoContainer({ className, style, videoPlayer: customVideoPlayer, fullscreen, }) {
4
- const containerRef = useRef(null);
5
- const videoPlayer = useVideoPlayer(customVideoPlayer ?? undefined);
6
- useEffect(() => {
7
- if (videoPlayer && containerRef.current) {
8
- videoPlayer.setParentElement(containerRef.current);
9
- return () => videoPlayer.resetParentElement();
10
- }
11
- }, [videoPlayer]);
12
- const fullscreenCustomStyle = typeof fullscreen === 'object' ? fullscreen.style : style;
13
- return (React.createElement("div", { ref: containerRef, className: className, style: fullscreen
14
- ? { position: 'absolute', zIndex: 1, top: 0, left: 0, width: '100vw', height: '100vh', ...fullscreenCustomStyle }
15
- : { position: 'relative', ...style } }));
16
- }
@@ -1,4 +0,0 @@
1
- import { AudioClip, CogsAudioPlayer } from '@clockworkdog/cogs-client';
2
- export default function useAudioClips(audioPlayer: CogsAudioPlayer | null): {
3
- [path: string]: AudioClip;
4
- };
@@ -1,10 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- export default function useAudioClips(audioPlayer) {
3
- const [audioClips, setAudioClips] = useState({});
4
- useEffect(() => {
5
- const listener = (event) => setAudioClips(event.detail.clips);
6
- audioPlayer?.addEventListener('state', listener);
7
- return () => audioPlayer?.removeEventListener('state', listener);
8
- }, [audioPlayer]);
9
- return audioClips;
10
- }
@@ -1,6 +0,0 @@
1
- import { CogsConnection, MediaObjectFit } from '@clockworkdog/cogs-client';
2
- export type Image = {
3
- file: string;
4
- fit: MediaObjectFit;
5
- };
6
- export default function useImages<Connection extends CogsConnection<any>>(connection: Connection): Image[];
@@ -1,27 +0,0 @@
1
- import { useCallback, useState } from 'react';
2
- import useCogsMessage from './useCogsMessage';
3
- export default function useImages(connection) {
4
- const [images, setImages] = useState([]);
5
- useCogsMessage(connection, useCallback((message) => {
6
- switch (message.type) {
7
- case 'image_show':
8
- {
9
- const newImage = { file: message.file, fit: message.fit };
10
- setImages((images) => (message.hideOthers ? [newImage] : [...images, newImage]));
11
- }
12
- break;
13
- case 'image_hide':
14
- if (message.file) {
15
- setImages((images) => images.filter(({ file }) => file !== message.file));
16
- }
17
- else {
18
- setImages([]);
19
- }
20
- break;
21
- case 'image_set_fit':
22
- setImages((images) => images.map((image) => (!message.file || message.file === image.file ? { ...image, fit: message.fit } : image)));
23
- break;
24
- }
25
- }, []));
26
- return images;
27
- }