From 02af3226f440cd4b287b180bb6922b63eb64da9e Mon Sep 17 00:00:00 2001 From: iseulde Date: Wed, 31 Jul 2019 14:23:50 +0200 Subject: [PATCH] Native Multi Block Selection --- .../src/components/block-list/index.js | 31 +++++++++++++++++++ .../src/components/block-list/style.scss | 30 ------------------ .../src/components/rich-text/index.js | 4 +++ packages/rich-text/src/component/editable.js | 4 +++ packages/rich-text/src/component/index.js | 2 ++ 5 files changed, 41 insertions(+), 30 deletions(-) diff --git a/packages/block-editor/src/components/block-list/index.js b/packages/block-editor/src/components/block-list/index.js index e6fa2d7b8cb60..3a853518b082d 100644 --- a/packages/block-editor/src/components/block-list/index.js +++ b/packages/block-editor/src/components/block-list/index.js @@ -68,6 +68,37 @@ class BlockList extends Component { window.removeEventListener( 'mousemove', this.setLastClientY ); } + componentDidUpdate() { + const { + hasMultiSelection, + selectionStart, + selectionEnd, + blockClientIds, + } = this.props; + + if ( ! hasMultiSelection ) { + return; + } + + const startIndex = blockClientIds.indexOf( selectionStart ); + + // The selected block is not in this block list. + if ( startIndex === -1 ) { + return; + } + + const startNode = document.querySelector( `[data-block="${ selectionStart }"]` ); + const endNode = document.querySelector( `[data-block="${ selectionEnd }"]` ); + const selection = window.getSelection(); + const range = document.createRange(); + + range.setStartBefore( startNode ); + range.setEndAfter( endNode ); + + selection.removeAllRanges(); + selection.addRange( range ); + } + setLastClientY( { clientY } ) { this.lastClientY = clientY; } diff --git a/packages/block-editor/src/components/block-list/style.scss b/packages/block-editor/src/components/block-list/style.scss index ba4ea474e1d32..a4948926a6c4a 100644 --- a/packages/block-editor/src/components/block-list/style.scss +++ b/packages/block-editor/src/components/block-list/style.scss @@ -247,36 +247,6 @@ * Cross-block selection */ -.block-editor-block-list__layout .block-editor-block-list__block { - ::-moz-selection { - background-color: $blue-medium-highlight; - } - - ::selection { - background-color: $blue-medium-highlight; - } - - // Selection style for multiple blocks. - &.is-multi-selected *::selection { - background-color: transparent; - } - - &.is-multi-selected .block-editor-block-list__block-edit::before { - background: $blue-medium-highlight; - - // Use opacity to work in various editor styles. - mix-blend-mode: multiply; - - // Collapse extra vertical padding on selection. - top: -$block-padding; - bottom: -$block-padding; - - .is-dark-theme & { - mix-blend-mode: soft-light; - } - } -} - /** * Block styles and alignments diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index 818c3ef690d14..767e6cd20c002 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -337,6 +337,7 @@ class RichTextWrapper extends Component { undo, placeholder, keepPlaceholderOnFocus, + hasMultiSelection, // eslint-disable-next-line no-unused-vars allowedFormats, withoutInteractiveFormatting, @@ -404,6 +405,7 @@ class RichTextWrapper extends Component { __unstableMarkAutomaticChange={ this.markAutomaticChange } __unstableDidAutomaticChange={ didAutomaticChange } __unstableUndo={ undo } + __unstableContentEditable={ ! hasMultiSelection } > { ( { isSelected, value, onChange, Editable } ) => <> @@ -465,6 +467,7 @@ const RichTextContainer = compose( [ getSelectionEnd, getSettings, didAutomaticChange, + hasMultiSelection, } = select( 'core/block-editor' ); const selectionStart = getSelectionStart(); @@ -486,6 +489,7 @@ const RichTextContainer = compose( [ selectionEnd: isSelected ? selectionEnd.offset : undefined, isSelected, didAutomaticChange: didAutomaticChange(), + hasMultiSelection: hasMultiSelection(), }; } ), withDispatch( ( dispatch, { diff --git a/packages/rich-text/src/component/editable.js b/packages/rich-text/src/component/editable.js index e108af6d4bfc6..156ba3e8b3f89 100644 --- a/packages/rich-text/src/component/editable.js +++ b/packages/rich-text/src/component/editable.js @@ -49,6 +49,10 @@ export default class Editable extends Component { this.editorNode.reversed = nextProps.reversed; } + if ( this.props.contentEditable !== nextProps.contentEditable ) { + this.editorNode.contentEditable = nextProps.contentEditable; + } + const { removedKeys, updatedKeys } = diffAriaProps( this.props, nextProps ); removedKeys.forEach( ( key ) => this.editorNode.removeAttribute( key ) ); diff --git a/packages/rich-text/src/component/index.js b/packages/rich-text/src/component/index.js index ef4b5b763f63a..488ed625baa46 100644 --- a/packages/rich-text/src/component/index.js +++ b/packages/rich-text/src/component/index.js @@ -941,6 +941,7 @@ class RichText extends Component { style, className, placeholder, + __unstableContentEditable, } = this.props; // Generating a key that includes `tagName` ensures that if the tag // changes, we replace the relevant element. This is needed because we @@ -974,6 +975,7 @@ class RichText extends Component { onKeyUp={ this.onSelectionChange } onMouseUp={ this.onSelectionChange } onTouchEnd={ this.onSelectionChange } + contentEditable={ __unstableContentEditable } /> ); }