From 098b54b04bd8dd45bd1875b9d1ca234693967e31 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Wed, 1 Sep 2021 11:51:26 +1000 Subject: [PATCH 01/20] Initial commit --- .../block-styles-preview-panel.js | 47 ++++++++ .../src/components/block-styles/index.js | 107 +++++++++++++----- .../src/components/block-styles/style.scss | 66 ++++++++++- 3 files changed, 187 insertions(+), 33 deletions(-) create mode 100644 packages/block-editor/src/components/block-styles/block-styles-preview-panel.js diff --git a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js new file mode 100644 index 00000000000000..280559c9b412b5 --- /dev/null +++ b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js @@ -0,0 +1,47 @@ +/** + * WordPress dependencies + */ +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import BlockPreview from '../block-preview'; +import { getActiveStyle, replaceActiveStyle } from './utils'; + +export default function BlockStylesPreviewPanel( { + genericPreviewBlock, + viewportWidth, + style, + className, + activeStyle, +} ) { + const styleClassName = replaceActiveStyle( + className, + activeStyle, + style + ); + const previewBlocks = useMemo( () => { + return { + ...genericPreviewBlock, + attributes: { + ...genericPreviewBlock.attributes, + className: styleClassName + ' block-editor-block-styles__block-preview-container', + }, + }; + }, [ genericPreviewBlock, styleClassName ] ); + + return ( +
+
+ +
+
+ { style.label || style.name } +
+
+ ); +} diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index 107b971c439f62..0eb12fdfe6b201 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -7,7 +7,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useMemo } from '@wordpress/element'; +import {useCallback, useMemo, useState} from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; import { ENTER, SPACE } from '@wordpress/keycodes'; import { _x } from '@wordpress/i18n'; @@ -17,12 +17,13 @@ import { getBlockFromExample, store as blocksStore, } from '@wordpress/blocks'; - +import { Button, Popover} from '@wordpress/components'; /** * Internal dependencies */ import { getActiveStyle, replaceActiveStyle } from './utils'; import BlockPreview from '../block-preview'; +import BlockStylesPreviewPanel from './block-styles-preview-panel'; import { store as blockEditorStore } from '../../store'; const EMPTY_OBJECT = {}; @@ -75,6 +76,13 @@ function BlockStyles( { const { updateBlockAttributes } = useDispatch( blockEditorStore ); const genericPreviewBlock = useGenericPreviewBlock( block, type ); + const [ hoveredStyle, setHoveredStyle ] = useState( null ); + const onStyleHover = useCallback( + ( item ) => { + setHoveredStyle( item ); + }, + [ setHoveredStyle ] + ); if ( ! styles || styles.length === 0 ) { return null; @@ -91,37 +99,82 @@ function BlockStyles( { ...styles, ]; + /* TODO + - get top offset of styles panel + - create a portal into the Editor content container `interface-interface-skeleton__content` or the block-editor__container + - inject the preview and assign right:0 + + */ const activeStyle = getActiveStyle( renderedStyles, className ); return (
- { renderedStyles.map( ( style ) => { - const styleClassName = replaceActiveStyle( - className, - activeStyle, - style - ); - return ( - + { renderedStyles.map( ( style ) => { + const styleClassName = replaceActiveStyle( + className, + activeStyle, + style + ); + const buttonText = style.label || style.name; + + return ( + + // { + // updateBlockAttributes( clientId, { + // className: styleClassName, + // } ); + // onHoverClassName( null ); + // onSwitch(); + // } } + // onBlur={ () => onHoverClassName( null ) } + // onHover={ () => { + // onHoverClassName( styleClassName ); + // } } + // style={ style } + // styleClassName={ styleClassName } + // itemRole={ itemRole } + // /> + ); + } ) } +
+ { hoveredStyle && ( + + { - updateBlockAttributes( clientId, { - className: styleClassName, - } ); - onHoverClassName( null ); - onSwitch(); - } } - onBlur={ () => onHoverClassName( null ) } - onHover={ () => onHoverClassName( styleClassName ) } - style={ style } - styleClassName={ styleClassName } - itemRole={ itemRole } /> - ); - } ) } + + ) } ); } diff --git a/packages/block-editor/src/components/block-styles/style.scss b/packages/block-editor/src/components/block-styles/style.scss index 90d810d9f37540..cca3dc6670daa3 100644 --- a/packages/block-editor/src/components/block-styles/style.scss +++ b/packages/block-editor/src/components/block-styles/style.scss @@ -1,9 +1,3 @@ -.block-editor-block-styles { - display: flex; - flex-wrap: wrap; - justify-content: space-between; -} - .block-editor-block-styles__item { width: calc(50% - #{ $grid-unit-05 }); margin: $grid-unit-05 0; @@ -42,6 +36,66 @@ } } +// Block style previews +.block-editor-block-styles__popover { + width: 300px; +} + +// Applied to block containers to make them stretch the width of the preview pane. +.block-editor-block-styles__block-preview-container { + +} + +.block-editor-block-styles__preview-container { + display: none; + width: 300px; + background: $white; + border-radius: $radius-block-ui; + border: $border-width solid $gray-300; + max-height: calc(100% - #{$grid-unit-40}); + overflow-y: hidden; + @include break-medium { + display: block; + } +} + +.block-editor-block-styles__preview-content { + min-height: $grid-unit-60 * 3; + background: $gray-100; + display: grid; + flex-grow: 1; + align-items: center; +} + +.block-editor-block-styles__preview-panel-label { + font-weight: bold; + color: $gray-900; + padding: 8px 0 8px 10px +} + +.block-editor-block-styles__variants { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin-bottom: $grid-unit-20; + + .block-editor-block-styles__button { + color: $gray-700; + box-shadow: inset 0 0 0 1px $gray-700; + display: inline-block; + min-width: calc(50% - #{$grid-unit-05}); + margin-bottom: $grid-unit-10; + + &.is-active, + &:focus, + &:hover:not( :disabled ) { + color: $gray-900; + box-shadow: inset 0 0 0 2px $gray-900; + font-weight: bold; + } + } +} + // Show a little preview thumbnail for style variations. .block-editor-block-styles__item-preview { outline: $border-width solid transparent; // Shown in Windows High Contrast mode. From 6fb45f348e574e5e1a0340906a6d446320909c27 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Tue, 14 Sep 2021 15:23:30 +1000 Subject: [PATCH 02/20] Tweaking text and hover colours Removing commented out code Consolidating handlers --- .../src/components/block-styles/index.js | 135 +++++------------- .../src/components/block-styles/style.scss | 29 ++-- 2 files changed, 50 insertions(+), 114 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index 0eb12fdfe6b201..75a1608e2a4a9b 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -7,7 +7,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import {useCallback, useMemo, useState} from '@wordpress/element'; +import { useCallback, useMemo, useState } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; import { ENTER, SPACE } from '@wordpress/keycodes'; import { _x } from '@wordpress/i18n'; @@ -17,12 +17,11 @@ import { getBlockFromExample, store as blocksStore, } from '@wordpress/blocks'; -import { Button, Popover} from '@wordpress/components'; +import { Button, Popover } from '@wordpress/components'; /** * Internal dependencies */ import { getActiveStyle, replaceActiveStyle } from './utils'; -import BlockPreview from '../block-preview'; import BlockStylesPreviewPanel from './block-styles-preview-panel'; import { store as blockEditorStore } from '../../store'; @@ -98,65 +97,56 @@ function BlockStyles( { }, ...styles, ]; + const activeStyle = getActiveStyle( renderedStyles, className ); - /* TODO - - get top offset of styles panel - - create a portal into the Editor content container `interface-interface-skeleton__content` or the block-editor__container - - inject the preview and assign right:0 + const onSelectStyle = ( style ) => { + const styleClassName = replaceActiveStyle( + className, + activeStyle, + style + ); + updateBlockAttributes( clientId, { + className: styleClassName, + } ); + onHoverClassName( null ); + setHoveredStyle( null ); + onSwitch(); + }; - */ - const activeStyle = getActiveStyle( renderedStyles, className ); return (
{ renderedStyles.map( ( style ) => { - const styleClassName = replaceActiveStyle( - className, - activeStyle, - style - ); const buttonText = style.label || style.name; return ( - // { - // updateBlockAttributes( clientId, { - // className: styleClassName, - // } ); - // onHoverClassName( null ); - // onSwitch(); - // } } - // onBlur={ () => onHoverClassName( null ) } - // onHover={ () => { - // onHoverClassName( styleClassName ); - // } } - // style={ style } - // styleClassName={ styleClassName } - // itemRole={ itemRole } - // /> + onClick={ () => onSelectStyle( style ) } + role={ itemRole || 'button' } + tabIndex="0" + > + { buttonText } + ); } ) }
@@ -179,57 +169,4 @@ function BlockStyles( { ); } -function BlockStyleItem( { - genericPreviewBlock, - viewportWidth, - style, - isActive, - onBlur, - onHover, - onSelect, - styleClassName, - itemRole, -} ) { - const previewBlocks = useMemo( () => { - return { - ...genericPreviewBlock, - attributes: { - ...genericPreviewBlock.attributes, - className: styleClassName, - }, - }; - }, [ genericPreviewBlock, styleClassName ] ); - - return ( -
onSelect() } - onKeyDown={ ( event ) => { - if ( ENTER === event.keyCode || SPACE === event.keyCode ) { - event.preventDefault(); - onSelect(); - } - } } - onMouseEnter={ onHover } - onMouseLeave={ onBlur } - role={ itemRole || 'button' } - tabIndex="0" - aria-label={ style.label || style.name } - > -
- -
-
- { style.label || style.name } -
-
- ); -} - export default BlockStyles; diff --git a/packages/block-editor/src/components/block-styles/style.scss b/packages/block-editor/src/components/block-styles/style.scss index cca3dc6670daa3..8fa82fa5538c4f 100644 --- a/packages/block-editor/src/components/block-styles/style.scss +++ b/packages/block-editor/src/components/block-styles/style.scss @@ -48,7 +48,7 @@ .block-editor-block-styles__preview-container { display: none; - width: 300px; + min-width: 300px; background: $white; border-radius: $radius-block-ui; border: $border-width solid $gray-300; @@ -70,7 +70,7 @@ .block-editor-block-styles__preview-panel-label { font-weight: bold; color: $gray-900; - padding: 8px 0 8px 10px + padding: 8px 0 8px 10px; } .block-editor-block-styles__variants { @@ -80,19 +80,18 @@ margin-bottom: $grid-unit-20; .block-editor-block-styles__button { - color: $gray-700; - box-shadow: inset 0 0 0 1px $gray-700; - display: inline-block; - min-width: calc(50% - #{$grid-unit-05}); - margin-bottom: $grid-unit-10; - - &.is-active, - &:focus, - &:hover:not( :disabled ) { - color: $gray-900; - box-shadow: inset 0 0 0 2px $gray-900; - font-weight: bold; - } + color: $gray-800; + box-shadow: inset 0 0 0 1px $gray-400; + display: inline-block; + min-width: calc(50% - #{$grid-unit-05}); + margin-bottom: $grid-unit-10; + + &.is-active, + &:focus, + &:hover:not(:disabled) { + color: $gray-900; + box-shadow: inset 0 0 0 1px $gray-900; + } } } From 04e7ac11bc01c827b1fbf4949d9028e54615c13f Mon Sep 17 00:00:00 2001 From: ramonjd Date: Tue, 14 Sep 2021 15:54:38 +1000 Subject: [PATCH 03/20] Adding container ref to try to position the popover --- .../block-editor/src/components/block-styles/index.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index 75a1608e2a4a9b..d3170d3937171e 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -7,7 +7,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useCallback, useMemo, useState } from '@wordpress/element'; +import { useCallback, useMemo, useRef, useState } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; import { ENTER, SPACE } from '@wordpress/keycodes'; import { _x } from '@wordpress/i18n'; @@ -83,6 +83,8 @@ function BlockStyles( { [ setHoveredStyle ] ); + const stylesContainerRef = useRef(); + if ( ! styles || styles.length === 0 ) { return null; } @@ -113,8 +115,11 @@ function BlockStyles( { onSwitch(); }; + // const getAnchorRect = () => + // stylesContainerRef?.current?.getBoundingClientRect(); + return ( -
+
{ renderedStyles.map( ( style ) => { const buttonText = style.label || style.name; @@ -155,6 +160,8 @@ function BlockStyles( { className="block-editor-block-styles__popover" position="middle left" focusOnMount={ false } + anchorRef={ stylesContainerRef?.current } + //getAnchorRect={ getAnchorRect } > Date: Thu, 16 Sep 2021 22:22:49 +1000 Subject: [PATCH 04/20] Experimenting with removing the default style picker select dropdown with a button click, based on the active style Updating block supports readme to remove references to the select dropdown Refactoring DefaultStylePicker Replacing the transform menu style switcher with a menu --- .../block-api/block-supports.md | 2 +- .../src/components/block-inspector/index.js | 2 +- .../block-styles-preview-panel.js | 13 ++- .../src/components/block-styles/index.js | 45 +++++++--- .../src/components/block-styles/style.scss | 17 ++-- .../components/default-style-picker/index.js | 90 +++++++++++++------ .../default-style-picker/style.scss | 9 ++ packages/block-editor/src/style.scss | 1 + 8 files changed, 122 insertions(+), 57 deletions(-) create mode 100644 packages/block-editor/src/components/default-style-picker/style.scss diff --git a/docs/reference-guides/block-api/block-supports.md b/docs/reference-guides/block-api/block-supports.md index 485b5b165e70be..cbad8789e464dd 100644 --- a/docs/reference-guides/block-api/block-supports.md +++ b/docs/reference-guides/block-api/block-supports.md @@ -415,7 +415,7 @@ supports: { - Type: `boolean` - Default value: `true` -When the style picker is shown, a dropdown is displayed so the user can select a default style for this block type. If you prefer not to show the dropdown, set this property to `false`. +When the style picker is shown, the user can set a default style for a block type based on the block's currently active style. If you prefer not to make this option available, set this property to `false`. ```js supports: { diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js index b7f85f4e5084e1..a2945babcb5a73 100644 --- a/packages/block-editor/src/components/block-inspector/index.js +++ b/packages/block-editor/src/components/block-inspector/index.js @@ -124,7 +124,7 @@ const BlockInspectorSingleBlock = ( { blockName, 'defaultStylePicker', true - ) && } + ) && }
) } diff --git a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js index 280559c9b412b5..02074a06359f31 100644 --- a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js +++ b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js @@ -7,7 +7,7 @@ import { useMemo } from '@wordpress/element'; * Internal dependencies */ import BlockPreview from '../block-preview'; -import { getActiveStyle, replaceActiveStyle } from './utils'; +import { replaceActiveStyle } from './utils'; export default function BlockStylesPreviewPanel( { genericPreviewBlock, @@ -16,21 +16,20 @@ export default function BlockStylesPreviewPanel( { className, activeStyle, } ) { - const styleClassName = replaceActiveStyle( - className, - activeStyle, - style - ); + const styleClassName = replaceActiveStyle( className, activeStyle, style ); const previewBlocks = useMemo( () => { return { ...genericPreviewBlock, attributes: { ...genericPreviewBlock.attributes, - className: styleClassName + ' block-editor-block-styles__block-preview-container', + className: + styleClassName + + ' block-editor-block-styles__block-preview-container', }, }; }, [ genericPreviewBlock, styleClassName ] ); + // TODO: look at packages/block-editor/src/components/block-switcher/preview-block-popover.js return (
diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index d3170d3937171e..5e359c7a074aed 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -7,7 +7,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useCallback, useMemo, useRef, useState } from '@wordpress/element'; +import { useCallback, useMemo, useState } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; import { ENTER, SPACE } from '@wordpress/keycodes'; import { _x } from '@wordpress/i18n'; @@ -17,7 +17,9 @@ import { getBlockFromExample, store as blocksStore, } from '@wordpress/blocks'; -import { Button, Popover } from '@wordpress/components'; +import { Button, MenuItem, Popover } from '@wordpress/components'; +import { check } from '@wordpress/icons'; + /** * Internal dependencies */ @@ -61,6 +63,7 @@ function BlockStyles( { const blockType = getBlockType( block.name ); const { getBlockStyles } = select( blocksStore ); + return { block, type: blockType, @@ -78,13 +81,14 @@ function BlockStyles( { const [ hoveredStyle, setHoveredStyle ] = useState( null ); const onStyleHover = useCallback( ( item ) => { + if ( hoveredStyle === item ) { + return; + } setHoveredStyle( item ); }, [ setHoveredStyle ] ); - const stylesContainerRef = useRef(); - if ( ! styles || styles.length === 0 ) { return null; } @@ -115,11 +119,29 @@ function BlockStyles( { onSwitch(); }; - // const getAnchorRect = () => - // stylesContainerRef?.current?.getBoundingClientRect(); + if ( itemRole === 'menuitem' ) { + return ( +
+ { renderedStyles.map( ( style ) => { + const menuItemText = style.label || style.name; + return ( + onSelectStyle( style ) } + > + { menuItemText } + + ); + } ) } +
+ ); + } return ( -
+
{ renderedStyles.map( ( style ) => { const buttonText = style.label || style.name; @@ -129,14 +151,17 @@ function BlockStyles( { className={ classnames( 'block-editor-block-styles__button', { - 'is-active': activeStyle === style, + 'is-active': + activeStyle.name === style.name, } ) } key={ style.name } variant="secondary" label={ buttonText } onMouseEnter={ () => onStyleHover( style ) } + onFocus={ () => onStyleHover( style ) } onMouseLeave={ () => setHoveredStyle( null ) } + onBlur={ () => setHoveredStyle( null ) } onKeyDown={ ( event ) => { if ( ENTER === event.keyCode || @@ -147,7 +172,7 @@ function BlockStyles( { } } } onClick={ () => onSelectStyle( style ) } - role={ itemRole || 'button' } + role="button" tabIndex="0" > { buttonText } @@ -160,8 +185,6 @@ function BlockStyles( { className="block-editor-block-styles__popover" position="middle left" focusOnMount={ false } - anchorRef={ stylesContainerRef?.current } - //getAnchorRect={ getAnchorRect } > { - const settings = select( blockEditorStore ).getSettings(); + const { getBlock, getSettings } = select( blockEditorStore ); + const block = getBlock( clientId ); + const settings = getSettings(); const preferredStyleVariations = settings.__experimentalPreferredStyleVariations; + const blockStyles = select( blocksStore ).getBlockStyles( + block.name + ); + const onUpdate = preferredStyleVariations?.onChange + ? ( blockStyle ) => + preferredStyleVariations?.onChange( + block.name, + blockStyle + ) + : null; + return { - preferredStyle: preferredStyleVariations?.value?.[ blockName ], - onUpdatePreferredStyleVariations: - preferredStyleVariations?.onChange ?? null, - styles: select( blocksStore ).getBlockStyles( blockName ), + preferredStyle: preferredStyleVariations?.value?.[ block.name ], + onUpdatePreferredStyleVariations: onUpdate, + styles: blockStyles, + blockName: block.name, + activeStyle: getActiveStyle( + blockStyles, + block.attributes.className || '' + ), }; }, - [ blockName ] - ); - const selectOptions = useMemo( - () => [ - { label: __( 'Not set' ), value: '' }, - ...styles.map( ( { label, name } ) => ( { label, value: name } ) ), - ], - [ styles ] - ); - const selectOnChange = useCallback( - ( blockStyle ) => { - onUpdatePreferredStyleVariations( blockName, blockStyle ); - }, - [ blockName, onUpdatePreferredStyleVariations ] + [ clientId ] ); + const selectOnChange = useCallback( () => { + onUpdatePreferredStyleVariations( activeStyle.name ); + }, [ activeStyle.name, onUpdatePreferredStyleVariations ] ); + + const preferredStyleLabel = useMemo( () => { + const preferredStyleObject = styles.find( + ( style ) => style.name === preferredStyle + ); + return preferredStyleObject?.label || preferredStyleObject?.name; + }, [ preferredStyle ] ); return ( onUpdatePreferredStyleVariations && ( - +
+
+ { __( 'Default style:' ) } + + { preferredStyleLabel } + +
+ { preferredStyle !== activeStyle.name && ( + + ) } +
) ); } diff --git a/packages/block-editor/src/components/default-style-picker/style.scss b/packages/block-editor/src/components/default-style-picker/style.scss new file mode 100644 index 00000000000000..1e1e7c41fa4303 --- /dev/null +++ b/packages/block-editor/src/components/default-style-picker/style.scss @@ -0,0 +1,9 @@ +.default-style-picker__current-default { + margin-bottom: $grid-unit-05; +} + +.default-style-picker__style-label { + font-weight: 600; + display: inline-block; + margin-left: $grid-unit-05; +} diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss index de72069bcde141..a7a27aa77410c2 100644 --- a/packages/block-editor/src/style.scss +++ b/packages/block-editor/src/style.scss @@ -30,6 +30,7 @@ @import "./components/colors-gradients/style.scss"; @import "./components/contrast-checker/style.scss"; @import "./components/default-block-appender/style.scss"; +@import "./components/default-style-picker/style.scss"; @import "./components/duotone-control/style.scss"; @import "./components/font-appearance-control/style.scss"; @import "./components/justify-content-control/style.scss"; From caf01b9d5cc33e946d9c1043b9b33cbadaef7361 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 17 Sep 2021 11:55:01 +1000 Subject: [PATCH 05/20] Abstract renderedStyles, which adds a default to the array for user selection on the frontend. --- .../src/components/block-styles/index.js | 17 +++-------- .../src/components/block-styles/utils.js | 28 +++++++++++++++++++ .../components/default-style-picker/index.js | 17 +++++++---- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index 5e359c7a074aed..3da3b44939b1d6 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { find, noop } from 'lodash'; +import { noop } from 'lodash'; import classnames from 'classnames'; /** @@ -10,7 +10,6 @@ import classnames from 'classnames'; import { useCallback, useMemo, useState } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; import { ENTER, SPACE } from '@wordpress/keycodes'; -import { _x } from '@wordpress/i18n'; import { getBlockType, cloneBlock, @@ -23,7 +22,7 @@ import { check } from '@wordpress/icons'; /** * Internal dependencies */ -import { getActiveStyle, replaceActiveStyle } from './utils'; +import { getActiveStyle, getRenderedStyles, replaceActiveStyle } from './utils'; import BlockStylesPreviewPanel from './block-styles-preview-panel'; import { store as blockEditorStore } from '../../store'; @@ -93,16 +92,8 @@ function BlockStyles( { return null; } - const renderedStyles = find( styles, 'isDefault' ) - ? styles - : [ - { - name: 'default', - label: _x( 'Default', 'block style' ), - isDefault: true, - }, - ...styles, - ]; + const renderedStyles = getRenderedStyles( styles ); + const activeStyle = getActiveStyle( renderedStyles, className ); const onSelectStyle = ( style ) => { diff --git a/packages/block-editor/src/components/block-styles/utils.js b/packages/block-editor/src/components/block-styles/utils.js index 278096085fff04..4d081aa80430d2 100644 --- a/packages/block-editor/src/components/block-styles/utils.js +++ b/packages/block-editor/src/components/block-styles/utils.js @@ -6,6 +6,7 @@ import { find } from 'lodash'; * WordPress dependencies */ import TokenList from '@wordpress/token-list'; +import { _x } from '@wordpress/i18n'; /** * Returns the active style from the given className. @@ -51,3 +52,30 @@ export function replaceActiveStyle( className, activeStyle, newStyle ) { return list.value; } + +/** + * Returns a collection of styles that can be represented on the frontend. + * The function checks a style collection for a default style. If none is found, it adds one to + * act as a fallback for when there is no active style applied to a block. The default item also serves + * as a switch on the frontend to deactivate non-default styles. + * + * @param {Array} styles Block style variations. + * + * @return {Array} The style collection. + */ +export function getRenderedStyles( styles ) { + if ( ! styles ) { + return []; + } + + return find( styles, 'isDefault' ) + ? styles + : [ + { + name: 'default', + label: _x( 'Default', 'block style' ), + isDefault: true, + }, + ...styles, + ]; +} diff --git a/packages/block-editor/src/components/default-style-picker/index.js b/packages/block-editor/src/components/default-style-picker/index.js index 37d0bfa9477474..736c1522425fa7 100644 --- a/packages/block-editor/src/components/default-style-picker/index.js +++ b/packages/block-editor/src/components/default-style-picker/index.js @@ -11,7 +11,7 @@ import { useSelect } from '@wordpress/data'; * Internal dependencies */ import { store as blockEditorStore } from '../../store'; -import { getActiveStyle } from '../block-styles/utils'; +import { getActiveStyle, getRenderedStyles } from '../block-styles/utils'; export default function DefaultStylePicker( { clientId } ) { const { @@ -36,14 +36,17 @@ export default function DefaultStylePicker( { clientId } ) { blockStyle ) : null; + // The blocks styles inspector shows a default option, + // so make sure this component knows about it too. + const renderedStyles = getRenderedStyles( blockStyles ); return { preferredStyle: preferredStyleVariations?.value?.[ block.name ], onUpdatePreferredStyleVariations: onUpdate, - styles: blockStyles, + styles: renderedStyles, blockName: block.name, activeStyle: getActiveStyle( - blockStyles, + renderedStyles, block.attributes.className || '' ), }; @@ -52,13 +55,15 @@ export default function DefaultStylePicker( { clientId } ) { ); const selectOnChange = useCallback( () => { onUpdatePreferredStyleVariations( activeStyle.name ); - }, [ activeStyle.name, onUpdatePreferredStyleVariations ] ); + }, [ activeStyle?.name, onUpdatePreferredStyleVariations ] ); const preferredStyleLabel = useMemo( () => { const preferredStyleObject = styles.find( ( style ) => style.name === preferredStyle ); - return preferredStyleObject?.label || preferredStyleObject?.name; + return preferredStyleObject + ? preferredStyleObject?.label || preferredStyleObject?.name + : __( 'Not set' ); }, [ preferredStyle ] ); return ( @@ -70,7 +75,7 @@ export default function DefaultStylePicker( { clientId } ) { { preferredStyleLabel }
- { preferredStyle !== activeStyle.name && ( + { preferredStyle !== activeStyle?.name && ( ) }
diff --git a/packages/block-editor/src/components/default-style-picker/style.scss b/packages/block-editor/src/components/default-style-picker/style.scss index 1e1e7c41fa4303..af1ec4c5cc1cff 100644 --- a/packages/block-editor/src/components/default-style-picker/style.scss +++ b/packages/block-editor/src/components/default-style-picker/style.scss @@ -1,9 +1,3 @@ -.default-style-picker__current-default { - margin-bottom: $grid-unit-05; -} - -.default-style-picker__style-label { - font-weight: 600; - display: inline-block; - margin-left: $grid-unit-05; +.default-style-picker__default-switcher { + text-align: center; } From 9aa6248a366cecf6e2fc036aae665be126b9ad7a Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 20 Sep 2021 12:56:33 +1000 Subject: [PATCH 07/20] Aligning preview with preview block popover styles Creating custom DOMRect object to pass to the PopOver component to set x value. --- .../block-styles-preview-panel.js | 47 ++++++++++++++----- .../src/components/block-styles/index.js | 29 +++++------- .../src/components/block-styles/style.scss | 45 ++++++++++++++++++ 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js index 02074a06359f31..ba42e85b41ffbf 100644 --- a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js +++ b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js @@ -1,13 +1,14 @@ /** * WordPress dependencies */ -import { useMemo } from '@wordpress/element'; +import { useMemo, useCallback } from '@wordpress/element'; /** * Internal dependencies */ import BlockPreview from '../block-preview'; import { replaceActiveStyle } from './utils'; +import { Popover } from '@wordpress/components'; export default function BlockStylesPreviewPanel( { genericPreviewBlock, @@ -15,6 +16,7 @@ export default function BlockStylesPreviewPanel( { style, className, activeStyle, + targetRef, } ) { const styleClassName = replaceActiveStyle( className, activeStyle, style ); const previewBlocks = useMemo( () => { @@ -29,17 +31,40 @@ export default function BlockStylesPreviewPanel( { }; }, [ genericPreviewBlock, styleClassName ] ); - // TODO: look at packages/block-editor/src/components/block-switcher/preview-block-popover.js + const getAnchorRect = useCallback( () => { + if ( ! targetRef?.current || ! window.DOMRect ) { + return null; + } + const rect = targetRef?.current.getBoundingClientRect(); + + return new window.DOMRect( + rect.x - targetRef?.current.offsetLeft, + rect.y, + rect.width, + rect.height + ); + }, [ targetRef?.current ] ); + return ( -
-
- -
-
- { style.label || style.name } +
+
+ +
+
+ { style.label || style.name } +
+ +
+
); diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index 19558264f0f830..721b4b9136ad0b 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -7,7 +7,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useCallback, useMemo, useState } from '@wordpress/element'; +import { useCallback, useMemo, useRef, useState } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; import { ENTER, SPACE } from '@wordpress/keycodes'; import { @@ -16,7 +16,7 @@ import { getBlockFromExample, store as blocksStore, } from '@wordpress/blocks'; -import { Button, MenuItem, Popover } from '@wordpress/components'; +import { Button, MenuItem } from '@wordpress/components'; import { check } from '@wordpress/icons'; /** @@ -95,6 +95,8 @@ function BlockStyles( { [ setHoveredStyle ] ); + const containerRef = useRef(); + if ( ! styles || styles.length === 0 ) { return null; } @@ -138,7 +140,7 @@ function BlockStyles( { } return ( -
+
{ renderedStyles.map( ( style ) => { const buttonText = style.label || style.name; @@ -178,19 +180,14 @@ function BlockStyles( { } ) }
{ hoveredStyle && ( - - - + ) }
); diff --git a/packages/block-editor/src/components/block-styles/style.scss b/packages/block-editor/src/components/block-styles/style.scss index eb339f694f92c3..25ceeb9329038e 100644 --- a/packages/block-editor/src/components/block-styles/style.scss +++ b/packages/block-editor/src/components/block-styles/style.scss @@ -37,6 +37,51 @@ } // Block style previews +.block-editor-block-switcher__popover__preview__parent { + .block-editor-block-switcher__popover__preview__container { + position: absolute; + top: -$grid-unit-15; + left: calc(100% + #{$grid-unit-40}); + } +} + +.block-editor-block-switcher__preview__popover { + display: none; + + // Position correctly. Needs specificity. + &.components-popover { + margin-left: $grid-unit-05; + margin-top: $grid-unit-15 - $border-width; + } + + @include break-medium() { + display: block; + } + + .components-popover__content { + box-shadow: none; + border: $border-width solid $gray-900; + background: $white; + border-radius: $radius-block-ui; + } + + .block-editor-block-switcher__preview { + width: 300px; + height: auto; + max-height: 500px; + padding: $grid-unit-20; + } +} + +.block-editor-block-switcher__preview-title { + margin-bottom: $grid-unit-15; + color: $gray-700; + text-transform: uppercase; + font-size: 11px; + font-weight: 500; +} + +/* -- OLD BOY */ .block-editor-block-styles__popover { width: 300px; } From a651c0190518ae58f14802a7ae76d590b0911612 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 20 Sep 2021 13:58:48 +1000 Subject: [PATCH 08/20] Fixed typo in expected label in the getRenderedStyles test --- packages/block-editor/src/components/block-styles/test/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-styles/test/utils.js b/packages/block-editor/src/components/block-styles/test/utils.js index 6898582e06644a..f49acaf1296ca3 100644 --- a/packages/block-editor/src/components/block-styles/test/utils.js +++ b/packages/block-editor/src/components/block-styles/test/utils.js @@ -93,7 +93,7 @@ describe( 'getRenderedStyles', () => { const styles = [ { name: 'pistachio' }, { name: 'peanut' } ]; const defaultStyle = { name: 'default', - label: 'default', + label: 'Default', isDefault: true, }; From 35ea380137db6e426c69ef455e3111216cef6892 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 20 Sep 2021 14:42:12 +1000 Subject: [PATCH 09/20] Cleaning up styles and classnames `.block-editor-block-styles__item` should exist for the e2e test: style-variation.test.js --- .../block-styles-preview-panel.js | 6 +- .../src/components/block-styles/index.js | 3 +- .../src/components/block-styles/style.scss | 106 +----------------- 3 files changed, 11 insertions(+), 104 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js index ba42e85b41ffbf..66640bce0bcb35 100644 --- a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js +++ b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js @@ -49,14 +49,14 @@ export default function BlockStylesPreviewPanel( {
-
-
+
+
{ style.label || style.name }
onSelectStyle( style ) } + className="block-editor-block-styles__item" > { menuItemText } @@ -148,7 +149,7 @@ function BlockStyles( { return (
) } diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index f820a14c944d99..211eb62456aad8 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -53,15 +53,12 @@ function BlockStyles( { itemRole, } ) { const selector = ( select ) => { - const { getBlock, getSettings } = select( blockEditorStore ); + const { getBlock } = select( blockEditorStore ); const block = getBlock( clientId ); if ( ! block ) { return EMPTY_OBJECT; } - const settings = getSettings(); - const preferredStyleVariations = - settings.__experimentalPreferredStyleVariations; const blockType = getBlockType( block.name ); const { getBlockStyles } = select( blocksStore ); @@ -70,17 +67,12 @@ function BlockStyles( { type: blockType, styles: getBlockStyles( block.name ), className: block.attributes.className || '', - preferredStyleName: preferredStyleVariations?.value?.[ block.name ], }; }; - const { - styles, - block, - type, - className, - preferredStyleName, - } = useSelect( selector, [ clientId ] ); + const { styles, block, type, className } = useSelect( selector, [ + clientId, + ] ); const { updateBlockAttributes } = useDispatch( blockEditorStore ); const genericPreviewBlock = useGenericPreviewBlock( block, type ); @@ -101,7 +93,7 @@ function BlockStyles( { return null; } - const renderedStyles = getRenderedStyles( styles, preferredStyleName ); + const renderedStyles = getRenderedStyles( styles ); const activeStyle = getActiveStyle( renderedStyles, className ); const onSelectStyle = ( style ) => { diff --git a/packages/block-editor/src/components/block-styles/style.scss b/packages/block-editor/src/components/block-styles/style.scss index d8e38587a53677..55f516e988918c 100644 --- a/packages/block-editor/src/components/block-styles/style.scss +++ b/packages/block-editor/src/components/block-styles/style.scss @@ -55,7 +55,6 @@ display: inline-block; min-width: calc(50% - #{$grid-unit-05}); margin-bottom: $grid-unit-10; - height: 42px; &:focus, &:hover { diff --git a/packages/block-editor/src/components/block-styles/test/utils.js b/packages/block-editor/src/components/block-styles/test/utils.js index f49acaf1296ca3..53a1ba84445367 100644 --- a/packages/block-editor/src/components/block-styles/test/utils.js +++ b/packages/block-editor/src/components/block-styles/test/utils.js @@ -3,6 +3,7 @@ */ import { getActiveStyle, + getDefaultStyle, getRenderedStyles, replaceActiveStyle, } from '../utils'; @@ -102,18 +103,25 @@ describe( 'getRenderedStyles', () => { ...styles, ] ); } ); +} ); - it( 'Should sort by `defaultStyleId` where passed', () => { +describe( 'getDefaultStyle', () => { + it( 'Should return default style object', () => { const styles = [ - { name: 'macadamia' }, - { name: 'brazil' }, - { name: 'almond', isDefault: true }, + { name: 'trout' }, + { name: 'bream', isDefault: true }, ]; - expect( getRenderedStyles( styles, 'brazil' ) ).toEqual( [ - { name: 'brazil' }, - { name: 'macadamia' }, - { name: 'almond', isDefault: true }, - ] ); + expect( getDefaultStyle( styles ) ).toEqual( styles[ 1 ] ); + } ); + + it( 'Should return `undefined` if there is no default', () => { + const styles = [ { name: 'snapper' }, { name: 'perch' } ]; + + expect( getDefaultStyle( styles ) ).toBeUndefined(); + } ); + + it( 'Should return `undefined` if `styles` argument is no passed', () => { + expect( getDefaultStyle() ).toBeUndefined(); } ); } ); diff --git a/packages/block-editor/src/components/block-styles/utils.js b/packages/block-editor/src/components/block-styles/utils.js index 32222146b0929a..80b1eeae5371dd 100644 --- a/packages/block-editor/src/components/block-styles/utils.js +++ b/packages/block-editor/src/components/block-styles/utils.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { find, sortBy } from 'lodash'; +import { find } from 'lodash'; /** * WordPress dependencies */ @@ -54,24 +54,21 @@ export function replaceActiveStyle( className, activeStyle, newStyle ) { } /** - * Returns a sorted collection of styles that can be represented on the frontend. + * Returns a collection of styles that can be represented on the frontend. * The function checks a style collection for a default style. If none is found, it adds one to * act as a fallback for when there is no active style applied to a block. The default item also serves * as a switch on the frontend to deactivate non-default styles. * - * If there is a default selected, we move that to the start of the array. + * @param {Array} styles Block style variations. * - * @param {Array} styles Block style variations. - * @param {string} defaultStyleId The currently-selected default style. - * - * @return {Array} The style collection. + * @return {Array} The style collection. */ -export function getRenderedStyles( styles, defaultStyleId ) { +export function getRenderedStyles( styles ) { if ( ! styles ) { return []; } - const renderedStyles = find( styles, 'isDefault' ) + return getDefaultStyle( styles ) ? styles : [ { @@ -81,13 +78,15 @@ export function getRenderedStyles( styles, defaultStyleId ) { }, ...styles, ]; +} - if ( defaultStyleId ) { - return sortBy( - renderedStyles, - ( style ) => style.name !== defaultStyleId - ); - } - - return renderedStyles; +/** + * Returns a style object from a collection of styles where that style object is the default block style. + * + * @param {Array} styles Block style variations. + * + * @return {Object?} The default style object, if found. + */ +export function getDefaultStyle( styles ) { + return find( styles, 'isDefault' ); } diff --git a/packages/block-editor/src/components/default-style-picker/index.js b/packages/block-editor/src/components/default-style-picker/index.js index 0a3d7fffd83452..c8c565b6fc8254 100644 --- a/packages/block-editor/src/components/default-style-picker/index.js +++ b/packages/block-editor/src/components/default-style-picker/index.js @@ -2,73 +2,67 @@ * WordPress dependencies */ import { store as blocksStore } from '@wordpress/blocks'; -import { useCallback } from '@wordpress/element'; +import { useMemo, useCallback } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { Button } from '@wordpress/components'; +import { SelectControl } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ import { store as blockEditorStore } from '../../store'; -import { getActiveStyle, getRenderedStyles } from '../block-styles/utils'; +import { getDefaultStyle } from '../block-styles/utils'; -export default function DefaultStylePicker( { clientId } ) { +export default function DefaultStylePicker( { blockName } ) { const { - activeStyle, - onUpdatePreferredStyleVariations, preferredStyle, + onUpdatePreferredStyleVariations, + styles, } = useSelect( ( select ) => { - const { getBlock, getSettings } = select( blockEditorStore ); - const block = getBlock( clientId ); - const settings = getSettings(); + const settings = select( blockEditorStore ).getSettings(); const preferredStyleVariations = settings.__experimentalPreferredStyleVariations; - const blockStyles = select( blocksStore ).getBlockStyles( - block.name - ); - const onUpdate = preferredStyleVariations?.onChange - ? ( blockStyle ) => - preferredStyleVariations?.onChange( - block.name, - blockStyle - ) - : null; - // The blocks styles inspector shows a default option, - // so make sure this component knows about it too. - const renderedStyles = getRenderedStyles( blockStyles ); - return { - preferredStyle: preferredStyleVariations?.value?.[ block.name ], - onUpdatePreferredStyleVariations: onUpdate, - blockName: block.name, - activeStyle: getActiveStyle( - renderedStyles, - block.attributes.className || '' - ), + preferredStyle: preferredStyleVariations?.value?.[ blockName ], + onUpdatePreferredStyleVariations: + preferredStyleVariations?.onChange ?? null, + styles: select( blocksStore ).getBlockStyles( blockName ), }; }, - [ clientId ] + [ blockName ] + ); + const selectOptions = useMemo( + () => [ + { label: __( 'Not set' ), value: '' }, + ...styles.map( ( { label, name } ) => ( { label, value: name } ) ), + ], + [ styles ] ); - const selectOnChange = useCallback( () => { - onUpdatePreferredStyleVariations( activeStyle.name ); - }, [ activeStyle?.name, onUpdatePreferredStyleVariations ] ); + const defaultStyleName = useMemo( () => getDefaultStyle( styles )?.name, [ + styles, + ] ); + const selectOnChange = useCallback( + ( blockStyle ) => { + onUpdatePreferredStyleVariations( blockName, blockStyle ); + }, + [ blockName, onUpdatePreferredStyleVariations ] + ); + + // Until the functionality is migrated to global styles, + // only show the default style picker if a non-default style has already been selected. + if ( ! preferredStyle || preferredStyle === defaultStyleName ) { + return null; + } return ( onUpdatePreferredStyleVariations && ( -
- { preferredStyle !== activeStyle?.name && ( - - ) } -
+ ) ); } From ebc57c541bec55da274d5c8d63e240a25c1746a5 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 1 Oct 2021 15:22:21 +1000 Subject: [PATCH 12/20] This commit: - debounces the setHoveredStyle state to avoid flickering effect in the preview when unsetting/setting value - we need to give more specificity to the classes that hide the preview on narrow widths to avoid overriding - giving the style buttons fixed widths with ellipses on overflowing text --- .../block-styles-preview-panel.js | 2 +- .../src/components/block-styles/index.js | 11 +++++---- .../src/components/block-styles/style.scss | 24 ++++++++++++++----- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js index 66640bce0bcb35..52199929e9373e 100644 --- a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js +++ b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js @@ -49,7 +49,7 @@ export default function BlockStylesPreviewPanel( {
{ if ( hoveredStyle === item ) { return; } - setHoveredStyle( item ); + debouncedSetHoveredStyle( item ); }, - [ setHoveredStyle ] + [ hoveredStyle ] ); const containerRef = useRef(); @@ -152,8 +155,8 @@ function BlockStyles( { label={ buttonText } onMouseEnter={ () => onStyleHover( style ) } onFocus={ () => onStyleHover( style ) } - onMouseLeave={ () => setHoveredStyle( null ) } - onBlur={ () => setHoveredStyle( null ) } + onMouseLeave={ () => onStyleHover( null ) } + onBlur={ () => onStyleHover( null ) } onKeyDown={ ( event ) => { if ( ENTER === event.keyCode || diff --git a/packages/block-editor/src/components/block-styles/style.scss b/packages/block-editor/src/components/block-styles/style.scss index 55f516e988918c..1d246344e4fe78 100644 --- a/packages/block-editor/src/components/block-styles/style.scss +++ b/packages/block-editor/src/components/block-styles/style.scss @@ -7,19 +7,22 @@ } } -.block-editor-block-styles__preview__popover { +// Do not show in narrow widths. Needs specificity. +.block-editor-block-styles__popover.block-editor-block-styles__preview__popover { display: none; + @include break-medium() { + display: flex; + } +} + +.block-editor-block-styles__preview__popover { // Position correctly. Needs specificity. &.components-popover { margin-left: $grid-unit-05; margin-top: $grid-unit-15 - $border-width; } - @include break-medium() { - display: block; - } - .components-popover__content { box-shadow: none; border: $border-width solid $gray-900; @@ -53,8 +56,11 @@ color: $gray-800; box-shadow: inset 0 0 0 1px $gray-400; display: inline-block; - min-width: calc(50% - #{$grid-unit-05}); + width: calc(50% - #{$grid-unit-05}); margin-bottom: $grid-unit-10; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; &:focus, &:hover { @@ -69,3 +75,9 @@ } } } + +// Try to prevent overflow in the preview container. +.block-editor-block-styles__block-preview-container, +.block-editor-block-styles__block-preview-container * { + box-sizing: border-box !important; +} From 51cf2f3cabf4f78ccddfa1ba4c52d4e7a467ab1a Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 1 Oct 2021 16:17:14 +1000 Subject: [PATCH 13/20] Removing `useCallback` function memo --- .../src/components/block-styles/index.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index dca7f8cae6aa80..4e0f0979f381ea 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -7,7 +7,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useCallback, useMemo, useRef, useState } from '@wordpress/element'; +import { useMemo, useRef, useState } from '@wordpress/element'; import { useDebounce } from '@wordpress/compose'; import { useSelect, useDispatch } from '@wordpress/data'; import { ENTER, SPACE } from '@wordpress/keycodes'; @@ -80,15 +80,12 @@ function BlockStyles( { const [ hoveredStyle, setHoveredStyle ] = useState( null ); const debouncedSetHoveredStyle = useDebounce( setHoveredStyle, 250 ); - const onStyleHover = useCallback( - ( item ) => { - if ( hoveredStyle === item ) { - return; - } - debouncedSetHoveredStyle( item ); - }, - [ hoveredStyle ] - ); + const onStyleHover = ( item ) => { + if ( hoveredStyle === item ) { + return; + } + debouncedSetHoveredStyle( item ); + }; const containerRef = useRef(); From 8373343e28eeba12a29c1a3588a3b9ed9f5a6b39 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Tue, 5 Oct 2021 14:23:07 +1100 Subject: [PATCH 14/20] Using the Text component to control character overflow. Removing ellipsis styles. This commit: - uses InserterPreviewPanel to show the block styles previews, adjusts the attributes being passed to this component so that it displays the correct title. - remove unused styles --- .../block-styles-preview-panel.js | 42 +++++++--------- .../src/components/block-styles/index.js | 16 ++++-- .../src/components/block-styles/style.scss | 49 +++++-------------- 3 files changed, 44 insertions(+), 63 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js index 52199929e9373e..ddc7d13e0d6572 100644 --- a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js +++ b/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js @@ -6,13 +6,12 @@ import { useMemo, useCallback } from '@wordpress/element'; /** * Internal dependencies */ -import BlockPreview from '../block-preview'; +import InserterPreviewPanel from '../inserter/preview-panel'; import { replaceActiveStyle } from './utils'; import { Popover } from '@wordpress/components'; export default function BlockStylesPreviewPanel( { genericPreviewBlock, - viewportWidth, style, className, activeStyle, @@ -22,7 +21,9 @@ export default function BlockStylesPreviewPanel( { const previewBlocks = useMemo( () => { return { ...genericPreviewBlock, - attributes: { + title: style.label || style.name, + description: style.description, + initialAttributes: { ...genericPreviewBlock.attributes, className: styleClassName + @@ -38,6 +39,8 @@ export default function BlockStylesPreviewPanel( { const rect = targetRef?.current.getBoundingClientRect(); return new window.DOMRect( + // The left position of the target element, + // minus any offset in relation to its parent container. rect.x - targetRef?.current.offsetLeft, rect.y, rect.width, @@ -46,26 +49,17 @@ export default function BlockStylesPreviewPanel( { }, [ targetRef?.current ] ); return ( -
-
- -
-
- { style.label || style.name } -
- -
-
-
-
+ + + ); } diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index 4e0f0979f381ea..c92892dc63d7fa 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -17,7 +17,11 @@ import { getBlockFromExample, store as blocksStore, } from '@wordpress/blocks'; -import { Button, MenuItem } from '@wordpress/components'; +import { + Button, + MenuItem, + __experimentalText as Text, +} from '@wordpress/components'; import { check } from '@wordpress/icons'; /** @@ -167,7 +171,14 @@ function BlockStyles( { role="button" tabIndex="0" > - { buttonText } + + { buttonText } + ); } ) } @@ -178,7 +189,6 @@ function BlockStyles( { className={ className } genericPreviewBlock={ genericPreviewBlock } style={ hoveredStyle } - viewportWidth={ type.example?.viewportWidth ?? 500 } targetRef={ containerRef } /> ) } diff --git a/packages/block-editor/src/components/block-styles/style.scss b/packages/block-editor/src/components/block-styles/style.scss index 1d246344e4fe78..0cacf5398441e8 100644 --- a/packages/block-editor/src/components/block-styles/style.scss +++ b/packages/block-editor/src/components/block-styles/style.scss @@ -1,12 +1,3 @@ -// Block style previews -.block-editor-block-styles__popover__preview__parent { - .block-editor-block-styles__popover__preview__container { - position: absolute; - top: -$grid-unit-15; - left: calc(100% + #{$grid-unit-40}); - } -} - // Do not show in narrow widths. Needs specificity. .block-editor-block-styles__popover.block-editor-block-styles__preview__popover { display: none; @@ -17,35 +8,21 @@ } .block-editor-block-styles__preview__popover { - // Position correctly. Needs specificity. - &.components-popover { - margin-left: $grid-unit-05; - margin-top: $grid-unit-15 - $border-width; + // Overrides for InserterPreviewPanel. + .block-editor-inserter__preview-container { + left: auto; + right: auto; + position: static; } - .components-popover__content { - box-shadow: none; - border: $border-width solid $gray-900; - background: $white; - border-radius: $radius-block-ui; + .block-editor-block-card__title.block-editor-block-card__title { + margin: 0; } - - .block-editor-block-styles__preview { - width: 300px; - height: auto; - max-height: 500px; - padding: $grid-unit-20; + .block-editor-block-icon { + display: none; } } -.block-editor-block-styles__preview-title { - margin-bottom: $grid-unit-15; - color: $gray-700; - text-transform: uppercase; - font-size: 11px; - font-weight: 500; -} - .block-editor-block-styles__variants { display: flex; flex-wrap: wrap; @@ -58,9 +35,6 @@ display: inline-block; width: calc(50% - #{$grid-unit-05}); margin-bottom: $grid-unit-10; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; &:focus, &:hover { @@ -76,8 +50,11 @@ } } -// Try to prevent overflow in the preview container. +// To prevent overflow in the preview container, +// ensure that block contents' margin and padding +// do not add to the block container's width. .block-editor-block-styles__block-preview-container, .block-editor-block-styles__block-preview-container * { box-sizing: border-box !important; } + From 7e1c8f586e2583784a7da7996ff560149b4b20eb Mon Sep 17 00:00:00 2001 From: ramonjd Date: Tue, 12 Oct 2021 15:58:49 +1100 Subject: [PATCH 15/20] This commit splits BlockStyles component into two components: one for the settings sidebar and one for inclusion within menu groups. We are abstracting much of the shared logic to a hook. We've replaced current usages of BlockStyles (2) with the new, specific components. Also, instead of using `getAnchorRect` to calculate the popover left position, let's overwrite with !important the position of the popover container using the width of the sidebar plus gutter. --- .../src/components/block-styles/index.js | 150 ++++-------------- .../src/components/block-styles/menu-items.js | 49 ++++++ ...yles-preview-panel.js => preview-panel.js} | 20 +-- .../src/components/block-styles/style.scss | 8 + .../src/components/block-styles/test/utils.js | 8 + .../block-styles/use-styles-for-block.js | 99 ++++++++++++ .../src/components/block-styles/utils.js | 2 +- .../block-switcher/block-styles-menu.js | 8 +- 8 files changed, 201 insertions(+), 143 deletions(-) create mode 100644 packages/block-editor/src/components/block-styles/menu-items.js rename packages/block-editor/src/components/block-styles/{block-styles-preview-panel.js => preview-panel.js} (66%) create mode 100644 packages/block-editor/src/components/block-styles/use-styles-for-block.js diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index c92892dc63d7fa..bf4c78573b06c2 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -7,139 +7,58 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useMemo, useRef, useState } from '@wordpress/element'; +import { useState } from '@wordpress/element'; import { useDebounce } from '@wordpress/compose'; -import { useSelect, useDispatch } from '@wordpress/data'; import { ENTER, SPACE } from '@wordpress/keycodes'; -import { - getBlockType, - cloneBlock, - getBlockFromExample, - store as blocksStore, -} from '@wordpress/blocks'; -import { - Button, - MenuItem, - __experimentalText as Text, -} from '@wordpress/components'; -import { check } from '@wordpress/icons'; +import { Button, __experimentalText as Text } from '@wordpress/components'; /** * Internal dependencies */ -import { getActiveStyle, getRenderedStyles, replaceActiveStyle } from './utils'; -import BlockStylesPreviewPanel from './block-styles-preview-panel'; -import { store as blockEditorStore } from '../../store'; +import BlockStylesPreviewPanel from './preview-panel'; +import useStylesForBlocks from './use-styles-for-block'; -const EMPTY_OBJECT = {}; - -function useGenericPreviewBlock( block, type ) { - return useMemo( () => { - const example = type?.example; - const blockName = type?.name; - - if ( example && blockName ) { - return getBlockFromExample( blockName, { - attributes: example.attributes, - innerBlocks: example.innerBlocks, - } ); - } - - if ( block ) { - return cloneBlock( block ); - } - }, [ type?.example ? block?.name : block, type ] ); -} - -function BlockStyles( { +// Block Styles component for the Settings Sidebar. +export default function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop, - itemRole, } ) { - const selector = ( select ) => { - const { getBlock } = select( blockEditorStore ); - const block = getBlock( clientId ); - - if ( ! block ) { - return EMPTY_OBJECT; - } - const blockType = getBlockType( block.name ); - const { getBlockStyles } = select( blocksStore ); - - return { - block, - type: blockType, - styles: getBlockStyles( block.name ), - className: block.attributes.className || '', - }; - }; - - const { styles, block, type, className } = useSelect( selector, [ + const { + onSelect, + stylesToRender, + activeStyle, + genericPreviewBlock, + className, + } = useStylesForBlocks( { clientId, - ] ); - - const { updateBlockAttributes } = useDispatch( blockEditorStore ); - const genericPreviewBlock = useGenericPreviewBlock( block, type ); + onSwitch, + } ); const [ hoveredStyle, setHoveredStyle ] = useState( null ); const debouncedSetHoveredStyle = useDebounce( setHoveredStyle, 250 ); - const onStyleHover = ( item ) => { - if ( hoveredStyle === item ) { - return; - } - debouncedSetHoveredStyle( item ); - }; - - const containerRef = useRef(); - - if ( ! styles || styles.length === 0 ) { + if ( ! stylesToRender || stylesToRender.length === 0 ) { return null; } - const renderedStyles = getRenderedStyles( styles ); - const activeStyle = getActiveStyle( renderedStyles, className ); - - const onSelectStyle = ( style ) => { - const styleClassName = replaceActiveStyle( - className, - activeStyle, - style - ); - updateBlockAttributes( clientId, { - className: styleClassName, - } ); + const onSelectStylePreview = ( style ) => { + onSelect( style ); onHoverClassName( null ); setHoveredStyle( null ); - onSwitch(); }; - if ( itemRole === 'menuitem' ) { - return ( -
- { renderedStyles.map( ( style ) => { - const menuItemText = style.label || style.name; - return ( - onSelectStyle( style ) } - className="block-editor-block-styles__item" - > - { menuItemText } - - ); - } ) } -
- ); - } + const styleItemHandler = ( item ) => { + if ( hoveredStyle === item ) { + return; + } + debouncedSetHoveredStyle( item ); + onHoverClassName( item?.name ?? null ); + }; return ( -
+
- { renderedStyles.map( ( style ) => { + { stylesToRender.map( ( style ) => { const buttonText = style.label || style.name; return ( @@ -154,20 +73,20 @@ function BlockStyles( { key={ style.name } variant="secondary" label={ buttonText } - onMouseEnter={ () => onStyleHover( style ) } - onFocus={ () => onStyleHover( style ) } - onMouseLeave={ () => onStyleHover( null ) } - onBlur={ () => onStyleHover( null ) } + onMouseEnter={ () => styleItemHandler( style ) } + onFocus={ () => styleItemHandler( style ) } + onMouseLeave={ () => styleItemHandler( null ) } + onBlur={ () => styleItemHandler( null ) } onKeyDown={ ( event ) => { if ( ENTER === event.keyCode || SPACE === event.keyCode ) { event.preventDefault(); - onSelectStyle( style ); + onSelectStylePreview( style ); } } } - onClick={ () => onSelectStyle( style ) } + onClick={ () => onSelectStylePreview( style ) } role="button" tabIndex="0" > @@ -189,11 +108,8 @@ function BlockStyles( { className={ className } genericPreviewBlock={ genericPreviewBlock } style={ hoveredStyle } - targetRef={ containerRef } /> ) }
); } - -export default BlockStyles; diff --git a/packages/block-editor/src/components/block-styles/menu-items.js b/packages/block-editor/src/components/block-styles/menu-items.js new file mode 100644 index 00000000000000..9f1a45502ec241 --- /dev/null +++ b/packages/block-editor/src/components/block-styles/menu-items.js @@ -0,0 +1,49 @@ +/** + * External dependencies + */ +import { noop } from 'lodash'; + +/** + * WordPress dependencies + */ +import { MenuItem, __experimentalText as Text } from '@wordpress/components'; +import { check } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +import useStylesForBlocks from './use-styles-for-block'; + +export default function BlockStylesMenuItems( { clientId, onSwitch = noop } ) { + const { onSelect, stylesToRender, activeStyle } = useStylesForBlocks( { + clientId, + onSwitch, + } ); + + if ( ! stylesToRender || stylesToRender.length === 0 ) { + return null; + } + return ( + <> + { stylesToRender.map( ( style ) => { + const menuItemText = style.label || style.name; + return ( + onSelect( style ) } + > + + { menuItemText } + + + ); + } ) } + + ); +} diff --git a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js b/packages/block-editor/src/components/block-styles/preview-panel.js similarity index 66% rename from packages/block-editor/src/components/block-styles/block-styles-preview-panel.js rename to packages/block-editor/src/components/block-styles/preview-panel.js index ddc7d13e0d6572..19e5877a388f5c 100644 --- a/packages/block-editor/src/components/block-styles/block-styles-preview-panel.js +++ b/packages/block-editor/src/components/block-styles/preview-panel.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { useMemo, useCallback } from '@wordpress/element'; +import { useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -15,7 +15,6 @@ export default function BlockStylesPreviewPanel( { style, className, activeStyle, - targetRef, } ) { const styleClassName = replaceActiveStyle( className, activeStyle, style ); const previewBlocks = useMemo( () => { @@ -32,29 +31,12 @@ export default function BlockStylesPreviewPanel( { }; }, [ genericPreviewBlock, styleClassName ] ); - const getAnchorRect = useCallback( () => { - if ( ! targetRef?.current || ! window.DOMRect ) { - return null; - } - const rect = targetRef?.current.getBoundingClientRect(); - - return new window.DOMRect( - // The left position of the target element, - // minus any offset in relation to its parent container. - rect.x - targetRef?.current.offsetLeft, - rect.y, - rect.width, - rect.height - ); - }, [ targetRef?.current ] ); - return ( { } ); describe( 'getRenderedStyles', () => { + it( 'Should return an empty array if styles is falsy', () => { + expect( getRenderedStyles( null ) ).toEqual( [] ); + } ); + + it( 'Should return an empty array if styles array is empty', () => { + expect( getRenderedStyles( [] ) ).toEqual( [] ); + } ); + it( 'Should return styles collection if there is a default', () => { const styles = [ { name: 'hazlenut' }, diff --git a/packages/block-editor/src/components/block-styles/use-styles-for-block.js b/packages/block-editor/src/components/block-styles/use-styles-for-block.js new file mode 100644 index 00000000000000..3215869c356d7d --- /dev/null +++ b/packages/block-editor/src/components/block-styles/use-styles-for-block.js @@ -0,0 +1,99 @@ +/** + * WordPress dependencies + */ +import { useDispatch, useSelect } from '@wordpress/data'; +import { + cloneBlock, + getBlockType, + getBlockFromExample, + store as blocksStore, +} from '@wordpress/blocks'; +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { getActiveStyle, getRenderedStyles, replaceActiveStyle } from './utils'; +import { store as blockEditorStore } from '../../store'; + +/** + * + * @param {WPBlock} block Block object. + * @param {WPBlockType} type Block type settings. + * @return {WPBlock} A generic block ready for styles preview. + */ +function useGenericPreviewBlock( block, type ) { + return useMemo( () => { + const example = type?.example; + const blockName = type?.name; + + if ( example && blockName ) { + return getBlockFromExample( blockName, { + attributes: example.attributes, + innerBlocks: example.innerBlocks, + } ); + } + + if ( block ) { + return cloneBlock( block ); + } + }, [ type?.example ? block?.name : block, type ] ); +} + +/** + * @typedef useStylesForBlocksArguments + * @property {string} clientId Block client ID. + * @property {() => void} onSwitch Block style switch callback function. + */ + +/** + * + * @param {useStylesForBlocksArguments} useStylesForBlocks arguments. + * @return {Object} Results of the select methods. + */ +export default function useStylesForBlocks( { clientId, onSwitch } ) { + const selector = ( select ) => { + const { getBlock } = select( blockEditorStore ); + const block = getBlock( clientId ); + + if ( ! block ) { + return {}; + } + const blockType = getBlockType( block.name ); + const { getBlockStyles } = select( blocksStore ); + + return { + block, + blockType, + styles: getBlockStyles( block.name ), + className: block.attributes.className || '', + }; + }; + const { styles, block, blockType, className } = useSelect( selector, [ + clientId, + ] ); + const { updateBlockAttributes } = useDispatch( blockEditorStore ); + const stylesToRender = getRenderedStyles( styles ); + const activeStyle = getActiveStyle( stylesToRender, className ); + const genericPreviewBlock = useGenericPreviewBlock( block, blockType ); + + const onSelect = ( style ) => { + const styleClassName = replaceActiveStyle( + className, + activeStyle, + style + ); + updateBlockAttributes( clientId, { + className: styleClassName, + } ); + onSwitch(); + }; + + return { + onSelect, + stylesToRender, + activeStyle, + genericPreviewBlock, + className, + }; +} diff --git a/packages/block-editor/src/components/block-styles/utils.js b/packages/block-editor/src/components/block-styles/utils.js index 80b1eeae5371dd..582d05e6e092e5 100644 --- a/packages/block-editor/src/components/block-styles/utils.js +++ b/packages/block-editor/src/components/block-styles/utils.js @@ -64,7 +64,7 @@ export function replaceActiveStyle( className, activeStyle, newStyle ) { * @return {Array} The style collection. */ export function getRenderedStyles( styles ) { - if ( ! styles ) { + if ( ! styles || styles.length === 0 ) { return []; } diff --git a/packages/block-editor/src/components/block-switcher/block-styles-menu.js b/packages/block-editor/src/components/block-switcher/block-styles-menu.js index 388bde2609a79f..7ca9c5e7c93256 100644 --- a/packages/block-editor/src/components/block-switcher/block-styles-menu.js +++ b/packages/block-editor/src/components/block-switcher/block-styles-menu.js @@ -7,7 +7,7 @@ import { MenuGroup } from '@wordpress/components'; /** * Internal dependencies */ -import BlockStyles from '../block-styles'; +import BlockStylesMenuItems from '../block-styles/menu-items'; export default function BlockStylesMenu( { hoveredBlock, onSwitch } ) { const { clientId } = hoveredBlock; @@ -17,11 +17,7 @@ export default function BlockStylesMenu( { hoveredBlock, onSwitch } ) { label={ __( 'Styles' ) } className="block-editor-block-switcher__styles__menugroup" > - + ); } From aa7bc1d0c8ef4bc803413530be09113b76964592 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Tue, 26 Oct 2021 16:04:06 +1100 Subject: [PATCH 16/20] This commit fixes the position of the block preview container and removes the popover. Adding panel header height to the top position of the preview panel, since there's going to be at least one. --- .../src/components/block-inspector/index.js | 5 +++- .../src/components/block-styles/index.js | 7 +++-- .../components/block-styles/preview-panel.js | 13 +-------- .../src/components/block-styles/style.scss | 28 ++++--------------- 4 files changed, 15 insertions(+), 38 deletions(-) diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js index b7f85f4e5084e1..4209b93ccd03ac 100644 --- a/packages/block-editor/src/components/block-inspector/index.js +++ b/packages/block-editor/src/components/block-inspector/index.js @@ -119,7 +119,10 @@ const BlockInspectorSingleBlock = ( { { hasBlockStyles && (
- + { hasBlockSupport( blockName, 'defaultStylePicker', diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index bf4c78573b06c2..9c4ad2062932c6 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -23,13 +23,14 @@ export default function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop, + className = '', } ) { const { onSelect, stylesToRender, activeStyle, genericPreviewBlock, - className, + className: previewClassName, } = useStylesForBlocks( { clientId, onSwitch, @@ -56,7 +57,7 @@ export default function BlockStyles( { }; return ( -
+
{ stylesToRender.map( ( style ) => { const buttonText = style.label || style.name; @@ -105,7 +106,7 @@ export default function BlockStyles( { { hoveredStyle && ( diff --git a/packages/block-editor/src/components/block-styles/preview-panel.js b/packages/block-editor/src/components/block-styles/preview-panel.js index 19e5877a388f5c..a1bba4cb42656d 100644 --- a/packages/block-editor/src/components/block-styles/preview-panel.js +++ b/packages/block-editor/src/components/block-styles/preview-panel.js @@ -8,7 +8,6 @@ import { useMemo } from '@wordpress/element'; */ import InserterPreviewPanel from '../inserter/preview-panel'; import { replaceActiveStyle } from './utils'; -import { Popover } from '@wordpress/components'; export default function BlockStylesPreviewPanel( { genericPreviewBlock, @@ -32,16 +31,6 @@ export default function BlockStylesPreviewPanel( { }, [ genericPreviewBlock, styleClassName ] ); return ( - - - + ); } diff --git a/packages/block-editor/src/components/block-styles/style.scss b/packages/block-editor/src/components/block-styles/style.scss index 1626919abbb006..70fe395b4fba2c 100644 --- a/packages/block-editor/src/components/block-styles/style.scss +++ b/packages/block-editor/src/components/block-styles/style.scss @@ -1,26 +1,11 @@ -// Do not show in narrow widths. Needs specificity. -.block-editor-block-styles__popover.block-editor-block-styles__preview__popover { - display: none; +.block-editor-block-styles { - @include break-medium() { - display: flex; - } -} - -.block-editor-block-styles__preview__popover { - @include break-medium() { - // The right position equals the sidebar width plus the - // left offset of .block-editor-inserter__preview-container. - // We need the !important to override the Popover inline styles. - right: calc(#{$sidebar-width} + #{$grid-unit-20}) !important; - left: auto !important; - } - - // Overrides for InserterPreviewPanel. - .block-editor-inserter__preview-container { + // Fixing the position is specific to the block inspector context. + &.block-inspector__block-styles .block-editor-inserter__preview-container { + position: fixed; + right: calc(#{$sidebar-width} + #{$grid-unit-40}); + top: calc(#{$header-height} + #{$panel-header-height}); left: auto; - right: auto; - position: static; } .block-editor-block-card__title.block-editor-block-card__title { @@ -65,4 +50,3 @@ .block-editor-block-styles__block-preview-container * { box-sizing: border-box !important; } - From e1c82942fd89fb46bbf2b36819d5ee0760fa5c28 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 29 Oct 2021 12:33:47 +1100 Subject: [PATCH 17/20] This is an attempt to ensure that we should the preview panel outside the confines of the sidebar container. Removing overflow: auto allows us to position elements beyond the container. We have to detect fullscreen vs non-fullscreen mode to allow for varying top positions. Also updated selected active states of the button. --- .../src/components/block-styles/index.js | 8 ++++++- .../src/components/block-styles/style.scss | 23 +++++++++++++++---- .../block-styles/use-styles-for-block.js | 14 ++++++++--- .../components/interface-skeleton/style.scss | 2 -- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index 9c4ad2062932c6..7d56f3b80723e5 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -31,6 +31,7 @@ export default function BlockStyles( { activeStyle, genericPreviewBlock, className: previewClassName, + isFullscreenActive, } = useStylesForBlocks( { clientId, onSwitch, @@ -57,7 +58,11 @@ export default function BlockStyles( { }; return ( -
+
{ stylesToRender.map( ( style ) => { const buttonText = style.label || style.name; @@ -95,6 +100,7 @@ export default function BlockStyles( { as="span" limit={ 12 } ellipsizeMode="tail" + className="block-editor-block-styles__item-text" truncate > { buttonText } diff --git a/packages/block-editor/src/components/block-styles/style.scss b/packages/block-editor/src/components/block-styles/style.scss index 70fe395b4fba2c..73512593d0acb4 100644 --- a/packages/block-editor/src/components/block-styles/style.scss +++ b/packages/block-editor/src/components/block-styles/style.scss @@ -3,11 +3,15 @@ // Fixing the position is specific to the block inspector context. &.block-inspector__block-styles .block-editor-inserter__preview-container { position: fixed; - right: calc(#{$sidebar-width} + #{$grid-unit-40}); - top: calc(#{$header-height} + #{$panel-header-height}); + right: $sidebar-width + $grid-unit-40; + top: $header-height + $grid-unit-40 + $admin-bar-height; // $admin-bar-height; left: auto; } + &.is-fullscreen-active.block-inspector__block-styles .block-editor-inserter__preview-container { + top: $header-height + $grid-unit-40; + } + .block-editor-block-card__title.block-editor-block-card__title { margin: 0; } @@ -32,13 +36,22 @@ &:focus, &:hover { color: var(--wp-admin-theme-color); - box-shadow: inset 0 0 0 1px var(--wp-admin-theme-color); + box-shadow: inset 0 0 0 2px var(--wp-admin-theme-color); } &.is-active, &.is-active:hover { - color: $gray-900; - box-shadow: inset 0 0 0 2px $gray-900; + background-color: $gray-800; + box-shadow: none; + } + + &.is-active .block-editor-block-styles__item-text, + &.is-active:hover .block-editor-block-styles__item-text { + color: $white; + } + + &.is-active:focus { + box-shadow: inset 0 0 0 1px $white, 0 0 0 2px var(--wp-admin-theme-color); } } } diff --git a/packages/block-editor/src/components/block-styles/use-styles-for-block.js b/packages/block-editor/src/components/block-styles/use-styles-for-block.js index 3215869c356d7d..437e0fa67b6d97 100644 --- a/packages/block-editor/src/components/block-styles/use-styles-for-block.js +++ b/packages/block-editor/src/components/block-styles/use-styles-for-block.js @@ -67,11 +67,18 @@ export default function useStylesForBlocks( { clientId, onSwitch } ) { blockType, styles: getBlockStyles( block.name ), className: block.attributes.className || '', + isFullscreenActive: select( 'core/edit-post' ).isFeatureActive( + 'fullscreenMode' + ), }; }; - const { styles, block, blockType, className } = useSelect( selector, [ - clientId, - ] ); + const { + styles, + block, + blockType, + className, + isFullscreenActive, + } = useSelect( selector, [ clientId ] ); const { updateBlockAttributes } = useDispatch( blockEditorStore ); const stylesToRender = getRenderedStyles( styles ); const activeStyle = getActiveStyle( stylesToRender, className ); @@ -95,5 +102,6 @@ export default function useStylesForBlocks( { clientId, onSwitch } ) { activeStyle, genericPreviewBlock, className, + isFullscreenActive, }; } diff --git a/packages/interface/src/components/interface-skeleton/style.scss b/packages/interface/src/components/interface-skeleton/style.scss index 12c14cfcd2e319..49b4a47f9324f9 100644 --- a/packages/interface/src/components/interface-skeleton/style.scss +++ b/packages/interface/src/components/interface-skeleton/style.scss @@ -113,8 +113,6 @@ html.interface-interface-skeleton__html-container { } .interface-interface-skeleton__sidebar { - overflow: auto; - @include break-medium() { border-left: $border-width solid $gray-200; } From 71fcad738205a1f52787ab4ba7ddacebba8eaca9 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Thu, 4 Nov 2021 23:18:40 +1100 Subject: [PATCH 18/20] This commit adds a slot in the editor content area for the block styles popover. We're also reverting changes from the previous commit, where we removed the overflow scroll on the sidebar. In order to position the preview correctly we need to keep an eye on the scroll top value of the content area. --- packages/block-editor/README.md | 4 ++ .../src/components/block-inspector/index.js | 1 + .../src/components/block-styles/index.js | 61 ++++++++++++++----- .../src/components/block-styles/style.scss | 33 ++++++---- .../block-styles/use-styles-for-block.js | 16 ++--- packages/block-editor/src/components/index.js | 1 + .../edit-post/src/components/layout/index.js | 3 +- .../components/interface-skeleton/style.scss | 2 + 8 files changed, 81 insertions(+), 40 deletions(-) diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 0b015bac1bf41a..94a227890243b6 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -209,6 +209,10 @@ _Returns_ - `WPElement`: Element. +### BlockStyles + +Undocumented declaration. + ### BlockTitle Renders the block's configured title as a string, or empty if the title diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js index 4209b93ccd03ac..425b527e96eac8 100644 --- a/packages/block-editor/src/components/block-inspector/index.js +++ b/packages/block-editor/src/components/block-inspector/index.js @@ -120,6 +120,7 @@ const BlockInspectorSingleBlock = ( {
diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index 7d56f3b80723e5..59d3a48df438f7 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -7,10 +7,15 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useState } from '@wordpress/element'; +import { useState, useMemo } from '@wordpress/element'; import { useDebounce } from '@wordpress/compose'; import { ENTER, SPACE } from '@wordpress/keycodes'; -import { Button, __experimentalText as Text } from '@wordpress/components'; +import { + Button, + __experimentalText as Text, + Slot, + Fill, +} from '@wordpress/components'; /** * Internal dependencies @@ -18,12 +23,26 @@ import { Button, __experimentalText as Text } from '@wordpress/components'; import BlockStylesPreviewPanel from './preview-panel'; import useStylesForBlocks from './use-styles-for-block'; +function BlockStylesPreviewPanelSlot( { scope } ) { + return ; +} + +function BlockStylesPreviewPanelFill( { children, className, style, scope } ) { + return ( + +
+ { children } +
+
+ ); +} + // Block Styles component for the Settings Sidebar. -export default function BlockStyles( { +function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop, - className = '', + scope, } ) { const { onSelect, @@ -31,13 +50,18 @@ export default function BlockStyles( { activeStyle, genericPreviewBlock, className: previewClassName, - isFullscreenActive, } = useStylesForBlocks( { clientId, onSwitch, } ); const [ hoveredStyle, setHoveredStyle ] = useState( null ); const debouncedSetHoveredStyle = useDebounce( setHoveredStyle, 250 ); + const containerScrollTop = useMemo( () => { + const scrollContainer = document.querySelector( + '.interface-interface-skeleton__content' + ); + return scrollContainer.scrollTop || 0; + }, [ hoveredStyle ] ); if ( ! stylesToRender || stylesToRender.length === 0 ) { return null; @@ -58,11 +82,7 @@ export default function BlockStyles( { }; return ( -
+
{ stylesToRender.map( ( style ) => { const buttonText = style.label || style.name; @@ -110,13 +130,22 @@ export default function BlockStyles( { } ) }
{ hoveredStyle && ( - + + + ) }
); } + +BlockStyles.Slot = BlockStylesPreviewPanelSlot; +export default BlockStyles; diff --git a/packages/block-editor/src/components/block-styles/style.scss b/packages/block-editor/src/components/block-styles/style.scss index 73512593d0acb4..dd36d852d9a25f 100644 --- a/packages/block-editor/src/components/block-styles/style.scss +++ b/packages/block-editor/src/components/block-styles/style.scss @@ -1,15 +1,27 @@ -.block-editor-block-styles { +// Do not show in narrow widths. Needs specificity. +.block-editor-block-styles__preview-panel { + display: none; + position: absolute; + right: $grid-unit-20; + top: $grid-unit-20; + border: $border-width solid $gray-300; + border-radius: $radius-block-ui; + background: $white; + width: 300px; + left: auto; + overflow: hidden; + z-index: 10; - // Fixing the position is specific to the block inspector context. - &.block-inspector__block-styles .block-editor-inserter__preview-container { - position: fixed; - right: $sidebar-width + $grid-unit-40; - top: $header-height + $grid-unit-40 + $admin-bar-height; // $admin-bar-height; - left: auto; + @include break-medium() { + display: block; } - &.is-fullscreen-active.block-inspector__block-styles .block-editor-inserter__preview-container { - top: $header-height + $grid-unit-40; + // Overrides for InserterPreviewPanel. + .block-editor-inserter__preview-container { + left: auto; + right: auto; + top: auto; + position: static; } .block-editor-block-card__title.block-editor-block-card__title { @@ -24,14 +36,13 @@ display: flex; flex-wrap: wrap; justify-content: space-between; - margin-bottom: $grid-unit-05; + gap: $grid-unit-10; .block-editor-block-styles__item { color: $gray-800; box-shadow: inset 0 0 0 1px $gray-400; display: inline-block; width: calc(50% - #{$grid-unit-05}); - margin-bottom: $grid-unit-10; &:focus, &:hover { diff --git a/packages/block-editor/src/components/block-styles/use-styles-for-block.js b/packages/block-editor/src/components/block-styles/use-styles-for-block.js index 437e0fa67b6d97..655688284ea6d3 100644 --- a/packages/block-editor/src/components/block-styles/use-styles-for-block.js +++ b/packages/block-editor/src/components/block-styles/use-styles-for-block.js @@ -49,7 +49,7 @@ function useGenericPreviewBlock( block, type ) { /** * * @param {useStylesForBlocksArguments} useStylesForBlocks arguments. - * @return {Object} Results of the select methods. + * @return {Object} Results of the select methods. */ export default function useStylesForBlocks( { clientId, onSwitch } ) { const selector = ( select ) => { @@ -67,18 +67,11 @@ export default function useStylesForBlocks( { clientId, onSwitch } ) { blockType, styles: getBlockStyles( block.name ), className: block.attributes.className || '', - isFullscreenActive: select( 'core/edit-post' ).isFeatureActive( - 'fullscreenMode' - ), }; }; - const { - styles, - block, - blockType, - className, - isFullscreenActive, - } = useSelect( selector, [ clientId ] ); + const { styles, block, blockType, className } = useSelect( selector, [ + clientId, + ] ); const { updateBlockAttributes } = useDispatch( blockEditorStore ); const stylesToRender = getRenderedStyles( styles ); const activeStyle = getActiveStyle( stylesToRender, className ); @@ -102,6 +95,5 @@ export default function useStylesForBlocks( { clientId, onSwitch } ) { activeStyle, genericPreviewBlock, className, - isFullscreenActive, }; } diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index dcccb216217e30..df3da7fc3545af 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -24,6 +24,7 @@ export { default as BlockColorsStyleSelector } from './color-style-selector'; export { default as BlockEdit, useBlockEditContext } from './block-edit'; export { default as BlockIcon } from './block-icon'; export { default as BlockNavigationDropdown } from './block-navigation/dropdown'; +export { default as BlockStyles } from './block-styles'; export { default as __experimentalBlockVariationPicker } from './block-variation-picker'; export { default as __experimentalBlockPatternSetup } from './block-pattern-setup'; export { default as __experimentalBlockVariationTransforms } from './block-variation-transforms'; diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index f0bd691a1019ff..6557aadfbb7bfd 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -16,7 +16,7 @@ import { store as editorStore, } from '@wordpress/editor'; import { useSelect, useDispatch } from '@wordpress/data'; -import { BlockBreadcrumb } from '@wordpress/block-editor'; +import { BlockBreadcrumb, BlockStyles } from '@wordpress/block-editor'; import { Button, ScrollLock, Popover } from '@wordpress/components'; import { useViewportMatch } from '@wordpress/compose'; import { PluginArea } from '@wordpress/plugins'; @@ -239,6 +239,7 @@ function Layout( { styles } ) { { isMobileViewport && sidebarIsOpened && ( ) } + } footer={ diff --git a/packages/interface/src/components/interface-skeleton/style.scss b/packages/interface/src/components/interface-skeleton/style.scss index 49b4a47f9324f9..12c14cfcd2e319 100644 --- a/packages/interface/src/components/interface-skeleton/style.scss +++ b/packages/interface/src/components/interface-skeleton/style.scss @@ -113,6 +113,8 @@ html.interface-interface-skeleton__html-container { } .interface-interface-skeleton__sidebar { + overflow: auto; + @include break-medium() { border-left: $border-width solid $gray-200; } From bf660574c8526f4096cbac9ffbba715e93663b49 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 5 Nov 2021 09:05:19 +1100 Subject: [PATCH 19/20] Fixing z-index to have the same z-index as the sidebar. Using useLayoutEffect for setting the scrollTop. --- .../src/components/block-styles/index.js | 20 +++++++++++-------- .../src/components/block-styles/style.scss | 5 +++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index 59d3a48df438f7..cf9f283ce680f3 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -7,8 +7,8 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useState, useMemo } from '@wordpress/element'; -import { useDebounce } from '@wordpress/compose'; +import { useState, useLayoutEffect } from '@wordpress/element'; +import { useDebounce, useViewportMatch } from '@wordpress/compose'; import { ENTER, SPACE } from '@wordpress/keycodes'; import { Button, @@ -55,13 +55,17 @@ function BlockStyles( { onSwitch, } ); const [ hoveredStyle, setHoveredStyle ] = useState( null ); - const debouncedSetHoveredStyle = useDebounce( setHoveredStyle, 250 ); - const containerScrollTop = useMemo( () => { + const [ containerScrollTop, setContainerScrollTop ] = useState( 0 ); + const isMobileViewport = useViewportMatch( 'medium', '<' ); + const debouncedSetHoveredStyle = useDebounce( setHoveredStyle, 300 ); + const hasHoveredStyle = hoveredStyle !== null; // Prevent multiple recalculation of scrollTop. + + useLayoutEffect( () => { const scrollContainer = document.querySelector( '.interface-interface-skeleton__content' ); - return scrollContainer.scrollTop || 0; - }, [ hoveredStyle ] ); + setContainerScrollTop( scrollContainer.scrollTop + 16 ); + }, [ hasHoveredStyle ] ); if ( ! stylesToRender || stylesToRender.length === 0 ) { return null; @@ -129,11 +133,11 @@ function BlockStyles( { ); } ) }
- { hoveredStyle && ( + { hoveredStyle && ! isMobileViewport && ( Date: Fri, 5 Nov 2021 09:54:57 +1100 Subject: [PATCH 20/20] Using lodash debounce so we can cancel the debounce when needed. Also hiding preview when mousing out of the preview container. --- .../src/components/block-styles/index.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js index cf9f283ce680f3..74c568d5db84c1 100644 --- a/packages/block-editor/src/components/block-styles/index.js +++ b/packages/block-editor/src/components/block-styles/index.js @@ -1,14 +1,14 @@ /** * External dependencies */ -import { noop } from 'lodash'; +import { noop, debounce } from 'lodash'; import classnames from 'classnames'; /** * WordPress dependencies */ import { useState, useLayoutEffect } from '@wordpress/element'; -import { useDebounce, useViewportMatch } from '@wordpress/compose'; +import { useViewportMatch } from '@wordpress/compose'; import { ENTER, SPACE } from '@wordpress/keycodes'; import { Button, @@ -27,12 +27,10 @@ function BlockStylesPreviewPanelSlot( { scope } ) { return ; } -function BlockStylesPreviewPanelFill( { children, className, style, scope } ) { +function BlockStylesPreviewPanelFill( { children, scope, ...props } ) { return ( -
- { children } -
+
{ children }
); } @@ -57,28 +55,30 @@ function BlockStyles( { const [ hoveredStyle, setHoveredStyle ] = useState( null ); const [ containerScrollTop, setContainerScrollTop ] = useState( 0 ); const isMobileViewport = useViewportMatch( 'medium', '<' ); - const debouncedSetHoveredStyle = useDebounce( setHoveredStyle, 300 ); - const hasHoveredStyle = hoveredStyle !== null; // Prevent multiple recalculation of scrollTop. useLayoutEffect( () => { const scrollContainer = document.querySelector( '.interface-interface-skeleton__content' ); setContainerScrollTop( scrollContainer.scrollTop + 16 ); - }, [ hasHoveredStyle ] ); + }, [ hoveredStyle ] ); if ( ! stylesToRender || stylesToRender.length === 0 ) { return null; } + const debouncedSetHoveredStyle = debounce( setHoveredStyle, 250 ); + const onSelectStylePreview = ( style ) => { onSelect( style ); onHoverClassName( null ); setHoveredStyle( null ); + debouncedSetHoveredStyle.cancel(); }; const styleItemHandler = ( item ) => { if ( hoveredStyle === item ) { + debouncedSetHoveredStyle.cancel(); return; } debouncedSetHoveredStyle( item ); @@ -138,6 +138,7 @@ function BlockStyles( { scope={ scope } className="block-editor-block-styles__preview-panel" style={ { top: containerScrollTop } } + onMouseLeave={ () => styleItemHandler( null ) } >