diff --git a/packages/global-styles-ui/src/hooks.ts b/packages/global-styles-ui/src/hooks.ts index f324476b8448da..b97be534c15cfb 100644 --- a/packages/global-styles-ui/src/hooks.ts +++ b/packages/global-styles-ui/src/hooks.ts @@ -36,17 +36,21 @@ extend( [ a11yPlugin ] ); * @param blockName The name of the block, if applicable. * @param readFrom Which source to read from: "base" (theme), "user" (customizations), or "merged" (final result). * @param shouldDecodeEncode Whether to decode and encode the style value. + * @param state Optional pseudo-selector state (e.g. `:hover`, `:focus`). When provided, + * reads from and writes to the state sub-object automatically. * @return An array containing the style value and a function to set the style * value. * * @example * const [ color, setColor ] = useStyle( 'color.text', 'core/button', 'merged' ); + * const [ hoverColor, setHoverColor ] = useStyle( 'color.text', 'core/button', 'user', true, ':hover' ); */ export function useStyle< T = any >( path: string, blockName?: string, readFrom: 'base' | 'user' | 'merged' = 'merged', - shouldDecodeEncode: boolean = true + shouldDecodeEncode: boolean = true, + state?: string ) { const { user, base, merged, onChange } = useContext( GlobalStylesContext ); @@ -57,22 +61,43 @@ export function useStyle< T = any >( sourceValue = user; } - const styleValue = useMemo( - () => getStyle< T >( sourceValue, path, blockName, shouldDecodeEncode ), - [ sourceValue, path, blockName, shouldDecodeEncode ] - ); + const styleValue = useMemo( () => { + const rawValue = getStyle< T >( + sourceValue, + path, + blockName, + shouldDecodeEncode + ); + if ( state ) { + return ( rawValue as any )?.[ state ] ?? {}; + } + return rawValue; + }, [ sourceValue, path, blockName, shouldDecodeEncode, state ] ); const setStyleValue = useCallback( ( newValue: T | undefined ) => { - const newGlobalStyles = setStyle< T >( + let valueToSet: any = newValue; + if ( state ) { + const fullCurrentValue = getStyle( + user, + path, + blockName, + false + ); + valueToSet = { + ...( fullCurrentValue as object ), + [ state ]: newValue, + }; + } + const newGlobalStyles = setStyle< any >( user, path, - newValue, + valueToSet, blockName ); onChange( newGlobalStyles ); }, - [ user, onChange, path, blockName ] + [ user, onChange, path, blockName, state ] ); return [ styleValue, setStyleValue ] as const; diff --git a/packages/global-styles-ui/src/screen-block.tsx b/packages/global-styles-ui/src/screen-block.tsx index 3918403cdbb39e..e316891234c567 100644 --- a/packages/global-styles-ui/src/screen-block.tsx +++ b/packages/global-styles-ui/src/screen-block.tsx @@ -114,43 +114,22 @@ function ScreenBlock( { name, variation }: ScreenBlockProps ) { const [ selectedState, setSelectedState ] = useState< string >( 'default' ); const validStates = useMemo( () => getValidStates( name ), [ name ] ); - const [ rawStyle ] = useStyle( prefix, name, 'user', false ); - const [ rawInheritedStyle, rawSetStyle ] = useStyle( + const stateParam = selectedState !== 'default' ? selectedState : undefined; + const [ style, setStyle ] = useStyle( + prefix, + name, + 'user', + false, + stateParam + ); + const [ inheritedStyle ] = useStyle( prefix, name, 'merged', - false + false, + stateParam ); - // Extract style for the selected state - const style = useMemo( () => { - if ( selectedState === 'default' ) { - return rawStyle || {}; - } - return rawStyle?.[ selectedState ] || {}; - }, [ rawStyle, selectedState ] ); - - const inheritedStyle = useMemo( () => { - if ( selectedState === 'default' ) { - return rawInheritedStyle || {}; - } - return rawInheritedStyle?.[ selectedState ] || {}; - }, [ rawInheritedStyle, selectedState ] ); - - // Wrapper for setStyle that handles states - const setStyle = ( newStyle: any ) => { - if ( selectedState === 'default' ) { - rawSetStyle( newStyle ); - } else { - // Merge the new style into the state - const updatedStyle = { - ...rawStyle, - [ selectedState ]: newStyle, - }; - rawSetStyle( updatedStyle ); - } - }; - const [ userSettings ] = useSetting( '', name, 'user' ); const [ rawSettings, setSettings ] = useSetting( '', name ); const settingsForBlockElement = useSettingsForBlockElement( @@ -355,11 +334,7 @@ function ScreenBlock( { name, variation }: ScreenBlockProps ) { name={ name } variation={ variation } selectedState={ selectedState } - stateStyles={ - selectedState !== 'default' - ? rawStyle?.[ selectedState ] - : undefined - } + stateStyles={ selectedState !== 'default' ? style : undefined } /> { hasVariationsPanel && (