Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Background image support: add background position controls #58592

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
52 changes: 50 additions & 2 deletions packages/block-editor/src/hooks/background.js
Expand Up @@ -18,6 +18,7 @@ import {
__experimentalVStack as VStack,
DropZone,
FlexItem,
FocalPointPicker,
MenuItem,
VisuallyHidden,
__experimentalItemGroup as ItemGroup,
Expand Down Expand Up @@ -59,13 +60,17 @@ export function hasBackgroundImageValue( style ) {

/**
* Checks if there is a current value in the background size block support
* attributes.
* attributes. Background size values include background size as well
* as background position.
*
* @param {Object} style Style attribute.
* @return {boolean} Whether or not the block has a background size value set.
*/
export function hasBackgroundSizeValue( style ) {
return style?.background?.backgroundSize !== undefined;
return (
style?.background?.backgroundPosition !== undefined ||
style?.background?.backgroundSize !== undefined
);
}

/**
Expand Down Expand Up @@ -130,6 +135,7 @@ function resetBackgroundSize( style = {}, setAttributes ) {
...style,
background: {
...style?.background,
backgroundPosition: undefined,
backgroundRepeat: undefined,
backgroundSize: undefined,
},
Expand Down Expand Up @@ -367,6 +373,26 @@ function backgroundSizeHelpText( value ) {
return __( 'Set a fixed width.' );
}

export const coordsToBackgroundPosition = ( value ) => {
if ( ! value || isNaN( value.x ) || isNaN( value.y ) ) {
return undefined;
}

return `${ value.x * 100 }% ${ value.y * 100 }%`;
};

export const backgroundPositionToCoords = ( value ) => {
if ( ! value ) {
return { x: undefined, y: undefined };
}

let [ x, y ] = value.split( ' ' ).map( ( v ) => parseFloat( v ) / 100 );
x = isNaN( x ) ? undefined : x;
y = isNaN( y ) ? x : y;

return { x, y };
};

function BackgroundSizePanelItem( {
clientId,
isShownByDefault,
Expand Down Expand Up @@ -446,6 +472,18 @@ function BackgroundSizePanelItem( {
} );
};

const updateBackgroundPosition = ( next ) => {
setAttributes( {
style: cleanEmptyObject( {
...style,
background: {
...style?.background,
backgroundPosition: coordsToBackgroundPosition( next ),
},
} ),
} );
};

const toggleIsRepeated = () => {
setAttributes( {
style: cleanEmptyObject( {
Expand All @@ -471,6 +509,16 @@ function BackgroundSizePanelItem( {
resetAllFilter={ resetAllFilter }
panelId={ clientId }
>
<FocalPointPicker
__nextHasNoMarginBottom
__next40pxDefaultSize
label={ __( 'Position' ) }
url={ style?.background?.backgroundImage?.url }
value={ backgroundPositionToCoords(
style?.background?.backgroundPosition
) }
onChange={ updateBackgroundPosition }
/>
<ToggleGroupControl
__nextHasNoMarginBottom
size={ '__unstable-large' }
Expand Down
50 changes: 50 additions & 0 deletions packages/block-editor/src/hooks/test/background.js
@@ -0,0 +1,50 @@
/**
* Internal dependencies
*/

import {
backgroundPositionToCoords,
coordsToBackgroundPosition,
} from '../background';

describe( 'backgroundPositionToCoords', () => {
it( 'should return the correct coordinates for a percentage value using 2-value syntax', () => {
expect( backgroundPositionToCoords( '25% 75%' ) ).toEqual( {
x: 0.25,
y: 0.75,
} );
} );

it( 'should return the correct coordinates for a percentage using 1-value syntax', () => {
expect( backgroundPositionToCoords( '50%' ) ).toEqual( {
x: 0.5,
y: 0.5,
} );
} );

it( 'should return undefined coords in given an empty value', () => {
expect( backgroundPositionToCoords( '' ) ).toEqual( {
x: undefined,
y: undefined,
} );
} );

it( 'should return undefined coords in given a string that cannot be converted', () => {
expect( backgroundPositionToCoords( 'apples' ) ).toEqual( {
x: undefined,
y: undefined,
} );
} );
} );

describe( 'coordsToBackgroundPosition', () => {
it( 'should return the correct background position for a set of coordinates', () => {
expect( coordsToBackgroundPosition( { x: 0.25, y: 0.75 } ) ).toBe(
'25% 75%'
);
} );

it( 'should return undefined if no coordinates are provided', () => {
expect( coordsToBackgroundPosition( {} ) ).toBeUndefined();
} );
} );
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Expand Up @@ -9,6 +9,7 @@

### Bug Fix

- `FocalPointPicker`: Allow `PointerCircle` to render in a default centered position when x and y coordinates are undefined ([#58592](https://github.com/WordPress/gutenberg/pull/58592)).
- `DateTime`: Add a timezone offset value for display purposes. ([#56682](https://github.com/WordPress/gutenberg/pull/56682)).
- `Placeholder`: Fix Placeholder component padding when body text font size is changed ([#58323](https://github.com/WordPress/gutenberg/pull/58323)).
- `Placeholder`: Fix Global Styles typography settings bleeding into placeholder component ([#58303](https://github.com/WordPress/gutenberg/pull/58303)).
Expand Down
4 changes: 2 additions & 2 deletions packages/components/src/focal-point-picker/index.tsx
Expand Up @@ -217,8 +217,8 @@ export function FocalPointPicker( {
};

const focalPointPosition = {
left: x * bounds.width,
top: y * bounds.height,
left: x !== undefined ? x * bounds.width : 0.5 * bounds.width,
top: y !== undefined ? y * bounds.height : 0.5 * bounds.height,
};

const classes = classnames(
Expand Down
19 changes: 18 additions & 1 deletion packages/style-engine/src/styles/background/index.ts
Expand Up @@ -40,6 +40,18 @@ const backgroundImage = {
},
};

const backgroundPosition = {
name: 'backgroundRepeat',
generate: ( style: Style, options: StyleOptions ) => {
return generateRule(
style,
options,
[ 'background', 'backgroundPosition' ],
'backgroundPosition'
);
},
};

const backgroundRepeat = {
name: 'backgroundRepeat',
generate: ( style: Style, options: StyleOptions ) => {
Expand Down Expand Up @@ -89,4 +101,9 @@ const backgroundSize = {
},
};

export default [ backgroundImage, backgroundRepeat, backgroundSize ];
export default [
backgroundImage,
backgroundPosition,
backgroundRepeat,
backgroundSize,
];
6 changes: 6 additions & 0 deletions packages/style-engine/src/test/index.js
Expand Up @@ -229,6 +229,7 @@ describe( 'getCSSRules', () => {
source: 'file',
url: 'https://example.com/image.jpg',
},
backgroundPosition: '50% 50%',
backgroundRepeat: 'no-repeat',
backgroundSize: '300px',
},
Expand Down Expand Up @@ -384,6 +385,11 @@ describe( 'getCSSRules', () => {
key: 'backgroundImage',
value: "url( 'https://example.com/image.jpg' )",
},
{
selector: '.some-selector',
key: 'backgroundPosition',
value: '50% 50%',
},
{
selector: '.some-selector',
key: 'backgroundRepeat',
Expand Down