From ff7b820ca56c1ca81f101a028fcf17dc1d845c8c 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 f827b169fa05e4..5afce2004382db 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 6688f057ca73b8..39a29d7cc48af6 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 c8a14b37c19d0a..8cbfd69427501d 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 fe0c59226c6495..ee31723bacb859 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 fd6245e5dd299a..41d08213520ebb 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 9e60e86a2bb520..df4ae931287681 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 9e1c1b238bf0a1..0c29623d82eaaf 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 && ! isPartOfMultiSelection && ! isTypingWithinBlock; const shouldRenderBlockSettings = ( isSelected || hoverArea === 'right' ) && ! isMultiSelecting && ! isPartOfMultiSelection && ! isTypingWithinBlock; @@ -421,6 +422,7 @@ export class BlockListBlock extends Component { 'has-warning': ! isValid || !! error, 'is-selected': shouldAppearSelected, 'is-multi-selected': isPartOfMultiSelection, + 'is-selected-parent': shouldAppearSelectedParent, 'is-hovered': isHovered && ! isEmptyDefaultBlock, 'is-shared': isSharedBlock( blockType ), 'is-hidden': dragging, @@ -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 ddea50def9bfd2..eca87d7c7c6b66 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 49d9d289719bcf..d972bc0ba581a4 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; } diff --git a/editor/components/block-toolbar/style.scss b/editor/components/block-toolbar/style.scss index 1fedaad2e9d6fd..389659b29aa2d2 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 3a5c27b33580e2..1b0ec86de0d87d 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;