From 647eb0d4f6ffb777cca2c9d48fccf383799a4f3f Mon Sep 17 00:00:00 2001 From: Jorge Date: Sun, 18 Feb 2018 22:30:59 +0000 Subject: [PATCH] Added a nested button functionality to cover image. --- blocks/library/cover-image/editor.scss | 20 ++ blocks/library/cover-image/index.js | 230 ++++++++++-------- blocks/library/cover-image/style.scss | 12 +- blocks/library/cover-image/test/index.js | 9 +- editor/components/block-list/block.js | 10 +- .../default-block-appender/index.js | 10 +- 6 files changed, 179 insertions(+), 112 deletions(-) diff --git a/blocks/library/cover-image/editor.scss b/blocks/library/cover-image/editor.scss index a9109c61172d83..e578b5ffeb3c77 100644 --- a/blocks/library/cover-image/editor.scss +++ b/blocks/library/cover-image/editor.scss @@ -1,4 +1,8 @@ .wp-block-cover-image { + .blocks-rich-text, .wp-block-button{ + width: 100%; + } + .blocks-rich-text__tinymce[data-is-empty="true"]:before { position: inherit; } @@ -30,4 +34,20 @@ &.has-right-content .block-rich-text__inline-toolbar{ justify-content: flex-end; } + + .editor-block-list__layout { + margin-top: 20px; + width: 100%; + } + + .editor-block-list__block[data-type="core/button"] { + &[data-align="center"] .editor-block-toolbar { + left: calc(50% - 100px); + } + + &:not([data-align]) .blocks-button__inline-link { + margin-left: 0px; + } + } + } diff --git a/blocks/library/cover-image/index.js b/blocks/library/cover-image/index.js index b7b4be7d82d0e9..e0e7b1d35e82f7 100644 --- a/blocks/library/cover-image/index.js +++ b/blocks/library/cover-image/index.js @@ -7,6 +7,7 @@ import { isEmpty } from 'lodash'; * WordPress dependencies */ import { IconButton, PanelBody, RangeControl, ToggleControl, Toolbar } from '@wordpress/components'; +import { withSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import classnames from 'classnames'; @@ -23,6 +24,7 @@ import ImagePlaceholder from '../../image-placeholder'; import BlockControls from '../../block-controls'; import BlockAlignmentToolbar from '../../block-alignment-toolbar'; import InspectorControls from '../../inspector-controls'; +import InnerBlocks from '../../inner-blocks'; const validAlignments = [ 'left', 'center', 'right', 'wide', 'full' ]; @@ -66,6 +68,10 @@ export const settings = { }, }, + supports: { + managedNesting: true, + }, + transforms: { from: [ { @@ -94,121 +100,142 @@ export const settings = { } }, - edit( { attributes, setAttributes, isSelected, className } ) { - const { url, title, align, contentAlign, id, hasParallax, dimRatio } = attributes; - const updateAlignment = ( nextAlign ) => setAttributes( { align: nextAlign } ); - const onSelectImage = ( media ) => setAttributes( { url: media.url, id: media.id } ); - const toggleParallax = () => setAttributes( { hasParallax: ! hasParallax } ); - const setDimRatio = ( ratio ) => setAttributes( { dimRatio: ratio } ); + edit: withSelect( ( select, ownProps ) => ( { + hasCallAction: !! select( 'core/editor' ).getBlocks( ownProps.id ).length, + } ) )( + ( { attributes, hasCallAction, setAttributes, isSelected, className, onReplace } ) => { + const { url, title, align, contentAlign, id, hasParallax, dimRatio } = attributes; + const updateAlignment = ( nextAlign ) => setAttributes( { align: nextAlign } ); + const onSelectImage = ( media ) => setAttributes( { url: media.url, id: media.id } ); + const toggleParallax = () => setAttributes( { hasParallax: ! hasParallax } ); + const toggleCallAction = () => onReplace( + createBlock( + 'core/cover-image', + attributes, + hasCallAction ? [] : [ + createBlock( 'core/button', { + align: 'center', + } ), + ] + ) + ); - const style = url ? - { backgroundImage: `url(${ url })` } : - undefined; - const classes = classnames( - className, - contentAlign !== 'center' && `has-${ contentAlign }-content`, - dimRatioToClass( dimRatio ), - { - 'has-background-dim': dimRatio !== 0, - 'has-parallax': hasParallax, - } - ); + const setDimRatio = ( ratio ) => setAttributes( { dimRatio: ratio } ); - const alignmentToolbar = ( - { - setAttributes( { contentAlign: nextAlign } ); - } } - /> - ); - const controls = isSelected && [ - - + const style = url ? + { backgroundImage: `url(${ url })` } : + undefined; + const classes = classnames( + className, + contentAlign !== 'center' && `has-${ contentAlign }-content`, + dimRatioToClass( dimRatio ), + { + 'has-background-dim': dimRatio !== 0, + 'has-parallax': hasParallax, + } + ); - { alignmentToolbar } - - ( - - ) } - /> - - , - -

{ __( 'Cover Image Settings' ) }

- - { + setAttributes( { contentAlign: nextAlign } ); + } } /> - - { alignmentToolbar } - -
, - ]; - - if ( ! url ) { - const hasTitle = ! isEmpty( title ); - const icon = hasTitle ? undefined : 'format-image'; - const label = hasTitle ? ( - setAttributes( { title: value } ) } - isSelected={ isSelected } - inlineToolbar - /> - ) : __( 'Cover Image' ); + ); + const controls = isSelected && [ + + - return [ - controls, - , + { alignmentToolbar } + + ( + + ) } + /> + + , + +

{ __( 'Cover Image Settings' ) }

+ + + + + { alignmentToolbar } + +
, ]; - } - return [ - controls, -
- { title || isSelected ? ( + if ( ! url ) { + const hasTitle = ! isEmpty( title ); + const icon = hasTitle ? undefined : 'format-image'; + const label = hasTitle ? ( setAttributes( { title: value } ) } isSelected={ isSelected } inlineToolbar /> - ) : null } -
, - ]; - }, + ) : __( 'Cover Image' ); + + return [ + controls, + , + ]; + } + + return [ + controls, +
+ { title || isSelected ? ( + setAttributes( { title: value } ) } + isSelected={ isSelected } + inlineToolbar + /> + ) : null } + +
, + ]; + } ), save( { attributes, className } ) { const { url, title, hasParallax, dimRatio, align, contentAlign } = attributes; @@ -229,6 +256,7 @@ export const settings = { return (

{ title }

+
); }, diff --git a/blocks/library/cover-image/style.scss b/blocks/library/cover-image/style.scss index 4ec232e2d20907..1db14b8d753afc 100644 --- a/blocks/library/cover-image/style.scss +++ b/blocks/library/cover-image/style.scss @@ -1,30 +1,28 @@ -.wp-block-cover-image { +section.wp-block-cover-image { position: relative; background-size: cover; height: 430px; width: 100%; margin: 0; display: flex; + flex-direction: column; justify-content: center; align-items: center; &.has-left-content { - justify-content: flex-start; h2 { - margin-left: 0; text-align: left; } } &.has-right-content { - justify-content: flex-end; h2 { - margin-right: 0; text-align: right; } } h2 { + width: 100%; color: white; font-size: 24pt; line-height: 1em; @@ -58,4 +56,8 @@ height: inherit; } + .wp-block-button { + width: calc( 100% - 40px ); + } + } diff --git a/blocks/library/cover-image/test/index.js b/blocks/library/cover-image/test/index.js index 4cd1d315f7c3de..3df95e8637c1c7 100644 --- a/blocks/library/cover-image/test/index.js +++ b/blocks/library/cover-image/test/index.js @@ -5,7 +5,14 @@ import { name, settings } from '../'; import { blockEditRender } from 'blocks/test/helpers'; jest.mock( 'blocks/media-upload', () => () => '*** Mock(Media upload button) ***' ); - +jest.mock( + '@wordpress/data', + () => ( { + withSelect() { + return ( BlockEdit ) => ( props ) => ; + }, + } ), +); describe( 'core/cover-image', () => { test( 'block edit matches snapshot', () => { const wrapper = blockEditRender( name, settings ); diff --git a/editor/components/block-list/block.js b/editor/components/block-list/block.js index 6f00b36419e0d1..14f512b039e878 100644 --- a/editor/components/block-list/block.js +++ b/editor/components/block-list/block.js @@ -23,6 +23,7 @@ import { cloneBlock, getBlockType, getSaveElement, + hasBlockSupport, isReusableBlock, isUnmodifiedDefaultBlock, } from '@wordpress/blocks'; @@ -521,6 +522,7 @@ export class BlockListBlock extends Component { isMultiSelected, isFirstMultiSelected, isLastInSelection, + rootHasManageNesting, } = this.props; const isHovered = this.state.isHovered && ! this.props.isMultiSelecting; const { name: blockName, isValid } = block; @@ -533,10 +535,11 @@ export class BlockListBlock extends Component { // If the block is selected and we're typing the block should not appear as selected unless the selection is not collapsed. // Empty paragraph blocks should always show up as unselected. const isEmptyDefaultBlock = isUnmodifiedDefaultBlock( block ); - const showSideInserter = ( isSelected || isHovered ) && isEmptyDefaultBlock; + const showSideInserter = ! rootHasManageNesting && ( isSelected || isHovered ) && isEmptyDefaultBlock; const isSelectedNotTyping = isSelected && ( ! this.props.isTyping || ! this.state.isSelectionCollapsed ); const shouldAppearSelected = ! showSideInserter && isSelectedNotTyping; - const shouldShowMovers = shouldAppearSelected || isHovered || ( isEmptyDefaultBlock && isSelectedNotTyping ); + const shouldShowMovers = ! rootHasManageNesting && + ( shouldAppearSelected || isHovered || ( isEmptyDefaultBlock && isSelectedNotTyping ) ); const shouldShowSettingsMenu = shouldShowMovers; const shouldShowContextualToolbar = shouldAppearSelected && isValid && showContextualToolbar; const shouldShowMobileToolbar = shouldAppearSelected; @@ -678,6 +681,7 @@ export class BlockListBlock extends Component { const mapStateToProps = ( state, { uid, rootUID } ) => { const isSelected = isBlockSelected( state, uid ); + const rootBlock = rootUID ? getBlock( state, rootUID ) : undefined; return { previousBlockUid: getPreviousBlockUid( state, uid ), nextBlockUid: getNextBlockUid( state, uid ), @@ -696,6 +700,8 @@ const mapStateToProps = ( state, { uid, rootUID } ) => { postType: getCurrentPostType( state ), initialPosition: getSelectedBlocksInitialCaretPosition( state ), isSelected, + rootHasManageNesting: !! rootBlock && + hasBlockSupport( rootBlock.name, 'managedNesting' ), }; }; diff --git a/editor/components/default-block-appender/index.js b/editor/components/default-block-appender/index.js index 80e41082ca7a04..cb61926b1d2d65 100644 --- a/editor/components/default-block-appender/index.js +++ b/editor/components/default-block-appender/index.js @@ -8,7 +8,7 @@ import { connect } from 'react-redux'; */ import { __ } from '@wordpress/i18n'; import { compose } from '@wordpress/element'; -import { isUnmodifiedDefaultBlock } from '@wordpress/blocks'; +import { hasBlockSupport, isUnmodifiedDefaultBlock } from '@wordpress/blocks'; import { withContext } from '@wordpress/components'; /** @@ -19,8 +19,8 @@ import BlockDropZone from '../block-drop-zone'; import { appendDefaultBlock, startTyping } from '../../store/actions'; import { getBlock, getBlockCount } from '../../store/selectors'; -export function DefaultBlockAppender( { isLocked, isVisible, onAppend, showPrompt } ) { - if ( isLocked || ! isVisible ) { +export function DefaultBlockAppender( { isLocked, isVisible, onAppend, rootHasManageNesting, showPrompt } ) { + if ( isLocked || ! isVisible || rootHasManageNesting ) { return null; } @@ -45,10 +45,14 @@ export default compose( const isEmpty = ! getBlockCount( state, ownProps.rootUID ); const lastBlock = getBlock( state, ownProps.lastBlockUID ); const isLastBlockEmptyDefault = lastBlock && isUnmodifiedDefaultBlock( lastBlock ); + const rootBlock = ownProps.rootUID ? getBlock( state, ownProps.rootUID ) : undefined; return { isVisible: isEmpty || ! isLastBlockEmptyDefault, showPrompt: isEmpty, + rootHasManageNesting: !! rootBlock && + hasBlockSupport( rootBlock.name, 'managedNesting' ), + }; }, ( dispatch, ownProps ) => ( {