From a529a6350d5ef6a4af9a88239f520b67f4b2b80e Mon Sep 17 00:00:00 2001 From: Andrew Serong Date: Thu, 21 Jan 2021 17:11:48 +1100 Subject: [PATCH 1/5] Remove iframe from starter page templates preview --- .../components/block-iframe-preview.js | 259 ------------------ .../components/block-layout-preview.js | 181 ++++++++++++ .../components/block-preview.js | 2 +- .../components/template-selector-preview.js | 9 +- .../styles/starter-page-templates-editor.scss | 10 +- 5 files changed, 191 insertions(+), 270 deletions(-) delete mode 100644 apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-iframe-preview.js create mode 100644 apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-iframe-preview.js b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-iframe-preview.js deleted file mode 100644 index 7a0729a1a7d7f..0000000000000 --- a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-iframe-preview.js +++ /dev/null @@ -1,259 +0,0 @@ -/** - * External dependencies - */ -import { each, filter, get, castArray, debounce, noop } from 'lodash'; -import classnames from 'classnames'; - -/** - * WordPress dependencies - */ -import { - createPortal, - useRef, - useEffect, - useState, - useMemo, - useReducer, - useLayoutEffect, - useCallback, -} from '@wordpress/element'; -import { withSelect } from '@wordpress/data'; -import { compose, withSafeTimeout } from '@wordpress/compose'; - -import { __ } from '@wordpress/i18n'; - -import CustomBlockPreview from './block-preview'; - -// Debounce time applied to the on resize window event. -const DEBOUNCE_TIMEOUT = 300; - -/** - * Copies the styles from the provided src document - * to the given iFrame head and body DOM references. - * - * @param {object} srcDocument the src document from which to copy the - * `link` and `style` Nodes from the `head` and `body` - * @param {object} targetiFrameDocument the target iframe's - * `contentDocument` where the `link` and `style` Nodes from the `head` and - * `body` will be copied - */ -const copyStylesToIframe = ( srcDocument, targetiFrameDocument ) => { - const styleNodes = [ 'link', 'style' ]; - - // See https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment - const targetDOMFragment = { - head: document.createDocumentFragment(), // eslint-disable-line no-undef - body: document.createDocumentFragment(), // eslint-disable-line no-undef - }; - - each( Object.keys( targetDOMFragment ), ( domReference ) => { - return each( - filter( srcDocument[ domReference ].children, ( { localName } ) => - // Only return specific style-related Nodes - styleNodes.includes( localName ) - ), - ( targetNode ) => { - // Clone the original node and append to the appropriate Fragement - const deep = true; - targetDOMFragment[ domReference ].appendChild( targetNode.cloneNode( deep ) ); - } - ); - } ); - - // Consolidate updates to iframe DOM - targetiFrameDocument.head.appendChild( targetDOMFragment.head ); - targetiFrameDocument.body.appendChild( targetDOMFragment.body ); -}; - -/** - * Performs a blocks preview using an iFrame. - * - * @param {object} props component's props - * @param {object} props.className CSS class to apply to component - * @param {string} props.bodyClassName CSS class to apply to the iframe's `` tag - * @param {number} props.viewportWidth pixel width of the viewable size of the preview - * @param {Array} props.blocks array of Gutenberg Block objects - * @param {object} props.settings block Editor settings object - * @param {Function} props.setTimeout safe version of window.setTimeout via `withSafeTimeout` - * @param {string} props.title Template Title - see #39831 for details. - */ -const BlockFramePreview = ( { - className = 'block-iframe-preview', - bodyClassName = 'block-iframe-preview-body', - viewportWidth, - blocks, - settings, - setTimeout = noop, - title, -} ) => { - const frameContainerRef = useRef(); - const iframeRef = useRef(); - - // Set the initial scale factor. - const [ style, setStyle ] = useState( { - transform: `scale( 1 )`, - } ); - - // Rendering blocks list. - const renderedBlocks = useMemo( () => castArray( blocks ), [ blocks ] ); - const [ recomputeBlockListKey, triggerRecomputeBlockList ] = useReducer( - ( state ) => state + 1, - 0 - ); - useLayoutEffect( triggerRecomputeBlockList, [ blocks ] ); - - /** - * This function re scales the viewport depending on - * the wrapper and the iframe width. - */ - const rescale = useCallback( () => { - const parentNode = get( frameContainerRef, [ 'current', 'parentNode' ] ); - if ( ! parentNode ) { - return; - } - - // Scaling iFrame. - const width = viewportWidth || frameContainerRef.current.offsetWidth; - const scale = parentNode.offsetWidth / viewportWidth; - const height = parentNode.offsetHeight / scale; - - setStyle( { - width, - height, - transform: `scale( ${ scale } )`, - } ); - }, [ viewportWidth ] ); - - /* - * Temporarily manually set the PostTitle from DOM. - * It isn't currently possible to manually force the `` component - * to render a title provided as a prop. A Core PR will rectify this (see below). - * Until then we use direct DOM manipulation to set the post title. - * - * See: https://github.com/WordPress/gutenberg/pull/20609/ - */ - useEffect( () => { - if ( ! title ) return; - - const iframeBody = get( iframeRef, [ 'current', 'contentDocument', 'body' ] ); - if ( ! iframeBody ) { - return; - } - - const templateTitle = iframeBody.querySelector( - '.editor-post-title .editor-post-title__input' - ); - - if ( ! templateTitle ) { - return; - } - - templateTitle.value = title; - }, [ recomputeBlockListKey ] ); - - // Populate iFrame styles. - useEffect( () => { - setTimeout( () => { - copyStylesToIframe( window.document, iframeRef.current.contentDocument ); - iframeRef.current.contentDocument.body.classList.add( - bodyClassName, - 'editor-styles-wrapper', - 'block-editor__container' - ); - /* - * Temporarly override height of the Post Title. - * Post Title component doesn't resize correctly, - * this quick CSS fix overrides the height to be auto - * A Core PR will rectify this (see below). - * - * See: https://github.com/WordPress/gutenberg/pull/20609/ - */ - iframeRef.current.contentDocument.head.innerHTML += - ''; - - // Prevent links and buttons from being clicked. This is applied within - // the iframe, because if we targeted the iframe itself it would prevent - // scrolling the iframe in Firefox. - iframeRef.current.contentDocument.head.innerHTML += - ''; - - rescale(); - }, 0 ); - }, [ setTimeout, bodyClassName, rescale ] ); - - // Scroll the preview to the top when the blocks change. - useEffect( () => { - const body = get( iframeRef, [ 'current', 'contentDocument', 'body' ] ); - if ( ! body ) { - return; - } - - // scroll to top when blocks changes. - body.scrollTop = 0; - }, [ recomputeBlockListKey ] ); - - // Handling windows resize event. - useEffect( () => { - const refreshPreview = debounce( rescale, DEBOUNCE_TIMEOUT ); - window.addEventListener( 'resize', refreshPreview ); - - return () => { - window.removeEventListener( 'resize', refreshPreview ); - }; - }, [ rescale ] ); - - // Handle wp-admin specific `wp-collapse-menu` event to refresh the preview on sidebar toggle. - useEffect( () => { - if ( window.jQuery ) { - window.jQuery( window.document ).on( 'wp-collapse-menu', rescale ); - } - return () => { - if ( window.jQuery ) { - window.jQuery( window.document ).off( 'wp-collapse-menu', rescale ); - } - }; - }, [ rescale ] ); - - /* eslint-disable wpcalypso/jsx-classname-namespace */ - return ( -
- -
- ); - /* eslint-enable wpcalypso/jsx-classname-namespace */ -}; - -export default compose( - withSafeTimeout, - withSelect( ( select ) => { - const blockEditorStore = select( 'core/block-editor' ); - return { - settings: blockEditorStore ? blockEditorStore.getSettings() : {}, - }; - } ) -)( BlockFramePreview ); diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js new file mode 100644 index 0000000000000..9961ccad90a96 --- /dev/null +++ b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js @@ -0,0 +1,181 @@ +/** + * External dependencies + */ +import { get, castArray, debounce, noop } from 'lodash'; +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { + useRef, + useEffect, + useState, + useMemo, + useReducer, + useLayoutEffect, + useCallback, +} from '@wordpress/element'; +import { withSelect } from '@wordpress/data'; +import { compose, withSafeTimeout } from '@wordpress/compose'; + +import CustomBlockPreview from './block-preview'; + +// Debounce time applied to the on resize window event. +const DEBOUNCE_TIMEOUT = 300; + +/** + * A blocks layout preview. + * + * @param {object} props component's props + * @param {object} props.className CSS class to apply to component + * @param {string} props.bodyClassName CSS class to apply to the preview body + * @param {number} props.viewportWidth pixel width of the viewable size of the preview + * @param {Array} props.blocks array of Gutenberg Block objects + * @param {object} props.settings block Editor settings object + * @param {string} props.title Template Title - see #39831 for details. + */ +const BlockLayoutPreview = ( { + className = 'spt-block-layout-preview', + bodyClassName = 'spt-block-layout-preview-body', + viewportWidth, + blocks, + settings, + title, +} ) => { + const frameContainerRef = useRef(); + + // Set the initial scale factor. + const [ style, setStyle ] = useState( { + transform: `scale( 1 )`, + } ); + + // Rendering blocks list. + const renderedBlocks = useMemo( () => castArray( blocks ), [ blocks ] ); + const [ recomputeBlockListKey, triggerRecomputeBlockList ] = useReducer( + ( state ) => state + 1, + 0 + ); + useLayoutEffect( triggerRecomputeBlockList, [ blocks ] ); + + /** + * This function re scales the viewport depending on + * the wrapper and the iframe width. + */ + const rescale = useCallback( () => { + const parentNode = get( frameContainerRef, [ 'current', 'parentNode' ] ); + if ( ! parentNode ) { + return; + } + + // Scaling iFrame. + const width = viewportWidth || frameContainerRef.current.offsetWidth; + const scale = parentNode.offsetWidth / viewportWidth; + const height = parentNode.offsetHeight / scale; + + setStyle( { + width, + height, + transform: `scale( ${ scale } )`, + } ); + }, [ viewportWidth ] ); + + /* + * Temporarily manually set the PostTitle from DOM. + * It isn't currently possible to manually force the `` component + * to render a title provided as a prop. A Core PR will rectify this (see below). + * Until then we use direct DOM manipulation to set the post title. + * + * See: https://github.com/WordPress/gutenberg/pull/20609/ + */ + useEffect( () => { + if ( ! title ) { + return; + } + + const previewBody = document.querySelector( `.${ className }` ); + + if ( ! previewBody ) { + return; + } + + const templateTitle = previewBody.querySelector( + '.editor-post-title .editor-post-title__input' + ); + + if ( ! templateTitle ) { + return; + } + + templateTitle.value = title; + }, [ recomputeBlockListKey ] ); + + // Scroll the preview to the top when the blocks change. + useEffect( () => { + const templatePreivew = document.querySelector( '.template-selector-preview' ); + if ( ! templatePreivew ) { + return; + } + + // scroll to top when blocks changes. + templatePreivew.scrollTop = 0; + }, [ recomputeBlockListKey ] ); + + // Handling windows resize event. + useEffect( () => { + const refreshPreview = debounce( rescale, DEBOUNCE_TIMEOUT ); + window.addEventListener( 'resize', refreshPreview ); + + return () => { + window.removeEventListener( 'resize', refreshPreview ); + }; + }, [ rescale ] ); + + // Handle wp-admin specific `wp-collapse-menu` event to refresh the preview on sidebar toggle. + useEffect( () => { + if ( window.jQuery ) { + window.jQuery( window.document ).on( 'wp-collapse-menu', rescale ); + } + return () => { + if ( window.jQuery ) { + window.jQuery( window.document ).off( 'wp-collapse-menu', rescale ); + } + }; + }, [ rescale ] ); + + /* eslint-disable wpcalypso/jsx-classname-namespace */ + return ( +
+
+
+
+
+
+ +
+
+
+
+
+
+ ); + /* eslint-enable wpcalypso/jsx-classname-namespace */ +}; + +export default compose( + withSafeTimeout, + withSelect( ( select ) => { + const blockEditorStore = select( 'core/block-editor' ); + return { + settings: blockEditorStore ? blockEditorStore.getSettings() : {}, + }; + } ) +)( BlockLayoutPreview ); diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-preview.js b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-preview.js index 438fd16ca6777..bcc4bc303a850 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-preview.js +++ b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-preview.js @@ -24,7 +24,7 @@ export default function ( { blocks, settings, hidePageTitle, recomputeBlockListK { ! hidePageTitle && ( -
+
) } diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/template-selector-preview.js b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/template-selector-preview.js index a2328d36db8f4..c286be2a83285 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/template-selector-preview.js +++ b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/template-selector-preview.js @@ -6,7 +6,7 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import BlockIframePreview from './block-iframe-preview'; +import BlockLayoutPreview from './block-layout-preview'; const TemplateSelectorPreview = ( { blocks = [], viewportWidth, title } ) => { const noBlocks = ! blocks.length; @@ -21,10 +21,9 @@ const TemplateSelectorPreview = ( { blocks = [], viewportWidth, title } ) => {
) } - { /* Always render preview iframe to ensure it's ready to populate with Blocks. */ - /* Without this some browsers will experience a noticavle delay - /* before Blocks are populated into the iframe. */ } - + { ! noBlocks && ( + + ) } /* eslint-enable wpcalypso/jsx-classname-namespace */ ); diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss index 4b1820b52e158..74296c7dbfef6 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss +++ b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss @@ -275,7 +275,7 @@ body.admin-bar:not( .is-fullscreen-mode ) .page-template-modal-screen-overlay { right: $preview-right-margin; background: $template-selector-empty-background; border-radius: 2px; - overflow: hidden; + overflow-y: scroll; box-shadow: 0 2px 2px 0 rgba( 0, 0, 0, 0.14 ), 0 3px 1px -2px rgba( 0, 0, 0, 0.12 ), 0 1px 5px 0 rgba( 0, 0, 0, 0.2 ); @@ -382,7 +382,7 @@ body.admin-bar:not( .is-fullscreen-mode ) .page-template-modal-screen-overlay { } } -.block-iframe-preview { +.spt-block-layout-preview { position: absolute; top: 0; left: 0; @@ -395,10 +395,10 @@ body.admin-bar:not( .is-fullscreen-mode ) .page-template-modal-screen-overlay { // Fallback viewport width. // Used when BlockFramePreview's viewportWidth prop is undefined. // Can be overridden through more specific CSS. - width: 1440px; + width: 100%; } -.block-iframe-preview-body { +.spt-block-layout-preview-body { margin: 0; padding: 0; overflow-x: hidden; @@ -471,7 +471,7 @@ body.admin-bar:not( .is-fullscreen-mode ) .page-template-modal-screen-overlay { } // Tweak template title (post-title) component. - .block-iframe-preview__template-title { + .spt-block-layout-preview__template-title { padding-top: 20px; } From 79a37895c62505b6cdc3450a13aedc8e85af4fd9 Mon Sep 17 00:00:00 2001 From: Andrew Serong Date: Thu, 21 Jan 2021 17:20:00 +1100 Subject: [PATCH 2/5] Set initial scale and fix typo in constant name --- .../components/block-layout-preview.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js index 9961ccad90a96..e06fa8ac755d5 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js +++ b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { get, castArray, debounce, noop } from 'lodash'; +import { get, castArray, debounce } from 'lodash'; import classnames from 'classnames'; /** @@ -112,13 +112,13 @@ const BlockLayoutPreview = ( { // Scroll the preview to the top when the blocks change. useEffect( () => { - const templatePreivew = document.querySelector( '.template-selector-preview' ); - if ( ! templatePreivew ) { + const templatePreview = document.querySelector( '.template-selector-preview' ); + if ( ! templatePreview ) { return; } // scroll to top when blocks changes. - templatePreivew.scrollTop = 0; + templatePreview.scrollTop = 0; }, [ recomputeBlockListKey ] ); // Handling windows resize event. @@ -126,6 +126,9 @@ const BlockLayoutPreview = ( { const refreshPreview = debounce( rescale, DEBOUNCE_TIMEOUT ); window.addEventListener( 'resize', refreshPreview ); + // Call once initially to ensure layouts are set to the correct scale at the outset. + rescale(); + return () => { window.removeEventListener( 'resize', refreshPreview ); }; From 159fa92c1e17d6517cacf92f9da46d0f791a9673 Mon Sep 17 00:00:00 2001 From: Andrew Serong Date: Thu, 21 Jan 2021 17:35:47 +1100 Subject: [PATCH 3/5] Fix horizontal scrollbar on empty state in Firefox --- .../styles/starter-page-templates-editor.scss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss index 74296c7dbfef6..5f89332c7a9c2 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss +++ b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss @@ -324,12 +324,11 @@ body.admin-bar:not( .is-fullscreen-mode ) .page-template-modal-screen-overlay { .template-selector-preview__empty-state { position: absolute; - width: 100%; - text-align: center; height: 50px; line-height: 50px; top: 50%; - margin: -25px 0 0; + left: 50%; + transform: translate( -50%, -50% ); } } } From d7ccfd572b74bbcd9e5609bda06b9fb1f8acba00 Mon Sep 17 00:00:00 2001 From: Andrew Serong Date: Fri, 22 Jan 2021 12:26:58 +1100 Subject: [PATCH 4/5] Fix selector for scrollTop --- .../page-template-modal/components/block-layout-preview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js index e06fa8ac755d5..45fdfdd5e5096 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js +++ b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js @@ -112,7 +112,7 @@ const BlockLayoutPreview = ( { // Scroll the preview to the top when the blocks change. useEffect( () => { - const templatePreview = document.querySelector( '.template-selector-preview' ); + const templatePreview = document.querySelector( `.${ className }` ); if ( ! templatePreview ) { return; } From fc61a8a56c25a243f833910b2822ddfcd0626771 Mon Sep 17 00:00:00 2001 From: Andrew Serong Date: Fri, 22 Jan 2021 17:28:19 +1100 Subject: [PATCH 5/5] Hide Add Title placeholder text in the post title within the preview --- .../components/block-layout-preview.js | 31 ++++++++++--------- .../styles/starter-page-templates-editor.scss | 5 +++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js index 45fdfdd5e5096..078a9053a6778 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js +++ b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/components/block-layout-preview.js @@ -89,25 +89,28 @@ const BlockLayoutPreview = ( { * See: https://github.com/WordPress/gutenberg/pull/20609/ */ useEffect( () => { - if ( ! title ) { - return; - } + // Perform update next render, as the post title input field may not yet be available. + setTimeout( () => { + if ( ! title ) { + return; + } - const previewBody = document.querySelector( `.${ className }` ); + const previewBody = document.querySelector( `.${ className }` ); - if ( ! previewBody ) { - return; - } + if ( ! previewBody ) { + return; + } - const templateTitle = previewBody.querySelector( - '.editor-post-title .editor-post-title__input' - ); + const templateTitle = previewBody.querySelector( + '.editor-post-title .editor-post-title__input' + ); - if ( ! templateTitle ) { - return; - } + if ( ! templateTitle ) { + return; + } - templateTitle.value = title; + templateTitle.value = title; + }, 0 ); }, [ recomputeBlockListKey ] ); // Scroll the preview to the top when the blocks change. diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss index 5f89332c7a9c2..9e1d34dcc9959 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss +++ b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss @@ -409,6 +409,11 @@ body.admin-bar:not( .is-fullscreen-mode ) .page-template-modal-screen-overlay { margin: 0; } + // Hide page title placeholder. + .editor-post-title__input::placeholder { + color: transparent !important; + } + // Hide inserter/appender. .block-list-appender, .block-editor-inserter {