Skip to content

Commit

Permalink
Refactor the effects panel as a generic UI Styles component (#49571)
Browse files Browse the repository at this point in the history
  • Loading branch information
youknowriad authored Apr 5, 2023
1 parent 82ed8b7 commit 1da7ad3
Show file tree
Hide file tree
Showing 10 changed files with 332 additions and 226 deletions.
228 changes: 228 additions & 0 deletions packages/block-editor/src/components/global-styles/effects-panel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import {
__experimentalToolsPanel as ToolsPanel,
__experimentalToolsPanelItem as ToolsPanelItem,
__experimentalItemGroup as ItemGroup,
__experimentalHStack as HStack,
__experimentalVStack as VStack,
__experimentalGrid as Grid,
__experimentalHeading as Heading,
FlexItem,
Dropdown,
__experimentalDropdownContentWrapper as DropdownContentWrapper,
Button,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useCallback } from '@wordpress/element';
import { shadow as shadowIcon, Icon, check } from '@wordpress/icons';

/**
* Internal dependencies
*/
import { getValueFromVariable } from './utils';
import { immutableSet } from '../../utils/object';

export function useHasEffectsPanel( settings ) {
const hasShadowControl = useHasShadowControl( settings );
return hasShadowControl;
}

function useHasShadowControl( settings ) {
return !! settings?.shadow;
}

function EffectsToolsPanel( {
resetAllFilter,
onChange,
value,
panelId,
children,
} ) {
const resetAll = () => {
const updatedValue = resetAllFilter( value );
onChange( updatedValue );
};

return (
<ToolsPanel
label={ __( 'Effects' ) }
resetAll={ resetAll }
panelId={ panelId }
>
{ children }
</ToolsPanel>
);
}

const DEFAULT_CONTROLS = {
shadow: true,
};

export default function EffectsPanel( {
as: Wrapper = EffectsToolsPanel,
value,
onChange,
inheritedValue = value,
settings,
panelId,
defaultControls = DEFAULT_CONTROLS,
} ) {
const decodeValue = ( rawValue ) =>
getValueFromVariable( { settings }, '', rawValue );

// Shadow
const hasShadowEnabled = useHasShadowControl( settings );
const shadow = decodeValue( inheritedValue?.shadow );
const setShadow = ( newValue ) => {
onChange( immutableSet( value, [ 'shadow' ], newValue ) );
};
const hasShadow = () => !! value?.shadow;
const resetShadow = () => setShadow( undefined );

const resetAllFilter = useCallback( ( previousValue ) => {
return {
...previousValue,
shadow: undefined,
};
}, [] );

return (
<Wrapper
resetAllFilter={ resetAllFilter }
value={ value }
onChange={ onChange }
panelId={ panelId }
>
{ hasShadowEnabled && (
<ToolsPanelItem
label={ __( 'Shadow' ) }
hasValue={ hasShadow }
onDeselect={ resetShadow }
isShownByDefault={ defaultControls.shadow }
panelId={ panelId }
>
<ItemGroup isBordered isSeparated>
<ShadowPopover
shadow={ shadow }
onShadowChange={ setShadow }
settings={ settings }
/>
</ItemGroup>
</ToolsPanelItem>
) }
</Wrapper>
);
}

const ShadowPopover = ( { shadow, onShadowChange, settings } ) => {
const popoverProps = {
placement: 'left-start',
offset: 36,
shift: true,
};

return (
<Dropdown
popoverProps={ popoverProps }
className="block-editor-global-styles-effects-panel__shadow-dropdown"
renderToggle={ renderShadowToggle() }
renderContent={ () => (
<DropdownContentWrapper paddingSize="medium">
<ShadowPopoverContainer
shadow={ shadow }
onShadowChange={ onShadowChange }
settings={ settings }
/>
</DropdownContentWrapper>
) }
/>
);
};

function renderShadowToggle() {
return ( { onToggle, isOpen } ) => {
const toggleProps = {
onClick: onToggle,
className: classnames( { 'is-open': isOpen } ),
'aria-expanded': isOpen,
};

return (
<Button { ...toggleProps }>
<HStack justify="flex-start">
<Icon
className="block-editor-global-styles-effects-panel__toggle-icon"
icon={ shadowIcon }
size={ 24 }
/>
<FlexItem>{ __( 'Shadow' ) }</FlexItem>
</HStack>
</Button>
);
};
}

function ShadowPopoverContainer( { shadow, onShadowChange, settings } ) {
const defaultShadows = settings?.shadow?.presets?.default;
const themeShadows = settings?.shadow?.presets?.theme;
const defaultPresetsEnabled = settings?.shadow?.defaultPresets;

const shadows = [
...( defaultPresetsEnabled ? defaultShadows : [] ),
...( themeShadows || [] ),
];

return (
<div className="block-editor-global-styles-effects-panel__shadow-popover-container">
<VStack spacing={ 4 }>
<Heading level={ 5 }>{ __( 'Shadow' ) }</Heading>
<ShadowPresets
presets={ shadows }
activeShadow={ shadow }
onSelect={ onShadowChange }
/>
</VStack>
</div>
);
}

function ShadowPresets( { presets, activeShadow, onSelect } ) {
return ! presets ? null : (
<Grid columns={ 6 } gap={ 0 } align="center" justify="center">
{ presets.map( ( { name, slug, shadow } ) => (
<ShadowIndicator
key={ slug }
label={ name }
isActive={ shadow === activeShadow }
onSelect={ () =>
onSelect( shadow === activeShadow ? undefined : shadow )
}
shadow={ shadow }
/>
) ) }
</Grid>
);
}

function ShadowIndicator( { label, isActive, onSelect, shadow } ) {
return (
<div className="block-editor-global-styles-effects-panel__shadow-indicator-wrapper">
<Button
className="block-editor-global-styles-effects-panel__shadow-indicator"
onClick={ onSelect }
label={ label }
style={ { boxShadow: shadow } }
showTooltip
>
{ isActive && <Icon icon={ check } /> }
</Button>
</div>
);
}
4 changes: 4 additions & 0 deletions packages/block-editor/src/components/global-styles/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,10 @@ export function useSettingsForBlockElement(
}
} );

updatedSettings.shadow = supportedStyles.includes( 'shadow' )
? updatedSettings.shadow
: false;

return updatedSettings;
}, [ parentSettings, supportedStyles, supports ] );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export {
} from './dimensions-panel';
export { default as BorderPanel, useHasBorderPanel } from './border-panel';
export { default as ColorPanel, useHasColorPanel } from './color-panel';
export { default as EffectsPanel, useHasEffectsPanel } from './effects-panel';
42 changes: 42 additions & 0 deletions packages/block-editor/src/components/global-styles/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.block-editor-global-styles-effects-panel__toggle-icon {
fill: currentColor;
}

.block-editor-global-styles-effects-panel__shadow-popover-container {
width: 230px;
}

.block-editor-global-styles-effects-panel__shadow-dropdown {
display: block;
padding: 0;

> button {
width: 100%;
padding: $grid-unit-10;

&.is-open {
background-color: $gray-100;
}
}
}

// wrapper to clip the shadow beyond 6px
.block-editor-global-styles-effects-panel__shadow-indicator-wrapper {
padding: 6px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}

// These styles are similar to the color palette.
.block-editor-global-styles-effects-panel__shadow-indicator {
color: $gray-800;
border: $gray-200 $border-width solid;
border-radius: $radius-block-ui;
cursor: pointer;
padding: 0;

height: 24px;
width: 24px;
}
1 change: 1 addition & 0 deletions packages/block-editor/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
@import "./components/date-format-picker/style.scss";
@import "./components/duotone-control/style.scss";
@import "./components/font-appearance-control/style.scss";
@import "./components/global-styles/style.scss";
@import "./components/height-control/style.scss";
@import "./components/image-size-control/style.scss";
@import "./components/inserter-list-item/style.scss";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ import { useHasVariationsPanel } from './variations-panel';
import { NavigationButtonAsItem } from './navigation-button';
import { IconWithCurrentColor } from './icon-with-current-color';
import { ScreenVariations } from './screen-variations';
import { useHasShadowControl } from './shadow-panel';
import { unlock } from '../../private-apis';

const {
useHasDimensionsPanel,
useHasTypographyPanel,
useHasBorderPanel,
useHasColorPanel,
useHasEffectsPanel,
useGlobalSetting,
useSettingsForBlockElement,
} = unlock( blockEditorPrivateApis );
Expand All @@ -50,7 +50,7 @@ function ContextMenu( { name, parentMenu = '' } ) {
const hasTypographyPanel = useHasTypographyPanel( settings );
const hasColorPanel = useHasColorPanel( settings );
const hasBorderPanel = useHasBorderPanel( settings );
const hasEffectsPanel = useHasShadowControl( name );
const hasEffectsPanel = useHasEffectsPanel( settings );
const hasFilterPanel = useHasFilterPanel( name );
const hasDimensionsPanel = useHasDimensionsPanel( settings );
const hasLayoutPanel = hasDimensionsPanel;
Expand Down Expand Up @@ -109,9 +109,9 @@ function ContextMenu( { name, parentMenu = '' } ) {
<NavigationButtonAsItem
icon={ shadow }
path={ parentMenu + '/effects' }
aria-label={ __( 'Shadow' ) }
aria-label={ __( 'Effects' ) }
>
{ __( 'Shadow' ) }
{ __( 'Effects' ) }
</NavigationButtonAsItem>
) }
{ hasFilterPanel && (
Expand Down
40 changes: 40 additions & 0 deletions packages/edit-site/src/components/global-styles/effects-panel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* WordPress dependencies
*/
import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import { unlock } from '../../private-apis';

const {
useGlobalSetting,
useGlobalStyle,
EffectsPanel: StylesEffectsPanel,
useSettingsForBlockElement,
} = unlock( blockEditorPrivateApis );

export default function EffectsPanel( { name, variation = '' } ) {
let prefixParts = [];
if ( variation ) {
prefixParts = [ 'variations', variation ].concat( prefixParts );
}
const prefix = prefixParts.join( '.' );

const [ style ] = useGlobalStyle( prefix, name, 'user', false );
const [ inheritedStyle, setStyle ] = useGlobalStyle( prefix, name, 'all', {
shouldDecodeEncode: false,
} );
const [ rawSettings ] = useGlobalSetting( '', name );
const settings = useSettingsForBlockElement( rawSettings, name );

return (
<StylesEffectsPanel
inheritedValue={ inheritedStyle }
value={ style }
onChange={ setStyle }
settings={ settings }
/>
);
}
Loading

1 comment on commit 1da7ad3

@github-actions
Copy link

Choose a reason for hiding this comment

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

Flaky tests detected in 1da7ad3.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4616720622
📝 Reported issues:

Please sign in to comment.