refactor(react,html): implement hook-style component architecture for MuteButton

- Create shared state definitions for MuteButton in both React and HTML packages
- Refactor React MuteButton to use centralized state definition
- Refactor HTML MuteButton to use centralized state definition
- Replace useState/useEffect pattern with useMemo for better performance
- Consolidate state logic for better maintainability across implementations

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Christian Pillsbury
2025-09-08 17:15:40 -07:00
committed by Christian Pillsbury
co-authored by Claude
parent 882019f458
commit 7842a36658
6 changed files with 143 additions and 44 deletions
@@ -4,6 +4,7 @@ import {
PropsHook,
} from '../utils/component-factory';
import { MediaChromeButton } from './media-chrome-button';
import { muteButtonStateDefinition } from './state-definitions/mute-button';
export class MuteButtonBase extends MediaChromeButton {
_state:
@@ -57,18 +58,10 @@ export const useMuteButtonState: StateHook<{
muted: boolean;
volumeLevel: string;
}> = {
keys: ['muted', 'volumeLevel'],
keys: muteButtonStateDefinition.keys,
transform: (rawState, mediaStore) => ({
muted: rawState.muted ?? false,
volumeLevel: rawState.volumeLevel ?? 'off',
requestMute() {
const type = 'muterequest';
mediaStore.dispatch({ type });
},
requestUnmute() {
const type = 'unmuterequest';
mediaStore.dispatch({ type });
},
...muteButtonStateDefinition.stateTransform(rawState),
...muteButtonStateDefinition.createRequestMethods(mediaStore.dispatch),
}),
};
@@ -0,0 +1,35 @@
export interface MuteButtonState {
muted: boolean;
volumeLevel: string;
}
export interface MuteButtonMethods {
requestMute: () => void;
requestUnmute: () => void;
}
export interface MuteButtonStateDefinition {
keys: string[];
stateTransform: (rawState: any) => MuteButtonState;
createRequestMethods: (
dispatch: (action: { type: string }) => void,
) => MuteButtonMethods;
}
/**
* MuteButton state definition
* Defines the core state logic that can be shared between implementations
*/
export const muteButtonStateDefinition: MuteButtonStateDefinition = {
keys: ['muted', 'volumeLevel'],
stateTransform: (rawState: any): MuteButtonState => ({
muted: rawState.muted ?? (false as boolean),
volumeLevel: rawState.volumeLevel ?? ('off' as string),
}),
createRequestMethods: (dispatch): MuteButtonMethods => ({
requestMute: () => dispatch({ type: 'muterequest' }),
requestUnmute: () => dispatch({ type: 'unmuterequest' }),
}),
};
@@ -0,0 +1,33 @@
export interface PlayButtonState {
paused: boolean;
}
export interface PlayButtonMethods {
requestPlay: () => void;
requestPause: () => void;
}
export interface PlayButtonStateDefinition {
keys: string[];
stateTransform: (rawState: any) => PlayButtonState;
createRequestMethods: (
dispatch: (action: { type: string }) => void,
) => PlayButtonMethods;
}
/**
* PlayButton state definition
* Defines the core state logic that can be shared between implementations
*/
export const playButtonStateDefinition: PlayButtonStateDefinition = {
keys: ['paused'],
stateTransform: (rawState: any): PlayButtonState => ({
paused: rawState.paused ?? true,
}),
createRequestMethods: (dispatch): PlayButtonMethods => ({
requestPlay: () => dispatch({ type: 'playrequest' }),
requestPause: () => dispatch({ type: 'pauserequest' }),
}),
};
@@ -1,53 +1,25 @@
import {
shallowEqual,
// useMediaDispatch,
useMediaSelector,
useMediaStore,
} from '@vjs-10/react-media-store';
import * as React from 'react';
import { toConnectedComponent } from '../utils/component-factory';
/**
* 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<typeof useMediaStore>) => {
return {
requestMute() {
const type = 'muterequest';
mediaStore.dispatch({ type });
},
requestUnmute() {
const type = 'unmuterequest';
mediaStore.dispatch({ type });
},
};
},
} as const;
import { muteButtonStateDefinition } from './state-definitions/mute-button';
export const useMuteButtonState = (_props: any) => {
const mediaStore = useMediaStore();
/** @TODO Fix type issues with hooks (CJP) */
const mediaState = useMediaSelector(
muteButtonStateDef.stateTransform,
muteButtonStateDefinition.stateTransform,
shallowEqual,
);
const [methods, setMethods] = React.useState(
muteButtonStateDef.requestMethods(mediaStore),
const methods = React.useMemo(
() => muteButtonStateDefinition.createRequestMethods(mediaStore.dispatch),
[mediaStore],
);
React.useEffect(() => {
setMethods(muteButtonStateDef.requestMethods(mediaStore));
}, [mediaStore]);
return {
volumeLevel: mediaState.volumeLevel,
muted: mediaState.muted,
@@ -0,0 +1,33 @@
export interface MuteButtonState {
muted: boolean;
volumeLevel: string;
}
export interface MuteButtonMethods {
requestMute: () => void;
requestUnmute: () => void;
}
export interface MuteButtonStateDefinition {
keys: string[];
stateTransform: (rawState: any) => MuteButtonState;
createRequestMethods: (dispatch: (action: { type: string }) => void) => MuteButtonMethods;
}
/**
* MuteButton state definition
* Defines the core state logic that can be shared between implementations
*/
export const muteButtonStateDefinition: MuteButtonStateDefinition = {
keys: ['muted', 'volumeLevel'],
stateTransform: (rawState: any): MuteButtonState => ({
muted: rawState.muted ?? false,
volumeLevel: rawState.volumeLevel ?? 'off',
}),
createRequestMethods: (dispatch): MuteButtonMethods => ({
requestMute: () => dispatch({ type: 'muterequest' }),
requestUnmute: () => dispatch({ type: 'unmuterequest' }),
}),
};
@@ -0,0 +1,33 @@
export interface PlayButtonState {
paused: boolean;
}
export interface PlayButtonMethods {
requestPlay: () => void;
requestPause: () => void;
}
export interface PlayButtonStateDefinition {
keys: string[];
stateTransform: (rawState: any) => PlayButtonState;
createRequestMethods: (
dispatch: (action: { type: string }) => void,
) => PlayButtonMethods;
}
/**
* PlayButton state definition
* Defines the core state logic that can be shared between implementations
*/
export const playButtonStateDefinition: PlayButtonStateDefinition = {
keys: ['paused'],
stateTransform: (rawState: any): PlayButtonState => ({
paused: rawState.paused ?? true,
}),
createRequestMethods: (dispatch): PlayButtonMethods => ({
requestPlay: () => dispatch({ type: 'playrequest' }),
requestPause: () => dispatch({ type: 'pauserequest' }),
}),
};