Skip to content

Commit

Permalink
Try a new hover and select approach to improve nested block selection (
Browse files Browse the repository at this point in the history
…#6773)

* Alternate hover approach WIP

* Show outline on parent blocks

* Block Breadcrumb: Render arrow as RTL compatible

* Writing Flow: Force tab stop at focusable wrapper when inner blocks exist

* Block List: Remove unused variables

* Inner Blocks: Show overlay for small screen, unselected root block

* Try a refined approach to drag and drop

This commit changes how drag and drop works, so that nested blocks do not have any invisible side affordance for the grabby handle. You can still use the inner padding for dragging, and in a separate enhancement we should make the hover label draggable.

This makes it easier to select the parent block, by allowing you to click the available space below the side UI to select the parent.

Kinda.

There is still an affordance for hovering the side of the block to access the side UI (movers, settings, trash), and this extends the height of 4 stacked buttons on the side. If you hover the area below that, yes you can click the thing below.

This is a balancing act, and I'd like for you to try this. The branch has been thoroughly rebased and squashed prior to this to make it easy to undo this change if it doesn't feel right.

* Fix the empty appender in more than columns block

The empty appender, when on mobile, or in a nested block, shows a reduced version. Previously this was only in the columns block, now it's any block that uses nested children.

* Tune hover label again.

* Fix rebase issue.

* hide outlines from empty default blocks

* Fix paddings and hover breadcrumb on classic block.

* Fade the title block border.

* Address feedback.

Add border to switcher component instead.

Add comment to explain z index.
  • Loading branch information
jasmussen authored and youknowriad committed Jun 1, 2018
1 parent 17f1963 commit 5a57e6f
Show file tree
Hide file tree
Showing 28 changed files with 596 additions and 262 deletions.
15 changes: 0 additions & 15 deletions core-blocks/columns/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,3 @@
margin-right: $block-side-ui-padding;
}
}

// Hide appender shortcuts in columns
// @todo This essentially duplicates the mobile styles for the appender component
// It would be nice to be able to use element queries in that component instead https://github.com/tomhodgins/element-queries-spec
.wp-block-columns {
.editor-inserter-with-shortcuts {
display: none;
}

.editor-block-list__empty-block-inserter,
.editor-default-block-appender .editor-inserter {
left: auto;
right: $item-spacing;
}
}
9 changes: 6 additions & 3 deletions core-blocks/columns/style.scss
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
.wp-block-columns {
display: grid;
grid-auto-flow: dense;

.editor-inner-blocks {
display: grid;
grid-auto-flow: dense;
}

@for $i from 2 through 6 {
&.has-#{ $i }-columns {
&.has-#{ $i }-columns .editor-inner-blocks {
grid-auto-columns: #{ 100% / $i };
}
}
Expand Down
4 changes: 2 additions & 2 deletions core-blocks/freeform/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
}

// Don't show block type label for classic block
&.is-hovered .editor-block-breadcrumb {
&.is-hovered .editor-block-list__breadcrumb {
display: none;
}
}
Expand All @@ -140,7 +140,7 @@ div[data-type="core/freeform"] .editor-block-contextual-toolbar + div {

.freeform-toolbar {
width: auto;
margin: -$block-padding;
margin: #{ -$block-padding } #{ -$parent-block-padding };
margin-bottom: $block-padding;
position: sticky;
z-index: z-index( '.freeform-toolbar' );
Expand Down
4 changes: 2 additions & 2 deletions edit-post/assets/stylesheets/_animations.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
animation: slide_in_right 0.1s forwards;
}

@mixin fade_in {
animation: fade-in 0.3s ease-out;
@mixin fade_in( $speed: 0.2s ) {
animation: fade-in $speed ease-out;
animation-fill-mode: forwards;
}
1 change: 1 addition & 0 deletions edit-post/assets/stylesheets/_colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ $blue-medium-300: #66C6E4;
$blue-medium-200: #BFE7F3;
$blue-medium-100: #E5F5FA;
$blue-medium-highlight: #b3e7fe;
$blue-medium-focus: #007cba;

// Alert colors
$alert-yellow: #f0b849;
Expand Down
15 changes: 0 additions & 15 deletions edit-post/assets/stylesheets/_mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,6 @@
}
}

/**
* Editor Width mixin
*
* This mixin seeks to take the vinegar out of the responsive alignments in the editor.
*/

@mixin editor-width( $width ) {
@media ( min-width: #{ ( $width ) } ) {
@content;
}
}

$content-width-padding: $content-width + $block-side-ui-padding + $block-side-ui-padding;
$float-margin: calc( 50% - #{ $content-width-padding / 2 } );

/**
* Button states and focus styles
*/
Expand Down
14 changes: 8 additions & 6 deletions edit-post/assets/stylesheets/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ $inserter-tabs-height: 36px;
$block-toolbar-height: 37px;

// Blocks
$block-padding: 14px;
$block-mover-margin: 18px;
$block-spacing: 4px;
$block-side-ui-padding: 36px;
$block-side-ui-width: 28px; // The side UI max height matches a single line of text, 56px. 28px is half, allowing 2 mover arrows
$block-side-ui-clearance: 2px;
$parent-block-padding: 28px; // padding of top level blocks, should be larger than $block-padding, otherwise a user can't select the parent from a child
$block-padding: 14px; // padding of nested blocks
$block-spacing: 4px; // vertical space between blocks

$block-side-ui-width: 28px; // width of the side UI, matches half matches half of a single line of text, so two buttons stacke matches 1
$block-side-ui-clearance: 2px; // space between side UI and block
$block-side-ui-padding: $block-side-ui-width + $block-side-ui-clearance; // total space used to accommodate side UI
$block-parent-side-ui-clearance: $parent-block-padding - $block-padding; // space between side UI and block on top level blocks

// Buttons & UI Widgets
$button-style__radius-roundrect: 4px;
Expand Down
9 changes: 9 additions & 0 deletions edit-post/assets/stylesheets/_z-index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ $z-layers: (
'.editor-block-list__block {core/image aligned left or right}': 20,
'.editor-block-list__block {core/image aligned wide or fullwide}': 20,
'.freeform-toolbar': 10,
'.editor-block-list__breadcrumb': 1,
'.editor-warning': 1,
'.components-form-toggle__input': 1,
'.editor-inserter__tabs': 1,
Expand All @@ -26,6 +27,10 @@ $z-layers: (
'.core-blocks-button__inline-link .editor-url-input__suggestions': 6, // URL suggestions for button block above sibling inserter
'.wp-block-image__resize-handlers': 1, // Resize handlers above sibling inserter

// Side UI active buttons
'.editor-block-settings-remove': 1,
'.editor-block-mover__control': 1,

// Should have lower index than anything else positioned inside the block containers
'.editor-block-list__block-draggable': 0,

Expand All @@ -44,6 +49,10 @@ $z-layers: (
// should overlap most block content.
'.editor-block-list__block.is-{selected,hovered} .editor-block-{settings-menu,mover}': 80,

// Small screen inner blocks overlay must be displayed above drop zone,
// settings menu, and movers.
'.editor-inner-blocks__small-screen-overlay:after': 120,

// Show sidebar above wp-admin navigation bar for mobile viewports:
// #wpadminbar { z-index: 99999 }
'.edit-post-sidebar': 100000,
Expand Down
8 changes: 4 additions & 4 deletions edit-post/components/visual-editor/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@

@include break-small() {
.editor-block-list__block-edit {
margin-left: -$block-side-ui-padding;
margin-right: -$block-side-ui-padding;
margin-left: -$block-side-ui-width;
margin-right: -$block-side-ui-width;
}

&[data-align="full"] > .editor-block-contextual-toolbar,
Expand Down Expand Up @@ -87,8 +87,8 @@
// include space for side UI on desktops
@include break-small() {
> div {
margin-left: -$block-side-ui-padding - 1px;
margin-right: -$block-side-ui-padding - 1px;
margin-left: -$block-side-ui-width;
margin-right: -$block-side-ui-width;
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions editor/components/block-edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export class BlockEdit extends Component {
} = this.props;

return {
uid,
BlockList: createInnerBlockList( uid ),
canUserUseUnfilteredHTML: get( user.data, [
'capabilities',
Expand Down Expand Up @@ -76,6 +77,7 @@ export class BlockEdit extends Component {
}

BlockEdit.childContextTypes = {
uid: noop,
BlockList: noop,
canUserUseUnfilteredHTML: noop,
};
Expand Down
16 changes: 10 additions & 6 deletions editor/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ export class BlockListBlock extends Component {
isLargeViewport,
isEmptyDefaultBlock,
isPreviousBlockADefaultEmptyBlock,
hasSelectedInnerBlock,
} = this.props;
const isHovered = this.state.isHovered && ! isMultiSelecting;
const { name: blockName, isValid } = block;
Expand All @@ -424,14 +425,14 @@ export class BlockListBlock extends Component {

// If the block is selected and we're typing the block should not appear.
// Empty paragraph blocks should always show up as unselected.
const isSelectedNotTyping = isSelected && ! isTypingWithinBlock;
const showEmptyBlockSideInserter = ( isSelected || isHovered ) && isEmptyDefaultBlock;
const shouldAppearSelected = ! showEmptyBlockSideInserter && isSelectedNotTyping;
const showSideInserter = ( isSelected || isHovered ) && isEmptyDefaultBlock;
const shouldAppearSelected = ! showSideInserter && ( isSelected || hasSelectedInnerBlock ) && ! isTypingWithinBlock;
// We render block movers and block settings to keep them tabbale even if hidden
const shouldRenderMovers = ( isSelected || hoverArea === 'left' ) && ! showEmptyBlockSideInserter && ! isMultiSelecting && ! isMultiSelected && ! isTypingWithinBlock;
const shouldRenderBlockSettings = ( isSelected || hoverArea === 'right' ) && ! isMultiSelecting && ! isMultiSelected && ! isTypingWithinBlock;
const shouldShowBreadcrumb = isHovered;
const shouldShowContextualToolbar = shouldAppearSelected && isValid && ( ! hasFixedToolbar || ! isLargeViewport );
const shouldShowBreadcrumb = isHovered && ! isEmptyDefaultBlock;
const shouldShowContextualToolbar = ! showSideInserter && isSelected && ! isTypingWithinBlock && isValid && ( ! hasFixedToolbar || ! isLargeViewport );
const shouldShowMobileToolbar = shouldAppearSelected;
const { error, dragging } = this.state;

Expand All @@ -446,7 +447,7 @@ export class BlockListBlock extends Component {
'has-warning': ! isValid || !! error,
'is-selected': shouldAppearSelected,
'is-multi-selected': isMultiSelected,
'is-hovered': isHovered,
'is-hovered': isHovered && ! isEmptyDefaultBlock,
'is-shared': isSharedBlock( blockType ),
'is-hidden': dragging,
'is-typing': isTypingWithinBlock,
Expand Down Expand Up @@ -620,8 +621,10 @@ const applyWithSelect = withSelect( ( select, { uid, rootUID } ) => {
isSelectionEnabled,
getSelectedBlocksInitialCaretPosition,
getEditorSettings,
hasSelectedInnerBlock,
} = select( 'core/editor' );
const isSelected = isBlockSelected( uid );
const isParentOfSelectedBlock = hasSelectedInnerBlock( uid );
const { templateLock, hasFixedToolbar } = getEditorSettings();
const block = getBlock( uid );
const previousBlockUid = getPreviousBlockUid( uid );
Expand All @@ -632,9 +635,10 @@ const applyWithSelect = withSelect( ( select, { uid, rootUID } ) => {
isMultiSelected: isBlockMultiSelected( uid ),
isFirstMultiSelected: isFirstMultiSelectedBlock( uid ),
isMultiSelecting: isMultiSelecting(),
hasSelectedInnerBlock: isParentOfSelectedBlock,
// We only care about this prop when the block is selected
// Thus to avoid unnecessary rerenders we avoid updating the prop if the block is not selected.
isTypingWithinBlock: isSelected && isTyping(),
isTypingWithinBlock: ( isSelected || isParentOfSelectedBlock ) && isTyping(),
order: getBlockIndex( uid, rootUID ),
meta: getEditedPostAttribute( 'meta' ),
mode: getBlockMode( uid ),
Expand Down
38 changes: 9 additions & 29 deletions editor/components/block-list/breadcrumb.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { compose, Component } from '@wordpress/element';
import { IconButton, Toolbar } from '@wordpress/components';
import { withDispatch, withSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { compose, Component, Fragment } from '@wordpress/element';
import { Toolbar } from '@wordpress/components';
import { withSelect } from '@wordpress/data';

/**
* Internal dependencies
Expand Down Expand Up @@ -53,22 +47,16 @@ export class BlockBreadcrumb extends Component {
}

render( ) {
const { uid, rootUID, selectRootBlock, isHidden } = this.props;
const { isFocused } = this.state;
const { uid, rootUID } = this.props;

return (
<div className={ classnames( 'editor-block-list__breadcrumb', {
'is-visible': ! isHidden || isFocused,
} ) }>
<div className={ 'editor-block-list__breadcrumb' }>
<Toolbar>
{ rootUID && (
<IconButton
onClick={ selectRootBlock }
onFocus={ this.onFocus }
onBlur={ this.onBlur }
label={ __( 'Select parent block' ) }
icon="arrow-left-alt"
/>
<Fragment>
<BlockTitle uid={ rootUID } />
<span className="editor-block-list__descendant-arrow" />
</Fragment>
) }
<BlockTitle uid={ uid } />
</Toolbar>
Expand All @@ -86,12 +74,4 @@ export default compose( [
rootUID: getBlockRootUID( uid ),
};
} ),
withDispatch( ( dispatch, ownProps ) => {
const { rootUID } = ownProps;
const { selectBlock } = dispatch( 'core/editor' );

return {
selectRootBlock: () => selectBlock( rootUID ),
};
} ),
] )( BlockBreadcrumb );
Loading

0 comments on commit 5a57e6f

Please sign in to comment.