Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add block inspector to the widget screen #16203

Merged
merged 1 commit into from
Jun 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions packages/block-editor/src/components/block-inspector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@ import InspectorControls from '../inspector-controls';
import InspectorAdvancedControls from '../inspector-advanced-controls';
import BlockStyles from '../block-styles';
import MultiSelectionInspector from '../multi-selection-inspector';

const BlockInspector = ( { selectedBlockClientId, selectedBlockName, blockType, count, hasBlockStyles } ) => {
const BlockInspector = ( {
blockType,
count,
hasBlockStyles,
selectedBlockClientId,
selectedBlockName,
showNoBlockSelectedMessage = true,
} ) => {
if ( count > 1 ) {
return <MultiSelectionInspector />;
}
Expand All @@ -33,7 +39,14 @@ const BlockInspector = ( { selectedBlockClientId, selectedBlockName, blockType,
* because we want the user to focus on the unregistered block warning, not block settings.
*/
if ( ! blockType || ! selectedBlockClientId || isSelectedBlockUnregistered ) {
return <span className="editor-block-inspector__no-blocks block-editor-block-inspector__no-blocks">{ __( 'No block selected.' ) }</span>;
if ( showNoBlockSelectedMessage ) {
return (
<span className="editor-block-inspector__no-blocks block-editor-block-inspector__no-blocks">
{ __( 'No block selected.' ) }
</span>
);
}
return null;
}

return (
Expand Down
6 changes: 5 additions & 1 deletion packages/edit-widgets/src/components/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { navigateRegions, Popover, SlotFillProvider } from '@wordpress/components';
import {
navigateRegions,
Popover,
SlotFillProvider,
} from '@wordpress/components';

/**
* Internal dependencies
Expand Down
10 changes: 8 additions & 2 deletions packages/edit-widgets/src/components/sidebar/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/**
* WordPress dependencies
*/
import { Panel } from '@wordpress/components';
import { createSlotFill, Panel } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

export const { Fill: BlockSidebarFill, Slot: BlockSidebarSlot } = createSlotFill( 'EditWidgetsBlockSidebar' );

function Sidebar() {
return (
<div
Expand All @@ -12,9 +14,13 @@ function Sidebar() {
aria-label={ __( 'Widgets advanced settings' ) }
tabIndex="-1"
>
<Panel header={ __( 'Block Areas' ) } />
<Panel header={ __( 'Block Areas' ) }>
<BlockSidebarSlot bubblesVirtually />
</Panel>
</div>
);
}

Sidebar.Inspector = BlockSidebarFill;

export default Sidebar;
4 changes: 4 additions & 0 deletions packages/edit-widgets/src/components/sidebar/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@
background: $light-gray-200;
}
}

.block-editor-block-inspector__card {
margin: 0;
}
}
24 changes: 21 additions & 3 deletions packages/edit-widgets/src/components/widget-area/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,20 @@ import { uploadMedia } from '@wordpress/media-utils';
import { compose } from '@wordpress/compose';
import { Panel, PanelBody } from '@wordpress/components';
import {
BlockInspector,
BlockEditorProvider,
BlockList,
ObserveTyping,
WritingFlow,
ObserveTyping,
} from '@wordpress/block-editor';
import { withDispatch, withSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import Sidebar from '../sidebar';
import SelectionObserver from './selection-observer';

function getBlockEditorSettings( blockEditorSettings, hasUploadPermissions ) {
if ( ! hasUploadPermissions ) {
return blockEditorSettings;
Expand All @@ -38,10 +45,12 @@ function getBlockEditorSettings( blockEditorSettings, hasUploadPermissions ) {
function WidgetArea( {
blockEditorSettings,
blocks,
hasUploadPermissions,
initialOpen,
isSelectedArea,
onBlockSelected,
updateBlocks,
widgetAreaName,
hasUploadPermissions,
} ) {
const settings = useMemo(
() => getBlockEditorSettings( blockEditorSettings, hasUploadPermissions ),
Expand All @@ -59,6 +68,13 @@ function WidgetArea( {
onChange={ updateBlocks }
settings={ settings }
>
<SelectionObserver
isSelectedArea={ isSelectedArea }
onBlockSelected={ onBlockSelected }
/>
<Sidebar.Inspector>
<BlockInspector showNoBlockSelectedMessage={ false } />
</Sidebar.Inspector>
<WritingFlow>
<ObserveTyping>
<BlockList />
Expand Down Expand Up @@ -88,7 +104,9 @@ export default compose( [
withDispatch( ( dispatch, { id } ) => {
return {
updateBlocks( blocks ) {
const { updateBlocksInWidgetArea } = dispatch( 'core/edit-widgets' );
const {
updateBlocksInWidgetArea,
} = dispatch( 'core/edit-widgets' );
updateBlocksInWidgetArea( id, blocks );
},
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* WordPress dependencies
*/
import { Component } from '@wordpress/element';
import { compose } from '@wordpress/compose';
import { withSelect, withDispatch } from '@wordpress/data';

/**
* Component which calls onBlockSelected prop when a block becomes selected. It
* can be used to ensuring that only one block appears as selected
* when multiple editors exist in a page.
*
* @type {WPComponent}
*/

class SelectionObserver extends Component {
componentDidUpdate( prevProps ) {
const {
hasSelectedBlock,
onBlockSelected,
isSelectedArea,
clearSelectedBlock,
} = this.props;

if ( hasSelectedBlock && ! prevProps.hasSelectedBlock ) {
onBlockSelected();
}

if ( ! isSelectedArea && prevProps.isSelectedArea ) {
clearSelectedBlock();
}
}

render() {
return null;
}
}

export default compose( [
withSelect( ( select ) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

useSelect, useDispatch? ;)

Copy link
Member Author

Choose a reason for hiding this comment

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

I tried to use hooks for this component but hooks did not work as expected, I always got unexpected results.
I tried to use a simple version where I relied on effects that execute when prop changes, and I also tried a usePrevious hook https://usehooks.com/usePrevious/ that allowed an implementation almost equal to this class component version, and both versions did not work properly. It is a very strange case I may be missing something.

const { hasSelectedBlock } = select( 'core/block-editor' );

return {
hasSelectedBlock: hasSelectedBlock(),
};
} ),
withDispatch( ( dispatch ) => {
const { clearSelectedBlock } = dispatch( 'core/block-editor' );

return {
clearSelectedBlock,
};
} ),
] )( SelectionObserver );
11 changes: 11 additions & 0 deletions packages/edit-widgets/src/components/widget-areas/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* WordPress dependencies
*/
import { useMemo, useState } from '@wordpress/element';
import { compose } from '@wordpress/compose';
import { withSelect } from '@wordpress/data';

Expand All @@ -10,8 +11,18 @@ import { withSelect } from '@wordpress/data';
import WidgetArea from '../widget-area';

function WidgetAreas( { areas, blockEditorSettings } ) {
const [ selectedArea, setSelectedArea ] = useState( 0 );
Copy link
Contributor

Choose a reason for hiding this comment

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

do we really need this here? It feels like this could be local state for WidgetArea

Copy link
Member Author

Choose a reason for hiding this comment

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

The widget area controls which of the areas contains a selected block, when a new area is selected other becomes unselected, each WidgetArea is a sibling of each other and siblings can not "communicate" between each other. This local state in WidgetAreas that is the parent of each WidgetArea allows the WidgetArea components to communicate with each other, when one becomes selected the others become unselected and the corresponding effects get executed, I don't think is possible to make this state part of the WidgetArea component.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok makes sense.

const onBlockSelectedInArea = useMemo(
() => areas.map( ( value, index ) => ( () => {
setSelectedArea( index );
} ) ),
[ areas, setSelectedArea ]
);

return areas.map( ( { id }, index ) => (
<WidgetArea
isSelectedArea={ index === selectedArea }
onBlockSelected={ onBlockSelectedInArea[ index ] }
blockEditorSettings={ blockEditorSettings }
key={ id }
id={ id }
Expand Down