From 455cdae52002dac62c8031a42f52eff011073c20 Mon Sep 17 00:00:00 2001 From: Joen Asmussen Date: Tue, 12 Jun 2018 10:47:22 +0200 Subject: [PATCH] Allow collapsing margins & adjust block toolbar This PR refactors how the block toolbar is positioned. Because we use sticky, the toolbar is part of the flow of the block itself. In this PR it uses translate to pull it out of the flow, making the positioning more resilient. The primary purpose of this PR is to allow margins to collapse. When two margins meet, and no borders or paddings are present, they collapse. I.e. a `p` with a 20px margin next to a similar `p` will have only 20px margin between them, not 40px, because the two siblings collapse to whichever margin is the largest. By allowing margins on blocks to collapse, we can make it easier to theme the editor to look like the frontend. --- core-blocks/columns/editor.scss | 1 + edit-post/assets/stylesheets/_variables.scss | 3 +- edit-post/assets/stylesheets/_z-index.scss | 1 + .../header/header-toolbar/style.scss | 21 ++- edit-post/components/visual-editor/style.scss | 18 +- editor/components/block-list/block.js | 7 +- editor/components/block-list/style.scss | 160 +++++++++++------- editor/components/block-mover/style.scss | 2 + .../components/block-settings-menu/style.scss | 2 + editor/components/block-toolbar/style.scss | 9 +- .../default-block-appender/style.scss | 50 +++--- 11 files changed, 172 insertions(+), 102 deletions(-) diff --git a/core-blocks/columns/editor.scss b/core-blocks/columns/editor.scss index 6688f057ca73b..39a29d7cc48af 100644 --- a/core-blocks/columns/editor.scss +++ b/core-blocks/columns/editor.scss @@ -1,6 +1,7 @@ // These margins make sure that nested blocks stack/overlay with the parent block chrome // This is sort of an experiment at making sure the editor looks as much like the end result as possible // Potentially the rules here can apply to all nested blocks and enable stacking, in which case it should be moved elsewhere +// Note that when using CSS grid, margins do not collapse on the container .wp-block-columns .editor-block-list__layout { margin-left: 0; margin-right: 0; diff --git a/edit-post/assets/stylesheets/_variables.scss b/edit-post/assets/stylesheets/_variables.scss index c8a14b37c19d0..8cbfd69427501 100644 --- a/edit-post/assets/stylesheets/_variables.scss +++ b/edit-post/assets/stylesheets/_variables.scss @@ -24,11 +24,12 @@ $admin-bar-height-big: 46px; $admin-sidebar-width: 160px; $admin-sidebar-width-big: 190px; $admin-sidebar-width-collapsed: 36px; +$empty-paragraph-height: $text-editor-font-size * 4; // Visuals $shadow-popover: 0 3px 30px rgba( $dark-gray-900, .1 ); $shadow-toolbar: 0 2px 10px rgba( $dark-gray-900, .1 ), 0 0 2px rgba( $dark-gray-900, .1 ); -$shadow-below-only: 0 5px 10px rgba( $dark-gray-900, .1 ), 0 2px 2px rgba( $dark-gray-900, .1 ); +$shadow-below-only: 0 5px 10px rgba( $dark-gray-900, .05 ), 0 2px 2px rgba( $dark-gray-900, .05 ); // Editor Widths $sidebar-width: 280px; diff --git a/edit-post/assets/stylesheets/_z-index.scss b/edit-post/assets/stylesheets/_z-index.scss index a4c704297de97..810b799433bcc 100644 --- a/edit-post/assets/stylesheets/_z-index.scss +++ b/edit-post/assets/stylesheets/_z-index.scss @@ -21,6 +21,7 @@ $z-layers: ( '.editor-block-switcher__menu': 5, '.components-popover__close': 5, '.editor-block-list__insertion-point': 5, + '.editor-inserter-with-shortcuts': 5, '.core-blocks-gallery-item__inline-menu': 20, '.editor-url-input__suggestions': 30, '.edit-post-header': 30, diff --git a/edit-post/components/header/header-toolbar/style.scss b/edit-post/components/header/header-toolbar/style.scss index fd6245e5dd299..3afa02aa5f7cf 100644 --- a/edit-post/components/header/header-toolbar/style.scss +++ b/edit-post/components/header/header-toolbar/style.scss @@ -1,4 +1,4 @@ -// hide all action buttons except the inserter on mobile +// Hide all action buttons except the inserter on mobile. .edit-post-header-toolbar > .components-button { display: none; @@ -18,15 +18,26 @@ } } +// Block toolbar when fixed to the top of the screen. .edit-post-header-toolbar__block-toolbar { - // stacked toolbar + // Stack toolbar below Editor Bar. position: absolute; top: $header-height; left: 0; right: 0; + width: 100%; background: $white; - border-bottom: 1px solid $light-gray-500; min-height: $block-toolbar-height; + border-bottom: 1px solid $light-gray-500; + + .editor-block-toolbar { + border-left: none; + } + + .editor-block-toolbar .components-toolbar { + border-top: none; + border-bottom: none; + } .is-sidebar-opened & { display: none; @@ -39,8 +50,8 @@ } } - // merge toolbars after this breakpoint - @include break-large { // we should try and lower this breakpoint through an ellipsis overflow feature + // Move toolbar into top Editor Bar. + @include break-large { padding-left: $item-spacing; position: static; left: auto; diff --git a/edit-post/components/visual-editor/style.scss b/edit-post/components/visual-editor/style.scss index 709b39468a323..7ddf0364bb7b7 100644 --- a/edit-post/components/visual-editor/style.scss +++ b/edit-post/components/visual-editor/style.scss @@ -2,6 +2,7 @@ position: relative; padding: 50px 0; + .editor-default-block-appender__content, // The default appender should match a single paragraph. &, & p { font-family: $editor-font; @@ -49,11 +50,18 @@ margin-right: -$block-side-ui-width; } - &[data-align="full"] > .editor-block-contextual-toolbar, - &[data-align="wide"] > .editor-block-contextual-toolbar { // Don't affect nested block toolbars. - max-width: $content-width + $parent-block-padding; // Add 1px border left and right. - margin-left: auto; - margin-right: auto; + // Center the block toolbar on wide and full-wide blocks. + &[data-align="full"] > .editor-block-list__block-edit > .editor-block-contextual-toolbar, + &[data-align="wide"] > .editor-block-list__block-edit > .editor-block-contextual-toolbar { // Don't affect nested block toolbars. + width: calc( 100% + #{ $parent-block-padding + $parent-block-padding + $border-width + $border-width } ); + height: 0px; // This collapses the container to an invisible element without margin. + text-align: center; + + .editor-block-toolbar { + max-width: $content-width + $block-padding + $block-padding; + width: 100%; + position: relative; + } } } diff --git a/editor/components/block-list/block.js b/editor/components/block-list/block.js index 2f411c3c6d007..7a1d41a6ed5bf 100644 --- a/editor/components/block-list/block.js +++ b/editor/components/block-list/block.js @@ -404,7 +404,8 @@ export class BlockListBlock extends Component { // Empty paragraph blocks should always show up as unselected. const showEmptyBlockSideInserter = ( isSelected || isHovered ) && isEmptyDefaultBlock; const showSideInserter = ( isSelected || isHovered ) && isEmptyDefaultBlock; - const shouldAppearSelected = ! showSideInserter && ( isSelected || hasSelectedInnerBlock ) && ! isTypingWithinBlock; + const shouldAppearSelected = ! showSideInserter && isSelected && ! isTypingWithinBlock; + const shouldAppearSelectedParent = ! showSideInserter && 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; @@ -423,6 +424,7 @@ export class BlockListBlock extends Component { const wrapperClassName = classnames( 'editor-block-list__block', { 'has-warning': ! isValid || !! error, 'is-selected': shouldAppearSelected, + 'is-selected-parent': shouldAppearSelectedParent, 'is-multi-selected': isMultiSelected, 'is-hovered': isHovered && ! isEmptyDefaultBlock, 'is-shared': isSharedBlock( blockType ), @@ -516,7 +518,6 @@ export class BlockListBlock extends Component { /> ) } { shouldShowBreadcrumb && } - { shouldShowContextualToolbar && } { isFirstMultiSelected && } - + { shouldShowContextualToolbar && } { isValid && mode === 'visual' && ( .editor-block-list__block-edit:before, &.is-selected > .editor-block-list__block-edit:before { // use opacity to work in various editor styles outline: $border-width solid $dark-opacity-light-500; - top: -$block-padding; - bottom: -$block-padding; .is-dark-theme & { outline-color: $light-opacity-light-500; @@ -403,7 +405,7 @@ // Mover and settings above > .editor-block-mover, > .editor-block-settings-menu { - top: -$block-side-ui-width - $border-width; // This moves the menu up by the height of the button + border. + top: -$block-side-ui-width - $block-padding - $border-width; bottom: auto; min-height: 0; height: auto; @@ -416,11 +418,11 @@ } > .editor-block-mover { - left: 10px; + left: $parent-block-padding; } > .editor-block-settings-menu { - right: 10px; + right: $parent-block-padding; width: $block-side-ui-width * 2; flex-direction: row; } @@ -528,7 +530,7 @@ /** - * Left and right side UI + * Left and right side UI, & Unified toolbar on Mobile */ .editor-block-list__block { @@ -537,12 +539,17 @@ > .editor-block-settings-menu, > .editor-block-mover { position: absolute; - top: 0; width: $block-side-ui-width + $block-side-ui-clearance; height: 100%; // stretch to fill half of the available space to increase hoverable area max-height: $block-side-ui-width * 4; // stretch to fill half of the available space to increase hoverable area } + // Position depending on whether selected or not. + > .editor-block-settings-menu, + > .editor-block-mover { + top: -$block-padding - $border-width; + } + // Elevate when selected or hovered @include break-small() { &.is-multi-selected, @@ -606,11 +613,13 @@ .editor-block-list__block-mobile-toolbar { display: flex; flex-direction: row; - margin-top: $item-spacing + $block-toolbar-height; // Make room for the height of the block toolbar above. + margin-top: $item-spacing + $block-toolbar-height - $block-padding; // Make room for the height of the block toolbar above. margin-right: -$block-padding; - margin-bottom: -$block-padding - $border-width; margin-left: -$block-padding; border-top: $border-width solid $light-gray-500; + height: $block-toolbar-height; + + transform: translateY( #{ $block-padding + $border-width } ); @include break-small() { display: none; @@ -618,7 +627,7 @@ // Show a shadow below the selected block to imply separation. box-shadow: $shadow-below-only; - @include break-mobile() { + @include break-small() { box-shadow: none; } @@ -674,6 +683,7 @@ /** * In-Canvas Inserter */ + .editor-block-list .editor-inserter { margin: $item-spacing; cursor: move;/* Fallback for IE/Edge < 14 */ @@ -703,13 +713,15 @@ } position: absolute; - top: 0; bottom: auto; left: 0; right: 0; - height: $block-padding * 2; // Matches the whole empty space between two blocks + height: $block-padding * 2; // Matches the whole empty space between two blocks. justify-content: center; + // Position above block. + top: -$block-padding; + // Show a clickable plus. .editor-block-list__insertion-point-button { margin-top: -4px; @@ -788,7 +800,7 @@ * Block Toolbar */ - .editor-block-list__block .editor-block-contextual-toolbar { +.editor-block-list__block .editor-block-contextual-toolbar { position: sticky; z-index: z-index( '.editor-block-contextual-toolbar' ); white-space: nowrap; @@ -798,22 +810,45 @@ // Position toolbar below the block on mobile. position: absolute; - bottom: $block-toolbar-height; - left: $block-padding; - right: $block-padding; + bottom: $block-toolbar-height - $block-padding; + left: 0; + right: 0; + + // Paint the borders on the toolbar itself on mobile. + border-top: 1px solid $light-gray-500; + .components-toolbar { + border-top: none; + border-bottom: none; + + } + + @include break-small() { + border-top: none; + .components-toolbar { + border-top: 1px solid $light-gray-500; + border-bottom: 1px solid $light-gray-500; + } + } // Position the contextual toolbar above the block. - @include break-mobile() { + @include break-small() { position: sticky; bottom: auto; left: auto; right: auto; - margin-top: -$block-toolbar-height - $border-width; - margin-bottom: $block-padding + $border-width; - } + box-shadow: none; - @include break-small() { - top: -$border-width; + // This is an important one. Because the toolbar is sticky, it's part of the flow. + // It behaves as relative, in other words, until it reaches an edge and then behaves as fixed. + // But by applying a float, we take it out of this flow. The benefit is that we don't need to compensate for margins. + // In turn, this allows margins on sibling elements to collapse to parent elements. + float: left; + + // Move the block toolbar out of the flow using translate. + transform: translateY( -$block-toolbar-height -$block-padding -$border-width ); + + // Compensate for translate, so the sticky sticks to the top. + top: $block-toolbar-height + $block-padding; } // Floated items have special needs for the contextual toolbar position. @@ -828,13 +863,13 @@ margin-right: -$block-padding - $border-width; @include break-small() { - margin-left: -$parent-block-padding - $block-side-ui-width - $border-width; - margin-right: -$parent-block-padding - $block-side-ui-width - $border-width; + margin-left: -$parent-block-padding - $border-width; + margin-right: -$parent-block-padding - $border-width; // Position toolbar for nested contexts. .editor-block-list__block & { - margin-left: -$block-padding - $block-side-ui-width - $border-width; - margin-right: -$block-padding - $block-side-ui-padding - $border-width; + margin-left: -$block-padding - $border-width; + margin-right: -$block-padding - $border-width; } // Except for wide elements, this causes a horizontal scrollbar. @@ -848,13 +883,11 @@ & > * { pointer-events: auto; } - } +// Position the block toolbar when contextual. .editor-block-contextual-toolbar .editor-block-toolbar { width: 100%; - background: $white; - border: $border-width solid $light-gray-500; // Hide right border on desktop, where the .components-toolbar instead has a right border. @include break-small() { @@ -862,8 +895,10 @@ } // This prevents floats from messing up the position. - position: absolute; - left: 0; + @include break-small() { + position: absolute; + left: 0; + } .editor-block-list__block[data-align="right"] & { left: auto; @@ -878,18 +913,15 @@ /** * Hover label */ - .editor-block-list__breadcrumb { + +.editor-block-list__breadcrumb { position: absolute; line-height: 1; z-index: z-index( '.editor-block-list__breadcrumb' ); - // Position in the top right of the border - right: -$block-side-ui-clearance; - - @include break-small() { - right: -$block-parent-side-ui-clearance; - } - top: 0; + // Position in the top right of the border. + right: -$block-parent-side-ui-clearance; + top: -$block-padding - $border-width; // Nested .editor-block-list__block-edit & { diff --git a/editor/components/block-mover/style.scss b/editor/components/block-mover/style.scss index ddea50def9bfd..eca87d7c7c6b6 100644 --- a/editor/components/block-mover/style.scss +++ b/editor/components/block-mover/style.scss @@ -1,4 +1,6 @@ .editor-block-mover { + min-height: $empty-paragraph-height; + opacity: 0; &.is-visible { diff --git a/editor/components/block-settings-menu/style.scss b/editor/components/block-settings-menu/style.scss index dfad9afba418d..9d1f5226f9e5f 100644 --- a/editor/components/block-settings-menu/style.scss +++ b/editor/components/block-settings-menu/style.scss @@ -1,4 +1,6 @@ .editor-block-settings-menu { + min-height: $empty-paragraph-height; + line-height: 1; opacity: 0; diff --git a/editor/components/block-toolbar/style.scss b/editor/components/block-toolbar/style.scss index 1fedaad2e9d6f..dee5d69ddf12a 100644 --- a/editor/components/block-toolbar/style.scss +++ b/editor/components/block-toolbar/style.scss @@ -2,7 +2,6 @@ display: inline-flex; flex-grow: 1; width: 100%; - background: $white; overflow: auto; // Allow horizontal scrolling on mobile. position: relative; @@ -11,8 +10,14 @@ overflow: inherit; } + // Show a left border on the parent container. + border-left: $border-width solid $light-gray-500; + + // The component is born with a border, but we only need some of them. .components-toolbar { - border: none; + border: 0; + border-top: $border-width solid $light-gray-500; + border-bottom: $border-width solid $light-gray-500; // Add a right border to show as separator in the block toolbar. border-right: $border-width solid $light-gray-500; diff --git a/editor/components/default-block-appender/style.scss b/editor/components/default-block-appender/style.scss index 3a5c27b33580e..72a0f478c087c 100644 --- a/editor/components/default-block-appender/style.scss +++ b/editor/components/default-block-appender/style.scss @@ -1,26 +1,19 @@ -$empty-paragraph-height: $text-editor-font-size * 4; - .editor-default-block-appender { input[type=text].editor-default-block-appender__content { // needs specificity border: none; background: none; box-shadow: none; display: block; - margin: 0; + margin-left: 0; + margin-right: 0; max-width: none; // fixes a bleed issue from the admin - padding: $block-padding; - font-size: $editor-font-size; - font-family: $editor-font; cursor: text; width: 100%; - font-family: $editor-font; outline: 1px solid transparent; transition: 0.2s outline; - // match the height of an empty paragraph - // to prevent margins from collapsing we add 1px padding top and bottom to both .editor-block-list__block and .editor-block-list__block-edit (coming to a total of 4px extra) - // @todo: revisit when we allow margins to collapse - height: $empty-paragraph-height + 4px; + // Emulate the dimensions of a paragraph block. + padding: 0 #{ $block-padding + $border-width }; // use opacity to work in various editor styles color: $dark-opacity-300; @@ -30,7 +23,7 @@ $empty-paragraph-height: $text-editor-font-size * 4; } } - // Show quick insertion icons faded until hover + // Show quick insertion icons faded until hover. .editor-inserter-with-shortcuts { opacity: .5; transition: opacity 0.2s; @@ -49,7 +42,7 @@ $empty-paragraph-height: $text-editor-font-size * 4; opacity: 1; } - // Show the inserter if mousing over or there is a tip + // Show the inserter if mousing over or there is a tip. &:not( .has-tip ) { .editor-inserter__toggle:not( [aria-expanded="true"] ) { opacity: 0; @@ -60,18 +53,32 @@ $empty-paragraph-height: $text-editor-font-size * 4; } } - // Dropzone + // Dropzone. .components-drop-zone__content-icon { display: none; } } -// Left side inserter icon +// Quick shortcuts, left and right. +.editor-block-list__empty-block-inserter, // Empty paragraph +.editor-default-block-appender .editor-inserter, // Empty appender +.editor-inserter-with-shortcuts { // Right side quick shortcuts + position: absolute; + top: 0; + + // Change the size of the buttons to match that of the default paragraph height. + .components-icon-button { + width: $block-side-ui-width; + height: $block-side-ui-width; + padding: 4px; + margin-right: 12px; + } +} + +// Left side. .editor-block-list__empty-block-inserter, .editor-default-block-appender .editor-inserter { - position: absolute; - top: $item-spacing; - right: $item-spacing; // show on the right on mobile + right: $item-spacing; // Show to the right on mobile. @include break-small { left: -$block-side-ui-width - $block-padding - $block-side-ui-clearance; @@ -101,12 +108,11 @@ $empty-paragraph-height: $text-editor-font-size * 4; } } -// Quick block insertion icons on the right +// Quick block insertion icons on the right side. .editor-inserter-with-shortcuts { - position: absolute; - top: $item-spacing; right: $block-padding; - display: none; + display: none; // Don't show on mobile. + z-index: z-index( '.editor-inserter-with-shortcuts' ); // Elevate above the sibling inserter. @include break-small { right: 0;