diff --git a/packages/block-editor/src/components/inserter/hooks/use-insertion-point.js b/packages/block-editor/src/components/inserter/hooks/use-insertion-point.js index fec66c1ef0913d..178f42ec04b159 100644 --- a/packages/block-editor/src/components/inserter/hooks/use-insertion-point.js +++ b/packages/block-editor/src/components/inserter/hooks/use-insertion-point.js @@ -59,7 +59,7 @@ function useInsertionPoint( { let _destinationRootClientId = rootClientId; let _destinationIndex; - if ( insertionIndex ) { + if ( insertionIndex !== undefined ) { // Insert into a specific index. _destinationIndex = insertionIndex; } else if ( clientId ) { diff --git a/packages/edit-widgets/src/blocks/widget-area/edit/index.js b/packages/edit-widgets/src/blocks/widget-area/edit/index.js index 9f2388265b0b23..1957361586e5a6 100644 --- a/packages/edit-widgets/src/blocks/widget-area/edit/index.js +++ b/packages/edit-widgets/src/blocks/widget-area/edit/index.js @@ -15,6 +15,7 @@ import { */ import WidgetAreaInnerBlocks from './inner-blocks'; import { store as editWidgetsStore } from '../../../store'; +import useIsDraggingWithin from './use-is-dragging-within'; /** @typedef {import('@wordpress/element').RefObject} RefObject */ @@ -68,16 +69,17 @@ export default function WidgetAreaEdit( { // unmounted when the panel is collapsed. Unmounting legacy // widgets may have unintended consequences (e.g. TinyMCE // not being properly reinitialized) - -
- - - -
+ + + + ) } @@ -117,51 +119,3 @@ const useIsDragging = ( elementRef ) => { return isDragging; }; - -/** - * A React hook to determine if it's dragging within the target element. - * - * @param {RefObject} elementRef The target elementRef object. - * - * @return {boolean} Is dragging within the target element. - */ -const useIsDraggingWithin = ( elementRef ) => { - const [ isDraggingWithin, setIsDraggingWithin ] = useState( false ); - - useEffect( () => { - const { ownerDocument } = elementRef.current; - - function handleDragStart( event ) { - // Check the first time when the dragging starts. - handleDragEnter( event ); - } - - // Set to false whenever the user cancel the drag event by either releasing the mouse or press Escape. - function handleDragEnd() { - setIsDraggingWithin( false ); - } - - function handleDragEnter( event ) { - // Check if the current target is inside the item element. - if ( elementRef.current.contains( event.target ) ) { - setIsDraggingWithin( true ); - } else { - setIsDraggingWithin( false ); - } - } - - // Bind these events to the document to catch all drag events. - // Ideally, we can also use `event.relatedTarget`, but sadly that doesn't work in Safari. - ownerDocument.addEventListener( 'dragstart', handleDragStart ); - ownerDocument.addEventListener( 'dragend', handleDragEnd ); - ownerDocument.addEventListener( 'dragenter', handleDragEnter ); - - return () => { - ownerDocument.removeEventListener( 'dragstart', handleDragStart ); - ownerDocument.removeEventListener( 'dragend', handleDragEnd ); - ownerDocument.removeEventListener( 'dragenter', handleDragEnter ); - }; - }, [] ); - - return isDraggingWithin; -}; diff --git a/packages/edit-widgets/src/blocks/widget-area/edit/inner-blocks.js b/packages/edit-widgets/src/blocks/widget-area/edit/inner-blocks.js index 15ca45640a4c1a..38d17428fac5f2 100644 --- a/packages/edit-widgets/src/blocks/widget-area/edit/inner-blocks.js +++ b/packages/edit-widgets/src/blocks/widget-area/edit/inner-blocks.js @@ -1,21 +1,53 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { useEntityBlockEditor } from '@wordpress/core-data'; -import { InnerBlocks } from '@wordpress/block-editor'; +import { + InnerBlocks, + __experimentalUseInnerBlocksProps, +} from '@wordpress/block-editor'; +import { useRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import useIsDraggingWithin from './use-is-dragging-within'; export default function WidgetAreaInnerBlocks() { const [ blocks, onInput, onChange ] = useEntityBlockEditor( 'root', 'postType' ); + const innerBlocksRef = useRef(); + const isDraggingWithinInnerBlocks = useIsDraggingWithin( innerBlocksRef ); + const shouldHighlightDropZone = isDraggingWithinInnerBlocks; + // Using the experimental hook so that we can control the className of the element. + const innerBlocksProps = __experimentalUseInnerBlocksProps( + { ref: innerBlocksRef }, + { + value: blocks, + onInput, + onChange, + templateLock: false, + renderAppender: InnerBlocks.ButtonBlockAppender, + } + ); + return ( - +
+
+
); } diff --git a/packages/edit-widgets/src/blocks/widget-area/edit/use-is-dragging-within.js b/packages/edit-widgets/src/blocks/widget-area/edit/use-is-dragging-within.js new file mode 100644 index 00000000000000..4588c7bda34a9d --- /dev/null +++ b/packages/edit-widgets/src/blocks/widget-area/edit/use-is-dragging-within.js @@ -0,0 +1,56 @@ +/** + * WordPress dependencies + */ +import { useState, useEffect } from '@wordpress/element'; + +/** @typedef {import('@wordpress/element').RefObject} RefObject */ + +/** + * A React hook to determine if it's dragging within the target element. + * + * @param {RefObject} elementRef The target elementRef object. + * + * @return {boolean} Is dragging within the target element. + */ +const useIsDraggingWithin = ( elementRef ) => { + const [ isDraggingWithin, setIsDraggingWithin ] = useState( false ); + + useEffect( () => { + const { ownerDocument } = elementRef.current; + + function handleDragStart( event ) { + // Check the first time when the dragging starts. + handleDragEnter( event ); + } + + // Set to false whenever the user cancel the drag event by either releasing the mouse or press Escape. + function handleDragEnd() { + setIsDraggingWithin( false ); + } + + function handleDragEnter( event ) { + // Check if the current target is inside the item element. + if ( elementRef.current.contains( event.target ) ) { + setIsDraggingWithin( true ); + } else { + setIsDraggingWithin( false ); + } + } + + // Bind these events to the document to catch all drag events. + // Ideally, we can also use `event.relatedTarget`, but sadly that doesn't work in Safari. + ownerDocument.addEventListener( 'dragstart', handleDragStart ); + ownerDocument.addEventListener( 'dragend', handleDragEnd ); + ownerDocument.addEventListener( 'dragenter', handleDragEnter ); + + return () => { + ownerDocument.removeEventListener( 'dragstart', handleDragStart ); + ownerDocument.removeEventListener( 'dragend', handleDragEnd ); + ownerDocument.removeEventListener( 'dragenter', handleDragEnter ); + }; + }, [] ); + + return isDraggingWithin; +}; + +export default useIsDraggingWithin; diff --git a/packages/edit-widgets/src/blocks/widget-area/editor.scss b/packages/edit-widgets/src/blocks/widget-area/editor.scss index e1c1fcbc69bc02..94c637fd08d6b6 100644 --- a/packages/edit-widgets/src/blocks/widget-area/editor.scss +++ b/packages/edit-widgets/src/blocks/widget-area/editor.scss @@ -1,3 +1,5 @@ +$panel-title-height: 48px; + .wp-block[data-type="core/widget-area"] { max-width: $widget-area-width; margin-left: auto; @@ -5,37 +7,66 @@ .components-panel__body > .components-panel__body-title { font-family: $default-font; - margin-bottom: 0; + margin: 0; + height: $panel-title-height; + // Create a stacking context and make sure it's higher is than the content. + // Since the inner blocks will be stretched to cover the whole panel, + // we still want the title to be interactive. + position: relative; + z-index: 1; + background: $white; + // z-index should be enough to create a new stacking context, + // unfortunately, Safari needs this to stop it from flickering while dragging. + // The reason behind that is still unknown, probably a bug in the browser. + transform: translateZ(0); // Remove default hover background in panel title. See #25752. &:hover { - background: inherit; + background: $white; } } - .components-panel__body .editor-styles-wrapper { - margin: 0 (-$grid-unit-20) (-$grid-unit-20) (-$grid-unit-20); - padding: $grid-unit-20; - } - .block-list-appender.wp-block { width: initial; } + // Override theme custom widths for blocks. .editor-styles-wrapper .wp-block.wp-block.wp-block.wp-block.wp-block { max-width: 100%; } + + .components-panel__body.is-opened { + padding: 0; + } } -// Add some spacing above the inner blocks so that the block toolbar doesn't -// overlap the panel header. -.wp-block-widget-area > .components-panel__body > div > .editor-styles-wrapper > .block-editor-inner-blocks { - padding-top: $grid-unit-30; +.blocks-widgets-container .wp-block-widget-area__inner-blocks.editor-styles-wrapper { + margin: 0; + padding: 0; - // Ensure the widget area block lists have a minimum height so that it doesn't - // collapse to zero height when it has no blocks. When that happens the block - // can't be used as a drop target. > .block-editor-block-list__layout { + // Stretch the inner-blocks container to cover the entire panel, + // so that dragging onto anywhere in it works. + margin-top: -$panel-title-height; + // Add some spacing above the inner blocks so that the block toolbar doesn't + // overlap the panel header. + padding: ($panel-title-height + $grid-unit-30) $grid-unit-20 $grid-unit-20; + + // Ensure the widget area block lists have a minimum height so that it doesn't + // collapse to zero height when it has no blocks. When that happens the block + // can't be used as a drop target. min-height: $grid-unit-40; } } + +.wp-block-widget-area__highlight-drop-zone { + outline: var(--wp-admin-border-width-focus) solid var(--wp-admin-theme-color); +} + +// Prevent "dragenter" event from firing when dragging onto the title component. +body.is-dragging-components-draggable .wp-block[data-type="core/widget-area"] .components-panel__body > .components-panel__body-title { + &, + * { + pointer-events: none; + } +}