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

Edit block style variations from global styles #46343

Merged
merged 27 commits into from
Jan 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
85a9598
Edit block style variations from global styles
tellthemachines Dec 7, 2022
6c065bf
It's not working yet but we'll get there
tellthemachines Dec 8, 2022
6943f00
Hardcoded a bunch of stuff to see if it works
tellthemachines Dec 9, 2022
9f89d2e
Add back empty line
tellthemachines Dec 13, 2022
d6bf36b
update panel paths to use encodeURIComponent
tellthemachines Dec 13, 2022
fd3451b
Move updated sanitize function to 6.2 folder
tellthemachines Dec 13, 2022
91350f4
Output CSS for edited style variations
tellthemachines Dec 13, 2022
564fd4e
Any [a-z]* style variation name should be possible
tellthemachines Dec 14, 2022
822b800
Fix test failures
tellthemachines Dec 14, 2022
201f6a0
Add handling of feature selectors
tellthemachines Dec 15, 2022
6e9f10c
Add colors and typography
tellthemachines Dec 15, 2022
df3c408
Re-add changes to class-wp-theme-json
tellthemachines Dec 19, 2022
79d760b
Fix color paths
tellthemachines Dec 20, 2022
6cfb120
Add dimensions styles
tellthemachines Dec 20, 2022
3467f9d
Bump up front end specificity.
tellthemachines Dec 20, 2022
fa02475
Only core variations should be editable
tellthemachines Dec 20, 2022
60d95e2
Basic functionality to create a new variation
tellthemachines Dec 21, 2022
174f1c7
Revert adding new variations for now
tellthemachines Jan 2, 2023
510aa3f
Add preview panel to variation screen.
tellthemachines Jan 3, 2023
25048fe
ItemGroup UI
tellthemachines Jan 3, 2023
8dab200
Fix color screen bug
tellthemachines Jan 3, 2023
aac1e1b
Disable editing on default styles.
tellthemachines Jan 3, 2023
d8972ce
Fix variation showing on general block preview
tellthemachines Jan 5, 2023
967e319
Fix previews for design tools screens inside variations.
tellthemachines Jan 5, 2023
127305a
Address feedback.
tellthemachines Jan 6, 2023
513db1c
Remove default variation from panel.
tellthemachines Jan 6, 2023
a6b2d9c
Default style should always be called Default.
tellthemachines Jan 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 85 additions & 8 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -713,9 +713,17 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n
$schema_styles_blocks = array();
$schema_settings_blocks = array();
foreach ( $valid_block_names as $block ) {
$schema_settings_blocks[ $block ] = static::VALID_SETTINGS;
$schema_styles_blocks[ $block ] = $styles_non_top_level;
$schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
// Build the schema for each block style variation.
$style_variation_names = isset( $input['styles']['blocks'][ $block ]['variations'] ) ? array_keys( $input['styles']['blocks'][ $block ]['variations'] ) : array();
$schema_styles_variations = array();
if ( ! empty( $style_variation_names ) ) {
$schema_styles_variations = array_fill_keys( $style_variation_names, $styles_non_top_level );
}

$schema_settings_blocks[ $block ] = static::VALID_SETTINGS;
$schema_styles_blocks[ $block ] = $styles_non_top_level;
$schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
$schema_styles_blocks[ $block ]['variations'] = $schema_styles_variations;
}

$schema['styles'] = static::VALID_STYLES;
Expand Down Expand Up @@ -863,6 +871,16 @@ protected static function get_blocks_metadata() {
}
static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = implode( ',', $element_selector );
}

// If the block has style variations, append their selectors to the block metadata.
if ( ! empty( $block_type->styles ) ) {
$style_selectors = array();
foreach ( $block_type->styles as $style ) {
// The style variation classname is duplicated in the selector to ensure that it overrides core block styles.
$style_selectors[ $style['name'] ] = static::append_to_selector( '.is-style-' . $style['name'] . '.is-style-' . $style['name'], static::$blocks_metadata[ $block_name ]['selector'] );
tellthemachines marked this conversation as resolved.
Show resolved Hide resolved
}
static::$blocks_metadata[ $block_name ]['styleVariations'] = $style_selectors;
}
}

return static::$blocks_metadata;
Expand Down Expand Up @@ -2145,12 +2163,23 @@ private static function get_block_nodes( $theme_json, $selectors = array() ) {
$feature_selectors = $selectors[ $name ]['features'];
}

$variation_selectors = array();
if ( isset( $node['variations'] ) ) {
foreach ( $node['variations'] as $variation => $node ) {
$variation_selectors[] = array(
'path' => array( 'styles', 'blocks', $name, 'variations', $variation ),
'selector' => $selectors[ $name ]['styleVariations'][ $variation ],
);
}
}

$nodes[] = array(
'name' => $name,
'path' => array( 'styles', 'blocks', $name ),
'selector' => $selector,
'duotone' => $duotone_selector,
'features' => $feature_selectors,
'name' => $name,
'path' => array( 'styles', 'blocks', $name ),
'selector' => $selector,
'duotone' => $duotone_selector,
'features' => $feature_selectors,
'variations' => $variation_selectors,
);

if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'] ) ) {
Expand Down Expand Up @@ -2230,6 +2259,49 @@ public function get_styles_for_block( $block_metadata ) {
}
}

// If there are style variations, generate the declarations for them, including any feature selectors the block may have.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker, but I wonder if in a follow-up there's an opportunity to either consolidate some of this logic with the feature declarations above, or split it out into a separate function, since this function is now quite long? Definitely not something to worry about in this PR, just jotting down the thought 🙂

$style_variation_declarations = array();
if ( ! empty( $block_metadata['variations'] ) ) {
foreach ( $block_metadata['variations'] as $style_variation ) {
$style_variation_node = _wp_array_get( $this->theme_json, $style_variation['path'], array() );
$style_variation_selector = $style_variation['selector'];

// If the block has feature selectors, generate the declarations for them within the current style variation.
if ( ! empty( $block_metadata['features'] ) ) {
andrewserong marked this conversation as resolved.
Show resolved Hide resolved
foreach ( $block_metadata['features'] as $feature_name => $feature_selector ) {
if ( ! empty( $style_variation_node[ $feature_name ] ) ) {
// Prepend the variation selector to the feature selector.
$split_feature_selectors = explode( ',', $feature_selector );
$feature_selectors = array_map(
function( $split_feature_selector ) use ( $style_variation_selector ) {
return trim( $style_variation_selector ) . trim( $split_feature_selector );
},
$split_feature_selectors
);
$combined_feature_selectors = implode( ',', $feature_selectors );

// Compute declarations for the feature.
$new_feature_declarations = static::compute_style_properties( array( $feature_name => $style_variation_node[ $feature_name ] ), $settings, null, $this->theme_json );

// Merge new declarations with any that already exist for
// the feature selector. This may occur when multiple block
// support features use the same custom selector.
if ( isset( $style_variation_declarations[ $combined_feature_selectors ] ) ) {
$style_variation_declarations[ $combined_feature_selectors ] = array_merge( $style_variation_declarations[ $combined_feature_selectors ], $new_feature_declarations );
} else {
$style_variation_declarations[ $combined_feature_selectors ] = $new_feature_declarations;
}
// Remove the feature from the variation's node now the
// styles will be included under the feature level selector.
unset( $style_variation_node[ $feature_name ] );
}
}
}
// Compute declarations for remaining styles not covered by feature level selectors.
$style_variation_declarations[ $style_variation_selector ] = static::compute_style_properties( $style_variation_node, $settings, null, $this->theme_json );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took me a second to work out why this area has two calls to compute_style_properties. It looks like the second call here is for anything not already covered by feature level selectors (since the feature level ones will have unset the feature from the $style_variation_node).

Would it be worth adding a comment prior to this line, something along the lines of "Compute declarations for remaining styles not covered by feature level selectors" or something like that?

}
}

/*
* Get a reference to element name from path.
* $block_metadata['path'] = array( 'styles','elements','link' );
Expand Down Expand Up @@ -2320,6 +2392,11 @@ function( $pseudo_selector ) use ( $selector ) {
$block_rules .= static::to_ruleset( $feature_selector, $individual_feature_declarations );
}

// 6. Generate and append the style variation rulesets.
foreach ( $style_variation_declarations as $style_variation_selector => $individual_style_variation_declarations ) {
$block_rules .= static::to_ruleset( $style_variation_selector, $individual_style_variation_declarations );
}

return $block_rules;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
Popover,
} from '@wordpress/components';
import deprecated from '@wordpress/deprecated';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
Expand Down Expand Up @@ -64,7 +65,9 @@ function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop } ) {
<div className="block-editor-block-styles">
<div className="block-editor-block-styles__variants">
{ stylesToRender.map( ( style ) => {
const buttonText = style.label || style.name;
const buttonText = style.isDefault
? __( 'Default' )
: style.label || style.name;

return (
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,25 @@ import { getBlockType, getBlockFromExample } from '@wordpress/blocks';
import { useResizeObserver } from '@wordpress/compose';
import { __experimentalSpacer as Spacer } from '@wordpress/components';

const BlockPreviewPanel = ( { name } ) => {
const BlockPreviewPanel = ( { name, variation = '' } ) => {
const [
containerResizeListener,
{ width: containerWidth, height: containerHeight },
] = useResizeObserver();
const blockExample = getBlockType( name )?.example;
const blocks = blockExample && getBlockFromExample( name, blockExample );
const blockExampleWithVariation = {
...blockExample,
attributes: {
...blockExample?.attributes,
className: variation,
},
};
const blocks =
blockExample &&
getBlockFromExample(
name,
variation ? blockExampleWithVariation : blockExample
);
const viewportWidth = blockExample?.viewportWidth || containerWidth;
const minHeight = containerHeight;

Expand Down
12 changes: 8 additions & 4 deletions packages/edit-site/src/components/global-styles/border-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,15 @@ function applyAllFallbackStyles( border ) {
return applyFallbackStyle( border );
}

export default function BorderPanel( { name } ) {
export default function BorderPanel( { name, variationPath = '' } ) {
// To better reflect if the user has customized a value we need to
// ensure the style value being checked is from the `user` origin.
const [ userBorderStyles ] = useStyle( 'border', name, 'user' );
const [ border, setBorder ] = useStyle( 'border', name );
const [ userBorderStyles ] = useStyle(
`${ variationPath }border`,
name,
'user'
);
const [ border, setBorder ] = useStyle( `${ variationPath }border`, name );
const colors = useColorsPerOrigin( name );

const showBorderColor = useHasBorderColorControl( name );
Expand All @@ -108,7 +112,7 @@ export default function BorderPanel( { name } ) {
// Border radius.
const showBorderRadius = useHasBorderRadiusControl( name );
const [ borderRadiusValues, setBorderRadius ] = useStyle(
'border.radius',
`${ variationPath }border.radius`,
name
);
const hasBorderRadius = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ import { useHasBorderPanel } from './border-panel';
import { useHasColorPanel } from './color-utils';
import { useHasDimensionsPanel } from './dimensions-panel';
import { useHasTypographyPanel } from './typography-panel';
import { useHasVariationsPanel } from './variations-panel';
import { NavigationButtonAsItem } from './navigation-button';
import { ScreenVariations } from './screen-variations';

function ContextMenu( { name, parentMenu = '' } ) {
const hasTypographyPanel = useHasTypographyPanel( name );
const hasColorPanel = useHasColorPanel( name );
const hasBorderPanel = useHasBorderPanel( name );
const hasDimensionsPanel = useHasDimensionsPanel( name );
const hasLayoutPanel = hasDimensionsPanel;
const hasVariationsPanel = useHasVariationsPanel( name, parentMenu );

return (
<ItemGroup>
Expand Down Expand Up @@ -59,6 +62,9 @@ function ContextMenu( { name, parentMenu = '' } ) {
{ __( 'Layout' ) }
</NavigationButtonAsItem>
) }
{ hasVariationsPanel && (
<ScreenVariations name={ name } path={ parentMenu } />
) }
</ItemGroup>
);
}
Expand Down
47 changes: 32 additions & 15 deletions packages/edit-site/src/components/global-styles/dimensions-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,11 @@ function useWideSizeProps( name ) {
}

// Props for managing `spacing.padding`.
function usePaddingProps( name ) {
const [ rawPadding, setRawPadding ] = useStyle( 'spacing.padding', name );
function usePaddingProps( name, variationPath = '' ) {
const [ rawPadding, setRawPadding ] = useStyle(
variationPath + 'spacing.padding',
name
);
const paddingValues = splitStyleValue( rawPadding );
const paddingSides = useCustomSides( name, 'padding' );
const isAxialPadding =
Expand All @@ -210,7 +213,11 @@ function usePaddingProps( name ) {
setRawPadding( padding );
};
const resetPaddingValue = () => setPaddingValues( {} );
const [ userSetPaddingValue ] = useStyle( 'spacing.padding', name, 'user' );
const [ userSetPaddingValue ] = useStyle(
variationPath + 'spacing.padding',
name,
'user'
);
// The `hasPaddingValue` check does not need a parsed value, as `userSetPaddingValue` will be `undefined` if not set.
const hasPaddingValue = () => !! userSetPaddingValue;

Expand All @@ -225,8 +232,11 @@ function usePaddingProps( name ) {
}

// Props for managing `spacing.margin`.
function useMarginProps( name ) {
const [ rawMargin, setRawMargin ] = useStyle( 'spacing.margin', name );
function useMarginProps( name, variationPath = '' ) {
const [ rawMargin, setRawMargin ] = useStyle(
variationPath + 'spacing.margin',
name
);
const marginValues = splitStyleValue( rawMargin );
const marginSides = useCustomSides( name, 'margin' );
const isAxialMargin =
Expand All @@ -252,14 +262,21 @@ function useMarginProps( name ) {
}

// Props for managing `spacing.blockGap`.
function useBlockGapProps( name ) {
const [ gapValue, setGapValue ] = useStyle( 'spacing.blockGap', name );
function useBlockGapProps( name, variationPath = '' ) {
const [ gapValue, setGapValue ] = useStyle(
variationPath + 'spacing.blockGap',
name
);
const gapValues = splitGapValue( gapValue );
const gapSides = useCustomSides( name, 'blockGap' );
const isAxialGap =
gapSides && gapSides.some( ( side ) => AXIAL_SIDES.includes( side ) );
const resetGapValue = () => setGapValue( undefined );
const [ userSetGapValue ] = useStyle( 'spacing.blockGap', name, 'user' );
const [ userSetGapValue ] = useStyle(
variationPath + 'spacing.blockGap',
name,
'user'
);
const hasGapValue = () => !! userSetGapValue;
const setGapValues = ( nextBoxGapValue ) => {
if ( ! nextBoxGapValue ) {
Expand Down Expand Up @@ -288,9 +305,9 @@ function useBlockGapProps( name ) {
}

// Props for managing `dimensions.minHeight`.
function useMinHeightProps( name ) {
function useMinHeightProps( name, variationPath = '' ) {
const [ minHeightValue, setMinHeightValue ] = useStyle(
'dimensions.minHeight',
variationPath + 'dimensions.minHeight',
name
);
const resetMinHeightValue = () => setMinHeightValue( undefined );
Expand All @@ -303,7 +320,7 @@ function useMinHeightProps( name ) {
};
}

export default function DimensionsPanel( { name } ) {
export default function DimensionsPanel( { name, variationPath = '' } ) {
const showContentSizeControl = useHasContentSize( name );
const showWideSizeControl = useHasWideSize( name );
const showPaddingControl = useHasPadding( name );
Expand Down Expand Up @@ -345,7 +362,7 @@ export default function DimensionsPanel( { name } ) {
setPaddingValues,
resetPaddingValue,
hasPaddingValue,
} = usePaddingProps( name );
} = usePaddingProps( name, variationPath );

// Props for managing `spacing.margin`.
const {
Expand All @@ -355,7 +372,7 @@ export default function DimensionsPanel( { name } ) {
setMarginValues,
resetMarginValue,
hasMarginValue,
} = useMarginProps( name );
} = useMarginProps( name, variationPath );

// Props for managing `spacing.blockGap`.
const {
Expand All @@ -367,15 +384,15 @@ export default function DimensionsPanel( { name } ) {
setGapValues,
resetGapValue,
hasGapValue,
} = useBlockGapProps( name );
} = useBlockGapProps( name, variationPath );

// Props for managing `dimensions.minHeight`.
const {
minHeightValue,
setMinHeightValue,
resetMinHeightValue,
hasMinHeightValue,
} = useMinHeightProps( name );
} = useMinHeightProps( name, variationPath );

const resetAll = () => {
resetPaddingValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
useStyle,
} from './hooks';

function ScreenBackgroundColor( { name } ) {
function ScreenBackgroundColor( { name, variationPath = '' } ) {
const supports = getSupportedGlobalStylesPanels( name );
const [ solids ] = useSetting( 'color.palette', name );
const [ gradients ] = useSetting( 'color.gradients', name );
Expand All @@ -39,16 +39,23 @@ function ScreenBackgroundColor( { name } ) {
supports.includes( 'background' ) &&
( gradients.length > 0 || areCustomGradientsEnabled );
const [ backgroundColor, setBackgroundColor ] = useStyle(
'color.background',
variationPath + 'color.background',
name
);
const [ userBackgroundColor ] = useStyle(
'color.background',
variationPath + 'color.background',
name,
'user'
);
const [ gradient, setGradient ] = useStyle(
variationPath + 'color.gradient',
name
);
const [ userGradient ] = useStyle(
variationPath + 'color.gradient',
name,
'user'
);
const [ gradient, setGradient ] = useStyle( 'color.gradient', name );
const [ userGradient ] = useStyle( 'color.gradient', name, 'user' );

if ( ! hasBackgroundColor && ! hasGradientColor ) {
return null;
Expand Down
Loading