{} } />
Date: Mon, 15 Jan 2024 15:43:41 +1100
Subject: [PATCH 25/32] Use drag chip as on trunk, but with opacity of 0.8
---
.../components/list-view/block-contents.js | 10 +---
.../src/components/list-view/leaf.js | 6 +-
.../src/components/list-view/style.scss | 56 +------------------
.../list-view/use-list-view-drop-zone.js | 18 +-----
.../components/use-moving-animation/index.js | 51 ++++++++---------
5 files changed, 29 insertions(+), 112 deletions(-)
diff --git a/packages/block-editor/src/components/list-view/block-contents.js b/packages/block-editor/src/components/list-view/block-contents.js
index a3de14e61ef235..0537a4b48cbe46 100644
--- a/packages/block-editor/src/components/list-view/block-contents.js
+++ b/packages/block-editor/src/components/list-view/block-contents.js
@@ -47,12 +47,8 @@ const ListViewBlockContents = forwardRef(
[]
);
- const {
- AdditionalBlockContent,
- insertedBlock,
- listViewInstanceId,
- setInsertedBlock,
- } = useListViewContext();
+ const { AdditionalBlockContent, insertedBlock, setInsertedBlock } =
+ useListViewContext();
const isBlockMoveTarget =
blockMovingClientId && selectedBlockInBlockEditor === clientId;
@@ -82,8 +78,6 @@ const ListViewBlockContents = forwardRef(
appendToOwnerDocument
clientIds={ draggableClientIds }
cloneClassname={ 'block-editor-list-view-draggable-chip' }
- dragComponent={ null }
- elementId={ `list-view-${ listViewInstanceId }-block-${ clientId }` }
>
{ ( { draggable, onDragStart, onDragEnd } ) => (
{
const animationRef = useMovingAnimation( {
- isSelected,
- adjustScrolling: false,
+ clientId: props[ 'data-block' ],
enableAnimation: true,
triggerAnimationOnChange: path,
- elementSelector: isDragged
- ? '.block-editor-list-view-draggable-chip .block-editor-list-view-leaf'
- : undefined,
} );
const mergedRef = useMergeRefs( [ ref, animationRef ] );
diff --git a/packages/block-editor/src/components/list-view/style.scss b/packages/block-editor/src/components/list-view/style.scss
index a73863f038c006..347b52069415ee 100644
--- a/packages/block-editor/src/components/list-view/style.scss
+++ b/packages/block-editor/src/components/list-view/style.scss
@@ -426,61 +426,7 @@
$block-navigation-max-indent: 8;
.block-editor-list-view-draggable-chip {
- .block-editor-list-view-leaf {
- // The drag chip uses a transparent background to ensure that the nesting level
- // for where a user drops the dragged block is visible.
- background-color: rgba(255, 255, 255, 0.5);
- border-radius: $radius-block-ui;
- box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
- display: flex;
- height: 36px;
- // Where possible, restrict the width of the cloned row to the width of the list view.
- max-width: 338px;
- opacity: 1;
-
- // Reset colors to use the admin color.
- td {
- background: none !important;
- .block-editor-list-view-block-select-button,
- .block-editor-block-icon,
- .components-button.has-icon {
- color: var(--wp-admin-theme-color) !important;
- }
- }
-
- .block-editor-list-view__expander {
- // Remove indent on the expander, as the dragged component offsets the entire row.
- margin-left: 0 !important;
- }
-
- // Apply a margin offset to account for nesting level.
- &[aria-level] {
- margin-left: ( $icon-size ) * $block-navigation-max-indent + 4 * ( $block-navigation-max-indent - 1 );
- }
-
- // When updating the margin for each indentation level, the corresponding
- // indentation in `use-list-view-drop-zone.js` must be updated as well
- // to ensure the drop zone is aligned with the indentation.
- @for $i from 0 to $block-navigation-max-indent {
- &[aria-level="#{ $i + 1 }"] {
- @if $i - 1 >= 0 {
- margin-left: ( $icon-size * $i ) + 4 * ($i - 1) !important;
- }
- @else {
- margin-left: ( $icon-size * $i ) !important;
- }
- }
- }
-
- .block-editor-list-view-block__contents-cell {
- flex: 1;
- }
-
- .block-editor-list-view-block__menu-cell {
- display: flex;
- align-items: center;
- }
- }
+ opacity: 0.8;
}
.block-editor-list-view-block__contents-cell,
diff --git a/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js b/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js
index ab6e9b62bdaa02..47ccdc8a1d1f88 100644
--- a/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js
+++ b/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js
@@ -490,7 +490,7 @@ export default function useListViewDropZone( {
const throttled = useThrottle(
useCallback(
( event, currentTarget ) => {
- let position = { x: event.clientX, y: event.clientY };
+ const position = { x: event.clientX, y: event.clientY };
const isBlockDrag = !! draggedBlockClientIds?.length;
const blockElements = Array.from(
@@ -531,22 +531,6 @@ export default function useListViewDropZone( {
};
} );
- const { ownerDocument } = currentTarget || {};
- const dragChipBlockElement = ownerDocument?.querySelector(
- '.block-editor-list-view-draggable-chip .block-editor-block-icon'
- );
-
- if ( dragChipBlockElement ) {
- const dragChipBlockRect =
- dragChipBlockElement.getBoundingClientRect();
- position = {
- x: rtl
- ? dragChipBlockRect.right
- : dragChipBlockRect.left,
- y: dragChipBlockRect.top + dragChipBlockRect.height / 2,
- };
- }
-
const newTarget = getListViewDropTarget(
blocksData,
position,
diff --git a/packages/block-editor/src/components/use-moving-animation/index.js b/packages/block-editor/src/components/use-moving-animation/index.js
index cbc33f047f5e0d..ee1a4610a1d4cf 100644
--- a/packages/block-editor/src/components/use-moving-animation/index.js
+++ b/packages/block-editor/src/components/use-moving-animation/index.js
@@ -21,6 +21,13 @@ import { store as blockEditorStore } from '../../store';
*/
const BLOCK_ANIMATION_THRESHOLD = 200;
+function getAbsolutePosition( element ) {
+ return {
+ top: element.offsetTop,
+ left: element.offsetLeft,
+ };
+}
+
/**
* Hook used to compute the styles required to move a div into a new position.
*
@@ -32,15 +39,15 @@ const BLOCK_ANIMATION_THRESHOLD = 200;
* - It uses the "resetAnimation" flag to reset the animation
* from the beginning in order to animate to the new destination point.
*
- * @param {Object} $1 Options
- * @param {*} $1.triggerAnimationOnChange Variable used to trigger the animation if it changes.
- * @param {string} $1.elementSelector A CSS selector string used to find the position of an element to animate from.
- * @param {string} $1.clientId
+ * @param {Object} $1 Options
+ * @param {boolean} $1.enableAnimation Whether to enable the animation.
+ * @param {*} $1.triggerAnimationOnChange Variable used to trigger the animation if it changes.
+ * @param {string} $1.clientId
*/
function useMovingAnimation( {
+ enableAnimation = true,
triggerAnimationOnChange,
clientId,
- elementSelector,
} ) {
const ref = useRef();
const {
@@ -54,30 +61,17 @@ function useMovingAnimation( {
// Whenever the trigger changes, we need to take a snapshot of the current
// position of the block to use it as a destination point for the animation.
- const { prevRect } = useMemo(
- () => {
- let previousPosition;
-
- if ( ref.current && elementSelector ) {
- const { ownerDocument } = ref.current;
- const element = ownerDocument.querySelector( elementSelector );
- if ( element ) {
- previousPosition = element.getBoundingClientRect();
- }
- } else if ( ref.current ) {
- previousPosition = ref.current.getBoundingClientRect();
- }
-
- return {
- prevRect: previousPosition,
- };
- },
+ const { previous, prevRect } = useMemo(
+ () => ( {
+ previous: ref.current && getAbsolutePosition( ref.current ),
+ prevRect: ref.current && ref.current.getBoundingClientRect(),
+ } ),
// eslint-disable-next-line react-hooks/exhaustive-deps
[ triggerAnimationOnChange ]
);
useLayoutEffect( () => {
- if ( ! prevRect || ! ref.current ) {
+ if ( ! previous || ! ref.current ) {
return;
}
@@ -104,6 +98,7 @@ function useMovingAnimation( {
// To do: consider enableing the _moving_ animation even for large
// posts, while only disabling the _insertion_ animation?
const disableAnimation =
+ ! enableAnimation ||
window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches ||
isTyping() ||
getGlobalBlockCount() > BLOCK_ANIMATION_THRESHOLD;
@@ -144,10 +139,10 @@ function useMovingAnimation( {
} );
ref.current.style.transform = undefined;
- const destination = ref.current.getBoundingClientRect();
+ const destination = getAbsolutePosition( ref.current );
- const x = Math.round( prevRect.left - destination.left );
- const y = Math.round( prevRect.top - destination.top );
+ const x = Math.round( previous.left - destination.left );
+ const y = Math.round( previous.top - destination.top );
controller.start( { x: 0, y: 0, from: { x, y } } );
@@ -155,8 +150,10 @@ function useMovingAnimation( {
controller.stop();
};
}, [
+ previous,
prevRect,
clientId,
+ enableAnimation,
isTyping,
getGlobalBlockCount,
isBlockSelected,
From 66ac213028d46f6ca9ce448bfb8421d465091af6 Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Mon, 15 Jan 2024 15:56:16 +1100
Subject: [PATCH 26/32] Consolidate drop indicator logic
---
.../list-view/drop-indicator-preview.js | 346 ------------------
.../components/list-view/drop-indicator.js | 180 ++++++---
.../src/components/list-view/index.js | 2 +-
3 files changed, 138 insertions(+), 390 deletions(-)
delete mode 100644 packages/block-editor/src/components/list-view/drop-indicator-preview.js
diff --git a/packages/block-editor/src/components/list-view/drop-indicator-preview.js b/packages/block-editor/src/components/list-view/drop-indicator-preview.js
deleted file mode 100644
index 9879221b8c6b6e..00000000000000
--- a/packages/block-editor/src/components/list-view/drop-indicator-preview.js
+++ /dev/null
@@ -1,346 +0,0 @@
-/**
- * External dependencies
- */
-import classnames from 'classnames';
-
-/**
- * WordPress dependencies
- */
-import {
- __experimentalHStack as HStack,
- __experimentalTruncate as Truncate,
- Popover,
-} from '@wordpress/components';
-
-import { getScrollContainer } from '@wordpress/dom';
-import { useCallback, useMemo } from '@wordpress/element';
-import { isRTL } from '@wordpress/i18n';
-
-/**
- * Internal dependencies
- */
-import BlockIcon from '../block-icon';
-import useBlockDisplayInformation from '../use-block-display-information';
-import useBlockDisplayTitle from '../block-title/use-block-display-title';
-import ListViewExpander from './expander';
-
-export default function ListViewDropIndicatorPreview( {
- draggedBlockClientId,
- listViewRef,
- blockDropTarget,
-} ) {
- const blockInformation = useBlockDisplayInformation( draggedBlockClientId );
- const blockTitle = useBlockDisplayTitle( {
- clientId: draggedBlockClientId,
- context: 'list-view',
- } );
-
- const { rootClientId, clientId, dropPosition } = blockDropTarget || {};
-
- const [ rootBlockElement, blockElement ] = useMemo( () => {
- if ( ! listViewRef.current ) {
- return [];
- }
-
- // The rootClientId will be defined whenever dropping into inner
- // block lists, but is undefined when dropping at the root level.
- const _rootBlockElement = rootClientId
- ? listViewRef.current.querySelector(
- `[data-block="${ rootClientId }"]`
- )
- : undefined;
-
- // The clientId represents the sibling block, the dragged block will
- // usually be inserted adjacent to it. It will be undefined when
- // dropping a block into an empty block list.
- const _blockElement = clientId
- ? listViewRef.current.querySelector(
- `[data-block="${ clientId }"]`
- )
- : undefined;
-
- return [ _rootBlockElement, _blockElement ];
- }, [ listViewRef, rootClientId, clientId ] );
-
- // The targetElement is the element that the drop indicator will appear
- // before or after. When dropping into an empty block list, blockElement
- // is undefined, so the indicator will appear after the rootBlockElement.
- const targetElement = blockElement || rootBlockElement;
-
- const rtl = isRTL();
-
- const getDropIndicatorWidth = useCallback(
- ( targetElementRect, indent ) => {
- if ( ! targetElement ) {
- return 0;
- }
-
- // Default to assuming that the width of the drop indicator
- // should be the same as the target element.
- let width = targetElement.offsetWidth;
-
- // In deeply nested lists, where a scrollbar is present,
- // the width of the drop indicator should be the width of
- // the scroll container, minus the distance from the left
- // edge of the scroll container to the left edge of the
- // target element.
- const scrollContainer = getScrollContainer(
- targetElement,
- 'horizontal'
- );
-
- const ownerDocument = targetElement.ownerDocument;
- const windowScroll =
- scrollContainer === ownerDocument.body ||
- scrollContainer === ownerDocument.documentElement;
-
- if ( scrollContainer && ! windowScroll ) {
- const scrollContainerRect =
- scrollContainer.getBoundingClientRect();
-
- const distanceBetweenContainerAndTarget = isRTL()
- ? scrollContainerRect.right - targetElementRect.right
- : targetElementRect.left - scrollContainerRect.left;
-
- const scrollContainerWidth = scrollContainer.clientWidth;
-
- if (
- scrollContainerWidth <
- width + distanceBetweenContainerAndTarget
- ) {
- width =
- scrollContainerWidth -
- distanceBetweenContainerAndTarget;
- }
-
- // LTR logic for ensuring the drop indicator does not extend
- // beyond the right edge of the scroll container.
- if (
- ! rtl &&
- targetElementRect.left + indent < scrollContainerRect.left
- ) {
- width -= scrollContainerRect.left - targetElementRect.left;
- return width;
- }
-
- // RTL logic for ensuring the drop indicator does not extend
- // beyond the right edge of the scroll container.
- if (
- rtl &&
- targetElementRect.right - indent > scrollContainerRect.right
- ) {
- width -=
- targetElementRect.right - scrollContainerRect.right;
- return width;
- }
- }
-
- // Subtract the indent from the final width of the indicator.
- return width - indent;
- },
- [ rtl, targetElement ]
- );
-
- const style = useMemo( () => {
- if ( ! targetElement ) {
- return {};
- }
-
- const targetElementRect = targetElement.getBoundingClientRect();
-
- return {
- width: getDropIndicatorWidth( targetElementRect, 0 ),
- };
- }, [ getDropIndicatorWidth, targetElement ] );
-
- const horizontalScrollOffsetStyle = useMemo( () => {
- if ( ! targetElement ) {
- return {};
- }
-
- const scrollContainer = getScrollContainer( targetElement );
- const ownerDocument = targetElement.ownerDocument;
- const windowScroll =
- scrollContainer === ownerDocument.body ||
- scrollContainer === ownerDocument.documentElement;
-
- if ( scrollContainer && ! windowScroll ) {
- const scrollContainerRect = scrollContainer.getBoundingClientRect();
- const targetElementRect = targetElement.getBoundingClientRect();
-
- const distanceBetweenContainerAndTarget = rtl
- ? scrollContainerRect.right - targetElementRect.right
- : targetElementRect.left - scrollContainerRect.left;
-
- if ( ! rtl && scrollContainerRect.left > targetElementRect.left ) {
- return {
- transform: `translateX( ${ distanceBetweenContainerAndTarget }px )`,
- };
- }
-
- if ( rtl && scrollContainerRect.right < targetElementRect.right ) {
- return {
- transform: `translateX( ${
- distanceBetweenContainerAndTarget * -1
- }px )`,
- };
- }
- }
-
- return {};
- }, [ rtl, targetElement ] );
-
- const ariaLevel = useMemo( () => {
- if ( ! rootBlockElement ) {
- return 1;
- }
-
- const _ariaLevel = parseInt(
- rootBlockElement.getAttribute( 'aria-level' ),
- 10
- );
-
- return _ariaLevel ? _ariaLevel + 1 : 1;
- }, [ rootBlockElement ] );
-
- const hasAdjacentSelectedBranch = useMemo( () => {
- if ( ! targetElement ) {
- return false;
- }
-
- return targetElement.classList.contains( 'is-branch-selected' );
- }, [ targetElement ] );
-
- const popoverAnchor = useMemo( () => {
- const isValidDropPosition =
- dropPosition === 'top' ||
- dropPosition === 'bottom' ||
- dropPosition === 'inside';
- if ( ! targetElement || ! isValidDropPosition ) {
- return undefined;
- }
-
- return {
- contextElement: targetElement,
- getBoundingClientRect() {
- const rect = targetElement.getBoundingClientRect();
- // In RTL languages, the drop indicator should be positioned
- // to the left of the target element, with the width of the
- // indicator determining the indent at the right edge of the
- // target element. In LTR languages, the drop indicator should
- // end at the right edge of the target element, with the indent
- // added to the position of the left edge of the target element.
- // let left = rtl ? rect.left : rect.left + indent;
- let left = rect.left;
- let top = 0;
-
- // In deeply nested lists, where a scrollbar is present,
- // the width of the drop indicator should be the width of
- // the visible area of the scroll container. Additionally,
- // the left edge of the drop indicator line needs to be
- // offset by the distance the left edge of the target element
- // and the left edge of the scroll container. The ensures
- // that the drop indicator position never breaks out of the
- // visible area of the scroll container.
- const scrollContainer = getScrollContainer(
- targetElement,
- 'horizontal'
- );
-
- const doc = targetElement.ownerDocument;
- const windowScroll =
- scrollContainer === doc.body ||
- scrollContainer === doc.documentElement;
-
- // If the scroll container is not the window, offset the left position, if need be.
- if ( scrollContainer && ! windowScroll ) {
- const scrollContainerRect =
- scrollContainer.getBoundingClientRect();
-
- // In RTL languages, a vertical scrollbar is present on the
- // left edge of the scroll container. The width of the
- // scrollbar needs to be accounted for when positioning the
- // drop indicator.
- const scrollbarWidth = rtl
- ? scrollContainer.offsetWidth -
- scrollContainer.clientWidth
- : 0;
-
- if ( left < scrollContainerRect.left + scrollbarWidth ) {
- left = scrollContainerRect.left + scrollbarWidth;
- }
- }
-
- if ( dropPosition === 'top' ) {
- top = rect.top - rect.height * 2;
- } else {
- // `dropPosition` is either `bottom` or `inside`
- top = rect.top;
- }
-
- const width = getDropIndicatorWidth( rect, 0 );
- const height = rect.height;
-
- return new window.DOMRect( left, top, width, height );
- },
- };
- }, [ targetElement, dropPosition, getDropIndicatorWidth, rtl ] );
-
- if ( ! targetElement ) {
- return null;
- }
-
- return (
-
-
-
-
- {} } />
-
-
-
-
- { blockTitle }
-
-
-
-
-
-
-
-
- );
-}
diff --git a/packages/block-editor/src/components/list-view/drop-indicator.js b/packages/block-editor/src/components/list-view/drop-indicator.js
index d46ca03c4bd0e8..9879221b8c6b6e 100644
--- a/packages/block-editor/src/components/list-view/drop-indicator.js
+++ b/packages/block-editor/src/components/list-view/drop-indicator.js
@@ -1,15 +1,40 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
/**
* WordPress dependencies
*/
-import { Popover } from '@wordpress/components';
+import {
+ __experimentalHStack as HStack,
+ __experimentalTruncate as Truncate,
+ Popover,
+} from '@wordpress/components';
+
import { getScrollContainer } from '@wordpress/dom';
import { useCallback, useMemo } from '@wordpress/element';
import { isRTL } from '@wordpress/i18n';
-export default function ListViewDropIndicator( {
+/**
+ * Internal dependencies
+ */
+import BlockIcon from '../block-icon';
+import useBlockDisplayInformation from '../use-block-display-information';
+import useBlockDisplayTitle from '../block-title/use-block-display-title';
+import ListViewExpander from './expander';
+
+export default function ListViewDropIndicatorPreview( {
+ draggedBlockClientId,
listViewRef,
blockDropTarget,
} ) {
+ const blockInformation = useBlockDisplayInformation( draggedBlockClientId );
+ const blockTitle = useBlockDisplayTitle( {
+ clientId: draggedBlockClientId,
+ context: 'list-view',
+ } );
+
const { rootClientId, clientId, dropPosition } = blockDropTarget || {};
const [ rootBlockElement, blockElement ] = useMemo( () => {
@@ -35,7 +60,7 @@ export default function ListViewDropIndicator( {
: undefined;
return [ _rootBlockElement, _blockElement ];
- }, [ rootClientId, clientId ] );
+ }, [ listViewRef, rootClientId, clientId ] );
// The targetElement is the element that the drop indicator will appear
// before or after. When dropping into an empty block list, blockElement
@@ -44,27 +69,6 @@ export default function ListViewDropIndicator( {
const rtl = isRTL();
- const getDropIndicatorIndent = useCallback(
- ( targetElementRect ) => {
- if ( ! rootBlockElement ) {
- return 0;
- }
-
- // Calculate the indent using the block icon of the root block.
- // Using a classname selector here might be flaky and could be
- // improved.
- const rootBlockIconElement = rootBlockElement.querySelector(
- '.block-editor-block-icon'
- );
- const rootBlockIconRect =
- rootBlockIconElement.getBoundingClientRect();
- return rtl
- ? targetElementRect.right - rootBlockIconRect.left
- : rootBlockIconRect.right - targetElementRect.left;
- },
- [ rootBlockElement, rtl ]
- );
-
const getDropIndicatorWidth = useCallback(
( targetElementRect, indent ) => {
if ( ! targetElement ) {
@@ -143,12 +147,69 @@ export default function ListViewDropIndicator( {
}
const targetElementRect = targetElement.getBoundingClientRect();
- const indent = getDropIndicatorIndent( targetElementRect );
return {
- width: getDropIndicatorWidth( targetElementRect, indent ),
+ width: getDropIndicatorWidth( targetElementRect, 0 ),
};
- }, [ getDropIndicatorIndent, getDropIndicatorWidth, targetElement ] );
+ }, [ getDropIndicatorWidth, targetElement ] );
+
+ const horizontalScrollOffsetStyle = useMemo( () => {
+ if ( ! targetElement ) {
+ return {};
+ }
+
+ const scrollContainer = getScrollContainer( targetElement );
+ const ownerDocument = targetElement.ownerDocument;
+ const windowScroll =
+ scrollContainer === ownerDocument.body ||
+ scrollContainer === ownerDocument.documentElement;
+
+ if ( scrollContainer && ! windowScroll ) {
+ const scrollContainerRect = scrollContainer.getBoundingClientRect();
+ const targetElementRect = targetElement.getBoundingClientRect();
+
+ const distanceBetweenContainerAndTarget = rtl
+ ? scrollContainerRect.right - targetElementRect.right
+ : targetElementRect.left - scrollContainerRect.left;
+
+ if ( ! rtl && scrollContainerRect.left > targetElementRect.left ) {
+ return {
+ transform: `translateX( ${ distanceBetweenContainerAndTarget }px )`,
+ };
+ }
+
+ if ( rtl && scrollContainerRect.right < targetElementRect.right ) {
+ return {
+ transform: `translateX( ${
+ distanceBetweenContainerAndTarget * -1
+ }px )`,
+ };
+ }
+ }
+
+ return {};
+ }, [ rtl, targetElement ] );
+
+ const ariaLevel = useMemo( () => {
+ if ( ! rootBlockElement ) {
+ return 1;
+ }
+
+ const _ariaLevel = parseInt(
+ rootBlockElement.getAttribute( 'aria-level' ),
+ 10
+ );
+
+ return _ariaLevel ? _ariaLevel + 1 : 1;
+ }, [ rootBlockElement ] );
+
+ const hasAdjacentSelectedBranch = useMemo( () => {
+ if ( ! targetElement ) {
+ return false;
+ }
+
+ return targetElement.classList.contains( 'is-branch-selected' );
+ }, [ targetElement ] );
const popoverAnchor = useMemo( () => {
const isValidDropPosition =
@@ -163,14 +224,14 @@ export default function ListViewDropIndicator( {
contextElement: targetElement,
getBoundingClientRect() {
const rect = targetElement.getBoundingClientRect();
- const indent = getDropIndicatorIndent( rect );
// In RTL languages, the drop indicator should be positioned
// to the left of the target element, with the width of the
// indicator determining the indent at the right edge of the
// target element. In LTR languages, the drop indicator should
// end at the right edge of the target element, with the indent
// added to the position of the left edge of the target element.
- let left = rtl ? rect.left : rect.left + indent;
+ // let left = rtl ? rect.left : rect.left + indent;
+ let left = rect.left;
let top = 0;
// In deeply nested lists, where a scrollbar is present,
@@ -211,25 +272,19 @@ export default function ListViewDropIndicator( {
}
if ( dropPosition === 'top' ) {
- top = rect.top - 4;
+ top = rect.top - rect.height * 2;
} else {
// `dropPosition` is either `bottom` or `inside`
- top = rect.bottom + rect.height - 4;
+ top = rect.top;
}
- const width = getDropIndicatorWidth( rect, indent );
- const height = 4;
+ const width = getDropIndicatorWidth( rect, 0 );
+ const height = rect.height;
return new window.DOMRect( left, top, width, height );
},
};
- }, [
- targetElement,
- dropPosition,
- getDropIndicatorIndent,
- getDropIndicatorWidth,
- rtl,
- ] );
+ }, [ targetElement, dropPosition, getDropIndicatorWidth, rtl ] );
if ( ! targetElement ) {
return null;
@@ -240,13 +295,52 @@ export default function ListViewDropIndicator( {
animate={ false }
anchor={ popoverAnchor }
focusOnMount={ false }
- className="block-editor-list-view-drop-indicator"
+ className="block-editor-list-view-drop-indicator--preview"
variant="unstyled"
>
+ className={ classnames(
+ 'block-editor-list-view-drop-indicator__line',
+ {
+ 'block-editor-list-view-drop-indicator__line--darker':
+ hasAdjacentSelectedBranch,
+ }
+ ) }
+ >
+
+
+ {} } />
+
+
+
+
+ { blockTitle }
+
+
+
+
+
+
+
);
}
diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js
index 376609ca113017..3506257b793c5d 100644
--- a/packages/block-editor/src/components/list-view/index.js
+++ b/packages/block-editor/src/components/list-view/index.js
@@ -33,7 +33,7 @@ import { __ } from '@wordpress/i18n';
*/
import ListViewBranch from './branch';
import { ListViewContext } from './context';
-import ListViewDropIndicatorPreview from './drop-indicator-preview';
+import ListViewDropIndicatorPreview from './drop-indicator';
import useBlockSelection from './use-block-selection';
import useListViewBlockIndexes from './use-list-view-block-indexes';
import useListViewClientIds from './use-list-view-client-ids';
From 3839470dfe7259fb1ade10c3da98f5b679f07cab Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Tue, 16 Jan 2024 15:21:19 +1100
Subject: [PATCH 27/32] Fix drop indicator when dragging files
---
.../src/components/list-view/branch.js | 38 +++++++++++++++----
.../components/list-view/drop-indicator.js | 2 +
.../src/components/list-view/style.scss | 6 +++
3 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/packages/block-editor/src/components/list-view/branch.js b/packages/block-editor/src/components/list-view/branch.js
index 4d10bcd3d2370f..9471fcd1e880d1 100644
--- a/packages/block-editor/src/components/list-view/branch.js
+++ b/packages/block-editor/src/components/list-view/branch.js
@@ -155,17 +155,22 @@ function ListViewBranch( props ) {
let isNesting;
let isAfterDraggedBlocks;
- if ( firstDraggedBlockIndex !== undefined && ! isDragged ) {
+ if ( ! isDragged ) {
const thisBlockIndex = blockIndexes[ clientId ];
isAfterDraggedBlocks =
thisBlockIndex > firstDraggedBlockIndex;
+ isNesting =
+ typeof blockDropTargetIndex === 'number' &&
+ blockDropTargetIndex - 1 === thisBlockIndex &&
+ blockDropPosition === 'inside';
// Determine where to displace the position of the current block, relative
// to the blocks being dragged (in their original position) and the drop target
// (the position where a user is currently dragging the blocks to).
if (
blockDropTargetIndex !== undefined &&
- blockDropTargetIndex !== null
+ blockDropTargetIndex !== null &&
+ firstDraggedBlockIndex !== undefined
) {
// If the block is being dragged and there is a valid drop target,
// determine if the block being rendered should be displaced up or down.
@@ -191,11 +196,10 @@ function ListViewBranch( props ) {
displacement = 'normal';
}
}
-
- isNesting =
- blockDropTargetIndex - 1 === thisBlockIndex &&
- blockDropPosition === 'inside';
- } else if ( blockDropTargetIndex === null ) {
+ } else if (
+ blockDropTargetIndex === null &&
+ firstDraggedBlockIndex !== undefined
+ ) {
// A `null` value for `blockDropTargetIndex` indicates that the
// drop target is outside of the valid areas within the list view.
// In this case, the drag is still active, but as there is no
@@ -209,6 +213,26 @@ function ListViewBranch( props ) {
} else {
displacement = 'normal';
}
+ } else if (
+ blockDropTargetIndex !== undefined &&
+ blockDropTargetIndex !== null &&
+ firstDraggedBlockIndex === undefined
+ ) {
+ // If the blockdrop target is defined, but there are no dragged blocks,
+ // then the block should be displaced relative to the drop target.
+ if (
+ thisBlockIndex !== undefined
+ // blockDropTargetIndex !== 0 &&
+ // blockDropPosition !== 'top'
+ ) {
+ if ( thisBlockIndex < blockDropTargetIndex ) {
+ displacement = 'normal';
+ } else {
+ displacement = 'down';
+ }
+ }
+ } else if ( blockDropTargetIndex === null ) {
+ displacement = 'normal';
}
}
diff --git a/packages/block-editor/src/components/list-view/drop-indicator.js b/packages/block-editor/src/components/list-view/drop-indicator.js
index 9879221b8c6b6e..ed989222022935 100644
--- a/packages/block-editor/src/components/list-view/drop-indicator.js
+++ b/packages/block-editor/src/components/list-view/drop-indicator.js
@@ -297,6 +297,8 @@ export default function ListViewDropIndicatorPreview( {
focusOnMount={ false }
className="block-editor-list-view-drop-indicator--preview"
variant="unstyled"
+ flip={ false }
+ resize={ true }
>
Date: Tue, 16 Jan 2024 15:33:14 +1100
Subject: [PATCH 28/32] Don't add nesting classname when dragging files as the
editor thinks we can nest for any block
---
packages/block-editor/src/components/list-view/branch.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/packages/block-editor/src/components/list-view/branch.js b/packages/block-editor/src/components/list-view/branch.js
index 9471fcd1e880d1..26b2065cb004cf 100644
--- a/packages/block-editor/src/components/list-view/branch.js
+++ b/packages/block-editor/src/components/list-view/branch.js
@@ -159,10 +159,6 @@ function ListViewBranch( props ) {
const thisBlockIndex = blockIndexes[ clientId ];
isAfterDraggedBlocks =
thisBlockIndex > firstDraggedBlockIndex;
- isNesting =
- typeof blockDropTargetIndex === 'number' &&
- blockDropTargetIndex - 1 === thisBlockIndex &&
- blockDropPosition === 'inside';
// Determine where to displace the position of the current block, relative
// to the blocks being dragged (in their original position) and the drop target
@@ -195,6 +191,10 @@ function ListViewBranch( props ) {
} else {
displacement = 'normal';
}
+ isNesting =
+ typeof blockDropTargetIndex === 'number' &&
+ blockDropTargetIndex - 1 === thisBlockIndex &&
+ blockDropPosition === 'inside';
}
} else if (
blockDropTargetIndex === null &&
From 2dd5f23f7ce889c32725474d2aecf91c97e2fd0b Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Wed, 17 Jan 2024 15:32:32 +1100
Subject: [PATCH 29/32] Move displacement logic to a helper function, add tests
---
.../src/components/list-view/branch.js | 98 ++------
.../src/components/list-view/index.js | 4 +
.../src/components/list-view/test/utils.js | 219 +++++++++++++++++-
.../src/components/list-view/utils.js | 116 ++++++++++
4 files changed, 351 insertions(+), 86 deletions(-)
diff --git a/packages/block-editor/src/components/list-view/branch.js b/packages/block-editor/src/components/list-view/branch.js
index 26b2065cb004cf..abb36ea4e5d90a 100644
--- a/packages/block-editor/src/components/list-view/branch.js
+++ b/packages/block-editor/src/components/list-view/branch.js
@@ -14,7 +14,7 @@ import { AsyncModeProvider, useSelect } from '@wordpress/data';
import { Appender } from './appender';
import ListViewBlock from './block';
import { useListViewContext } from './context';
-import { isClientIdSelected } from './utils';
+import { getDragDisplacementValues, isClientIdSelected } from './utils';
import { store as blockEditorStore } from '../../store';
import useBlockDisplayInformation from '../use-block-display-information';
@@ -151,90 +151,18 @@ function ListViewBranch( props ) {
const isDragged = !! draggedClientIds?.includes( clientId );
- let displacement;
- let isNesting;
- let isAfterDraggedBlocks;
-
- if ( ! isDragged ) {
- const thisBlockIndex = blockIndexes[ clientId ];
- isAfterDraggedBlocks =
- thisBlockIndex > firstDraggedBlockIndex;
-
- // Determine where to displace the position of the current block, relative
- // to the blocks being dragged (in their original position) and the drop target
- // (the position where a user is currently dragging the blocks to).
- if (
- blockDropTargetIndex !== undefined &&
- blockDropTargetIndex !== null &&
- firstDraggedBlockIndex !== undefined
- ) {
- // If the block is being dragged and there is a valid drop target,
- // determine if the block being rendered should be displaced up or down.
-
- if ( thisBlockIndex !== undefined ) {
- if (
- thisBlockIndex >= firstDraggedBlockIndex &&
- thisBlockIndex < blockDropTargetIndex
- ) {
- // If the current block appears after the set of dragged blocks
- // (in their original position), but is before the drop target,
- // then the current block should be displaced up.
- displacement = 'up';
- } else if (
- thisBlockIndex < firstDraggedBlockIndex &&
- thisBlockIndex >= blockDropTargetIndex
- ) {
- // If the current block appears before the set of dragged blocks
- // (in their original position), but is after the drop target,
- // then the current block should be displaced down.
- displacement = 'down';
- } else {
- displacement = 'normal';
- }
- isNesting =
- typeof blockDropTargetIndex === 'number' &&
- blockDropTargetIndex - 1 === thisBlockIndex &&
- blockDropPosition === 'inside';
- }
- } else if (
- blockDropTargetIndex === null &&
- firstDraggedBlockIndex !== undefined
- ) {
- // A `null` value for `blockDropTargetIndex` indicates that the
- // drop target is outside of the valid areas within the list view.
- // In this case, the drag is still active, but as there is no
- // valid drop target, we should remove the gap indicating where
- // the block would be inserted.
- if (
- thisBlockIndex !== undefined &&
- thisBlockIndex >= firstDraggedBlockIndex
- ) {
- displacement = 'up';
- } else {
- displacement = 'normal';
- }
- } else if (
- blockDropTargetIndex !== undefined &&
- blockDropTargetIndex !== null &&
- firstDraggedBlockIndex === undefined
- ) {
- // If the blockdrop target is defined, but there are no dragged blocks,
- // then the block should be displaced relative to the drop target.
- if (
- thisBlockIndex !== undefined
- // blockDropTargetIndex !== 0 &&
- // blockDropPosition !== 'top'
- ) {
- if ( thisBlockIndex < blockDropTargetIndex ) {
- displacement = 'normal';
- } else {
- displacement = 'down';
- }
- }
- } else if ( blockDropTargetIndex === null ) {
- displacement = 'normal';
- }
- }
+ // Determine the displacement of the block while dragging. This
+ // works out whether the current block should be displaced up or
+ // down, relative to the dragged blocks and the drop target.
+ const { displacement, isAfterDraggedBlocks, isNesting } =
+ getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex,
+ blockDropPosition,
+ clientId,
+ firstDraggedBlockIndex,
+ isDragged,
+ } );
const { itemInView } = fixedListWindow;
const blockInView = itemInView( nextPosition );
diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js
index 3506257b793c5d..5270a7af3a2962 100644
--- a/packages/block-editor/src/components/list-view/index.js
+++ b/packages/block-editor/src/components/list-view/index.js
@@ -221,6 +221,9 @@ function ListViewComponent(
const firstDraggedBlockClientId = draggedClientIds?.[ 0 ];
+ // Convert a blockDropTarget into indexes relative to the blocks in the list view.
+ // These values are used to determine which blocks should be displaced to make room
+ // for the drop indicator. See `ListViewBranch` and `getDragDisplacementValues`.
const { blockDropTargetIndex, blockDropPosition, firstDraggedBlockIndex } =
useMemo( () => {
let _blockDropTargetIndex, _firstDraggedBlockIndex;
@@ -235,6 +238,7 @@ function ListViewComponent(
? foundBlockIndex
: foundBlockIndex + 1;
} else if ( blockDropTarget === null ) {
+ // A `null` value is used to indicate that the user is dragging outside of the list view.
_blockDropTargetIndex = null;
}
diff --git a/packages/block-editor/src/components/list-view/test/utils.js b/packages/block-editor/src/components/list-view/test/utils.js
index 78d78a9d90069c..d603d9ef1bb8b4 100644
--- a/packages/block-editor/src/components/list-view/test/utils.js
+++ b/packages/block-editor/src/components/list-view/test/utils.js
@@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
-import { getCommonDepthClientIds } from '../utils';
+import { getCommonDepthClientIds, getDragDisplacementValues } from '../utils';
describe( 'getCommonDepthClientIds', () => {
it( 'should return start and end when no depth is provided', () => {
@@ -48,3 +48,220 @@ describe( 'getCommonDepthClientIds', () => {
expect( result ).toEqual( { start: 'start-3', end: 'clicked-id' } );
} );
} );
+
+describe( 'getDragDisplacementValues', () => {
+ const blockIndexes = {
+ 'block-a': 0,
+ 'block-b': 1,
+ 'block-c': 2,
+ 'block-d': 3,
+ 'block-e': 4,
+ 'block-f': 5,
+ 'block-g': 6,
+ 'block-h': 7,
+ };
+
+ it( 'should return displacement of normal when block is after dragged block and drop target', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: 3,
+ blockDropPosition: 'bottom',
+ clientId: 'block-h',
+ firstDraggedBlockIndex: 5,
+ isDragged: false,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: 'normal',
+ isAfterDraggedBlocks: true,
+ isNesting: false,
+ } );
+ } );
+
+ it( 'should return displacement of up when block is after dragged block and before the drop target', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: 7,
+ blockDropPosition: 'bottom',
+ clientId: 'block-d',
+ firstDraggedBlockIndex: 2,
+ isDragged: false,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: 'up',
+ isAfterDraggedBlocks: true,
+ isNesting: false,
+ } );
+ } );
+
+ it( 'should return displacement of down when block is before dragged block and after the drop target', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: 1,
+ blockDropPosition: 'bottom',
+ clientId: 'block-d',
+ firstDraggedBlockIndex: 6,
+ isDragged: false,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: 'down',
+ isAfterDraggedBlocks: false,
+ isNesting: false,
+ } );
+ } );
+
+ it( 'should return isNesting of true when block is just before the drop target and drop position is inside', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: 1,
+ blockDropPosition: 'inside',
+ clientId: 'block-a',
+ firstDraggedBlockIndex: 6,
+ isDragged: false,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: 'normal',
+ isAfterDraggedBlocks: false,
+ isNesting: true,
+ } );
+ } );
+
+ it( 'should return isNesting of false when block is not just before the drop target and drop position is inside', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: 1,
+ blockDropPosition: 'inside',
+ clientId: 'block-b',
+ firstDraggedBlockIndex: 6,
+ isDragged: false,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: 'down',
+ isAfterDraggedBlocks: false,
+ isNesting: false,
+ } );
+ } );
+
+ it( 'should return displacement of up when drop target index is null and block is after dragged block', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: null,
+ blockDropPosition: 'bottom',
+ clientId: 'block-h',
+ firstDraggedBlockIndex: 5,
+ isDragged: false,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: 'up',
+ isAfterDraggedBlocks: true,
+ isNesting: false,
+ } );
+ } );
+
+ it( 'should return displacement of normal when drop target index is null and block is before dragged block', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: null,
+ blockDropPosition: 'bottom',
+ clientId: 'block-c',
+ firstDraggedBlockIndex: 5,
+ isDragged: false,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: 'normal',
+ isAfterDraggedBlocks: false,
+ isNesting: false,
+ } );
+ } );
+
+ it( 'should return displacement of normal when dragging a file (no dragged block) and the block is before the target index', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: 3,
+ blockDropPosition: 'bottom',
+ clientId: 'block-b',
+ firstDraggedBlockIndex: undefined,
+ isDragged: false,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: 'normal',
+ isAfterDraggedBlocks: false,
+ isNesting: false,
+ } );
+ } );
+
+ it( 'should return displacement of down when dragging a file (no dragged block) and the block is after the target index', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: 3,
+ blockDropPosition: 'bottom',
+ clientId: 'block-h',
+ firstDraggedBlockIndex: undefined,
+ isDragged: false,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: 'down',
+ isAfterDraggedBlocks: false,
+ isNesting: false,
+ } );
+ } );
+
+ it( 'should return displacement of normal when dragging a file (no dragged block) and dragging outside the list view (drop target of null)', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: null,
+ blockDropPosition: 'bottom',
+ clientId: 'block-h',
+ firstDraggedBlockIndex: undefined,
+ isDragged: false,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: 'normal',
+ isAfterDraggedBlocks: false,
+ isNesting: false,
+ } );
+ } );
+
+ it( 'should return undefined displacement if the target index is undefined', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: undefined,
+ blockDropPosition: 'bottom',
+ clientId: 'block-h',
+ firstDraggedBlockIndex: undefined,
+ isDragged: false,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: undefined,
+ isAfterDraggedBlocks: false,
+ isNesting: false,
+ } );
+ } );
+
+ it( 'should return all undefined values if the block is dragged', () => {
+ const result = getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex: 3,
+ blockDropPosition: 'bottom',
+ clientId: 'block-h',
+ firstDraggedBlockIndex: 7,
+ isDragged: true,
+ } );
+
+ expect( result ).toEqual( {
+ displacement: undefined,
+ isAfterDraggedBlocks: undefined,
+ isNesting: undefined,
+ } );
+ } );
+} );
diff --git a/packages/block-editor/src/components/list-view/utils.js b/packages/block-editor/src/components/list-view/utils.js
index 632173e120691f..ed7a321dea0c86 100644
--- a/packages/block-editor/src/components/list-view/utils.js
+++ b/packages/block-editor/src/components/list-view/utils.js
@@ -93,3 +93,119 @@ export function focusListItem( focusClientId, treeGridElementRef ) {
} );
}
}
+
+/**
+ * Get values for the block that flag whether the block should be displaced up or down,
+ * whether the block is being nested, and whether the block appears after the dragged
+ * blocks. These values are used to determine the class names to apply to the block.
+ * The list view rows are displaced visually via CSS rules. Displacement rules:
+ * - `normal`: no displacement — used to apply a translateY of `0` so that the block
+ * appears in its original position, and moves to that position smoothly when dragging
+ * outside of the list view area.
+ * - `up`: the block should be displaced up, creating room beneath the block for the drop indicator.
+ * - `down`: the block should be displaced down, creating room above the block for the drop indicator.
+ *
+ * @param {Object} props
+ * @param {Object} props.blockIndexes The indexes of all the blocks in the list view, keyed by clientId.
+ * @param {number|null|undefined} props.blockDropTargetIndex The index of the block that the user is dropping to.
+ * @param {?string} props.blockDropPosition The position relative to the block that the user is dropping to.
+ * @param {string} props.clientId The client id for the current block.
+ * @param {?number} props.firstDraggedBlockIndex The index of the first dragged block.
+ * @param {?boolean} props.isDragged Whether the current block is being dragged. Dragged blocks skip displacement.
+ * @return {Object} An object containing the `displacement`, `isAfterDraggedBlocks` and `isNesting` values.
+ */
+export function getDragDisplacementValues( {
+ blockIndexes,
+ blockDropTargetIndex,
+ blockDropPosition,
+ clientId,
+ firstDraggedBlockIndex,
+ isDragged,
+} ) {
+ let displacement;
+ let isNesting;
+ let isAfterDraggedBlocks;
+
+ if ( ! isDragged ) {
+ isNesting = false;
+ const thisBlockIndex = blockIndexes[ clientId ];
+ isAfterDraggedBlocks = thisBlockIndex > firstDraggedBlockIndex;
+
+ // Determine where to displace the position of the current block, relative
+ // to the blocks being dragged (in their original position) and the drop target
+ // (the position where a user is currently dragging the blocks to).
+ if (
+ blockDropTargetIndex !== undefined &&
+ blockDropTargetIndex !== null &&
+ firstDraggedBlockIndex !== undefined
+ ) {
+ // If the block is being dragged and there is a valid drop target,
+ // determine if the block being rendered should be displaced up or down.
+
+ if ( thisBlockIndex !== undefined ) {
+ if (
+ thisBlockIndex >= firstDraggedBlockIndex &&
+ thisBlockIndex < blockDropTargetIndex
+ ) {
+ // If the current block appears after the set of dragged blocks
+ // (in their original position), but is before the drop target,
+ // then the current block should be displaced up.
+ displacement = 'up';
+ } else if (
+ thisBlockIndex < firstDraggedBlockIndex &&
+ thisBlockIndex >= blockDropTargetIndex
+ ) {
+ // If the current block appears before the set of dragged blocks
+ // (in their original position), but is after the drop target,
+ // then the current block should be displaced down.
+ displacement = 'down';
+ } else {
+ displacement = 'normal';
+ }
+ isNesting =
+ typeof blockDropTargetIndex === 'number' &&
+ blockDropTargetIndex - 1 === thisBlockIndex &&
+ blockDropPosition === 'inside';
+ }
+ } else if (
+ blockDropTargetIndex === null &&
+ firstDraggedBlockIndex !== undefined
+ ) {
+ // A `null` value for `blockDropTargetIndex` indicates that the
+ // drop target is outside of the valid areas within the list view.
+ // In this case, the drag is still active, but as there is no
+ // valid drop target, we should remove the gap indicating where
+ // the block would be inserted.
+ if (
+ thisBlockIndex !== undefined &&
+ thisBlockIndex >= firstDraggedBlockIndex
+ ) {
+ displacement = 'up';
+ } else {
+ displacement = 'normal';
+ }
+ } else if (
+ blockDropTargetIndex !== undefined &&
+ blockDropTargetIndex !== null &&
+ firstDraggedBlockIndex === undefined
+ ) {
+ // If the blockdrop target is defined, but there are no dragged blocks,
+ // then the block should be displaced relative to the drop target.
+ if ( thisBlockIndex !== undefined ) {
+ if ( thisBlockIndex < blockDropTargetIndex ) {
+ displacement = 'normal';
+ } else {
+ displacement = 'down';
+ }
+ }
+ } else if ( blockDropTargetIndex === null ) {
+ displacement = 'normal';
+ }
+ }
+
+ return {
+ displacement,
+ isNesting,
+ isAfterDraggedBlocks,
+ };
+}
From 66ba7a25efb1fb6dfad3851979d0e802ad41fed4 Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Wed, 17 Jan 2024 15:35:49 +1100
Subject: [PATCH 30/32] Remove unneeded changes from useMovingAnimation
---
.../src/components/use-moving-animation/index.js | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/packages/block-editor/src/components/use-moving-animation/index.js b/packages/block-editor/src/components/use-moving-animation/index.js
index ee1a4610a1d4cf..4a66fe6fb6e637 100644
--- a/packages/block-editor/src/components/use-moving-animation/index.js
+++ b/packages/block-editor/src/components/use-moving-animation/index.js
@@ -39,16 +39,11 @@ function getAbsolutePosition( element ) {
* - It uses the "resetAnimation" flag to reset the animation
* from the beginning in order to animate to the new destination point.
*
- * @param {Object} $1 Options
- * @param {boolean} $1.enableAnimation Whether to enable the animation.
- * @param {*} $1.triggerAnimationOnChange Variable used to trigger the animation if it changes.
- * @param {string} $1.clientId
+ * @param {Object} $1 Options
+ * @param {*} $1.triggerAnimationOnChange Variable used to trigger the animation if it changes.
+ * @param {string} $1.clientId
*/
-function useMovingAnimation( {
- enableAnimation = true,
- triggerAnimationOnChange,
- clientId,
-} ) {
+function useMovingAnimation( { triggerAnimationOnChange, clientId } ) {
const ref = useRef();
const {
isTyping,
@@ -98,7 +93,6 @@ function useMovingAnimation( {
// To do: consider enableing the _moving_ animation even for large
// posts, while only disabling the _insertion_ animation?
const disableAnimation =
- ! enableAnimation ||
window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches ||
isTyping() ||
getGlobalBlockCount() > BLOCK_ANIMATION_THRESHOLD;
@@ -153,7 +147,6 @@ function useMovingAnimation( {
previous,
prevRect,
clientId,
- enableAnimation,
isTyping,
getGlobalBlockCount,
isBlockSelected,
From a931c1b9f954456390f5198ac9f5325c612eac76 Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Wed, 17 Jan 2024 15:45:19 +1100
Subject: [PATCH 31/32] Add explanatory comments
---
.../src/components/list-view/style.scss | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/packages/block-editor/src/components/list-view/style.scss b/packages/block-editor/src/components/list-view/style.scss
index 01df68f1d70791..11cf1fafa0e14b 100644
--- a/packages/block-editor/src/components/list-view/style.scss
+++ b/packages/block-editor/src/components/list-view/style.scss
@@ -139,6 +139,12 @@
border-radius: 0;
}
+ // List view items will be displaced up or down relative to their original position
+ // when a user is dragging a block within the list view. This creates a space for a
+ // visual indicator of where the block will be placed when dropped. The `normal` state
+ // is used to allow rows to smoothly transition back into their original position,
+ // without attaching the transition to the list view leaf itself. This prevents rows
+ // from animating too much once the user has dropped the block.
&.is-displacement-normal {
transition: transform 0.2s;
transform: translateY(0);
@@ -157,7 +163,10 @@
@include reduce-motion("transition");
}
- // Collapse multi-selections down into a single row space while dragging.
+ // Collapse multi-selections down into a single row space while dragging. The following
+ // rules ensure that during a multi-selection, the space for additional blocks is factored in
+ // when displacing up and down. The result is that there should only ever be a single row's
+ // worth of space for the visual indicator of where a block will be placed when dropped.
&.is-after-dragged-blocks {
transition: transform 0.2s;
transform: translateY(calc(var(--wp-admin--list-view-dragged-items-height, 36px) * -1));
@@ -176,6 +185,9 @@
@include reduce-motion("transition");
}
+ // To ensure displaced rows behave correctly, ensure that blocks that are currently being dragged
+ // are visually hidden. The below rules are used in favor of `display: none` to ensure that
+ // there is no flicker when a user begins to drag a block.
&.is-dragging {
opacity: 0;
// The row's left position is set to 0 to ensure that the animation
From c397ce1e7a0e57c6baf982e3be27fa7a54f4ed44 Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Mon, 22 Jan 2024 14:11:26 +1100
Subject: [PATCH 32/32] Try a timeout for the list view drop zone updates of
50ms instead of 200ms
---
.../src/components/list-view/use-list-view-drop-zone.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js b/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js
index 47ccdc8a1d1f88..3354b3f41d391c 100644
--- a/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js
+++ b/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js
@@ -550,7 +550,7 @@ export default function useListViewDropZone( {
rtl,
]
),
- 200
+ 50
);
const ref = useDropZone( {