Skip to content

Commit

Permalink
Move data to style.layout.position
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewserong committed Oct 24, 2022
1 parent 42b4dab commit 0b7cbb2
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 58 deletions.
57 changes: 35 additions & 22 deletions lib/block-supports/layout.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,42 +26,54 @@ function gutenberg_register_layout_support( $block_type ) {
}

/**
* Generates the CSS for position support from the layout object.
* Generates the CSS for position support from the style object.
*
* @param string $selector CSS selector.
* @param array $layout Layout object. The one that is passed has already checked
* the existence of default block layout.
* @param array $style Style object.
* @return string CSS styles on success. Else, empty string.
*/
function gutenberg_get_layout_position_style( $selector, $layout ) {
function gutenberg_get_layout_position_style( $selector, $style ) {
$position_styles = array();

$position_type = _wp_array_get( $layout, array( 'position', 'type' ), '' );
$position_side = _wp_array_get( $layout, array( 'position', 'side' ), '' );
$offset_value = '0';
$position_type = _wp_array_get( $style, array( 'layout', 'position' ), '' );

if (
in_array( $position_type, array( 'fixed', 'sticky' ), true ) &&
in_array( $position_side, array( 'top', 'right', 'bottom', 'left' ), true )
in_array( $position_type, array( 'fixed', 'sticky' ), true )
) {
/*
* For fixed or sticky top positions,
* ensure the value includes an offset for the logged in admin bar.
*/
if (
'top' === $position_side &&
'fixed' === $position_type ||
'sticky' === $position_type
) {
$offset_value = 'var(--wp-admin--admin-bar--height, 0px)';
$sides = array( 'top', 'right', 'bottom', 'left' );

foreach( $sides as $side ) {
$side_value = _wp_array_get( $style, array( 'layout', $side ) );
if ( $side_value !== null ) {

/*
* For fixed or sticky top positions,
* ensure the value includes an offset for the logged in admin bar.
*/
if (
'top' === $side &&
'fixed' === $position_type ||
'sticky' === $position_type
) {
// TODO: wrap the following value in a `calc()` + `$side_value`,
// so that any included value is treated as an offset.
$side_value = 'var(--wp-admin--admin-bar--height, 0px)';
}

$position_styles[] =
array(
'selector' => "$selector",
'declarations' => array(
$side => $side_value
),
);
}
}

$position_styles[] =
array(
'selector' => "$selector",
'declarations' => array(
'position' => $position_type,
$position_side => $offset_value,
'z-index' => '250', // TODO: This hard-coded value should live somewhere else.
),
);
Expand Down Expand Up @@ -464,7 +476,8 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) {
$block_spacing
);

$style .= gutenberg_get_layout_position_style( ".$block_classname.$container_class", $used_layout );
$style_attribute = _wp_array_get( $block, array( 'attrs', 'style' ), null );
$style .= gutenberg_get_layout_position_style( ".$block_classname.$container_class", $style_attribute );

// Only add container class and enqueue block support styles if unique styles were generated.
if ( ! empty( $style ) ) {
Expand Down
94 changes: 74 additions & 20 deletions packages/block-editor/src/hooks/position.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const POSITION_OPTIONS = [
},
];

const POSITION_SIDES = [ 'top', 'right', 'bottom', 'left' ];

/**
* Determines if there is position support.
*
Expand All @@ -51,7 +53,7 @@ export function hasPositionSupport( blockType ) {
* @return {boolean} Whether or not the block has a position value set.
*/
export function hasPositionValue( props ) {
return props.attributes.layout?.position !== undefined;
return props.attributes.style?.layout?.position !== undefined;
}

/**
Expand All @@ -63,12 +65,19 @@ export function hasPositionValue( props ) {
* @param {Object} props.setAttributes Function to set block's attributes.
*/
export function resetPosition( { attributes = {}, setAttributes } ) {
const { layout = {} } = attributes;
const { style = {} } = attributes;

setAttributes( {
layout: cleanEmptyObject( {
...layout,
position: undefined,
style: cleanEmptyObject( {
...style,
layout: {
...style?.layout,
position: undefined,
top: undefined,
right: undefined,
bottom: undefined,
left: undefined,
},
} ),
} );
}
Expand All @@ -86,6 +95,29 @@ export function useIsPositionDisabled( { name: blockName } = {} ) {
return ! hasPositionSupport( blockName ) || isDisabled;
}

/**
* From a style.layout object, find the first side with a value.
*
* This allows inferring the selected area based on the presence of a value for one of
* the four sides, `top`, `bottom`, `right`, and `left.
*
* @param {Object} styleLayout An object that can contain `top`, `bottom`, `right`, and `left` keys.
* @return {?string} The side with a value.
*/
function getFirstActiveAreaValue( styleLayout ) {
if ( ! styleLayout ) {
return;
}
const foundSide = Object.entries( styleLayout ).find(
( [ key, value ] ) =>
POSITION_SIDES.includes( key ) && value !== undefined
);

if ( foundSide ) {
return foundSide[ 0 ];
}
}

/**
* Inspector control panel containing the padding related configuration
*
Expand All @@ -95,7 +127,7 @@ export function useIsPositionDisabled( { name: blockName } = {} ) {
*/
export function PositionEdit( props ) {
const {
attributes: { layout = {} },
attributes: { style = {} },
setAttributes,
} = props;

Expand All @@ -104,33 +136,55 @@ export function PositionEdit( props ) {
}

const onChangeSide = ( next ) => {
const newLayout = {
...layout,
position: {
...layout?.position,
side: next,
if ( next !== undefined && ! POSITION_SIDES.includes( next ) ) {
return;
}

// For now, use a hard-coded `0px` value for the position.
// `0px` is preferred over `0` as it can be used in `calc()` functions.
// In the future, it could be useful to allow for an offset value.
const newValue = '0px';

const newSides = {
top: undefined,
right: undefined,
bottom: undefined,
left: undefined,
};

if ( next !== undefined ) {
newSides[ next ] = newValue;
}

const newStyle = {
...style,
layout: {
...style?.layout,
...newSides,
},
};

setAttributes( {
layout: cleanEmptyObject( newLayout ),
style: cleanEmptyObject( newStyle ),
} );
};

const onChangeType = ( next ) => {
const newLayout = {
...layout,
position: {
...layout?.position,
type: next,
const newStyle = {
...style,
layout: {
...style?.layout,
position: next,
},
};

setAttributes( {
layout: cleanEmptyObject( newLayout ),
style: cleanEmptyObject( newStyle ),
} );
};

const areaValue = getFirstActiveAreaValue( style?.layout );

return Platform.select( {
web: (
<>
Expand All @@ -139,14 +193,14 @@ export function PositionEdit( props ) {
'The area of a page that this block should occupy'
) }
onChange={ onChangeSide }
value={ layout?.position?.side }
value={ areaValue }
/>
<ToggleGroupControl
label={ __( 'Position' ) }
help={ __(
"Lock this block to an area of the page so it doesn't scroll with page content"
) }
value={ layout?.position?.type || '' }
value={ style?.layout?.position || '' }
onChange={ ( newValue ) => {
onChangeType( newValue );
} }
Expand Down
2 changes: 1 addition & 1 deletion packages/block-editor/src/layouts/constrained.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ export default {
}

// Add position CSS where applicable.
output += getPositionCSS( { selector, layout } );
output += getPositionCSS( { selector, style } );

return output;
},
Expand Down
2 changes: 1 addition & 1 deletion packages/block-editor/src/layouts/flex.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export default {
}

// Add position CSS where applicable.
output += getPositionCSS( { selector, layout } );
output += getPositionCSS( { selector, style } );

return output;
},
Expand Down
3 changes: 1 addition & 2 deletions packages/block-editor/src/layouts/flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export default {
},
getLayoutStyle: function getLayoutStyle( {
selector,
layout,
style,
blockName,
hasBlockGapSupport,
Expand Down Expand Up @@ -54,7 +53,7 @@ export default {
}

// Add position CSS where applicable.
output += getPositionCSS( { selector, layout } );
output += getPositionCSS( { selector, style } );

return output;
},
Expand Down
25 changes: 13 additions & 12 deletions packages/block-editor/src/layouts/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,27 +76,28 @@ const VALID_POSITION_TYPES = [ 'sticky', 'fixed' ];
*
* @param {Object} props Component props.
* @param {string} props.selector Selector to use.
* @param {Object} props.layout Layout object.
* @param {Object} props.style Style object.
* @return {string} The generated CSS rules.
*/
export function getPositionCSS( { selector, layout } ) {
export function getPositionCSS( { selector, style } ) {
let output = '';

const { type, side } = layout?.position || {};
const { position } = style?.layout || {};

if (
! VALID_POSITION_TYPES.includes( type ) ||
! VALID_POSITION_SIDES.includes( side )
) {
if ( ! VALID_POSITION_TYPES.includes( position ) ) {
return output;
}

const offsetValue = '0px';

output += `${ selector } {`;
output += `position: ${ type };`;
output += `${ side }: ${ offsetValue };`;
if ( type === 'sticky' || type === 'fixed' ) {
output += `position: ${ position };`;

VALID_POSITION_SIDES.forEach( ( side ) => {
if ( style?.layout?.[ side ] !== undefined ) {
output += `${ side }: ${ style.layout[ side ] };`;
}
} );

if ( position === 'sticky' || position === 'fixed' ) {
// TODO: Work out where to put the magic z-index value.
output += `z-index: 250`;
}
Expand Down

0 comments on commit 0b7cbb2

Please sign in to comment.