From a57cc161a594e00bb12a83d6f2e4921bad70389f Mon Sep 17 00:00:00 2001 From: etoledom Date: Tue, 17 Nov 2020 21:46:43 +0100 Subject: [PATCH 1/3] [RNMobile] File Block II (#26360) * Dim Download button when upload is in progress * Implementing replace file toolbar button * Implement Hide Download Button switch * Implementing Copy Link option * Implementing "Open in new tab" setting * Implement Alignment render of block elements * Small design improvements * Showing block toolbar buttons only when the update finishes * Dont hide bottom sheet after copying url * Styles refinements: - Copy URL action button color - Media Placeholder icon color (BlockIcon mod) * Using constant for timer timeout * Disable Copy Link button while upload is in progress * Dim buttons when they are dissabled --- .../src/components/block-icon/index.native.js | 24 +- .../components/block-icon/style.native.scss | 7 + .../block-library/src/file/edit.native.js | 250 ++++++++++++++++-- .../block-library/src/file/style.native.scss | 18 +- 4 files changed, 269 insertions(+), 30 deletions(-) create mode 100644 packages/block-editor/src/components/block-icon/style.native.scss diff --git a/packages/block-editor/src/components/block-icon/index.native.js b/packages/block-editor/src/components/block-icon/index.native.js index f0845e6b74f8a..3e1bca650976a 100644 --- a/packages/block-editor/src/components/block-icon/index.native.js +++ b/packages/block-editor/src/components/block-icon/index.native.js @@ -8,15 +8,33 @@ import { View } from 'react-native'; */ import { Icon } from '@wordpress/components'; import { blockDefault } from '@wordpress/icons'; +import { withPreferredColorScheme } from '@wordpress/compose'; -export default function BlockIcon( { icon, showColors = false } ) { +/** + * Internal dependencies + */ +import styles from './style.scss'; + +export function BlockIcon( { + icon, + showColors = false, + getStylesFromColorScheme, +} ) { if ( icon?.src === 'block-default' ) { icon = { src: blockDefault, }; } - const renderedIcon = ; + const renderedIcon = ( + + ); const style = showColors ? { backgroundColor: icon && icon.background, @@ -26,3 +44,5 @@ export default function BlockIcon( { icon, showColors = false } ) { return { renderedIcon }; } + +export default withPreferredColorScheme( BlockIcon ); diff --git a/packages/block-editor/src/components/block-icon/style.native.scss b/packages/block-editor/src/components/block-icon/style.native.scss new file mode 100644 index 0000000000000..605312709ef5c --- /dev/null +++ b/packages/block-editor/src/components/block-icon/style.native.scss @@ -0,0 +1,7 @@ +.iconPlaceholder { + fill: $gray-dark; +} + +.iconPlaceholderDark { + fill: $white; +} diff --git a/packages/block-library/src/file/edit.native.js b/packages/block-library/src/file/edit.native.js index 08493cc417be2..a2fe3a2a55825 100644 --- a/packages/block-library/src/file/edit.native.js +++ b/packages/block-library/src/file/edit.native.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { View, Text } from 'react-native'; +import { View, Text, Clipboard } from 'react-native'; import React from 'react'; /** @@ -13,17 +13,30 @@ import { MediaUploadProgress, RichText, PlainText, + BlockControls, + MediaUpload, + InspectorControls, } from '@wordpress/block-editor'; -import { file as icon } from '@wordpress/icons'; +import { + ToolbarButton, + ToolbarGroup, + PanelBody, + ToggleControl, + BottomSheet, +} from '@wordpress/components'; +import { file as icon, replace, button, external } from '@wordpress/icons'; import { Component } from '@wordpress/element'; import { __, _x } from '@wordpress/i18n'; +import { withPreferredColorScheme } from '@wordpress/compose'; /** * Internal dependencies */ import styles from './style.scss'; -export default class FileEdit extends Component { +const URL_COPIED_NOTIFICATION_DURATION_MS = 1500; + +export class FileEdit extends Component { constructor( props ) { super( props ); @@ -31,6 +44,8 @@ export default class FileEdit extends Component { isUploadInProgress: false, }; + this.timerRef = null; + this.onSelectFile = this.onSelectFile.bind( this ); this.onChangeFileName = this.onChangeFileName.bind( this ); this.onChangeDownloadButtonText = this.onChangeDownloadButtonText.bind( @@ -40,6 +55,14 @@ export default class FileEdit extends Component { this.finishMediaUploadWithSuccess = this.finishMediaUploadWithSuccess.bind( this ); + this.getFileComponent = this.getFileComponent.bind( this ); + this.onChangeDownloadButtonVisibility = this.onChangeDownloadButtonVisibility.bind( + this + ); + this.onCopyURL = this.onCopyURL.bind( this ); + this.onChangeOpenInNewWindow = this.onChangeOpenInNewWindow.bind( + this + ); } componentDidMount() { @@ -53,6 +76,10 @@ export default class FileEdit extends Component { } } + componentWillUnmount() { + clearTimeout( this.timerRef ); + } + onSelectFile( media ) { this.props.setAttributes( { href: media.url, @@ -70,6 +97,29 @@ export default class FileEdit extends Component { this.props.setAttributes( { downloadButtonText } ); } + onChangeDownloadButtonVisibility( showDownloadButton ) { + this.props.setAttributes( { showDownloadButton } ); + } + + onCopyURL() { + if ( this.state.isUrlCopied ) { + return; + } + const { href } = this.props.attributes; + Clipboard.setString( href ); + + this.setState( { isUrlCopied: true } ); + this.timerRef = setTimeout( () => { + this.setState( { isUrlCopied: false } ); + }, URL_COPIED_NOTIFICATION_DURATION_MS ); + } + + onChangeOpenInNewWindow( newValue ) { + this.props.setAttributes( { + textLinkTarget: newValue ? '_blank' : false, + } ); + } + updateMediaProgress( payload ) { const { setAttributes } = this.props; if ( payload.mediaUrl ) { @@ -110,24 +160,113 @@ export default class FileEdit extends Component { ); } - render() { - const { attributes } = this.props; - const { href, fileName, downloadButtonText, id } = attributes; + getToolbarEditButton( open ) { + return ( + + + + + + ); + } - if ( ! href ) { - return ( - } - labels={ { - title: __( 'File' ), - instructions: __( 'CHOOSE A FILE' ), - } } - onSelect={ this.onSelectFile } - onFocus={ this.props.onFocus } - allowedTypes={ [ 'other' ] } - /> - ); + getInspectorControls( + { showDownloadButton, textLinkTarget }, + isUploadInProgress, + isUploadFailed + ) { + const actionButtonStyle = this.props.getStylesFromColorScheme( + styles.actionButton, + styles.actionButtonDark + ); + + const isCopyUrlDisabled = isUploadFailed || isUploadInProgress; + const dimmedStyle = isCopyUrlDisabled && styles.disabledButton; + const finalButtonStyle = Object.assign( + {}, + actionButtonStyle, + dimmedStyle + ); + + return ( + + + + + + + + + ); + } + + getStyleForAlignment( align ) { + const getFlexAlign = ( alignment ) => { + switch ( alignment ) { + case 'right': + return 'flex-end'; + case 'center': + return 'center'; + default: + return 'flex-start'; + } + }; + return { alignSelf: getFlexAlign( align ) }; + } + + getTextAlignmentForAlignment( align ) { + switch ( align ) { + case 'right': + return 'right'; + case 'center': + return 'center'; + default: + return 'left'; } + } + + getFileComponent( openMediaOptions, getMediaOptions ) { + const { attributes } = this.props; + const { + fileName, + downloadButtonText, + id, + showDownloadButton, + align, + } = attributes; + + const dimmedStyle = + this.state.isUploadInProgress && styles.disabledButton; + const finalButtonStyle = Object.assign( + {}, + styles.defaultButton, + dimmedStyle + ); return ( {} } onMediaUploadStateReset={ this.mediaUploadStateReset } - renderContent={ ( { isUploadFailed, retryMessage } ) => { + renderContent={ ( { + isUploadInProgress, + isUploadFailed, + retryMessage, + } ) => { if ( isUploadFailed ) { return this.getErrorComponent( retryMessage ); } return ( + { isUploadInProgress || + this.getToolbarEditButton( openMediaOptions ) } + { getMediaOptions() } + { this.getInspectorControls( + attributes, + isUploadInProgress, + isUploadFailed + ) } - - - </View> + { showDownloadButton && ( + <View + style={ [ + finalButtonStyle, + this.getStyleForAlignment( align ), + ] } + > + <PlainText + style={ styles.buttonText } + value={ downloadButtonText } + onChange={ + this.onChangeDownloadButtonText + } + /> + </View> + ) } </View> ); } } /> ); } + + render() { + const { attributes } = this.props; + const { href } = attributes; + + if ( ! href ) { + return ( + <MediaPlaceholder + icon={ <BlockIcon icon={ icon } /> } + labels={ { + title: __( 'File' ), + instructions: __( 'CHOOSE A FILE' ), + } } + onSelect={ this.onSelectFile } + onFocus={ this.props.onFocus } + allowedTypes={ [ 'other' ] } + /> + ); + } + + return ( + <MediaUpload + allowedTypes={ [ 'other' ] } + isReplacingMedia={ true } + onSelect={ this.onSelectFile } + render={ ( { open, getMediaOptions } ) => { + return this.getFileComponent( open, getMediaOptions ); + } } + /> + ); + } } + +export default withPreferredColorScheme( FileEdit ); diff --git a/packages/block-library/src/file/style.native.scss b/packages/block-library/src/file/style.native.scss index 272b34172390a..f3a83da6c8404 100644 --- a/packages/block-library/src/file/style.native.scss +++ b/packages/block-library/src/file/style.native.scss @@ -4,8 +4,16 @@ border-width: $border-width; margin-top: $grid-unit-20; background-color: $button-fallback-bg; +} + +.buttonText { + background-color: transparent; color: $white; - align-self: flex-start; + font-size: 16; +} + +.disabledButton { + opacity: 0.25; } .uploadFailedText { @@ -18,3 +26,11 @@ flex: 1; background-color: "rgba(0, 0, 0, 0.5)"; } + +.actionButton { + color: $blue-50; +} + +.actionButtonDark { + color: $blue-30; +} From bcd47755e141afe4201fa291440d55e4e88e8b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= <wp@iseulde.com> Date: Tue, 17 Nov 2020 22:59:53 +0200 Subject: [PATCH 2/3] Visual editor: remove 4 wrapper divs (#27035) * typing observer * clipboard and selection clearer * Collapse divs * Fix selector * Popover needs relative container * Fix keyboard nav test * Fix click redirect * Remove useless check --- .../block-selection-clearer/index.js | 24 ++- .../src/components/copy-handler/index.js | 144 +++++++++--------- packages/block-editor/src/components/index.js | 25 ++- .../multi-select-scroll-into-view/index.js | 43 +++--- .../src/components/observe-typing/index.js | 2 +- .../src/components/typewriter/index.js | 7 +- .../src/components/writing-flow/index.js | 5 +- .../various/keyboard-navigable-blocks.test.js | 4 +- .../src/components/visual-editor/index.js | 56 +++---- .../src/components/visual-editor/style.scss | 7 +- 10 files changed, 177 insertions(+), 140 deletions(-) diff --git a/packages/block-editor/src/components/block-selection-clearer/index.js b/packages/block-editor/src/components/block-selection-clearer/index.js index b97b8895b5a9b..8501d3179eacd 100644 --- a/packages/block-editor/src/components/block-selection-clearer/index.js +++ b/packages/block-editor/src/components/block-selection-clearer/index.js @@ -2,8 +2,9 @@ * WordPress dependencies */ import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect, useRef } from '@wordpress/element'; -function useBlockSelectionClearer() { +export function useBlockSelectionClearer( ref ) { const hasSelection = useSelect( ( select ) => { const { hasSelectedBlock, hasMultiSelection } = select( 'core/block-editor' @@ -13,14 +14,25 @@ function useBlockSelectionClearer() { } ); const { clearSelectedBlock } = useDispatch( 'core/block-editor' ); - return ( event ) => { - if ( event.target === event.currentTarget && hasSelection ) { + useEffect( () => { + if ( ! hasSelection ) { + return; + } + + function onFocus() { clearSelectedBlock(); } - }; + + ref.current.addEventListener( 'focus', onFocus ); + + return () => { + ref.current.removeEventListener( 'focus', onFocus ); + }; + }, [ hasSelection, clearSelectedBlock ] ); } export default function BlockSelectionClearer( props ) { - const onFocus = useBlockSelectionClearer(); - return <div tabIndex={ -1 } onFocus={ onFocus } { ...props } />; + const ref = useRef(); + useBlockSelectionClearer( ref ); + return <div tabIndex={ -1 } ref={ ref } { ...props } />; } diff --git a/packages/block-editor/src/components/copy-handler/index.js b/packages/block-editor/src/components/copy-handler/index.js index 808c9cedf2417..887005b48488f 100644 --- a/packages/block-editor/src/components/copy-handler/index.js +++ b/packages/block-editor/src/components/copy-handler/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { useCallback, useRef } from '@wordpress/element'; +import { useCallback, useEffect, useRef } from '@wordpress/element'; import { serialize, pasteHandler } from '@wordpress/blocks'; import { documentHasSelection, @@ -71,97 +71,99 @@ export function useNotifyCopy() { }, [] ); } -function CopyHandler( { children } ) { - const containerRef = useRef(); - +export function useClipboardHandler( ref ) { const { getBlocksByClientId, getSelectedBlockClientIds, hasMultiSelection, getSettings, } = useSelect( ( select ) => select( 'core/block-editor' ), [] ); - const { flashBlock, removeBlocks, replaceBlocks } = useDispatch( 'core/block-editor' ); - const notifyCopy = useNotifyCopy(); - const { - __experimentalCanUserUseUnfilteredHTML: canUserUseUnfilteredHTML, - } = getSettings(); + useEffect( () => { + function handler( event ) { + const selectedBlockClientIds = getSelectedBlockClientIds(); - const handler = ( event ) => { - const selectedBlockClientIds = getSelectedBlockClientIds(); + if ( selectedBlockClientIds.length === 0 ) { + return; + } - if ( selectedBlockClientIds.length === 0 ) { - return; - } + // Always handle multiple selected blocks. + if ( ! hasMultiSelection() ) { + const { target } = event; + const { ownerDocument } = target; + // If copying, only consider actual text selection as selection. + // Otherwise, any focus on an input field is considered. + const hasSelection = + event.type === 'copy' || event.type === 'cut' + ? documentHasUncollapsedSelection( ownerDocument ) + : documentHasSelection( ownerDocument ); + + // Let native copy behaviour take over in input fields. + if ( hasSelection ) { + return; + } + } - // Always handle multiple selected blocks. - if ( ! hasMultiSelection() ) { - const { target } = event; - const { ownerDocument } = target; - // If copying, only consider actual text selection as selection. - // Otherwise, any focus on an input field is considered. - const hasSelection = - event.type === 'copy' || event.type === 'cut' - ? documentHasUncollapsedSelection( ownerDocument ) - : documentHasSelection( ownerDocument ); - - // Let native copy behaviour take over in input fields. - if ( hasSelection ) { + if ( ! ref.current.contains( event.target ) ) { return; } - } + event.preventDefault(); + + if ( event.type === 'copy' || event.type === 'cut' ) { + if ( selectedBlockClientIds.length === 1 ) { + flashBlock( selectedBlockClientIds[ 0 ] ); + } + notifyCopy( event.type, selectedBlockClientIds ); + const blocks = getBlocksByClientId( selectedBlockClientIds ); + const serialized = serialize( blocks ); + + event.clipboardData.setData( 'text/plain', serialized ); + event.clipboardData.setData( 'text/html', serialized ); + } - if ( ! containerRef.current.contains( event.target ) ) { - return; + if ( event.type === 'cut' ) { + removeBlocks( selectedBlockClientIds ); + } else if ( event.type === 'paste' ) { + const { + __experimentalCanUserUseUnfilteredHTML: canUserUseUnfilteredHTML, + } = getSettings(); + const { plainText, html } = getPasteEventData( event ); + const blocks = pasteHandler( { + HTML: html, + plainText, + mode: 'BLOCKS', + canUserUseUnfilteredHTML, + } ); + + replaceBlocks( + selectedBlockClientIds, + blocks, + blocks.length - 1, + -1 + ); + } } - event.preventDefault(); - if ( event.type === 'copy' || event.type === 'cut' ) { - if ( selectedBlockClientIds.length === 1 ) { - flashBlock( selectedBlockClientIds[ 0 ] ); - } - notifyCopy( event.type, selectedBlockClientIds ); - const blocks = getBlocksByClientId( selectedBlockClientIds ); - const serialized = serialize( blocks ); + ref.current.addEventListener( 'copy', handler ); + ref.current.addEventListener( 'cut', handler ); + ref.current.addEventListener( 'paste', handler ); - event.clipboardData.setData( 'text/plain', serialized ); - event.clipboardData.setData( 'text/html', serialized ); - } + return () => { + ref.current.removeEventListener( 'copy', handler ); + ref.current.removeEventListener( 'cut', handler ); + ref.current.removeEventListener( 'paste', handler ); + }; + }, [] ); +} - if ( event.type === 'cut' ) { - removeBlocks( selectedBlockClientIds ); - } else if ( event.type === 'paste' ) { - const { plainText, html } = getPasteEventData( event ); - const blocks = pasteHandler( { - HTML: html, - plainText, - mode: 'BLOCKS', - canUserUseUnfilteredHTML, - } ); - - replaceBlocks( - selectedBlockClientIds, - blocks, - blocks.length - 1, - -1 - ); - } - }; - - return ( - <div - ref={ containerRef } - onCopy={ handler } - onCut={ handler } - onPaste={ handler } - > - { children } - </div> - ); +function CopyHandler( { children } ) { + const ref = useRef(); + useClipboardHandler( ref ); + return <div ref={ ref }>{ children }</div>; } export default CopyHandler; diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index e8a079a3af165..40c6510d292c9 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -83,24 +83,39 @@ export { } from './block-list/block-wrapper'; export { default as BlockMover } from './block-mover'; export { default as BlockPreview } from './block-preview'; -export { default as BlockSelectionClearer } from './block-selection-clearer'; +export { + default as BlockSelectionClearer, + useBlockSelectionClearer as __unstableUseBlockSelectionClearer, +} from './block-selection-clearer'; export { default as BlockSettingsMenu } from './block-settings-menu'; export { default as BlockSettingsMenuControls } from './block-settings-menu-controls'; export { default as BlockTitle } from './block-title'; export { default as BlockToolbar } from './block-toolbar'; -export { default as CopyHandler } from './copy-handler'; +export { + default as CopyHandler, + useClipboardHandler as __unstableUseClipboardHandler, +} from './copy-handler'; export { default as DefaultBlockAppender } from './default-block-appender'; export { default as __unstableEditorStyles } from './editor-styles'; export { default as Inserter } from './inserter'; export { default as __experimentalLibrary } from './inserter/library'; export { default as __experimentalSearchForm } from './inserter/search-form'; export { default as BlockEditorKeyboardShortcuts } from './keyboard-shortcuts'; -export { default as MultiSelectScrollIntoView } from './multi-select-scroll-into-view'; +export { + default as MultiSelectScrollIntoView, + useScrollMultiSelectionIntoView as __unstableUseScrollMultiSelectionIntoView, +} from './multi-select-scroll-into-view'; export { default as NavigableToolbar } from './navigable-toolbar'; -export { default as ObserveTyping } from './observe-typing'; +export { + default as ObserveTyping, + useTypingObserver as __unstableUseTypingObserver, +} from './observe-typing'; export { default as PreserveScrollInReorder } from './preserve-scroll-in-reorder'; export { default as SkipToSelectedBlock } from './skip-to-selected-block'; -export { default as Typewriter } from './typewriter'; +export { + default as Typewriter, + useTypewriter as __unstableUseTypewriter, +} from './typewriter'; export { default as Warning } from './warning'; export { default as WritingFlow } from './writing-flow'; diff --git a/packages/block-editor/src/components/multi-select-scroll-into-view/index.js b/packages/block-editor/src/components/multi-select-scroll-into-view/index.js index fb142b7d0ef00..fca97d6621f83 100644 --- a/packages/block-editor/src/components/multi-select-scroll-into-view/index.js +++ b/packages/block-editor/src/components/multi-select-scroll-into-view/index.js @@ -15,32 +15,29 @@ import { getScrollContainer } from '@wordpress/dom'; */ import { getBlockDOMNode } from '../../utils/dom'; -/** - * Scrolls the multi block selection end into view if not in view already. This - * is important to do after selection by keyboard. - */ -export default function MultiSelectScrollIntoView() { - const selector = ( select ) => { +export function useScrollMultiSelectionIntoView( ref ) { + const selectionEnd = useSelect( ( select ) => { const { getBlockSelectionEnd, hasMultiSelection, isMultiSelecting, } = select( 'core/block-editor' ); - return { - selectionEnd: getBlockSelectionEnd(), - isMultiSelection: hasMultiSelection(), - isMultiSelecting: isMultiSelecting(), - }; - }; - const { isMultiSelection, selectionEnd, isMultiSelecting } = useSelect( - selector, - [] - ); - const ref = useRef(); + const blockSelectionEnd = getBlockSelectionEnd(); + + if ( + ! blockSelectionEnd || + isMultiSelecting() || + ! hasMultiSelection() + ) { + return; + } + + return blockSelectionEnd; + }, [] ); useEffect( () => { - if ( ! selectionEnd || isMultiSelecting || ! isMultiSelection ) { + if ( ! selectionEnd ) { return; } @@ -62,7 +59,15 @@ export default function MultiSelectScrollIntoView() { scrollIntoView( extentNode, scrollContainer, { onlyScrollIfNeeded: true, } ); - }, [ isMultiSelection, selectionEnd, isMultiSelecting ] ); + }, [ selectionEnd ] ); +} +/** + * Scrolls the multi block selection end into view if not in view already. This + * is important to do after selection by keyboard. + */ +export default function MultiSelectScrollIntoView() { + const ref = useRef(); + useScrollMultiSelectionIntoView( ref ); return <div ref={ ref } />; } diff --git a/packages/block-editor/src/components/observe-typing/index.js b/packages/block-editor/src/components/observe-typing/index.js index 269eaebf11aa5..e33628c92b374 100644 --- a/packages/block-editor/src/components/observe-typing/index.js +++ b/packages/block-editor/src/components/observe-typing/index.js @@ -43,7 +43,7 @@ function isKeyDownEligibleForStartTyping( event ) { return ! shiftKey && KEY_DOWN_ELIGIBLE_KEY_CODES.has( keyCode ); } -function useTypingObserver( ref ) { +export function useTypingObserver( ref ) { const isTyping = useSelect( ( select ) => select( 'core/block-editor' ).isTyping() ); diff --git a/packages/block-editor/src/components/typewriter/index.js b/packages/block-editor/src/components/typewriter/index.js index d0a05729a1396..522509f8e6756 100644 --- a/packages/block-editor/src/components/typewriter/index.js +++ b/packages/block-editor/src/components/typewriter/index.js @@ -10,8 +10,7 @@ const isIE = window.navigator.userAgent.indexOf( 'Trident' ) !== -1; const arrowKeyCodes = new Set( [ UP, DOWN, LEFT, RIGHT ] ); const initialTriggerPercentage = 0.75; -function Typewriter( { children } ) { - const ref = useRef(); +export function useTypewriter( ref ) { const hasSelectedBlock = useSelect( ( select ) => select( 'core/block-editor' ).hasSelectedBlock() ); @@ -242,7 +241,11 @@ function Typewriter( { children } ) { defaultView.cancelAnimationFrame( onKeyDownRafId ); }; }, [ hasSelectedBlock ] ); +} +function Typewriter( { children } ) { + const ref = useRef(); + useTypewriter( ref ); return ( <div ref={ ref } className="block-editor__typewriter"> { children } diff --git a/packages/block-editor/src/components/writing-flow/index.js b/packages/block-editor/src/components/writing-flow/index.js index 428e904194c66..d48428a80cf9c 100644 --- a/packages/block-editor/src/components/writing-flow/index.js +++ b/packages/block-editor/src/components/writing-flow/index.js @@ -708,7 +708,7 @@ export default function WritingFlow( { children } ) { // bubbling events from children to determine focus transition intents. /* eslint-disable jsx-a11y/no-static-element-interactions */ return ( - <div className={ className }> + <> <FocusCapture ref={ focusCaptureBeforeRef } selectedClientId={ selectedBlockClientId } @@ -719,6 +719,7 @@ export default function WritingFlow( { children } ) { /> <div ref={ container } + className={ className } onKeyDown={ onKeyDown } onMouseDown={ onMouseDown } > @@ -751,7 +752,7 @@ export default function WritingFlow( { children } ) { onClick={ focusLastTextField } className="block-editor-writing-flow__click-redirect" /> - </div> + </> ); /* eslint-enable jsx-a11y/no-static-element-interactions */ } diff --git a/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js b/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js index 99a9be8268fe1..730af28bdb10a 100644 --- a/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js @@ -110,7 +110,7 @@ describe( 'Order of block keyboard navigation', () => { // Clear the selected block and put focus in front of the block list. await page.evaluate( () => { - document.querySelector( '.edit-post-visual-editor' ).focus(); + document.querySelector( '.editor-styles-wrapper' ).focus(); } ); await page.keyboard.press( 'Tab' ); @@ -145,7 +145,7 @@ describe( 'Order of block keyboard navigation', () => { // Clear the selected block and put focus behind the block list. await page.evaluate( () => { - document.querySelector( '.edit-post-visual-editor' ).focus(); + document.querySelector( '.editor-styles-wrapper' ).focus(); document .querySelector( '.interface-interface-skeleton__sidebar' ) .focus(); diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js index 026acf6654bb5..a177981e04f17 100644 --- a/packages/edit-post/src/components/visual-editor/index.js +++ b/packages/edit-post/src/components/visual-editor/index.js @@ -7,16 +7,17 @@ import { } from '@wordpress/editor'; import { WritingFlow, - Typewriter, - ObserveTyping, BlockList, - CopyHandler, - BlockSelectionClearer, - MultiSelectScrollIntoView, + __unstableUseBlockSelectionClearer as useBlockSelectionClearer, + __unstableUseTypewriter as useTypewriter, + __unstableUseClipboardHandler as useClipboardHandler, + __unstableUseTypingObserver as useTypingObserver, + __unstableUseScrollMultiSelectionIntoView as useScrollMultiSelectionIntoView, __experimentalBlockSettingsMenuFirstItem, __experimentalUseResizeCanvas as useResizeCanvas, } from '@wordpress/block-editor'; import { Popover } from '@wordpress/components'; +import { useRef } from '@wordpress/element'; /** * Internal dependencies @@ -24,40 +25,41 @@ import { Popover } from '@wordpress/components'; import BlockInspectorButton from './block-inspector-button'; import { useSelect } from '@wordpress/data'; -function VisualEditor() { +export default function VisualEditor() { + const ref = useRef(); const deviceType = useSelect( ( select ) => { return select( 'core/edit-post' ).__experimentalGetPreviewDeviceType(); }, [] ); - const inlineStyles = useResizeCanvas( deviceType ); + useScrollMultiSelectionIntoView( ref ); + useBlockSelectionClearer( ref ); + useTypewriter( ref ); + useClipboardHandler( ref ); + useTypingObserver( ref ); + return ( - <BlockSelectionClearer - className="edit-post-visual-editor editor-styles-wrapper" - style={ inlineStyles } - > + <div className="edit-post-visual-editor"> <VisualEditorGlobalKeyboardShortcuts /> - <MultiSelectScrollIntoView /> <Popover.Slot name="block-toolbar" /> - <Typewriter> - <CopyHandler> - <WritingFlow> - <ObserveTyping> - <div className="edit-post-visual-editor__post-title-wrapper"> - <PostTitle /> - </div> - <BlockList /> - </ObserveTyping> - </WritingFlow> - </CopyHandler> - </Typewriter> + <div + ref={ ref } + className="editor-styles-wrapper" + tabIndex="-1" + style={ inlineStyles } + > + <WritingFlow> + <div className="edit-post-visual-editor__post-title-wrapper"> + <PostTitle /> + </div> + <BlockList /> + </WritingFlow> + </div> <__experimentalBlockSettingsMenuFirstItem> { ( { onClose } ) => ( <BlockInspectorButton onClick={ onClose } /> ) } </__experimentalBlockSettingsMenuFirstItem> - </BlockSelectionClearer> + </div> ); } - -export default VisualEditor; diff --git a/packages/edit-post/src/components/visual-editor/style.scss b/packages/edit-post/src/components/visual-editor/style.scss index a9a261a417eb8..4534cdefe6886 100644 --- a/packages/edit-post/src/components/visual-editor/style.scss +++ b/packages/edit-post/src/components/visual-editor/style.scss @@ -1,6 +1,5 @@ .edit-post-visual-editor { position: relative; - padding-top: 50px; // Default background color so that grey .edit-post-editor-regions__content color doesn't show through. background-color: $white; @@ -28,10 +27,8 @@ } } -.edit-post-visual-editor > .block-editor__typewriter, -.edit-post-visual-editor > .block-editor__typewriter > div, -.edit-post-visual-editor > .block-editor__typewriter > div > .block-editor-writing-flow, -.edit-post-visual-editor > .block-editor__typewriter > div > .block-editor-writing-flow > .block-editor-writing-flow__click-redirect { +.editor-styles-wrapper, +.editor-styles-wrapper > .block-editor-writing-flow__click-redirect { height: 100%; } From 4d18b77a1c1bf62a94cab5211514667a5c2f03c1 Mon Sep 17 00:00:00 2001 From: Noah Allen <noahtallen@gmail.com> Date: Tue, 17 Nov 2020 13:26:16 -0800 Subject: [PATCH 3/3] Run phpunit even when lint fials (#27024) --- .github/workflows/unit-test.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index efcc946cb9239..eedace95e743e 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -83,8 +83,17 @@ jobs: chmod -R 767 ./ # TODO: Possibly integrate in wp-env npm run wp-env start - - name: Running the tests - run: npm run test-php && npm run test-unit-php-multisite + - name: Running lint check + run: npm run lint-php + + - name: Running single site unit tests + run: npm run test-unit-php + if: ${{ success() || failure() }} + + - name: Running multisite unit tests + run: npm run test-unit-php-multisite + if: ${{ success() || failure() }} + mobile-unit-js: name: Mobile