From 966dab48153fca4eabb582a1e6854d8d9261ef83 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Fri, 13 Apr 2018 15:23:03 +0200 Subject: [PATCH 01/13] Edit Post: Add information for developers about `isSelected` changes introduced --- docs/deprecated.md | 1 + edit-post/index.js | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/docs/deprecated.md b/docs/deprecated.md index 97b9d25eff1475..6f905f7f38c717 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -9,6 +9,7 @@ Gutenberg's deprecation policy is intended to support backwards-compatibility fo ## 2.7.0 - `wp.element.getWrapperDisplayName` function removed. Please use `wp.element.createHigherOrderComponent` instead. +- `isSelected` usage is no longer mandatory with `BlockControls`, `InspectorControls` and `RichText`. It is now handled by the editor internally to ensure that controls are visible only when block is selected. See updated docs: https://github.com/WordPress/gutenberg/blob/master/blocks/README.md#components. ## 2.6.0 diff --git a/edit-post/index.js b/edit-post/index.js index 76a4fc7de7a389..540bf98f3bb9ba 100644 --- a/edit-post/index.js +++ b/edit-post/index.js @@ -57,6 +57,15 @@ export function initializeEditor( id, post, settings ) { const target = document.getElementById( id ); const reboot = reinitializeEditor.bind( null, target, settings ); + if ( 'production' !== process.env.NODE_ENV ) { + // Remove with 3.0 release. + window.console.info( + '`isSelected` usage is no longer mandatory with `BlockControls`, `InspectorControls` and `RichText`. ' + + 'It is now handled by the editor internally to ensure that controls are visible only when block is selected. ' + + 'See updated docs: https://github.com/WordPress/gutenberg/blob/master/blocks/README.md#components.' + ); + } + render( , target From b89bd580169c5667505c55362aa79da610cccae6 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Tue, 13 Feb 2018 13:34:24 +0100 Subject: [PATCH 02/13] Blocks: Refactor block controls to use block edit context --- blocks/block-controls/index.js | 9 +++- blocks/block-controls/test/index.js | 2 +- blocks/block-edit/context.js | 50 +++++++++++++++++++ blocks/block-edit/index.js | 2 + blocks/hooks/test/align.js | 4 +- blocks/inspector-controls/index.js | 12 ++++- blocks/library/paragraph/index.js | 23 +++++---- .../test/__snapshots__/index.js.snap | 44 ++++++++-------- element/index.js | 2 +- 9 files changed, 109 insertions(+), 39 deletions(-) create mode 100644 blocks/block-edit/context.js diff --git a/blocks/block-controls/index.js b/blocks/block-controls/index.js index ed25d5849d8160..290f1a50dbfe13 100644 --- a/blocks/block-controls/index.js +++ b/blocks/block-controls/index.js @@ -3,7 +3,12 @@ */ import { Toolbar, Fill } from '@wordpress/components'; -export default function BlockControls( { controls, children } ) { +/** + * Internal dependencies + */ +import { ifEditBlockSelected } from '../block-edit/context'; + +export function BlockControls( { controls, children } ) { return ( @@ -11,3 +16,5 @@ export default function BlockControls( { controls, children } ) { ); } + +export default ifEditBlockSelected( BlockControls ); diff --git a/blocks/block-controls/test/index.js b/blocks/block-controls/test/index.js index 5b4f2f831fe12b..29b03f251caa0c 100644 --- a/blocks/block-controls/test/index.js +++ b/blocks/block-controls/test/index.js @@ -6,7 +6,7 @@ import { shallow } from 'enzyme'; /** * Internal dependencies */ -import BlockControls from '../'; +import { BlockControls } from '../'; describe( 'BlockControls', () => { const controls = [ diff --git a/blocks/block-edit/context.js b/blocks/block-edit/context.js new file mode 100644 index 00000000000000..17000e4f850069 --- /dev/null +++ b/blocks/block-edit/context.js @@ -0,0 +1,50 @@ +/** + * External dependencies + */ +import { createContext, getWrapperDisplayName } from '@wordpress/element'; + +const EditBlockContext = createContext( { + isSelected: true, +} ); + +/** + * A Higher Order Component used to be provide a context for BlockEdit + * component. + * + * @param {Component} OriginalComponent Component to wrap. + * + * @return {Component} Component with a BlockEdit context set. + */ +export const withEditBlockContextProvider = ( OriginalComponent ) => { + const EnhancedComponent = ( props ) => ( + + + + ); + + EnhancedComponent.displayName = getWrapperDisplayName( OriginalComponent, 'withEditBlockContextProvider' ); + + return EnhancedComponent; +}; + +/** + * A Higher Order Component used to render conditionally the wrapped + * component only when the BlockEdit has selected state set. + * + * @param {Component} OriginalComponent Component to wrap. + * + * @return {Component} Component which renders only when the BlockEdit is selected. + */ +export const ifEditBlockSelected = ( OriginalComponent ) => { + const EnhancedComponent = ( props ) => ( + + { ( { isSelected } ) => isSelected && ( + + ) } + + ); + + EnhancedComponent.displayName = getWrapperDisplayName( OriginalComponent, 'ifEditBlockSelected' ); + + return EnhancedComponent; +}; diff --git a/blocks/block-edit/index.js b/blocks/block-edit/index.js index de65ee989b8ff3..cfcce5db262324 100644 --- a/blocks/block-edit/index.js +++ b/blocks/block-edit/index.js @@ -19,6 +19,7 @@ import { getBlockDefaultClassName, hasBlockSupport, } from '../api'; +import { withEditBlockContextProvider } from './context'; export class BlockEdit extends Component { getChildContext() { @@ -75,6 +76,7 @@ BlockEdit.childContextTypes = { }; export default compose( [ + withEditBlockContextProvider, withFilters( 'blocks.BlockEdit' ), withSelect( ( select ) => ( { postType: select( 'core/editor' ).getEditedPostAttribute( 'type' ), diff --git a/blocks/hooks/test/align.js b/blocks/hooks/test/align.js index 9a14ae843abf76..37b766f5333816 100644 --- a/blocks/hooks/test/align.js +++ b/blocks/hooks/test/align.js @@ -123,7 +123,9 @@ describe( 'align', () => { expect( wrapper.children() ).toHaveLength( 1 ); } ); - it( 'should render toolbar controls if valid alignments', () => { + // Skipped temporarily until Enzyme publishes new version that works with React 16.3.0 APIs. + // eslint-disable-next-line jest/no-disabled-tests + it.skip( 'should render toolbar controls if valid alignments', () => { registerBlockType( 'core/foo', { ...blockSettings, supports: { diff --git a/blocks/inspector-controls/index.js b/blocks/inspector-controls/index.js index 4a91e43d798fee..a0ea4fe7bac535 100644 --- a/blocks/inspector-controls/index.js +++ b/blocks/inspector-controls/index.js @@ -3,4 +3,14 @@ */ import { createSlotFill } from '@wordpress/components'; -export default createSlotFill( 'InspectorControls' ); +/** + * Internal dependencies + */ +import { ifEditBlockSelected } from '../block-edit/context'; + +const Fill = createSlotFill( 'InspectorControls' ); +const Slot = Fill.Slot; +const InspectorControls = ifEditBlockSelected( Fill ); +InspectorControls.Slot = Slot; + +export default InspectorControls; diff --git a/blocks/library/paragraph/index.js b/blocks/library/paragraph/index.js index c9cbb73bdbe8f0..bdfe355d967df4 100644 --- a/blocks/library/paragraph/index.js +++ b/blocks/library/paragraph/index.js @@ -8,7 +8,12 @@ import { findKey, isFinite, map, omit } from 'lodash'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { concatChildren, Component, RawHTML } from '@wordpress/element'; +import { + concatChildren, + Component, + Fragment, + RawHTML, +} from '@wordpress/element'; import { PanelBody, PanelColor, @@ -139,9 +144,9 @@ class ParagraphBlock extends Component { const fontSize = this.getFontSize(); - return [ - isSelected && ( - + return ( + + { @@ -149,9 +154,7 @@ class ParagraphBlock extends Component { } } /> - ), - isSelected && ( - +
@@ -224,8 +227,6 @@ class ParagraphBlock extends Component { /> - ), -
-
, - ]; + + ); } } diff --git a/blocks/library/paragraph/test/__snapshots__/index.js.snap b/blocks/library/paragraph/test/__snapshots__/index.js.snap index 0369b0add114df..4350e0121dc5bc 100644 --- a/blocks/library/paragraph/test/__snapshots__/index.js.snap +++ b/blocks/library/paragraph/test/__snapshots__/index.js.snap @@ -3,31 +3,29 @@ exports[`core/paragraph block edit matches snapshot 1`] = `
-
-
+
+
-
-
+

-

- Add text or type / to add content -

-
+ Add text or type / to add content +

diff --git a/element/index.js b/element/index.js index 56ad7dc410ac67..c603b07a0de368 100644 --- a/element/index.js +++ b/element/index.js @@ -99,7 +99,7 @@ export { Fragment }; /** * Creates a context object containing two components: a provider and consumer. * - * @param {Object} defaultValue Data stored in the context. + * @param {Object} defaultValue A default data stored in the context. * * @return {Object} Context object. */ From 91c718542f3b32bdcaaff1f5e377a526a15a06d1 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Mon, 12 Mar 2018 11:12:24 +0100 Subject: [PATCH 03/13] Docs: Update docs to reflect the change in how block controls are handled --- blocks/README.md | 22 +++++++--------------- docs/blocks-controls.md | 23 ++++++++++------------- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/blocks/README.md b/blocks/README.md index 42014611ca8bef..8ce7772cdeb4c7 100644 --- a/blocks/README.md +++ b/blocks/README.md @@ -275,12 +275,6 @@ buttons. This is useful for block-level modifications to be made available when a block is selected. For example, if your block supports alignment, you may want to display alignment options in the selected block's toolbar. -Because the toolbar should only be shown when the block is selected, it is -important that a `BlockControls` element is only returned when the block's -`isSelected` prop is -[truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), -meaning that the block is currently selected. - Example: ```js @@ -292,15 +286,13 @@ Example: function edit( props ) { return [ // Controls: (only visible when block is selected) - props.isSelected && ( - el( BlockControls, { key: 'controls' }, - el( AlignmentToolbar, { - value: props.align, - onChange: function( nextAlign ) { - props.setAttributes( { align: nextAlign } ) - } - } ) - ) + el( BlockControls, { key: 'controls' }, + el( AlignmentToolbar, { + value: props.align, + onChange: function( nextAlign ) { + props.setAttributes( { align: nextAlign } ) + } + } ) ), // Block content: (with alignment as attribute) diff --git a/docs/blocks-controls.md b/docs/blocks-controls.md index 729233edee040e..75590e21d1b6c2 100644 --- a/docs/blocks-controls.md +++ b/docs/blocks-controls.md @@ -39,8 +39,7 @@ registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-04', { edit: function( props ) { var content = props.attributes.content, - alignment = props.attributes.alignment, - isSelected = props.isSelected; + alignment = props.attributes.alignment; function onChangeContent( newContent ) { props.setAttributes( { content: newContent } ); @@ -51,7 +50,7 @@ registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-04', { } return [ - isSelected && el( + el( BlockControls, { key: 'controls' }, el( @@ -112,7 +111,7 @@ registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-04', { }, }, - edit( { attributes, className, isSelected, setAttributes } ) { + edit( { attributes, className, setAttributes } ) { const { content, alignment } = attributes; function onChangeContent( newContent ) { @@ -124,14 +123,12 @@ registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-04', { } return [ - isSelected && ( - - - - ), + + + , Date: Wed, 11 Apr 2018 13:38:44 +0200 Subject: [PATCH 04/13] Blocks: Add isSelected handling to InspectorAdvancedControls --- blocks/inspector-advanced-controls/index.js | 14 +++++++++++++- blocks/inspector-controls/index.js | 4 +++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/blocks/inspector-advanced-controls/index.js b/blocks/inspector-advanced-controls/index.js index b725f38ee72bf4..193250a1454215 100644 --- a/blocks/inspector-advanced-controls/index.js +++ b/blocks/inspector-advanced-controls/index.js @@ -3,4 +3,16 @@ */ import { createSlotFill } from '@wordpress/components'; -export default createSlotFill( 'InspectorAdvancedControls' ); +/** + * Internal dependencies + */ +import { ifEditBlockSelected } from '../block-edit/context'; + +const Fill = createSlotFill( 'InspectorAdvancedControls' ); +const { Slot } = Fill; + +const InspectorAdvancedControls = ifEditBlockSelected( Fill ); + +InspectorAdvancedControls.Slot = Slot; + +export default InspectorAdvancedControls; diff --git a/blocks/inspector-controls/index.js b/blocks/inspector-controls/index.js index a0ea4fe7bac535..6a0e98db0f61c0 100644 --- a/blocks/inspector-controls/index.js +++ b/blocks/inspector-controls/index.js @@ -9,8 +9,10 @@ import { createSlotFill } from '@wordpress/components'; import { ifEditBlockSelected } from '../block-edit/context'; const Fill = createSlotFill( 'InspectorControls' ); -const Slot = Fill.Slot; +const { Slot } = Fill; + const InspectorControls = ifEditBlockSelected( Fill ); + InspectorControls.Slot = Slot; export default InspectorControls; From 39b2561349e69f8cf4ec37d86a11da9d1c092481 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Wed, 11 Apr 2018 15:32:38 +0200 Subject: [PATCH 05/13] Blocks: Replace getWrapperDisplayName with its new alternative --- blocks/block-edit/context.js | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/blocks/block-edit/context.js b/blocks/block-edit/context.js index 17000e4f850069..b4ce1ec23d4f2b 100644 --- a/blocks/block-edit/context.js +++ b/blocks/block-edit/context.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { createContext, getWrapperDisplayName } from '@wordpress/element'; +import { createContext, createHigherOrderComponent } from '@wordpress/element'; const EditBlockContext = createContext( { isSelected: true, @@ -15,17 +15,13 @@ const EditBlockContext = createContext( { * * @return {Component} Component with a BlockEdit context set. */ -export const withEditBlockContextProvider = ( OriginalComponent ) => { - const EnhancedComponent = ( props ) => ( +export const withEditBlockContextProvider = createHigherOrderComponent( ( OriginalComponent ) => { + return ( props ) => ( ); - - EnhancedComponent.displayName = getWrapperDisplayName( OriginalComponent, 'withEditBlockContextProvider' ); - - return EnhancedComponent; -}; +}, 'withEditBlockContextProvider' ); /** * A Higher Order Component used to render conditionally the wrapped @@ -35,16 +31,12 @@ export const withEditBlockContextProvider = ( OriginalComponent ) => { * * @return {Component} Component which renders only when the BlockEdit is selected. */ -export const ifEditBlockSelected = ( OriginalComponent ) => { - const EnhancedComponent = ( props ) => ( +export const ifEditBlockSelected = createHigherOrderComponent( ( OriginalComponent ) => { + return ( props ) => ( { ( { isSelected } ) => isSelected && ( ) } ); - - EnhancedComponent.displayName = getWrapperDisplayName( OriginalComponent, 'ifEditBlockSelected' ); - - return EnhancedComponent; -}; +}, 'ifEditBlockSelected' ); From 458b6f398511fc697375dc28b56895cfd1f55fac Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Wed, 11 Apr 2018 15:59:10 +0200 Subject: [PATCH 06/13] Blocks: Use createSlotFill for BlockControls --- blocks/block-controls/index.js | 25 ++++++++++++++---------- blocks/block-controls/test/index.js | 4 +++- editor/components/block-toolbar/index.js | 3 ++- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/blocks/block-controls/index.js b/blocks/block-controls/index.js index 290f1a50dbfe13..42d1e6c82d6907 100644 --- a/blocks/block-controls/index.js +++ b/blocks/block-controls/index.js @@ -1,20 +1,25 @@ /** * WordPress dependencies */ -import { Toolbar, Fill } from '@wordpress/components'; +import { createSlotFill, Toolbar } from '@wordpress/components'; /** * Internal dependencies */ import { ifEditBlockSelected } from '../block-edit/context'; -export function BlockControls( { controls, children } ) { - return ( - - - { children } - - ); -} +const Fill = createSlotFill( 'BlockControls' ); +const { Slot } = Fill; -export default ifEditBlockSelected( BlockControls ); +const BlockControlsFill = ( { controls, children } ) => ( + + + { children } + +); + +const BlockControls = ifEditBlockSelected( BlockControlsFill ); + +BlockControls.Slot = Slot; + +export default BlockControls; diff --git a/blocks/block-controls/test/index.js b/blocks/block-controls/test/index.js index 29b03f251caa0c..1eee2fbf5af2a3 100644 --- a/blocks/block-controls/test/index.js +++ b/blocks/block-controls/test/index.js @@ -27,7 +27,9 @@ describe( 'BlockControls', () => { }, ]; - test( 'Should render a dynamic toolbar of controls', () => { + // Skipped temporarily until Enzyme publishes new version that works with React 16.3.0 APIs. + // eslint-disable-next-line jest/no-disabled-tests + test.skip( 'Should render a dynamic toolbar of controls', () => { expect( shallow( Child

} /> ) ).toMatchSnapshot(); } ); } ); diff --git a/editor/components/block-toolbar/index.js b/editor/components/block-toolbar/index.js index 76d910551f4f81..cb6fe761641cc8 100644 --- a/editor/components/block-toolbar/index.js +++ b/editor/components/block-toolbar/index.js @@ -1,6 +1,7 @@ /** * WordPress Dependencies */ +import { BlockControls } from '@wordpress/blocks'; import { Slot } from '@wordpress/components'; import { withSelect } from '@wordpress/data'; @@ -18,7 +19,7 @@ function BlockToolbar( { block, mode } ) { return (
- +
); From 4e4404a228d75d879242ad085f3f826d22e8f582 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Thu, 12 Apr 2018 13:38:45 +0200 Subject: [PATCH 07/13] Blocks: Introduce BlockFormatControls component --- blocks/block-format-controls/index.js | 18 ++++++++++++++++++ blocks/index.js | 1 + blocks/library/paragraph/index.js | 2 -- blocks/rich-text/index.js | 17 +++++++++-------- editor/components/block-toolbar/index.js | 5 ++--- 5 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 blocks/block-format-controls/index.js diff --git a/blocks/block-format-controls/index.js b/blocks/block-format-controls/index.js new file mode 100644 index 00000000000000..84a8419ccabe66 --- /dev/null +++ b/blocks/block-format-controls/index.js @@ -0,0 +1,18 @@ +/** + * WordPress dependencies + */ +import { createSlotFill } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { ifEditBlockSelected } from '../block-edit/context'; + +const Fill = createSlotFill( 'BlockFormatControls' ); +const { Slot } = Fill; + +const BlockFormatControls = ifEditBlockSelected( Fill ); + +BlockFormatControls.Slot = Slot; + +export default BlockFormatControls; diff --git a/blocks/index.js b/blocks/index.js index ca965030e23470..e92c66d0a72816 100644 --- a/blocks/index.js +++ b/blocks/index.js @@ -18,6 +18,7 @@ export { default as AlignmentToolbar } from './alignment-toolbar'; export { default as Autocomplete } from './autocomplete'; export { default as BlockAlignmentToolbar } from './block-alignment-toolbar'; export { default as BlockControls } from './block-controls'; +export { default as BlockFormatControls } from './block-format-controls'; export { default as BlockEdit } from './block-edit'; export { default as BlockIcon } from './block-icon'; export { default as ColorPalette } from './color-palette'; diff --git a/blocks/library/paragraph/index.js b/blocks/library/paragraph/index.js index bdfe355d967df4..55b9822f2e85c5 100644 --- a/blocks/library/paragraph/index.js +++ b/blocks/library/paragraph/index.js @@ -123,7 +123,6 @@ class ParagraphBlock extends Component { attributes, setAttributes, insertBlocksAfter, - isSelected, mergeBlocks, onReplace, className, @@ -259,7 +258,6 @@ class ParagraphBlock extends Component { onReplace={ this.onReplace } onRemove={ () => onReplace( [] ) } placeholder={ placeholder || __( 'Add text or type / to add content' ) } - isSelected={ isSelected } autocompleters={ autocompleters } /> diff --git a/blocks/rich-text/index.js b/blocks/rich-text/index.js index 7bc9b607455ae7..de96fe0244a375 100644 --- a/blocks/rich-text/index.js +++ b/blocks/rich-text/index.js @@ -22,7 +22,7 @@ import 'element-closest'; */ import { createElement, Component, renderToString, Fragment, compose } from '@wordpress/element'; import { keycodes, createBlobURL, isHorizontalEdge, getRectangleFromRange, getScrollContainer } from '@wordpress/utils'; -import { withSafeTimeout, Slot, Fill } from '@wordpress/components'; +import { withSafeTimeout, Slot } from '@wordpress/components'; import { withSelect } from '@wordpress/data'; /** @@ -31,6 +31,7 @@ import { withSelect } from '@wordpress/data'; import './style.scss'; import { rawHandler } from '../api'; import Autocomplete from '../autocomplete'; +import BlockFormatControls from '../block-format-controls'; import FormatToolbar from './format-toolbar'; import TinyMCE from './tinymce'; import { pickAriaProps } from './aria'; @@ -828,16 +829,16 @@ export class RichText extends Component { return (
- { isSelected && - - { ! inlineToolbar && formatToolbar } - - } - { isSelected && inlineToolbar && + { ! inlineToolbar && ( + + { formatToolbar } + + ) } + { isSelected && inlineToolbar && (
{ formatToolbar }
- } + ) } { ( { isExpanded, listBoxId, activeId } ) => ( diff --git a/editor/components/block-toolbar/index.js b/editor/components/block-toolbar/index.js index cb6fe761641cc8..75826e7cd5dc11 100644 --- a/editor/components/block-toolbar/index.js +++ b/editor/components/block-toolbar/index.js @@ -1,8 +1,7 @@ /** * WordPress Dependencies */ -import { BlockControls } from '@wordpress/blocks'; -import { Slot } from '@wordpress/components'; +import { BlockControls, BlockFormatControls } from '@wordpress/blocks'; import { withSelect } from '@wordpress/data'; /** @@ -20,7 +19,7 @@ function BlockToolbar( { block, mode } ) {
- +
); } From c650c188380dede5e372f62b0fea76faf0dce6df Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Thu, 12 Apr 2018 14:26:26 +0200 Subject: [PATCH 08/13] Blocks: Make sure that RichText controls are only displayed when block is selected This makes it backward compatible with the existing core blocks --- blocks/block-controls/index.js | 4 +- blocks/block-edit/context.js | 39 ++++++++++++++----- blocks/block-edit/index.js | 4 +- blocks/block-format-controls/index.js | 4 +- blocks/inspector-advanced-controls/index.js | 4 +- blocks/inspector-controls/index.js | 4 +- .../test/__snapshots__/index.js.snap | 8 +--- blocks/rich-text/README.md | 2 +- blocks/rich-text/index.js | 10 +++-- docs/blocks-editable.md | 4 +- 10 files changed, 51 insertions(+), 32 deletions(-) diff --git a/blocks/block-controls/index.js b/blocks/block-controls/index.js index 42d1e6c82d6907..a44d22c8fb7bfc 100644 --- a/blocks/block-controls/index.js +++ b/blocks/block-controls/index.js @@ -6,7 +6,7 @@ import { createSlotFill, Toolbar } from '@wordpress/components'; /** * Internal dependencies */ -import { ifEditBlockSelected } from '../block-edit/context'; +import { ifBlockEditSelected } from '../block-edit/context'; const Fill = createSlotFill( 'BlockControls' ); const { Slot } = Fill; @@ -18,7 +18,7 @@ const BlockControlsFill = ( { controls, children } ) => ( ); -const BlockControls = ifEditBlockSelected( BlockControlsFill ); +const BlockControls = ifBlockEditSelected( BlockControlsFill ); BlockControls.Slot = Slot; diff --git a/blocks/block-edit/context.js b/blocks/block-edit/context.js index b4ce1ec23d4f2b..a6eb90d66ab94a 100644 --- a/blocks/block-edit/context.js +++ b/blocks/block-edit/context.js @@ -3,7 +3,7 @@ */ import { createContext, createHigherOrderComponent } from '@wordpress/element'; -const EditBlockContext = createContext( { +const { Consumer, Provider } = createContext( { isSelected: true, } ); @@ -15,13 +15,34 @@ const EditBlockContext = createContext( { * * @return {Component} Component with a BlockEdit context set. */ -export const withEditBlockContextProvider = createHigherOrderComponent( ( OriginalComponent ) => { +export const withBlockEditContextProvider = createHigherOrderComponent( ( OriginalComponent ) => { return ( props ) => ( - + - + ); -}, 'withEditBlockContextProvider' ); +}, 'withBlockEditContextProvider' ); + +/** + * A Higher Order Component used to inject BlockEdit context to the + * wrapped component. + * + * @param {Component} OriginalComponent Component to wrap. + * + * @return {Component} Component which has BlockEdit context injected. + */ +export const withBlockEditContext = createHigherOrderComponent( ( OriginalComponent ) => { + return ( props ) => ( + + { ( context ) => ( + + ) } + + ); +}, 'withBlockEditContext' ); /** * A Higher Order Component used to render conditionally the wrapped @@ -31,12 +52,12 @@ export const withEditBlockContextProvider = createHigherOrderComponent( ( Origin * * @return {Component} Component which renders only when the BlockEdit is selected. */ -export const ifEditBlockSelected = createHigherOrderComponent( ( OriginalComponent ) => { +export const ifBlockEditSelected = createHigherOrderComponent( ( OriginalComponent ) => { return ( props ) => ( - + { ( { isSelected } ) => isSelected && ( ) } - + ); -}, 'ifEditBlockSelected' ); +}, 'ifBlockEditSelected' ); diff --git a/blocks/block-edit/index.js b/blocks/block-edit/index.js index cfcce5db262324..a2fe1cc730cb48 100644 --- a/blocks/block-edit/index.js +++ b/blocks/block-edit/index.js @@ -19,7 +19,7 @@ import { getBlockDefaultClassName, hasBlockSupport, } from '../api'; -import { withEditBlockContextProvider } from './context'; +import { withBlockEditContextProvider } from './context'; export class BlockEdit extends Component { getChildContext() { @@ -76,7 +76,7 @@ BlockEdit.childContextTypes = { }; export default compose( [ - withEditBlockContextProvider, + withBlockEditContextProvider, withFilters( 'blocks.BlockEdit' ), withSelect( ( select ) => ( { postType: select( 'core/editor' ).getEditedPostAttribute( 'type' ), diff --git a/blocks/block-format-controls/index.js b/blocks/block-format-controls/index.js index 84a8419ccabe66..5c46a043d33d43 100644 --- a/blocks/block-format-controls/index.js +++ b/blocks/block-format-controls/index.js @@ -6,12 +6,12 @@ import { createSlotFill } from '@wordpress/components'; /** * Internal dependencies */ -import { ifEditBlockSelected } from '../block-edit/context'; +import { ifBlockEditSelected } from '../block-edit/context'; const Fill = createSlotFill( 'BlockFormatControls' ); const { Slot } = Fill; -const BlockFormatControls = ifEditBlockSelected( Fill ); +const BlockFormatControls = ifBlockEditSelected( Fill ); BlockFormatControls.Slot = Slot; diff --git a/blocks/inspector-advanced-controls/index.js b/blocks/inspector-advanced-controls/index.js index 193250a1454215..3be1a366cec668 100644 --- a/blocks/inspector-advanced-controls/index.js +++ b/blocks/inspector-advanced-controls/index.js @@ -6,12 +6,12 @@ import { createSlotFill } from '@wordpress/components'; /** * Internal dependencies */ -import { ifEditBlockSelected } from '../block-edit/context'; +import { ifBlockEditSelected } from '../block-edit/context'; const Fill = createSlotFill( 'InspectorAdvancedControls' ); const { Slot } = Fill; -const InspectorAdvancedControls = ifEditBlockSelected( Fill ); +const InspectorAdvancedControls = ifBlockEditSelected( Fill ); InspectorAdvancedControls.Slot = Slot; diff --git a/blocks/inspector-controls/index.js b/blocks/inspector-controls/index.js index 6a0e98db0f61c0..84eb791883d86b 100644 --- a/blocks/inspector-controls/index.js +++ b/blocks/inspector-controls/index.js @@ -6,12 +6,12 @@ import { createSlotFill } from '@wordpress/components'; /** * Internal dependencies */ -import { ifEditBlockSelected } from '../block-edit/context'; +import { ifBlockEditSelected } from '../block-edit/context'; const Fill = createSlotFill( 'InspectorControls' ); const { Slot } = Fill; -const InspectorControls = ifEditBlockSelected( Fill ); +const InspectorControls = ifBlockEditSelected( Fill ); InspectorControls.Slot = Slot; diff --git a/blocks/library/paragraph/test/__snapshots__/index.js.snap b/blocks/library/paragraph/test/__snapshots__/index.js.snap index 4350e0121dc5bc..5e792137f9e81e 100644 --- a/blocks/library/paragraph/test/__snapshots__/index.js.snap +++ b/blocks/library/paragraph/test/__snapshots__/index.js.snap @@ -18,14 +18,10 @@ exports[`core/paragraph block edit matches snapshot 1`] = ` aria-multiline="false" class="wp-block-paragraph blocks-rich-text__tinymce" contenteditable="true" - data-is-placeholder-visible="true" + data-is-placeholder-visible="false" role="textbox" /> -

- Add text or type / to add content -

+
diff --git a/blocks/rich-text/README.md b/blocks/rich-text/README.md index a6bc71a973caab..74db6896146a39 100644 --- a/blocks/rich-text/README.md +++ b/blocks/rich-text/README.md @@ -53,7 +53,7 @@ a traditional `input` field, usually when the user exits the field. ### `isSelected: Boolean` -*Optional.* Whether to show the input is selected or not in order to show the formatting controls. +*Optional.* Whether to show the input is selected or not in order to show the formatting controls. By default it renders the controls when the block is selected. ### `keepPlaceholderOnFocus: Boolean` diff --git a/blocks/rich-text/index.js b/blocks/rich-text/index.js index de96fe0244a375..e4867d969a82f7 100644 --- a/blocks/rich-text/index.js +++ b/blocks/rich-text/index.js @@ -37,6 +37,7 @@ import TinyMCE from './tinymce'; import { pickAriaProps } from './aria'; import patterns from './patterns'; import { EVENTS } from './constants'; +import { withBlockEditContext } from '../block-edit/context'; const { BACKSPACE, DELETE, ENTER } = keycodes; @@ -802,7 +803,7 @@ export class RichText extends Component { placeholder, multiline: MultilineTag, keepPlaceholderOnFocus = false, - isSelected = false, + isSelected, formatters, autocompleters, } = this.props; @@ -829,7 +830,7 @@ export class RichText extends Component { return (
- { ! inlineToolbar && ( + { isSelected && ! inlineToolbar && ( { formatToolbar } @@ -888,10 +889,13 @@ RichText.defaultProps = { }; export default compose( [ - withSelect( ( select ) => { + withBlockEditContext, + withSelect( ( select, { isSelected, blockEditContext } ) => { const { isViewportMatch = identity } = select( 'core/viewport' ) || {}; + return { isViewportSmall: isViewportMatch( '< small' ), + isSelected: isSelected !== false && blockEditContext.isSelected, }; } ), withSafeTimeout, diff --git a/docs/blocks-editable.md b/docs/blocks-editable.md index af9e1e33394030..941e886204f3f2 100644 --- a/docs/blocks-editable.md +++ b/docs/blocks-editable.md @@ -44,7 +44,6 @@ registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-03', { className: props.className, onChange: onChangeContent, value: content, - isSelected: props.isSelected, } ); }, @@ -76,7 +75,7 @@ registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-03', { }, edit( { attributes, className, setAttributes } ) { - const { content, isSelected } = attributes; + const { content } = attributes; function onChangeContent( newContent ) { setAttributes( { content: newContent } ); @@ -88,7 +87,6 @@ registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-03', { className={ className } onChange={ onChangeContent } value={ content } - isSelected={ isSelected } /> ); }, From 8c95bb0c452882de4c20c66719b28a91d3bd99ea Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Thu, 12 Apr 2018 18:16:43 +0200 Subject: [PATCH 09/13] Blocks: Update test helper to work with block edit context --- blocks/library/paragraph/test/__snapshots__/index.js.snap | 8 ++++++-- blocks/test/helpers/index.js | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/blocks/library/paragraph/test/__snapshots__/index.js.snap b/blocks/library/paragraph/test/__snapshots__/index.js.snap index 5e792137f9e81e..4350e0121dc5bc 100644 --- a/blocks/library/paragraph/test/__snapshots__/index.js.snap +++ b/blocks/library/paragraph/test/__snapshots__/index.js.snap @@ -18,10 +18,14 @@ exports[`core/paragraph block edit matches snapshot 1`] = ` aria-multiline="false" class="wp-block-paragraph blocks-rich-text__tinymce" contenteditable="true" - data-is-placeholder-visible="false" + data-is-placeholder-visible="true" role="textbox" /> -
+

+ Add text or type / to add content +

diff --git a/blocks/test/helpers/index.js b/blocks/test/helpers/index.js index f46573240df852..b82bdb905c517d 100644 --- a/blocks/test/helpers/index.js +++ b/blocks/test/helpers/index.js @@ -13,6 +13,9 @@ import { registerBlockType, } from '../..'; import { BlockEdit } from '../../block-edit'; +import { withBlockEditContextProvider } from '../../block-edit/context'; + +const BlockEditWithContext = withBlockEditContextProvider( BlockEdit ); export const blockEditRender = ( name, settings ) => { if ( ! getBlockType( name ) ) { @@ -21,7 +24,7 @@ export const blockEditRender = ( name, settings ) => { const block = createBlock( name ); return render( - Date: Fri, 13 Apr 2018 12:08:32 +0200 Subject: [PATCH 10/13] Blocks: Make sure that EditContextProvider is only rerendered when isSelected changes --- blocks/block-edit/context.js | 37 ++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/blocks/block-edit/context.js b/blocks/block-edit/context.js index a6eb90d66ab94a..e8e322d9860e4a 100644 --- a/blocks/block-edit/context.js +++ b/blocks/block-edit/context.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { createContext, createHigherOrderComponent } from '@wordpress/element'; +import { Component, createContext, createHigherOrderComponent } from '@wordpress/element'; const { Consumer, Provider } = createContext( { isSelected: true, @@ -16,11 +16,36 @@ const { Consumer, Provider } = createContext( { * @return {Component} Component with a BlockEdit context set. */ export const withBlockEditContextProvider = createHigherOrderComponent( ( OriginalComponent ) => { - return ( props ) => ( - - - - ); + return class ComponentWithProvider extends Component { + constructor( props ) { + super( props ); + this.state = { + context: { + isSelected: props.isSelected, + }, + }; + } + + static getDerivedStateFromProps( nextProps, prevState ) { + if ( nextProps.isSelected === prevState.context.isSelected ) { + return null; + } + + return { + context: { + isSelected: nextProps.isSelected, + }, + }; + } + + render() { + return ( + + + + ); + } + }; }, 'withBlockEditContextProvider' ); /** From f47a184a5915780c8e9e032f1afbf09c341a5e9d Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Fri, 13 Apr 2018 13:49:14 +0200 Subject: [PATCH 11/13] Blocks: Merge Provider with BlockEdit --- blocks/block-edit/context.js | 43 ++------------------------------- blocks/block-edit/index.js | 38 +++++++++++++++++++++++------ blocks/block-edit/test/index.js | 6 ++--- blocks/test/helpers/index.js | 5 +--- 4 files changed, 36 insertions(+), 56 deletions(-) diff --git a/blocks/block-edit/context.js b/blocks/block-edit/context.js index e8e322d9860e4a..dd9a55359794f9 100644 --- a/blocks/block-edit/context.js +++ b/blocks/block-edit/context.js @@ -1,52 +1,13 @@ /** * External dependencies */ -import { Component, createContext, createHigherOrderComponent } from '@wordpress/element'; +import { createContext, createHigherOrderComponent } from '@wordpress/element'; const { Consumer, Provider } = createContext( { isSelected: true, } ); -/** - * A Higher Order Component used to be provide a context for BlockEdit - * component. - * - * @param {Component} OriginalComponent Component to wrap. - * - * @return {Component} Component with a BlockEdit context set. - */ -export const withBlockEditContextProvider = createHigherOrderComponent( ( OriginalComponent ) => { - return class ComponentWithProvider extends Component { - constructor( props ) { - super( props ); - this.state = { - context: { - isSelected: props.isSelected, - }, - }; - } - - static getDerivedStateFromProps( nextProps, prevState ) { - if ( nextProps.isSelected === prevState.context.isSelected ) { - return null; - } - - return { - context: { - isSelected: nextProps.isSelected, - }, - }; - } - - render() { - return ( - - - - ); - } - }; -}, 'withBlockEditContextProvider' ); +export { Provider as BlockEditContextProvider }; /** * A Higher Order Component used to inject BlockEdit context to the diff --git a/blocks/block-edit/index.js b/blocks/block-edit/index.js index a2fe1cc730cb48..091e90ff827946 100644 --- a/blocks/block-edit/index.js +++ b/blocks/block-edit/index.js @@ -19,9 +19,18 @@ import { getBlockDefaultClassName, hasBlockSupport, } from '../api'; -import { withBlockEditContextProvider } from './context'; +import { BlockEditContextProvider } from './context'; export class BlockEdit extends Component { + constructor( props ) { + super( props ); + this.state = { + context: { + isSelected: props.isSelected, + }, + }; + } + getChildContext() { const { id: uid, @@ -38,6 +47,18 @@ export class BlockEdit extends Component { }; } + static getDerivedStateFromProps( nextProps, prevState ) { + if ( nextProps.isSelected === prevState.context.isSelected ) { + return null; + } + + return { + context: { + isSelected: nextProps.isSelected, + }, + }; + } + render() { const { name, attributes = {}, isSelected } = this.props; const blockType = getBlockType( name ); @@ -60,12 +81,14 @@ export class BlockEdit extends Component { // For backwards compatibility concerns adds a focus and setFocus prop // These should be removed after some time (maybe when merging to Core) return ( - + + + ); } } @@ -76,7 +99,6 @@ BlockEdit.childContextTypes = { }; export default compose( [ - withBlockEditContextProvider, withFilters( 'blocks.BlockEdit' ), withSelect( ( select ) => ( { postType: select( 'core/editor' ).getEditedPostAttribute( 'type' ), diff --git a/blocks/block-edit/test/index.js b/blocks/block-edit/test/index.js index 47a853fa373079..3564c499e18677 100644 --- a/blocks/block-edit/test/index.js +++ b/blocks/block-edit/test/index.js @@ -38,7 +38,7 @@ describe( 'BlockEdit', () => { const wrapper = shallow( ); - expect( wrapper.type() ).toBe( edit ); + expect( wrapper.find( edit ) ).toBePresent(); } ); it( 'should use save implementation of block as fallback', () => { @@ -51,7 +51,7 @@ describe( 'BlockEdit', () => { const wrapper = shallow( ); - expect( wrapper.type() ).toBe( save ); + expect( wrapper.find( save ) ).toBePresent(); } ); it( 'should combine the default class name with a custom one', () => { @@ -70,6 +70,6 @@ describe( 'BlockEdit', () => { ); - expect( wrapper.prop( 'className' ) ).toBe( 'wp-block-test-block my-class' ); + expect( wrapper.find( edit ) ).toHaveClassName( 'wp-block-test-block my-class' ); } ); } ); diff --git a/blocks/test/helpers/index.js b/blocks/test/helpers/index.js index b82bdb905c517d..f46573240df852 100644 --- a/blocks/test/helpers/index.js +++ b/blocks/test/helpers/index.js @@ -13,9 +13,6 @@ import { registerBlockType, } from '../..'; import { BlockEdit } from '../../block-edit'; -import { withBlockEditContextProvider } from '../../block-edit/context'; - -const BlockEditWithContext = withBlockEditContextProvider( BlockEdit ); export const blockEditRender = ( name, settings ) => { if ( ! getBlockType( name ) ) { @@ -24,7 +21,7 @@ export const blockEditRender = ( name, settings ) => { const block = createBlock( name ); return render( - Date: Mon, 16 Apr 2018 07:55:49 +0200 Subject: [PATCH 12/13] Blocks: Improve state handling for BlockEdit context --- blocks/block-edit/index.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/blocks/block-edit/index.js b/blocks/block-edit/index.js index 091e90ff827946..9ab2b6bb2450ce 100644 --- a/blocks/block-edit/index.js +++ b/blocks/block-edit/index.js @@ -24,11 +24,7 @@ import { BlockEditContextProvider } from './context'; export class BlockEdit extends Component { constructor( props ) { super( props ); - this.state = { - context: { - isSelected: props.isSelected, - }, - }; + this.state = {}; } getChildContext() { @@ -48,7 +44,7 @@ export class BlockEdit extends Component { } static getDerivedStateFromProps( nextProps, prevState ) { - if ( nextProps.isSelected === prevState.context.isSelected ) { + if ( nextProps.isSelected === get( prevState, [ 'context', 'isSelected' ] ) ) { return null; } From cf63e10ec54eacb1322e32a3377d85b0fc8de3d4 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Mon, 16 Apr 2018 08:37:06 +0200 Subject: [PATCH 13/13] Blocks: Addressed feedback related to BlockEditContext changes --- blocks/library/paragraph/index.js | 70 ++++++++++--------- .../test/__snapshots__/index.js.snap | 44 ++++++------ docs/deprecated.md | 1 - 3 files changed, 59 insertions(+), 56 deletions(-) diff --git a/blocks/library/paragraph/index.js b/blocks/library/paragraph/index.js index 55b9822f2e85c5..f776299fda0bde 100644 --- a/blocks/library/paragraph/index.js +++ b/blocks/library/paragraph/index.js @@ -226,40 +226,42 @@ class ParagraphBlock extends Component { /> - { - setAttributes( { - content: nextContent, - } ); - } } - onSplit={ insertBlocksAfter ? - ( before, after, ...blocks ) => { - setAttributes( { content: before } ); - insertBlocksAfter( [ - ...blocks, - createBlock( 'core/paragraph', { content: after } ), - ] ); - } : - undefined - } - onMerge={ mergeBlocks } - onReplace={ this.onReplace } - onRemove={ () => onReplace( [] ) } - placeholder={ placeholder || __( 'Add text or type / to add content' ) } - autocompleters={ autocompleters } - /> +
+ { + setAttributes( { + content: nextContent, + } ); + } } + onSplit={ insertBlocksAfter ? + ( before, after, ...blocks ) => { + setAttributes( { content: before } ); + insertBlocksAfter( [ + ...blocks, + createBlock( 'core/paragraph', { content: after } ), + ] ); + } : + undefined + } + onMerge={ mergeBlocks } + onReplace={ this.onReplace } + onRemove={ () => onReplace( [] ) } + placeholder={ placeholder || __( 'Add text or type / to add content' ) } + autocompleters={ autocompleters } + /> +
); } diff --git a/blocks/library/paragraph/test/__snapshots__/index.js.snap b/blocks/library/paragraph/test/__snapshots__/index.js.snap index 4350e0121dc5bc..0369b0add114df 100644 --- a/blocks/library/paragraph/test/__snapshots__/index.js.snap +++ b/blocks/library/paragraph/test/__snapshots__/index.js.snap @@ -3,29 +3,31 @@ exports[`core/paragraph block edit matches snapshot 1`] = `
-
-
+
+
-
-

+

- Add text or type / to add content -

+

+ Add text or type / to add content +

+
diff --git a/docs/deprecated.md b/docs/deprecated.md index 6f905f7f38c717..97b9d25eff1475 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -9,7 +9,6 @@ Gutenberg's deprecation policy is intended to support backwards-compatibility fo ## 2.7.0 - `wp.element.getWrapperDisplayName` function removed. Please use `wp.element.createHigherOrderComponent` instead. -- `isSelected` usage is no longer mandatory with `BlockControls`, `InspectorControls` and `RichText`. It is now handled by the editor internally to ensure that controls are visible only when block is selected. See updated docs: https://github.com/WordPress/gutenberg/blob/master/blocks/README.md#components. ## 2.6.0