diff --git a/packages/html/html/src/components/media-mute-button.ts b/packages/html/html/src/components/media-mute-button.ts index caf0761d..35bbbb12 100644 --- a/packages/html/html/src/components/media-mute-button.ts +++ b/packages/html/html/src/components/media-mute-button.ts @@ -5,21 +5,21 @@ import { } from '../utils/component-factory'; import { MediaChromeButton } from './media-chrome-button'; -export class MediaMuteButton extends MediaChromeButton { +export class MuteButtonBase extends MediaChromeButton { _state: | { muted: boolean; volumeLevel: string; - requestUnmute: () => void; requestMute: () => void; + requestUnmute: () => void; } | undefined; handleEvent(event: Event) { const { type } = event; - if (type === 'click') { - const state = this._state; - if (state) { + const state = this._state; + if (state) { + if (type === 'click') { if (state.muted) { state.requestUnmute(); } else { @@ -39,6 +39,7 @@ export class MediaMuteButton extends MediaChromeButton { _update(props: any, state: any) { this._state = state; + /** @TODO Follow up with React vs. W.C. data-* attributes discrepancies (CJP) */ // Make generic this.toggleAttribute('data-muted', props['data-muted']); this.setAttribute('data-volume-level', props['data-volume-level']); @@ -102,7 +103,7 @@ export const useMuteButtonProps: PropsHook<{ * Equivalent to React's MuteButton = toConnectedComponent(...) */ export const MuteButton = toConnectedHTMLComponent( - MediaMuteButton, + MuteButtonBase, useMuteButtonState, useMuteButtonProps, 'MuteButton', diff --git a/packages/react/react/src/components/MuteButton.tsx b/packages/react/react/src/components/MuteButton.tsx index 07e92688..0db7a677 100644 --- a/packages/react/react/src/components/MuteButton.tsx +++ b/packages/react/react/src/components/MuteButton.tsx @@ -1,27 +1,58 @@ -import { useMediaDispatch, useMediaSelector } from '@vjs-10/react-media-store'; +import { + shallowEqual, + // useMediaDispatch, + useMediaSelector, + useMediaStore, +} from '@vjs-10/react-media-store'; import * as React from 'react'; import { toConnectedComponent } from '../utils/component-factory'; -export const useMuteButtonState = (_props: any) => { - /** @TODO Fix type issues with hooks (CJP) */ - const volumeLevel = useMediaSelector( - (state: any) => state.volumeLevel, - ) as string; - const muted = useMediaSelector((state: any) => state.muted) as boolean; +/** + * MuteButton state hook - equivalent to React's useMuteButtonState + * Handles media store state subscription and transformation + */ +export const muteButtonStateDef = { + keys: ['muted', 'volumeLevel'], + stateTransform: (rawState: any) => ({ + muted: rawState.muted ?? false, + volumeLevel: rawState.volumeLevel ?? 'off', + }), + /** @TODO Consider "promoting" this up to state-mediator defs + media store (CJP) */ + requestMethods: (mediaStore: ReturnType) => { + return { + requestMute() { + const type = 'muterequest'; + mediaStore.dispatch({ type }); + }, + requestUnmute() { + const type = 'unmuterequest'; + mediaStore.dispatch({ type }); + }, + }; + }, +} as const; - const dispatch = useMediaDispatch(); - const requestMute = React.useCallback(() => { - dispatch({ type: 'muterequest' }); - }, [dispatch]); - const requestUnmute = React.useCallback(() => { - dispatch({ type: 'unmuterequest' }); - }, [dispatch]); +export const useMuteButtonState = (_props: any) => { + const mediaStore = useMediaStore(); + /** @TODO Fix type issues with hooks (CJP) */ + const mediaState = useMediaSelector( + muteButtonStateDef.stateTransform, + shallowEqual, + ); + + const [methods, setMethods] = React.useState( + muteButtonStateDef.requestMethods(mediaStore), + ); + + React.useEffect(() => { + setMethods(muteButtonStateDef.requestMethods(mediaStore)); + }, [mediaStore]); return { - volumeLevel, - muted, - requestMute, - requestUnmute, + volumeLevel: mediaState.volumeLevel, + muted: mediaState.muted, + requestMute: methods.requestMute, + requestUnmute: methods.requestUnmute, } as const; };