From 7842a36658cec2cf7c107382f469b1ce65f988ae Mon Sep 17 00:00:00 2001 From: Christian Pillsbury Date: Mon, 8 Sep 2025 17:00:13 -0700 Subject: [PATCH] refactor(react,html): implement hook-style component architecture for MuteButton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .../html/src/components/media-mute-button.ts | 15 ++------ .../state-definitions/mute-button.ts | 35 +++++++++++++++++ .../state-definitions/play-button.ts | 33 ++++++++++++++++ .../react/react/src/components/MuteButton.tsx | 38 +++---------------- .../state-definitions/mute-button.ts | 33 ++++++++++++++++ .../state-definitions/play-button.ts | 33 ++++++++++++++++ 6 files changed, 143 insertions(+), 44 deletions(-) create mode 100644 packages/html/html/src/components/state-definitions/mute-button.ts create mode 100644 packages/html/html/src/components/state-definitions/play-button.ts create mode 100644 packages/react/react/src/components/state-definitions/mute-button.ts create mode 100644 packages/react/react/src/components/state-definitions/play-button.ts diff --git a/packages/html/html/src/components/media-mute-button.ts b/packages/html/html/src/components/media-mute-button.ts index 35bbbb12..eee4f3a1 100644 --- a/packages/html/html/src/components/media-mute-button.ts +++ b/packages/html/html/src/components/media-mute-button.ts @@ -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), }), }; diff --git a/packages/html/html/src/components/state-definitions/mute-button.ts b/packages/html/html/src/components/state-definitions/mute-button.ts new file mode 100644 index 00000000..be77ea62 --- /dev/null +++ b/packages/html/html/src/components/state-definitions/mute-button.ts @@ -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' }), + }), +}; \ No newline at end of file diff --git a/packages/html/html/src/components/state-definitions/play-button.ts b/packages/html/html/src/components/state-definitions/play-button.ts new file mode 100644 index 00000000..4f1f7859 --- /dev/null +++ b/packages/html/html/src/components/state-definitions/play-button.ts @@ -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' }), + }), +}; diff --git a/packages/react/react/src/components/MuteButton.tsx b/packages/react/react/src/components/MuteButton.tsx index 0db7a677..22b50af6 100644 --- a/packages/react/react/src/components/MuteButton.tsx +++ b/packages/react/react/src/components/MuteButton.tsx @@ -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) => { - 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, diff --git a/packages/react/react/src/components/state-definitions/mute-button.ts b/packages/react/react/src/components/state-definitions/mute-button.ts new file mode 100644 index 00000000..c2de4b95 --- /dev/null +++ b/packages/react/react/src/components/state-definitions/mute-button.ts @@ -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' }), + }), +}; \ No newline at end of file diff --git a/packages/react/react/src/components/state-definitions/play-button.ts b/packages/react/react/src/components/state-definitions/play-button.ts new file mode 100644 index 00000000..4f1f7859 --- /dev/null +++ b/packages/react/react/src/components/state-definitions/play-button.ts @@ -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' }), + }), +};