From e1098eaa340161f368109071a2231fe3dd9b98cf Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Wed, 20 Dec 2023 17:51:42 +1000 Subject: [PATCH 1/5] Allow access to the Global Styles data in Post Editor --- lib/block-editor-settings.php | 1 + .../class-wp-rest-block-editor-settings-controller.php | 2 +- .../editor/src/components/provider/use-block-editor-settings.js | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/block-editor-settings.php b/lib/block-editor-settings.php index 53668e114e04c..ba726ffe2ad5b 100644 --- a/lib/block-editor-settings.php +++ b/lib/block-editor-settings.php @@ -78,6 +78,7 @@ function gutenberg_get_block_editor_settings( $settings ) { $settings['styles'] = array_merge( $global_styles, get_block_editor_theme_styles() ); + $settings['__experimentalStyles'] = gutenberg_get_global_styles(); $settings['__experimentalFeatures'] = gutenberg_get_global_settings(); // These settings may need to be updated based on data coming from theme.json sources. if ( isset( $settings['__experimentalFeatures']['color']['palette'] ) ) { diff --git a/lib/experimental/class-wp-rest-block-editor-settings-controller.php b/lib/experimental/class-wp-rest-block-editor-settings-controller.php index 510ae573e3de8..ae6c485216670 100644 --- a/lib/experimental/class-wp-rest-block-editor-settings-controller.php +++ b/lib/experimental/class-wp-rest-block-editor-settings-controller.php @@ -157,7 +157,7 @@ public function get_item_schema() { '__experimentalStyles' => array( 'description' => __( 'Styles consolidated from core, theme, and user origins.', 'gutenberg' ), 'type' => 'object', - 'context' => array( 'mobile' ), + 'context' => array( 'post-editor', 'site-editor', 'widgets-editor', 'mobile' ), ), '__experimentalEnableQuoteBlockV2' => array( diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index eddc295766f8c..90f2e512fada6 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -25,6 +25,7 @@ const BLOCK_EDITOR_SETTINGS = [ '__experimentalBlockDirectory', '__experimentalDiscussionSettings', '__experimentalFeatures', + '__experimentalStyles', '__experimentalGlobalStylesBaseStyles', '__experimentalPreferredStyleVariations', '__unstableGalleryWithImageBlocks', From d33c5a1456df7bca0700460c56d8671414e08142 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Thu, 21 Dec 2023 16:21:43 +1000 Subject: [PATCH 2/5] Add CustomSelect and CustomSelectItem to private apis --- packages/components/src/private-apis.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/components/src/private-apis.ts b/packages/components/src/private-apis.ts index 6694c1d30bdce..6eb019f0f7c3e 100644 --- a/packages/components/src/private-apis.ts +++ b/packages/components/src/private-apis.ts @@ -14,6 +14,7 @@ import { useCompositeStore as useCompositeStoreV2, } from './composite/v2'; import { default as CustomSelectControl } from './custom-select-control'; +import { CustomSelect, CustomSelectItem } from './custom-select-control-v2'; import { positionToPlacement as __experimentalPopoverLegacyPositionToPlacement } from './popover/utils'; import { default as ProgressBar } from './progress-bar'; import { createPrivateSlotFill } from './slot-fill'; @@ -41,6 +42,8 @@ lock( privateApis, { CompositeRowV2, useCompositeStoreV2, CustomSelectControl, + CustomSelect, + CustomSelectItem, __experimentalPopoverLegacyPositionToPlacement, createPrivateSlotFill, ComponentsContext, From 5f09948f5048fcdbbf05068a9ff18add3c006e36 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 22 Dec 2023 11:59:36 +1000 Subject: [PATCH 3/5] Extend v2 CustomSelect We need a means of ensuring that the select popover has sufficient z-index to render above controls below it in the inspector. Additionally, we want to be able to avoid visually rendering the select's label. --- .../src/custom-select-control-v2/index.tsx | 22 +++++++++++++++---- .../src/custom-select-control-v2/styles.ts | 2 ++ .../src/custom-select-control-v2/types.ts | 10 +++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/packages/components/src/custom-select-control-v2/index.tsx b/packages/components/src/custom-select-control-v2/index.tsx index 614f52105513f..6bc38db3080bb 100644 --- a/packages/components/src/custom-select-control-v2/index.tsx +++ b/packages/components/src/custom-select-control-v2/index.tsx @@ -19,6 +19,7 @@ import type { CustomSelectContext as CustomSelectContextType, } from './types'; import type { WordPressComponentProps } from '../context'; +import { VisuallyHidden } from '../visually-hidden'; export const CustomSelectContext = createContext< CustomSelectContextType >( undefined ); @@ -45,11 +46,13 @@ function defaultRenderSelectedValue( value: CustomSelectProps[ 'value' ] ) { export function CustomSelect( { children, defaultValue, + hideLabelFromVision = false, label, onChange, size = 'default', value, renderSelectedValue = defaultRenderSelectedValue, + popoverProps, ...props }: WordPressComponentProps< CustomSelectProps, 'button', false > ) { const store = Ariakit.useSelectStore( { @@ -59,12 +62,23 @@ export function CustomSelect( { } ); const { value: currentValue } = store.useState(); + const selectPopoverProps = { + gutter: 12, + sameWidth: true, + ...popoverProps, + store, + }; return ( <> - - { label } - + { hideLabelFromVision && ( + { label } + ) } + { ! hideLabelFromVision && ( + + { label } + + ) } - + { children } diff --git a/packages/components/src/custom-select-control-v2/styles.ts b/packages/components/src/custom-select-control-v2/styles.ts index c04f6ac32e5ff..43bd224bb2bb9 100644 --- a/packages/components/src/custom-select-control-v2/styles.ts +++ b/packages/components/src/custom-select-control-v2/styles.ts @@ -63,6 +63,8 @@ export const CustomSelectPopover = styled( Ariakit.SelectPopover )` border-radius: ${ space( 0.5 ) }; background: ${ COLORS.white }; border: 1px solid ${ COLORS.gray[ 900 ] }; + /* Force the passed wrapper props z-index otherwise it's overridden. */ + z-index: ${ ( props ) => props.wrapperProps?.style?.zIndex }; `; export const CustomSelectItem = styled( Ariakit.SelectItem )` diff --git a/packages/components/src/custom-select-control-v2/types.ts b/packages/components/src/custom-select-control-v2/types.ts index 2aecc1d4746f5..49a9105cf54f0 100644 --- a/packages/components/src/custom-select-control-v2/types.ts +++ b/packages/components/src/custom-select-control-v2/types.ts @@ -23,6 +23,12 @@ export type CustomSelectProps = { * non-disabled item will be used. */ defaultValue?: string | string[]; + /** + * If true, the label will only be visible to screen readers. + * + * @default false + */ + hideLabelFromVision?: boolean; /** * Label for the control. */ @@ -31,6 +37,10 @@ export type CustomSelectProps = { * A function that receives the new value of the input. */ onChange?: ( newValue: string | string[] ) => void; + /** + * Optional props passed to the Select Popover. + */ + popoverProps?: Ariakit.SelectPopoverProps; /** * Can be used to render select UI with custom styled values. */ From ee04112df0e9dd5819f591115d3d79d76ef14a69 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 22 Dec 2023 12:01:34 +1000 Subject: [PATCH 4/5] Update BlockStyles control --- .../src/components/block-styles/index.js | 136 +++++++++++------- .../src/components/block-styles/style.scss | 52 +------ .../block-styles/use-styles-for-block.js | 19 ++- 3 files changed, 105 insertions(+), 102 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index a9fdbe94356ef..b9d53a3fc2bac 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -1,28 +1,50 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - /** * WordPress dependencies */ -import { useState } from '@wordpress/element'; -import { debounce, useViewportMatch } from '@wordpress/compose'; import { - Button, - __experimentalTruncate as Truncate, + ColorIndicator, + Flex, + FlexItem, Popover, + privateApis as componentsPrivateApis, + __experimentalHStack as HStack, + __experimentalZStack as ZStack, } from '@wordpress/components'; +import { debounce, useViewportMatch } from '@wordpress/compose'; +import { useState } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ +import { unlock } from '../../lock-unlock'; import BlockStylesPreviewPanel from './preview-panel'; import useStylesForBlocks from './use-styles-for-block'; +import { getDefaultStyle } from './utils'; const noop = () => {}; +const { CustomSelect, CustomSelectItem } = unlock( componentsPrivateApis ); + +const BlockStyleItem = ( { blockStyle } ) => { + const indicators = [ + blockStyle.styles?.color?.background, + blockStyle.styles?.color?.text, + ]; + + return ( + + + { indicators.map( ( indicator, index ) => ( + + + + ) ) } + + { blockStyle.label } + + ); +}; -// Block Styles component for the Settings Sidebar. function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop } ) { const { onSelect, @@ -30,10 +52,8 @@ function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop } ) { activeStyle, genericPreviewBlock, className: previewClassName, - } = useStylesForBlocks( { - clientId, - onSwitch, - } ); + } = useStylesForBlocks( { clientId, onSwitch } ); + const [ hoveredStyle, setHoveredStyle ] = useState( null ); const isMobileViewport = useViewportMatch( 'medium', '<' ); @@ -43,58 +63,64 @@ function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop } ) { const debouncedSetHoveredStyle = debounce( setHoveredStyle, 250 ); - const onSelectStylePreview = ( style ) => { - onSelect( style ); + const handleOnChange = ( style ) => { + onSelect( { name: style } ); onHoverClassName( null ); setHoveredStyle( null ); debouncedSetHoveredStyle.cancel(); }; - const styleItemHandler = ( item ) => { - if ( hoveredStyle === item ) { + const hoverStyleHandler = ( style ) => { + if ( hoveredStyle === style ) { debouncedSetHoveredStyle.cancel(); return; } - debouncedSetHoveredStyle( item ); - onHoverClassName( item?.name ?? null ); + + debouncedSetHoveredStyle( style ); + onHoverClassName( style?.name ?? null ); + }; + + const renderSelectedBlockStlye = ( currentStyle ) => { + const currentBlockStyle = stylesToRender.find( + ( style ) => style.name === currentStyle + ); + + if ( ! currentBlockStyle ) { + return null; + } + + return ; }; + const defaultStyle = getDefaultStyle( stylesToRender ); + return (
-
- { stylesToRender.map( ( style ) => { - const buttonText = style.label || style.name; - - return ( - - ); - } ) } -
+ + { stylesToRender.map( ( blockStyle, index ) => ( + hoverStyleHandler( blockStyle ) } + onMouseLeave={ () => hoverStyleHandler( null ) } + onFocus={ () => hoverStyleHandler( blockStyle ) } + onBlur={ () => hoverStyleHandler( null ) } + > + + + ) ) } + { hoveredStyle && ! isMobileViewport && (
styleItemHandler( null ) } + onMouseLeave={ () => hoverStyleHandler( null ) } >