From d4a2d69162604bc862c5032c66907215bacbade5 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Tue, 31 Jan 2023 14:11:40 +0200 Subject: [PATCH 1/5] Block Editor: Introduce loading screen component --- .../src/components/loading-screen/index.js | 123 ++++++++++++++++++ .../src/components/loading-screen/style.scss | 20 +++ 2 files changed, 143 insertions(+) create mode 100644 packages/block-editor/src/components/loading-screen/index.js create mode 100644 packages/block-editor/src/components/loading-screen/style.scss diff --git a/packages/block-editor/src/components/loading-screen/index.js b/packages/block-editor/src/components/loading-screen/index.js new file mode 100644 index 0000000000000..c22dbdf355c5d --- /dev/null +++ b/packages/block-editor/src/components/loading-screen/index.js @@ -0,0 +1,123 @@ +/** + * WordPress dependencies + */ +import { + createContext, + Suspense, + useEffect, + useState, +} from '@wordpress/element'; +import { Modal, Spinner } from '@wordpress/components'; +import { useSuspenseSelect } from '@wordpress/data'; + +const LoadingScreenContext = createContext( false ); + +/** + * Component that declares a data dependency. + * Will suspend if data has not resolved. + * + * @param {Object} props Component props + * @param {import('@wordpress/data').StoreDescriptor} props.store Data store descriptor + * @param {string} props.selector Selector name + * @param {Array} props.args Optional arguments to pass to the selector + */ +const SuspenseDataDependency = ( { store, selector, args = [] } ) => { + useSuspenseSelect( + ( select ) => select( store )[ selector ]( ...args ), + [] + ); + + return null; +}; + +/** + * Component that will render a loading screen if dependencies have not resolved, + * or its children if all dependencies have resolved. + * + * @param {Object} props Component props + * @param {Array} props.dataDependencies Array of dependencies + * @param {string} props.children Component children + */ +const SuspenseWithLoadingScreen = ( { dataDependencies, children } ) => { + const [ loaded, setLoaded ] = useState( false ); + + const finishedLoading = () => { + if ( ! loaded ) { + setLoaded( true ); + } + }; + + return ( + + { loaded ? ( + <> + + { children } + + ) : ( + } + > + { dataDependencies.map( + ( { store, selector, args }, depindex ) => ( + + ) + ) } + { children } + + ) } + + ); +}; + +/** + * Renders a loading screen. + * Supports automatic closing with the `autoClose` prop. + * + * @param {Object} props Component props + * @param {Function?} props.onUnmount Optional callback to call on unmount. + * @param {boolean} props.autoClose Whether to automatically close. + */ +const LoadingScreen = ( { onUnmount, autoClose } ) => { + const [ visible, setVisible ] = useState( true ); + + useEffect( () => { + if ( autoClose ) { + setTimeout( () => { + setVisible( false ); + }, 2000 ); + } + + return () => { + if ( onUnmount ) { + onUnmount(); + } + }; + } ); + + if ( ! visible ) { + return null; + } + + return ( + {} } + __experimentalHideHeader + className="block-editor-loading-screen-modal" + overlayClassName="block-editor-loading-screen-modal-overlay" + > +
+ +
+
+ ); +}; + +export default SuspenseWithLoadingScreen; diff --git a/packages/block-editor/src/components/loading-screen/style.scss b/packages/block-editor/src/components/loading-screen/style.scss new file mode 100644 index 0000000000000..61540cce40a39 --- /dev/null +++ b/packages/block-editor/src/components/loading-screen/style.scss @@ -0,0 +1,20 @@ +.block-editor-loading-screen-modal-overlay { + backdrop-filter: none; + background-color: transparent; + padding-top: $header-height; +} + +.block-editor-loading-screen-modal.is-full-screen { + box-shadow: 0 0 0 transparent; + width: 100%; + max-width: 100%; + max-height: 100%; + min-height: 100%; +} + +.block-editor-loading-screen-wrapper { + display: flex; + align-items: center; + justify-content: center; + height: 100%; +} From 9aa932a17fe78632ad8f85547188b3082267d1c6 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Tue, 31 Jan 2023 14:12:10 +0200 Subject: [PATCH 2/5] Block Editor: Expose LoadingScreen --- packages/block-editor/src/components/index.js | 1 + packages/block-editor/src/style.scss | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index f113ad3b05f63..77e0fbb7f48cc 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -71,6 +71,7 @@ export { default as __experimentalLinkControlSearchResults } from './link-contro export { default as __experimentalLinkControlSearchItem } from './link-control/search-item'; export { default as LineHeightControl } from './line-height-control'; export { default as __experimentalListView } from './list-view'; +export { default as __experimentalLoadingScreen } from './loading-screen'; export { default as MediaReplaceFlow } from './media-replace-flow'; export { default as MediaPlaceholder } from './media-placeholder'; export { default as MediaUpload } from './media-upload'; diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss index d5ec18cb4c69f..9b57a5445d583 100644 --- a/packages/block-editor/src/style.scss +++ b/packages/block-editor/src/style.scss @@ -35,6 +35,7 @@ @import "./components/justify-content-control/style.scss"; @import "./components/link-control/style.scss"; @import "./components/list-view/style.scss"; +@import "./components/loading-screen/style.scss"; @import "./components/media-replace-flow/style.scss"; @import "./components/multi-selection-inspector/style.scss"; @import "./components/responsive-block-control/style.scss"; From 676dc67db5e4be33809e692b74eb3f890281e45c Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Tue, 31 Jan 2023 14:13:09 +0200 Subject: [PATCH 3/5] Site Editor: Try loading screen with experimental dependencies --- .../edit-site/src/components/editor/index.js | 96 ++++++++++++++----- 1 file changed, 74 insertions(+), 22 deletions(-) diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 434554bbda7e8..dd2163160ac99 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -4,11 +4,12 @@ import { useMemo } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; import { Notice } from '@wordpress/components'; -import { EntityProvider } from '@wordpress/core-data'; +import { EntityProvider, store as coreStore } from '@wordpress/core-data'; import { store as preferencesStore } from '@wordpress/preferences'; import { BlockContextProvider, BlockBreadcrumb, + __experimentalLoadingScreen as LoadingScreen, store as blockEditorStore, } from '@wordpress/block-editor'; import { @@ -68,6 +69,7 @@ export default function Editor() { isListViewOpen, showIconLabels, showBlockBreadcrumbs, + globalStylesId, } = useSelect( ( select ) => { const { getEditedPostContext, @@ -76,8 +78,16 @@ export default function Editor() { isInserterOpened, isListViewOpened, } = unlock( select( editSiteStore ) ); + const { + __experimentalGetCurrentGlobalStylesId, + getEditedEntityRecord, + } = select( coreStore ); const { __unstableGetEditorMode } = select( blockEditorStore ); const { getActiveComplementaryArea } = select( interfaceStore ); + const _globalStylesId = __experimentalGetCurrentGlobalStylesId(); + const globalStylesRecord = _globalStylesId + ? getEditedEntityRecord( 'root', 'globalStyles', _globalStylesId ) + : undefined; // The currently selected entity to display. // Typically template or template part in the site editor. @@ -99,6 +109,8 @@ export default function Editor() { 'core/edit-site', 'showBlockBreadcrumbs' ), + globalStylesId: _globalStylesId, + globalStylesRecord, }; }, [] ); const { setEditedPostContext } = useDispatch( editSiteStore ); @@ -152,6 +164,42 @@ export default function Editor() { // action in from double-announcing. useTitle( hasLoadedPost && title ); + const contentDependencies = [ + // Global styles entity ID + { + store: coreStore, + selector: '__experimentalGetCurrentGlobalStylesId', + }, + // Global styles entity + globalStylesId && { + store: coreStore, + selector: 'getEditedEntityRecord', + args: [ 'root', 'globalStyles', globalStylesId ], + }, + // Menus + { + store: coreStore, + selector: 'getEntityRecords', + args: [ 'root', 'menu', { per_page: -1, context: 'edit' } ], + }, + // Pages + { + store: coreStore, + selector: 'getEntityRecords', + args: [ + 'postType', + 'page', + { + parent: 0, + order: 'asc', + orderby: 'id', + per_page: -1, + context: 'view', + }, + ], + }, + ].filter( Boolean ); + if ( ! hasLoadedPost ) { return ; } @@ -174,27 +222,31 @@ export default function Editor() { notices={ isEditMode && } content={ <> - - { isEditMode && } - { showVisualEditor && editedPost && ( - - ) } - { editorMode === 'text' && - editedPost && - isEditMode && } - { hasLoadedPost && ! editedPost && ( - - { __( - "You attempted to edit an item that doesn't exist. Perhaps it was deleted?" - ) } - - ) } - { isEditMode && ( - - ) } + + + { isEditMode && } + { showVisualEditor && editedPost && ( + + ) } + { editorMode === 'text' && + editedPost && + isEditMode && } + { hasLoadedPost && ! editedPost && ( + + { __( + "You attempted to edit an item that doesn't exist. Perhaps it was deleted?" + ) } + + ) } + { isEditMode && ( + + ) } + } secondarySidebar={ From 85b1deb4feb017fef31129f533f996b3aed8eb0a Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Tue, 31 Jan 2023 16:35:18 +0200 Subject: [PATCH 4/5] Add support for view canvas mode --- .../src/components/loading-screen/index.js | 44 ++++++++++++++----- .../src/components/loading-screen/style.scss | 4 ++ .../edit-site/src/components/editor/index.js | 5 +++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/packages/block-editor/src/components/loading-screen/index.js b/packages/block-editor/src/components/loading-screen/index.js index c22dbdf355c5d..ab614df128b52 100644 --- a/packages/block-editor/src/components/loading-screen/index.js +++ b/packages/block-editor/src/components/loading-screen/index.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import classNames from 'classnames'; + /** * WordPress dependencies */ @@ -34,11 +39,16 @@ const SuspenseDataDependency = ( { store, selector, args = [] } ) => { * Component that will render a loading screen if dependencies have not resolved, * or its children if all dependencies have resolved. * - * @param {Object} props Component props - * @param {Array} props.dataDependencies Array of dependencies - * @param {string} props.children Component children + * @param {Object} props Component props + * @param {Array} props.dataDependencies Array of dependencies + * @param {string} props.children Component children + * @param {string?} props.overlayClassName Additional overlay classname */ -const SuspenseWithLoadingScreen = ( { dataDependencies, children } ) => { +const SuspenseWithLoadingScreen = ( { + dataDependencies, + children, + overlayClassName, +} ) => { const [ loaded, setLoaded ] = useState( false ); const finishedLoading = () => { @@ -51,12 +61,20 @@ const SuspenseWithLoadingScreen = ( { dataDependencies, children } ) => { { loaded ? ( <> - + { children } ) : ( } + fallback={ + + } > { dataDependencies.map( ( { store, selector, args }, depindex ) => ( @@ -79,11 +97,12 @@ const SuspenseWithLoadingScreen = ( { dataDependencies, children } ) => { * Renders a loading screen. * Supports automatic closing with the `autoClose` prop. * - * @param {Object} props Component props - * @param {Function?} props.onUnmount Optional callback to call on unmount. - * @param {boolean} props.autoClose Whether to automatically close. + * @param {Object} props Component props + * @param {Function?} props.onUnmount Optional callback to call on unmount. + * @param {boolean} props.autoClose Whether to automatically close. + * @param {string?} props.overlayClassName Additional overlay classname */ -const LoadingScreen = ( { onUnmount, autoClose } ) => { +const LoadingScreen = ( { onUnmount, autoClose, overlayClassName } ) => { const [ visible, setVisible ] = useState( true ); useEffect( () => { @@ -111,7 +130,10 @@ const LoadingScreen = ( { onUnmount, autoClose } ) => { onRequestClose={ () => {} } __experimentalHideHeader className="block-editor-loading-screen-modal" - overlayClassName="block-editor-loading-screen-modal-overlay" + overlayClassName={ classNames( + 'block-editor-loading-screen-modal-overlay', + overlayClassName + ) } >
diff --git a/packages/block-editor/src/components/loading-screen/style.scss b/packages/block-editor/src/components/loading-screen/style.scss index 61540cce40a39..5764c01fd01f2 100644 --- a/packages/block-editor/src/components/loading-screen/style.scss +++ b/packages/block-editor/src/components/loading-screen/style.scss @@ -4,6 +4,10 @@ padding-top: $header-height; } +.block-editor-loading-screen-modal-overlay.is-canvas-view { + padding-top: 0; +} + .block-editor-loading-screen-modal.is-full-screen { box-shadow: 0 0 0 transparent; width: 100%; diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index dd2163160ac99..5ee724c3fd498 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -224,6 +224,11 @@ export default function Editor() { <> { isEditMode && } From 5444d21526d15bd4d0b32ee754f9bb509ae1aa4c Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Tue, 31 Jan 2023 16:55:23 +0200 Subject: [PATCH 5/5] Add current post entity as a dependency --- packages/edit-site/src/components/editor/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 5ee724c3fd498..44706ec97df19 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -165,6 +165,12 @@ export default function Editor() { useTitle( hasLoadedPost && title ); const contentDependencies = [ + // Current post entity, + { + store: coreStore, + selector: 'getEntityRecord', + args: [ 'postType', 'postType', editedPostId ], + }, // Global styles entity ID { store: coreStore,