From ec4e9bc5de3c9979fc05aff68eaf0211eb112463 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. --- components/toolbar/style.scss | 7 +- 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 | 20 +- edit-post/components/visual-editor/style.scss | 28 ++- editor/components/block-list/block.js | 7 +- editor/components/block-list/style.scss | 195 +++++++++++------- editor/components/block-mover/style.scss | 2 + .../components/block-settings-menu/style.scss | 2 + editor/components/block-toolbar/style.scss | 19 +- .../default-block-appender/style.scss | 51 ++--- 12 files changed, 216 insertions(+), 120 deletions(-) diff --git a/components/toolbar/style.scss b/components/toolbar/style.scss index f827b169fa05e..5afce2004382d 100644 --- a/components/toolbar/style.scss +++ b/components/toolbar/style.scss @@ -7,7 +7,12 @@ div.components-toolbar { &> div { - display: inline-flex; + // IE11 does not support `position: sticky`, or Flex very well, so use block. + display: inline-block; + @supports ( position: sticky ) { + display: inline-flex; + } + margin: 0; } 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 fe0c59226c649..ee31723bacb85 100644 --- a/edit-post/assets/stylesheets/_z-index.scss +++ b/edit-post/assets/stylesheets/_z-index.scss @@ -20,6 +20,7 @@ $z-layers: ( '.editor-block-contextual-toolbar': 21, '.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..41d08213520eb 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,25 @@ } } +// 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; 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 +49,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 9e60e86a2bb52..df4ae93128768 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; @@ -50,11 +51,28 @@ 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. + // Use specific selector to not affect nested block toolbars. + &[data-align="wide"] > .editor-block-list__block-edit > .editor-block-contextual-toolbar, + &[data-align="full"] > .editor-block-list__block-edit > .editor-block-contextual-toolbar { + 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; + } + } + + // The centering math changes when a fullwide image doesn't have block padding. + &[data-align="full"] > .editor-block-list__block-edit > .editor-block-contextual-toolbar { + width: calc( 100% + #{ $block-padding + $block-padding } ); + + .editor-block-toolbar { + max-width: $content-width - $border-width - $border-width; + } } } diff --git a/editor/components/block-list/block.js b/editor/components/block-list/block.js index 2284d5f335404..2732c4075178f 100644 --- a/editor/components/block-list/block.js +++ b/editor/components/block-list/block.js @@ -401,7 +401,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; @@ -420,6 +421,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 ), @@ -513,7 +515,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; @@ -406,7 +408,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; @@ -419,11 +421,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; } @@ -531,7 +533,7 @@ /** - * Left and right side UI + * Left and right side UI, & Unified toolbar on Mobile */ .editor-block-list__block { @@ -540,12 +542,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, @@ -609,11 +616,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; @@ -621,7 +630,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; } @@ -677,6 +686,7 @@ /** * In-Canvas Inserter */ + .editor-block-list .editor-inserter { margin: $item-spacing; cursor: move;/* Fallback for IE/Edge < 14 */ @@ -706,13 +716,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,10 +800,10 @@ /** - * Block Toolbar + * Block Toolbar when contextual. */ - .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; @@ -801,29 +813,23 @@ // 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; - @include break-small() { - top: -$border-width; - } + // Paint the borders on the toolbar itself on mobile. + border-top: 1px solid $light-gray-500; + .components-toolbar { + border-top: none; + border-bottom: none; - // Position the contextual toolbar above the block. - @include break-mobile() { - position: relative; - top: auto; - bottom: auto; - left: auto; - right: auto; - margin-top: -$block-toolbar-height - $border-width; - margin-bottom: $block-padding + $border-width; + } - // IE11 does not support `position: sticky`. - @supports (position: sticky) { - position: sticky; - // Avoid appearance of double border when toolbar sticks at the top of the editor. - top: -$border-width; + @include break-small() { + border-top: none; + .components-toolbar { + border-top: 1px solid $light-gray-500; + border-bottom: 1px solid $light-gray-500; } } @@ -839,13 +845,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. @@ -859,13 +865,47 @@ & > * { pointer-events: auto; } +} + +// Enable toolbar footprint collapsing +.editor-block-contextual-toolbar { + // Position the contextual toolbar above the block. + .editor-block-list__block & { + @include break-small() { + bottom: auto; + left: auto; + right: auto; + box-shadow: none; + + // Move the block toolbar out of the flow using translate. + transform: translateY( -$block-toolbar-height -$block-padding -$border-width ); + + // IE11 does not support `position: sticky`. + @supports ( position: sticky ) { + position: sticky; + + // Compensate for translate, so the sticky sticks to the top. + top: $block-toolbar-height + $block-padding; + } + + // 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; + } + } + .editor-block-list__block[data-align="right"] & { + @include break-small() { + float: right; + } + } } +// 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() { @@ -873,8 +913,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; @@ -886,21 +928,19 @@ } } + /** * 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 & { @@ -950,7 +990,7 @@ right: -$parent-block-padding - $block-padding; top: 0; } - + // Remove the fuzzy click area effect set above on nested blocks. // It should only applies to top-level blocks; applying this rule to // nested blocks will result in difficult-to-use and possibly overlapping @@ -959,5 +999,10 @@ left: 0; right: 0; } + + // Don't use this for full-wide blocks, as there's no clearance to accommodate extra area on the side. + &[data-align="full"]:before { + content: none; + } } } 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..389659b29aa2d 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; @@ -20,10 +25,10 @@ // This should be refactored to have its own class to target. > div { - display: flex; + // IE11 does not support `position: sticky`, or Flex very well, so use block. + display: block; + @supports ( position: sticky ) { + display: flex; + } } } - -.editor-block-toolbar .editor-block-switcher { - display: inline-flex; -} diff --git a/editor/components/default-block-appender/style.scss b/editor/components/default-block-appender/style.scss index 3a5c27b33580e..1b0ec86de0d87 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; @@ -87,7 +94,6 @@ $empty-paragraph-height: $text-editor-font-size * 4; border-radius: 50%; width: $block-side-ui-width; height: $block-side-ui-width; - top: 4px; padding: 4px; // use opacity to work in various editor styles @@ -101,12 +107,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;