From e1ebabba29082e24256ceca629cc19779820773c Mon Sep 17 00:00:00 2001 From: Joshua T Flowers Date: Mon, 31 Oct 2022 14:36:54 -0700 Subject: [PATCH] Fix up rich text editor initial selection and add blocks (#35286) * Fix double click toolbar behavior * Fix initial block selection on editor load * Add placeholder option to RichTextEditor * Add image and video blocks * Set toolbar height * Allow inserter to be shown * Allow media uploads in rich text editor * Add changelog entries * Fix media upload * Check for existence of selected blocks before checking length * Pass blocks to avoid race in detecting initially empty blocks --- .../changelog/fix-rich-text-editor-selection | 4 ++ .../rich-text-editor/editor-writing-flow.tsx | 41 +++++++++++------- .../src/rich-text-editor/rich-text-editor.tsx | 42 ++++++++++++++----- .../src/rich-text-editor/style.scss | 30 ++++++------- .../rich-text-editor/utils/register-blocks.ts | 4 ++ .../sections/product-details-section.tsx | 4 ++ .../changelog/fix-rich-text-editor-selection | 4 ++ 7 files changed, 90 insertions(+), 39 deletions(-) create mode 100644 packages/js/components/changelog/fix-rich-text-editor-selection create mode 100644 plugins/woocommerce/changelog/fix-rich-text-editor-selection diff --git a/packages/js/components/changelog/fix-rich-text-editor-selection b/packages/js/components/changelog/fix-rich-text-editor-selection new file mode 100644 index 00000000000..59caa9a16d8 --- /dev/null +++ b/packages/js/components/changelog/fix-rich-text-editor-selection @@ -0,0 +1,4 @@ +Significance: minor +Type: tweak + +Fix up initial block selection in RichTextEditor and add media blocks diff --git a/packages/js/components/src/rich-text-editor/editor-writing-flow.tsx b/packages/js/components/src/rich-text-editor/editor-writing-flow.tsx index b56a6ef08fd..2734c566484 100644 --- a/packages/js/components/src/rich-text-editor/editor-writing-flow.tsx +++ b/packages/js/components/src/rich-text-editor/editor-writing-flow.tsx @@ -3,8 +3,8 @@ */ import { useSelect, useDispatch } from '@wordpress/data'; import { useInstanceId } from '@wordpress/compose'; +import { BlockInstance, createBlock } from '@wordpress/blocks'; import { createElement, useEffect } from '@wordpress/element'; -import { createBlock } from '@wordpress/blocks'; import { BlockList, ObserveTyping, @@ -15,37 +15,50 @@ import { WritingFlow, } from '@wordpress/block-editor'; -export const EditorWritingFlow: React.VFC = () => { +type EditorWritingFlowProps = { + blocks: BlockInstance[]; + onChange: ( changes: BlockInstance[] ) => void; + placeholder?: string; +}; + +export const EditorWritingFlow = ( { + blocks, + onChange, + placeholder = '', +}: EditorWritingFlowProps ) => { const instanceId = useInstanceId( EditorWritingFlow ); + const firstBlock = blocks[ 0 ]; + const isEmpty = ! blocks.length; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore This action is available in the block editor data store. - const { insertBlock } = useDispatch( blockEditorStore ); - - const { isEmpty } = useSelect( ( select ) => { - const blocks = select( 'core/block-editor' ).getBlocks(); - + const { insertBlock, selectBlock } = useDispatch( blockEditorStore ); + const { selectedBlockClientIds } = useSelect( ( select ) => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore This selector is available in the block editor data store. const { getSelectedBlockClientIds } = select( blockEditorStore ); return { - isEmpty: blocks.length - ? blocks.length <= 1 && - blocks[ 0 ].attributes?.content?.trim() === '' - : true, - firstBlock: blocks[ 0 ], selectedBlockClientIds: getSelectedBlockClientIds(), }; } ); + useEffect( () => { + if ( selectedBlockClientIds?.length || ! firstBlock ) { + return; + } + selectBlock( firstBlock.clientId ); + }, [ firstBlock, selectedBlockClientIds ] ); + useEffect( () => { if ( isEmpty ) { const initialBlock = createBlock( 'core/paragraph', { content: '', + placeholder, } ); insertBlock( initialBlock ); + onChange( [ initialBlock ] ); } - }, [] ); + }, [ isEmpty ] ); return ( /* Gutenberg handles the keyboard events when focusing the content editable area. */ @@ -60,8 +73,6 @@ export const EditorWritingFlow: React.VFC = () => { - { /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */ } - { /* @ts-ignore This action is available in the block editor data store. */ } diff --git a/packages/js/components/src/rich-text-editor/rich-text-editor.tsx b/packages/js/components/src/rich-text-editor/rich-text-editor.tsx index d256503271c..3920a283970 100644 --- a/packages/js/components/src/rich-text-editor/rich-text-editor.tsx +++ b/packages/js/components/src/rich-text-editor/rich-text-editor.tsx @@ -1,18 +1,14 @@ /** * External dependencies */ -import { BaseControl, SlotFillProvider } from '@wordpress/components'; +import { BaseControl, Popover, SlotFillProvider } from '@wordpress/components'; import { BlockEditorProvider } from '@wordpress/block-editor'; import { BlockInstance } from '@wordpress/blocks'; +import { createElement, useEffect, useState, useRef } from '@wordpress/element'; import { debounce } from 'lodash'; -import { - createElement, - useCallback, - useEffect, - useState, - useRef, -} from '@wordpress/element'; import React from 'react'; +import { uploadMedia } from '@wordpress/media-utils'; +import { useUser } from '@woocommerce/data'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore No types for this exist yet. // eslint-disable-next-line @woocommerce/dependency-group @@ -31,15 +27,17 @@ type RichTextEditorProps = { label?: string; onChange: ( changes: BlockInstance[] ) => void; entryId?: string; + placeholder?: string; }; export const RichTextEditor: React.VFC< RichTextEditorProps > = ( { blocks, label, onChange, + placeholder = '', } ) => { const blocksRef = useRef( blocks ); - + const { currentUserCan } = useUser(); const [ , setRefresh ] = useState( 0 ); // If there is a props change we need to update the ref and force re-render. @@ -61,6 +59,24 @@ export const RichTextEditor: React.VFC< RichTextEditorProps > = ( { forceRerender(); }, 200 ); + const mediaUpload = currentUserCan( 'upload_files' ) + ? ( { + onError, + ...rest + }: { + onError: ( message: string ) => void; + } ) => { + uploadMedia( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore The upload function passes the remaining required props. + { + onError: ( { message } ) => onError( message ), + ...rest, + } + ); + } + : undefined; + return (
{ label && ( @@ -75,13 +91,19 @@ export const RichTextEditor: React.VFC< RichTextEditorProps > = ( { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore This property was recently added in the block editor data store. __experimentalClearBlockSelection: false, + mediaUpload, } } onInput={ debounceChange } onChange={ debounceChange } > - + +
diff --git a/packages/js/components/src/rich-text-editor/style.scss b/packages/js/components/src/rich-text-editor/style.scss index 47b277c8075..722e98d31bf 100644 --- a/packages/js/components/src/rich-text-editor/style.scss +++ b/packages/js/components/src/rich-text-editor/style.scss @@ -1,3 +1,5 @@ +$toolbar-height: 40px; + .woocommerce-rich-text-editor { .woocommerce-rich-text-editor__writing-flow { border: 1px solid $gray-600; @@ -9,21 +11,12 @@ box-sizing: border-box; } - .block-editor-inserter { - display: none; - } - .block-editor-block-contextual-toolbar.is-fixed, .block-editor-block-contextual-toolbar.is-fixed .block-editor-block-toolbar .components-toolbar-group, .block-editor-block-contextual-toolbar.is-fixed .block-editor-block-toolbar .components-toolbar { border-color: $gray-600; } - /* Hide rich text placeholder text */ - .rich-text [data-rich-text-placeholder] { - display: none !important; - } - /* hide block boundary background styling */ .rich-text:focus *[data-rich-text-format-boundary] { background: none !important; @@ -39,11 +32,6 @@ outline: none; } - .block-editor-block-list__empty-block-inserter, - .block-editor-block-list__insertion-point { - display: none !important; - } - .block-editor-writing-flow { padding: $gap-small; } @@ -56,11 +44,25 @@ } .components-accessible-toolbar { + height: $toolbar-height; width: 100%; background-color: $white; border-color: $gray-700; border-bottom-left-radius: 0; border-bottom-right-radius: 0; + + .components-button { + height: $toolbar-height; + } + } + + .block-editor-block-mover:not(.is-horizontal) .block-editor-block-mover__move-button-container > * { + height: calc( $toolbar-height / 2 ); + } + + .block-editor-block-contextual-toolbar.is-fixed, + .components-toolbar-group { + min-height: $toolbar-height; } .wp-block-quote { diff --git a/packages/js/components/src/rich-text-editor/utils/register-blocks.ts b/packages/js/components/src/rich-text-editor/utils/register-blocks.ts index cdcf514835e..566ff239bef 100644 --- a/packages/js/components/src/rich-text-editor/utils/register-blocks.ts +++ b/packages/js/components/src/rich-text-editor/utils/register-blocks.ts @@ -14,6 +14,8 @@ export const HEADING_BLOCK_ID = 'core/heading'; export const LIST_BLOCK_ID = 'core/list'; export const LIST_ITEM_BLOCK_ID = 'core/list-item'; export const QUOTE_BLOCK_ID = 'core/quote'; +export const IMAGE_BLOCK_ID = 'core/image'; +export const VIDEO_BLOCK_ID = 'core/video'; const ALLOWED_CORE_BLOCKS = [ PARAGRAPH_BLOCK_ID, @@ -21,6 +23,8 @@ const ALLOWED_CORE_BLOCKS = [ LIST_BLOCK_ID, LIST_ITEM_BLOCK_ID, QUOTE_BLOCK_ID, + IMAGE_BLOCK_ID, + VIDEO_BLOCK_ID, ]; const registerCoreBlocks = () => { diff --git a/plugins/woocommerce-admin/client/products/sections/product-details-section.tsx b/plugins/woocommerce-admin/client/products/sections/product-details-section.tsx index 7f8bfd0b979..b452d8d3478 100644 --- a/plugins/woocommerce-admin/client/products/sections/product-details-section.tsx +++ b/plugins/woocommerce-admin/client/products/sections/product-details-section.tsx @@ -226,6 +226,10 @@ export const ProductDetailsSection: React.FC = () => { setDescriptionBlocks( blocks ); setValue( 'description', serialize( blocks ) ); } } + placeholder={ __( + 'Describe this product. What makes it unique? What are its most important features?', + 'woocommerce' + ) } /> diff --git a/plugins/woocommerce/changelog/fix-rich-text-editor-selection b/plugins/woocommerce/changelog/fix-rich-text-editor-selection new file mode 100644 index 00000000000..88bcd847753 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-rich-text-editor-selection @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Add placeholder to description field