[Product Block Editor]: move Modal editor out of the description block edit component (#41878)
This commit is contained in:
commit
6fab5dc8eb
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: update
|
||||
|
||||
[Product Block Editor]: move Modal edittor out of the description block edit component
|
|
@ -2,7 +2,7 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { createElement } from '@wordpress/element';
|
||||
import { createElement, useEffect } from '@wordpress/element';
|
||||
import {
|
||||
BlockAttributes,
|
||||
BlockInstance,
|
||||
|
@ -19,10 +19,9 @@ import { useEntityProp } from '@wordpress/core-data';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import { ContentPreview } from '../../../components/content-preview';
|
||||
import { ModalEditor } from '../../../components/modal-editor';
|
||||
import { ProductEditorBlockEditProps } from '../../../types';
|
||||
import ModalEditorWelcomeGuide from '../../../components/modal-editor-welcome-guide';
|
||||
import { store as productEditorUiStore } from '../../../store/product-editor-ui';
|
||||
import { store } from '../../../store/product-editor-ui';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -58,19 +57,43 @@ export function DescriptionBlockEdit( {
|
|||
'description'
|
||||
);
|
||||
|
||||
// Check if the Modal editor is open from the store.
|
||||
const isModalEditorOpen = useSelect( ( select ) => {
|
||||
return select( productEditorUiStore ).isModalEditorOpen();
|
||||
}, [] );
|
||||
// Pick Modal editor data from the store.
|
||||
const { isModalEditorOpen, modalEditorBlocks, hasChanged } = useSelect(
|
||||
( select ) => {
|
||||
return {
|
||||
isModalEditorOpen: select( store ).isModalEditorOpen(),
|
||||
modalEditorBlocks: select( store ).getModalEditorBlocks(),
|
||||
hasChanged: select( store ).getModalEditorContentHasChanged(),
|
||||
};
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const { openModalEditor, closeModalEditor } =
|
||||
useDispatch( productEditorUiStore );
|
||||
const { openModalEditor, setModalEditorBlocks } = useDispatch( store );
|
||||
|
||||
// Update the description when the blocks change.
|
||||
useEffect( () => {
|
||||
if ( ! hasChanged ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! modalEditorBlocks?.length ) {
|
||||
setDescription( '' );
|
||||
}
|
||||
|
||||
const html = serialize( clearDescriptionIfEmpty( modalEditorBlocks ) );
|
||||
setDescription( html );
|
||||
}, [ modalEditorBlocks, setDescription, hasChanged ] );
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={ () => {
|
||||
if ( description ) {
|
||||
setModalEditorBlocks( parse( description ) );
|
||||
}
|
||||
|
||||
openModalEditor();
|
||||
recordEvent( 'product_add_description_click' );
|
||||
} }
|
||||
|
@ -80,20 +103,6 @@ export function DescriptionBlockEdit( {
|
|||
: __( 'Add description', 'woocommerce' ) }
|
||||
</Button>
|
||||
|
||||
{ isModalEditorOpen && (
|
||||
<ModalEditor
|
||||
initialBlocks={ parse( description ) }
|
||||
onChange={ ( blocks ) => {
|
||||
const html = serialize(
|
||||
clearDescriptionIfEmpty( blocks )
|
||||
);
|
||||
setDescription( html );
|
||||
} }
|
||||
onClose={ closeModalEditor }
|
||||
title={ __( 'Edit description', 'woocommerce' ) }
|
||||
/>
|
||||
) }
|
||||
|
||||
{ !! description.length && (
|
||||
<ContentPreview content={ description } />
|
||||
) }
|
||||
|
|
|
@ -6,6 +6,7 @@ import { createElement, useMemo, useLayoutEffect } from '@wordpress/element';
|
|||
import { useDispatch, useSelect, select as WPSelect } from '@wordpress/data';
|
||||
import { uploadMedia } from '@wordpress/media-utils';
|
||||
import { PluginArea } from '@wordpress/plugins';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore No types for this exist yet.
|
||||
|
@ -34,6 +35,8 @@ import {
|
|||
import { useConfirmUnsavedProductChanges } from '../../hooks/use-confirm-unsaved-product-changes';
|
||||
import { ProductEditorContext } from '../../types';
|
||||
import { PostTypeContext } from '../../contexts/post-type-context';
|
||||
import { ModalEditor } from '../modal-editor';
|
||||
import { store as productEditorUiStore } from '../../store/product-editor-ui';
|
||||
|
||||
type BlockEditorSettings = Partial<
|
||||
EditorSettings & EditorBlockListSettings
|
||||
|
@ -111,10 +114,26 @@ export function BlockEditor( {
|
|||
updateEditorSettings( settings ?? {} );
|
||||
}, [ productType, productId ] );
|
||||
|
||||
// Check if the Modal editor is open from the store.
|
||||
const isModalEditorOpen = useSelect( ( select ) => {
|
||||
return select( productEditorUiStore ).isModalEditorOpen();
|
||||
}, [] );
|
||||
|
||||
const { closeModalEditor } = useDispatch( productEditorUiStore );
|
||||
|
||||
if ( ! blocks ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( isModalEditorOpen ) {
|
||||
return (
|
||||
<ModalEditor
|
||||
onClose={ closeModalEditor }
|
||||
title={ __( 'Edit description', 'woocommerce' ) }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="woocommerce-product-block-editor">
|
||||
<BlockContextProvider value={ context }>
|
||||
|
@ -123,6 +142,7 @@ export function BlockEditor( {
|
|||
onInput={ onInput }
|
||||
onChange={ onChange }
|
||||
settings={ settings }
|
||||
useSubRegistry={ false }
|
||||
>
|
||||
{ /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */ }
|
||||
{ /* @ts-ignore No types for this exist yet. */ }
|
||||
|
|
|
@ -31,31 +31,41 @@ import { HeaderToolbar } from './header-toolbar/header-toolbar';
|
|||
import { ResizableEditor } from './resizable-editor';
|
||||
import { SecondarySidebar } from './secondary-sidebar/secondary-sidebar';
|
||||
import { useEditorHistory } from './hooks/use-editor-history';
|
||||
import { store as productEditorUiStore } from '../../store/product-editor-ui';
|
||||
|
||||
type IframeEditorProps = {
|
||||
closeModal?: () => void;
|
||||
initialBlocks?: BlockInstance[];
|
||||
onChange?: ( blocks: BlockInstance[] ) => void;
|
||||
onClose?: () => void;
|
||||
onInput?: ( blocks: BlockInstance[] ) => void;
|
||||
settings?: Partial< EditorSettings & EditorBlockListSettings > | undefined;
|
||||
showBackButton?: boolean;
|
||||
};
|
||||
|
||||
export function IframeEditor( {
|
||||
closeModal = () => {},
|
||||
initialBlocks = [],
|
||||
onChange = () => {},
|
||||
onClose,
|
||||
onInput = () => {},
|
||||
settings: __settings,
|
||||
showBackButton = false,
|
||||
}: IframeEditorProps ) {
|
||||
const [ resizeObserver ] = useResizeObserver();
|
||||
const [ blocks, setBlocks ] = useState< BlockInstance[] >( initialBlocks );
|
||||
const [ temporalBlocks, setTemporalBlocks ] =
|
||||
useState< BlockInstance[] >( initialBlocks );
|
||||
|
||||
// Pick the blocks from the store.
|
||||
const blocks: BlockInstance[] = useSelect( ( select ) => {
|
||||
return select( productEditorUiStore ).getModalEditorBlocks();
|
||||
}, [] );
|
||||
|
||||
const { setModalEditorBlocks: setBlocks, setModalEditorContentHasChanged } =
|
||||
useDispatch( productEditorUiStore );
|
||||
|
||||
const { appendEdit } = useEditorHistory( {
|
||||
setBlocks,
|
||||
} );
|
||||
|
||||
const {
|
||||
appendEdit: tempAppendEdit,
|
||||
hasRedo,
|
||||
|
@ -127,15 +137,16 @@ export function IframeEditor( {
|
|||
onSave={ () => {
|
||||
appendEdit( temporalBlocks );
|
||||
setBlocks( temporalBlocks );
|
||||
setModalEditorContentHasChanged( true );
|
||||
onChange( temporalBlocks );
|
||||
closeModal();
|
||||
onClose?.();
|
||||
} }
|
||||
onCancel={ () => {
|
||||
appendEdit( blocks );
|
||||
setBlocks( blocks );
|
||||
onChange( blocks );
|
||||
setTemporalBlocks( blocks );
|
||||
closeModal();
|
||||
onClose?.();
|
||||
} }
|
||||
/>
|
||||
<div className="woocommerce-iframe-editor__main">
|
||||
|
@ -157,7 +168,7 @@ export function IframeEditor( {
|
|||
{ /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */ }
|
||||
{ /* @ts-ignore */ }
|
||||
<BlockEditorKeyboardShortcuts.Register />
|
||||
{ onClose && (
|
||||
{ showBackButton && onClose && (
|
||||
<BackButton
|
||||
onClick={ () => {
|
||||
setTimeout( onClose, 550 );
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
import { BlockInstance } from '@wordpress/blocks';
|
||||
import { createElement } from '@wordpress/element';
|
||||
import { useDispatch } from '@wordpress/data';
|
||||
import {
|
||||
EditorSettings,
|
||||
EditorBlockListSettings,
|
||||
|
@ -14,11 +15,12 @@ import { useDebounce } from '@wordpress/compose';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import { IframeEditor } from '../iframe-editor';
|
||||
import { store as productEditorUiStore } from '../../store/product-editor-ui';
|
||||
|
||||
type ModalEditorProps = {
|
||||
initialBlocks?: BlockInstance[];
|
||||
onChange: ( blocks: BlockInstance[] ) => void;
|
||||
onClose: () => void;
|
||||
onChange?: ( blocks: BlockInstance[] ) => void;
|
||||
onClose?: () => void;
|
||||
settings?: Partial< EditorSettings & EditorBlockListSettings > | undefined;
|
||||
title: string;
|
||||
};
|
||||
|
@ -29,16 +31,19 @@ export function ModalEditor( {
|
|||
onClose,
|
||||
title,
|
||||
}: ModalEditorProps ) {
|
||||
const { closeModalEditor } = useDispatch( productEditorUiStore );
|
||||
|
||||
const debouncedOnChange = useDebounce( ( blocks: BlockInstance[] ) => {
|
||||
onChange( blocks );
|
||||
onChange?.( blocks );
|
||||
}, 250 );
|
||||
|
||||
function handleClose() {
|
||||
const blocks = debouncedOnChange.flush();
|
||||
if ( blocks ) {
|
||||
onChange( blocks );
|
||||
onChange?.( blocks );
|
||||
}
|
||||
onClose();
|
||||
closeModalEditor();
|
||||
onClose?.();
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -52,7 +57,7 @@ export function ModalEditor( {
|
|||
initialBlocks={ initialBlocks }
|
||||
onInput={ debouncedOnChange }
|
||||
onChange={ debouncedOnChange }
|
||||
closeModal={ handleClose }
|
||||
onClose={ handleClose }
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
|
|
|
@ -1,18 +1,36 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { BlockInstance } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
ACTION_MODAL_EDITOR_CLOSE,
|
||||
ACTION_MODAL_EDITOR_OPEN,
|
||||
ACTION_MODAL_EDITOR_SET_BLOCKS,
|
||||
ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED,
|
||||
} from './constants';
|
||||
|
||||
const modalEditorActions = {
|
||||
openModalEditor: () => ( {
|
||||
type: ACTION_MODAL_EDITOR_OPEN,
|
||||
} ),
|
||||
|
||||
closeModalEditor: () => ( {
|
||||
type: ACTION_MODAL_EDITOR_CLOSE,
|
||||
} ),
|
||||
|
||||
setModalEditorBlocks: ( blocks: BlockInstance ) => ( {
|
||||
type: ACTION_MODAL_EDITOR_SET_BLOCKS,
|
||||
blocks,
|
||||
} ),
|
||||
|
||||
setModalEditorContentHasChanged: ( hasChanged: boolean ) => ( {
|
||||
type: ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED,
|
||||
hasChanged,
|
||||
} ),
|
||||
};
|
||||
|
||||
export default {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/**
|
||||
* Full editor actions
|
||||
*/
|
||||
export const ACTION_MODAL_EDITOR_OPEN = 'MODAL_EDITOROPEN';
|
||||
export const ACTION_MODAL_EDITOR_CLOSE = 'MODAL_EDITORCLOSE';
|
||||
export const ACTION_MODAL_EDITOR_OPEN = 'MODAL_EDITOR_OPEN';
|
||||
export const ACTION_MODAL_EDITOR_CLOSE = 'MODAL_EDITOR_CLOSE';
|
||||
export const ACTION_MODAL_EDITOR_SET_BLOCKS = 'MODAL_EDITOR_SET_BLOCKS';
|
||||
export const ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED =
|
||||
'MODAL_EDITOR_CONTENT_HAS_CHANGED';
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED,
|
||||
ACTION_MODAL_EDITOR_CLOSE,
|
||||
ACTION_MODAL_EDITOR_OPEN,
|
||||
ACTION_MODAL_EDITOR_SET_BLOCKS,
|
||||
} from './constants';
|
||||
import type {
|
||||
ProductEditorModalEditorAction,
|
||||
|
@ -16,6 +18,8 @@ import type {
|
|||
const INITIAL_STATE: ProductEditorUIStateProps = {
|
||||
modalEditor: {
|
||||
isOpen: false,
|
||||
blocks: [],
|
||||
hasChanged: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -28,16 +32,37 @@ export default function reducer(
|
|||
return {
|
||||
...state,
|
||||
modalEditor: {
|
||||
...state.modalEditor,
|
||||
isOpen: true,
|
||||
},
|
||||
};
|
||||
|
||||
case ACTION_MODAL_EDITOR_CLOSE:
|
||||
return {
|
||||
...state,
|
||||
modalEditor: {
|
||||
...state.modalEditor,
|
||||
isOpen: false,
|
||||
},
|
||||
};
|
||||
|
||||
case ACTION_MODAL_EDITOR_SET_BLOCKS:
|
||||
return {
|
||||
...state,
|
||||
modalEditor: {
|
||||
...state.modalEditor,
|
||||
blocks: action.blocks || [],
|
||||
},
|
||||
};
|
||||
|
||||
case ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED:
|
||||
return {
|
||||
...state,
|
||||
modalEditor: {
|
||||
...state.modalEditor,
|
||||
hasChanged: action?.hasChanged || false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { BlockInstance } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
|
||||
import type { ProductEditorUIStateProps } from './types';
|
||||
|
||||
export default {
|
||||
|
@ -10,4 +14,16 @@ export default {
|
|||
) {
|
||||
return state.modalEditor.isOpen;
|
||||
},
|
||||
|
||||
getModalEditorBlocks: function getModalEditorBlocks(
|
||||
state: ProductEditorUIStateProps
|
||||
): BlockInstance[] {
|
||||
return state.modalEditor.blocks;
|
||||
},
|
||||
|
||||
getModalEditorContentHasChanged: function getModalEditorContentHasChanged(
|
||||
state: ProductEditorUIStateProps
|
||||
): boolean {
|
||||
return !! state.modalEditor.hasChanged;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,17 +1,34 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { BlockInstance } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED,
|
||||
ACTION_MODAL_EDITOR_CLOSE,
|
||||
ACTION_MODAL_EDITOR_OPEN,
|
||||
ACTION_MODAL_EDITOR_SET_BLOCKS,
|
||||
} from './constants';
|
||||
|
||||
export type ProductEditorUIStateProps = {
|
||||
modalEditor: {
|
||||
isOpen: boolean;
|
||||
blocks: BlockInstance[];
|
||||
hasChanged?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type ProductEditorModalEditorAction = {
|
||||
type: typeof ACTION_MODAL_EDITOR_OPEN | typeof ACTION_MODAL_EDITOR_CLOSE;
|
||||
type:
|
||||
| typeof ACTION_MODAL_EDITOR_OPEN
|
||||
| typeof ACTION_MODAL_EDITOR_CLOSE
|
||||
| typeof ACTION_MODAL_EDITOR_SET_BLOCKS
|
||||
| typeof ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED;
|
||||
|
||||
blocks?: BlockInstance[];
|
||||
|
||||
hasChanged?: boolean;
|
||||
};
|
||||
|
|
|
@ -26283,7 +26283,6 @@ packages:
|
|||
/flow-parser@0.223.3:
|
||||
resolution: {integrity: sha512-9KxxDKSB22ovMpSULbOL/QAQGPN6M0YMS3PubQvB0jVc4W7QP6VhasIVic7MzKcJSh0BAVs4J6SZjoH0lDDNlg==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
dev: true
|
||||
|
||||
/flush-write-stream@1.1.1:
|
||||
resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==}
|
||||
|
@ -31875,7 +31874,7 @@ packages:
|
|||
'@babel/register': 7.22.15(@babel/core@7.23.5)
|
||||
babel-core: 7.0.0-bridge.0(@babel/core@7.23.5)
|
||||
chalk: 4.1.2
|
||||
flow-parser: 0.206.0
|
||||
flow-parser: 0.223.3
|
||||
graceful-fs: 4.2.11
|
||||
micromatch: 4.0.5
|
||||
neo-async: 2.6.2
|
||||
|
|
Loading…
Reference in New Issue