diff --git a/lib/block-supports/shadow.php b/lib/block-supports/shadow.php
index 4a28c98b79325d..87258930faf10e 100644
--- a/lib/block-supports/shadow.php
+++ b/lib/block-supports/shadow.php
@@ -53,9 +53,8 @@ function gutenberg_apply_shadow_support( $block_type, $block_attributes ) {
$shadow_block_styles = array();
- $preset_shadow = array_key_exists( 'shadow', $block_attributes ) ? "var:preset|shadow|{$block_attributes['shadow']}" : null;
- $custom_shadow = isset( $block_attributes['style']['shadow'] ) ? $block_attributes['style']['shadow'] : null;
- $shadow_block_styles['shadow'] = $preset_shadow ? $preset_shadow : $custom_shadow;
+ $custom_shadow = $block_attributes['style']['shadow'] ?? null;
+ $shadow_block_styles['shadow'] = $custom_shadow;
$attributes = array();
$styles = gutenberg_style_engine_get_styles( $shadow_block_styles );
diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js
index 9cb3b89a7bc252..afdda89b6739ac 100644
--- a/packages/block-editor/src/components/block-inspector/index.js
+++ b/packages/block-editor/src/components/block-inspector/index.js
@@ -307,6 +307,10 @@ const BlockInspectorSingleBlock = ( { clientId, blockName } ) => {
label={ __( 'Background' ) }
/>
+
diff --git a/packages/block-editor/src/components/global-styles/effects-panel.js b/packages/block-editor/src/components/global-styles/effects-panel.js
index 9a9fd8d1258edd..94c1d119c354c9 100644
--- a/packages/block-editor/src/components/global-styles/effects-panel.js
+++ b/packages/block-editor/src/components/global-styles/effects-panel.js
@@ -26,6 +26,7 @@ import { shadow as shadowIcon, Icon, check } from '@wordpress/icons';
/**
* Internal dependencies
*/
+import { mergeOrigins } from '../use-settings';
import { getValueFromVariable, TOOLSPANEL_DROPDOWNMENU_PROPS } from './utils';
import { setImmutably } from '../../utils/object';
@@ -81,8 +82,22 @@ export default function EffectsPanel( {
// Shadow
const hasShadowEnabled = useHasShadowControl( settings );
const shadow = decodeValue( inheritedValue?.shadow );
+ const shadowPresets = settings?.shadow?.presets;
+ const mergedShadowPresets = shadowPresets
+ ? mergeOrigins( shadowPresets )
+ : [];
const setShadow = ( newValue ) => {
- onChange( setImmutably( value, [ 'shadow' ], newValue ) );
+ const slug = mergedShadowPresets?.find(
+ ( { shadow: shadowName } ) => shadowName === newValue
+ )?.slug;
+
+ onChange(
+ setImmutably(
+ value,
+ [ 'shadow' ],
+ slug ? `var:preset|shadow|${ slug }` : newValue || undefined
+ )
+ );
};
const hasShadow = () => !! value?.shadow;
const resetShadow = () => setShadow( undefined );
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/styles-tab.js b/packages/block-editor/src/components/inspector-controls-tabs/styles-tab.js
index d42b3bffce4ebc..6f24051ea2cfcb 100644
--- a/packages/block-editor/src/components/inspector-controls-tabs/styles-tab.js
+++ b/packages/block-editor/src/components/inspector-controls-tabs/styles-tab.js
@@ -46,6 +46,7 @@ const StylesTab = ( { blockName, clientId, hasBlockStyles } ) => {
label={ __( 'Dimensions' ) }
/>
+
>
);
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js b/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js
index 2a47ae5267ca4e..ff68be82a829f1 100644
--- a/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js
+++ b/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js
@@ -40,6 +40,7 @@ export default function useInspectorControlsTabs( blockName ) {
position: positionGroup,
styles: stylesGroup,
typography: typographyGroup,
+ effects: effectsGroup,
} = InspectorControlsGroups;
// List View Tab: If there are any fills for the list group add that tab.
@@ -55,6 +56,7 @@ export default function useInspectorControlsTabs( blockName ) {
...( useSlotFills( dimensionsGroup.Slot.__unstableName ) || [] ),
...( useSlotFills( stylesGroup.Slot.__unstableName ) || [] ),
...( useSlotFills( typographyGroup.Slot.__unstableName ) || [] ),
+ ...( useSlotFills( effectsGroup.Slot.__unstableName ) || [] ),
];
const hasStyleFills = styleFills.length;
diff --git a/packages/block-editor/src/components/inspector-controls/groups.js b/packages/block-editor/src/components/inspector-controls/groups.js
index b4eada4b6b4be6..9ca1a72b9918a6 100644
--- a/packages/block-editor/src/components/inspector-controls/groups.js
+++ b/packages/block-editor/src/components/inspector-controls/groups.js
@@ -20,6 +20,7 @@ const InspectorControlsTypography = createSlotFill(
);
const InspectorControlsListView = createSlotFill( 'InspectorControlsListView' );
const InspectorControlsStyles = createSlotFill( 'InspectorControlsStyles' );
+const InspectorControlsEffects = createSlotFill( 'InspectorControlsEffects' );
const groups = {
default: InspectorControlsDefault,
@@ -28,6 +29,7 @@ const groups = {
border: InspectorControlsBorder,
color: InspectorControlsColor,
dimensions: InspectorControlsDimensions,
+ effects: InspectorControlsEffects,
filter: InspectorControlsFilter,
list: InspectorControlsListView,
position: InspectorControlsPosition,
diff --git a/packages/block-editor/src/hooks/effects.js b/packages/block-editor/src/hooks/effects.js
new file mode 100644
index 00000000000000..92d9a2310f1c40
--- /dev/null
+++ b/packages/block-editor/src/hooks/effects.js
@@ -0,0 +1,59 @@
+/**
+ * WordPress dependencies
+ */
+import { hasBlockSupport } from '@wordpress/blocks';
+import { useSelect } from '@wordpress/data';
+/**
+ * Internal dependencies
+ */
+import StylesEffectsPanel, {
+ useHasEffectsPanel,
+} from '../components/global-styles/effects-panel';
+import { InspectorControls } from '../components';
+import { store as blockEditorStore } from '../store';
+
+export const SHADOW_SUPPORT_KEY = 'shadow';
+export const EFFECTS_SUPPORT_KEYS = [ SHADOW_SUPPORT_KEY ];
+
+export function hasEffectsSupport( blockName ) {
+ return EFFECTS_SUPPORT_KEYS.some( ( key ) =>
+ hasBlockSupport( blockName, key )
+ );
+}
+
+function EffectsInspectorControl( { children, resetAllFilter } ) {
+ return (
+
+ { children }
+
+ );
+}
+export function EffectsPanel( { clientId, setAttributes, settings } ) {
+ const isEnabled = useHasEffectsPanel( settings );
+ const blockAttributes = useSelect(
+ ( select ) => select( blockEditorStore ).getBlockAttributes( clientId ),
+ [ clientId ]
+ );
+ const shadow = blockAttributes?.style?.shadow;
+ const value = { shadow };
+
+ const onChange = ( newValue ) => {
+ setAttributes( {
+ style: { ...blockAttributes.style, shadow: newValue.shadow },
+ } );
+ };
+
+ if ( ! isEnabled ) {
+ return null;
+ }
+
+ return (
+
+ );
+}
diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js
index f17c0a22166e4e..cb0ca4e2ff3e58 100644
--- a/packages/block-editor/src/hooks/index.js
+++ b/packages/block-editor/src/hooks/index.js
@@ -68,6 +68,7 @@ createBlockSaveFilter( [
export { useCustomSides } from './dimensions';
export { useLayoutClasses, useLayoutStyles } from './layout';
export { getBorderClassesAndStyles, useBorderProps } from './use-border-props';
+export { getShadowClassesAndStyles, useShadowProps } from './use-shadow-props';
export { getColorClassesAndStyles, useColorProps } from './use-color-props';
export { getSpacingClassesAndStyles } from './use-spacing-props';
export { getTypographyClassesAndStyles } from './use-typography-props';
diff --git a/packages/block-editor/src/hooks/index.native.js b/packages/block-editor/src/hooks/index.native.js
index 55ae7e19df7037..6e4c1c6a17ba54 100644
--- a/packages/block-editor/src/hooks/index.native.js
+++ b/packages/block-editor/src/hooks/index.native.js
@@ -28,6 +28,7 @@ createBlockSaveFilter( [
] );
export { getBorderClassesAndStyles, useBorderProps } from './use-border-props';
+export { getShadowClassesAndStyles, useShadowProps } from './use-shadow-props';
export { getColorClassesAndStyles, useColorProps } from './use-color-props';
export { getSpacingClassesAndStyles } from './use-spacing-props';
export { useCachedTruthy } from './use-cached-truthy';
diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js
index 7221de63456cd5..dec046f888a468 100644
--- a/packages/block-editor/src/hooks/style.js
+++ b/packages/block-editor/src/hooks/style.js
@@ -27,6 +27,11 @@ import {
SPACING_SUPPORT_KEY,
DimensionsPanel,
} from './dimensions';
+import {
+ EFFECTS_SUPPORT_KEYS,
+ SHADOW_SUPPORT_KEY,
+ EffectsPanel,
+} from './effects';
import {
shouldSkipSerialization,
useStyleOverride,
@@ -37,6 +42,7 @@ import { useBlockEditingMode } from '../components/block-editing-mode';
const styleSupportKeys = [
...TYPOGRAPHY_SUPPORT_KEYS,
+ ...EFFECTS_SUPPORT_KEYS,
BORDER_SUPPORT_KEY,
COLOR_SUPPORT_KEY,
DIMENSIONS_SUPPORT_KEY,
@@ -110,6 +116,7 @@ const skipSerializationPathsEdit = {
[ `${ SPACING_SUPPORT_KEY }.__experimentalSkipSerialization` ]: [
SPACING_SUPPORT_KEY,
],
+ [ `${ SHADOW_SUPPORT_KEY }` ]: [ SHADOW_SUPPORT_KEY ],
};
/**
@@ -336,6 +343,7 @@ function BlockStyleControls( {
+
>
);
}
diff --git a/packages/block-editor/src/hooks/supports.js b/packages/block-editor/src/hooks/supports.js
index 2cf08d46fa8fe2..4e116494029bf1 100644
--- a/packages/block-editor/src/hooks/supports.js
+++ b/packages/block-editor/src/hooks/supports.js
@@ -59,8 +59,10 @@ const TYPOGRAPHY_SUPPORT_KEYS = [
WRITING_MODE_SUPPORT_KEY,
LETTER_SPACING_SUPPORT_KEY,
];
+const EFFECTS_SUPPORT_KEYS = [ 'shadow' ];
const SPACING_SUPPORT_KEY = 'spacing';
const styleSupportKeys = [
+ ...EFFECTS_SUPPORT_KEYS,
...TYPOGRAPHY_SUPPORT_KEYS,
BORDER_SUPPORT_KEY,
COLOR_SUPPORT_KEY,
diff --git a/packages/block-editor/src/hooks/test/effects.js b/packages/block-editor/src/hooks/test/effects.js
new file mode 100644
index 00000000000000..b4fe61745744b1
--- /dev/null
+++ b/packages/block-editor/src/hooks/test/effects.js
@@ -0,0 +1,39 @@
+/**
+ * Internal dependencies
+ */
+import { hasEffectsSupport } from '../effects';
+
+describe( 'effects', () => {
+ describe( 'hasEffectsSupport', () => {
+ it( 'should return false if the block does not support effects', () => {
+ const settings = {
+ supports: {
+ shadow: false,
+ },
+ };
+
+ expect( hasEffectsSupport( settings ) ).toBe( false );
+ } );
+
+ it( 'should return true if the block supports effects', () => {
+ const settings = {
+ supports: {
+ shadow: true,
+ },
+ };
+
+ expect( hasEffectsSupport( settings ) ).toBe( true );
+ } );
+
+ it( 'should return true if the block supports effects and other features', () => {
+ const settings = {
+ supports: {
+ shadow: true,
+ align: true,
+ },
+ };
+
+ expect( hasEffectsSupport( settings ) ).toBe( true );
+ } );
+ } );
+} );
diff --git a/packages/block-editor/src/hooks/use-shadow-props.js b/packages/block-editor/src/hooks/use-shadow-props.js
new file mode 100644
index 00000000000000..fdc601366245c9
--- /dev/null
+++ b/packages/block-editor/src/hooks/use-shadow-props.js
@@ -0,0 +1,37 @@
+/**
+ * Internal dependencies
+ */
+import { getInlineStyles } from './style';
+
+// This utility is intended to assist where the serialization of the shadow
+// block support is being skipped for a block but the shadow related CSS classes
+// & styles still need to be generated so they can be applied to inner elements.
+
+/**
+ * Provides the CSS class names and inline styles for a block's shadow support
+ * attributes.
+ *
+ * @param {Object} attributes Block attributes.
+ * @return {Object} Shadow block support derived CSS classes & styles.
+ */
+export function getShadowClassesAndStyles( attributes ) {
+ const shadow = attributes.style?.shadow || '';
+
+ return {
+ className: undefined,
+ style: getInlineStyles( { shadow } ),
+ };
+}
+
+/**
+ * Derives the shadow related props for a block from its shadow block support
+ * attributes.
+ *
+ * @param {Object} attributes Block attributes.
+ *
+ * @return {Object} ClassName & style props from shadow block support.
+ */
+export function useShadowProps( attributes ) {
+ const shadowProps = getShadowClassesAndStyles( attributes );
+ return shadowProps;
+}
diff --git a/packages/block-editor/src/hooks/utils.js b/packages/block-editor/src/hooks/utils.js
index e63029e4e34e81..ea31a516ac6343 100644
--- a/packages/block-editor/src/hooks/utils.js
+++ b/packages/block-editor/src/hooks/utils.js
@@ -221,6 +221,7 @@ export function useBlockSettings( name, parentLayout ) {
isTextEnabled,
isHeadingEnabled,
isButtonEnabled,
+ shadow,
] = useSettings(
'background.backgroundImage',
'background.backgroundSize',
@@ -268,7 +269,8 @@ export function useBlockSettings( name, parentLayout ) {
'color.link',
'color.text',
'color.heading',
- 'color.button'
+ 'color.button',
+ 'shadow'
);
const rawSettings = useMemo( () => {
@@ -345,6 +347,7 @@ export function useBlockSettings( name, parentLayout ) {
},
layout,
parentLayout,
+ shadow,
};
}, [
backgroundImage,
@@ -395,6 +398,7 @@ export function useBlockSettings( name, parentLayout ) {
isTextEnabled,
isHeadingEnabled,
isButtonEnabled,
+ shadow,
] );
return useSettingsForBlockElement( rawSettings, name );
diff --git a/packages/block-editor/src/index.js b/packages/block-editor/src/index.js
index 1dbc4501e92180..83475b9358723e 100644
--- a/packages/block-editor/src/index.js
+++ b/packages/block-editor/src/index.js
@@ -11,6 +11,8 @@ export {
useCustomSides as __experimentalUseCustomSides,
getSpacingClassesAndStyles as __experimentalGetSpacingClassesAndStyles,
getGapCSSValue as __experimentalGetGapCSSValue,
+ getShadowClassesAndStyles as __experimentalGetShadowClassesAndStyles,
+ useShadowProps as __experimentalUseShadowProps,
useCachedTruthy,
} from './hooks';
export * from './components';
diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js
index b46e145d760ad5..a0994ce3f84b12 100644
--- a/packages/block-library/src/button/edit.js
+++ b/packages/block-library/src/button/edit.js
@@ -32,6 +32,7 @@ import {
__experimentalUseBorderProps as useBorderProps,
__experimentalUseColorProps as useColorProps,
__experimentalGetSpacingClassesAndStyles as useSpacingProps,
+ __experimentalUseShadowProps as useShadowProps,
__experimentalLinkControl as LinkControl,
__experimentalGetElementClassName,
store as blockEditorStore,
@@ -184,6 +185,7 @@ function ButtonEdit( props ) {
const borderProps = useBorderProps( attributes );
const colorProps = useColorProps( attributes );
const spacingProps = useSpacingProps( attributes );
+ const shadowProps = useShadowProps( attributes );
const ref = useRef();
const richTextRef = useRef();
const blockProps = useBlockProps( {
@@ -266,6 +268,7 @@ function ButtonEdit( props ) {
...borderProps.style,
...colorProps.style,
...spacingProps.style,
+ ...shadowProps.style,
} }
onSplit={ ( value ) =>
createBlock( 'core/button', {
diff --git a/packages/block-library/src/button/save.js b/packages/block-library/src/button/save.js
index e12936e8c92457..ba0fbd45f083c9 100644
--- a/packages/block-library/src/button/save.js
+++ b/packages/block-library/src/button/save.js
@@ -12,6 +12,7 @@ import {
__experimentalGetBorderClassesAndStyles as getBorderClassesAndStyles,
__experimentalGetColorClassesAndStyles as getColorClassesAndStyles,
__experimentalGetSpacingClassesAndStyles as getSpacingClassesAndStyles,
+ __experimentalGetShadowClassesAndStyles as getShadowClassesAndStyles,
__experimentalGetElementClassName,
} from '@wordpress/block-editor';
@@ -40,6 +41,7 @@ export default function save( { attributes, className } ) {
const borderProps = getBorderClassesAndStyles( attributes );
const colorProps = getColorClassesAndStyles( attributes );
const spacingProps = getSpacingClassesAndStyles( attributes );
+ const shadowProps = getShadowClassesAndStyles( attributes );
const buttonClasses = classnames(
'wp-block-button__link',
colorProps.className,
@@ -56,6 +58,7 @@ export default function save( { attributes, className } ) {
...borderProps.style,
...colorProps.style,
...spacingProps.style,
+ ...shadowProps.style,
};
// The use of a `title` attribute here is soft-deprecated, but still applied
diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 950d902a9502f7..3c5d91a6b68249 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -10,6 +10,7 @@
- `PaletteEdit` and `CircularOptionPicker`: improve unit tests ([#57809](https://github.com/WordPress/gutenberg/pull/57809)).
- `Tooltip`: no-op when nested inside other `Tooltip` components ([#57202](https://github.com/WordPress/gutenberg/pull/57202)).
- `Tooltip` and `Button`: tidy up unit tests ([#57975](https://github.com/WordPress/gutenberg/pull/57975)).
+- `SlotFill`: fix typo in use-slot-fills return docs ([#57654](https://github.com/WordPress/gutenberg/pull/57654))
### Bug Fix
diff --git a/packages/components/src/slot-fill/bubbles-virtually/use-slot-fills.ts b/packages/components/src/slot-fill/bubbles-virtually/use-slot-fills.ts
index 599f0bc5667711..0131bbfc434e59 100644
--- a/packages/components/src/slot-fill/bubbles-virtually/use-slot-fills.ts
+++ b/packages/components/src/slot-fill/bubbles-virtually/use-slot-fills.ts
@@ -19,6 +19,6 @@ export default function useSlotFills( name: SlotKey ) {
const fills = useSnapshot( registry.fills, { sync: true } );
// The important bit here is that this call ensures that the hook
// only causes a re-render if the "fills" of a given slot name
- // change change, not any fills.
+ // change, not any fills.
return fills.get( name );
}
diff --git a/schemas/json/block.json b/schemas/json/block.json
index fd69ea1badb339..9cc7a83c2304dd 100644
--- a/schemas/json/block.json
+++ b/schemas/json/block.json
@@ -543,6 +543,11 @@
}
}
},
+ "shadow": {
+ "type": "boolean",
+ "description": "Allow blocks to define a box shadow.",
+ "default": false
+ },
"typography": {
"type": "object",
"description": "This value signals that a block supports some of the CSS style properties related to typography. When it does, the block editor will show UI controls for the user to set their values if the theme declares support.\n\nWhen the block declares support for a specific typography property, its attributes definition is extended to include the style attribute.",