Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List View: Update drop indicator width to be aware of scroll containers #49786

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 67 additions & 22 deletions packages/block-editor/src/components/list-view/drop-indicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* WordPress dependencies
*/
import { Popover } from '@wordpress/components';
import { getScrollContainer } from '@wordpress/dom';
import { useCallback, useMemo } from '@wordpress/element';

export default function ListViewDropIndicator( {
Expand Down Expand Up @@ -40,33 +41,74 @@ export default function ListViewDropIndicator( {
// is undefined, so the indicator will appear after the rootBlockElement.
const targetElement = blockElement || rootBlockElement;

const getDropIndicatorIndent = useCallback( () => {
if ( ! rootBlockElement ) {
return 0;
}
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 rootBlockIconRect.right - targetElementRect.left;
},
[ rootBlockElement ]
);

// Calculate the indent using the block icon of the root block.
// Using a classname selector here might be flaky and could be
// improved.
const targetElementRect = targetElement.getBoundingClientRect();
const rootBlockIconElement = rootBlockElement.querySelector(
'.block-editor-block-icon'
);
const rootBlockIconRect = rootBlockIconElement.getBoundingClientRect();
return rootBlockIconRect.right - targetElementRect.left;
}, [ rootBlockElement, targetElement ] );
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'
);

if ( scrollContainer ) {
const scrollContainerRect =
scrollContainer.getBoundingClientRect();

if ( scrollContainer.clientWidth < width ) {
width =
scrollContainer.clientWidth -
( targetElementRect.left - scrollContainerRect.left );
}
}

// Subtract the indent from the final width of the indicator.
return width - indent;
},
[ targetElement ]
);

const style = useMemo( () => {
if ( ! targetElement ) {
return {};
}

const indent = getDropIndicatorIndent();
const targetElementRect = targetElement.getBoundingClientRect();
const indent = getDropIndicatorIndent( targetElementRect );

return {
width: targetElement.offsetWidth - indent,
width: getDropIndicatorWidth( targetElementRect, indent ),
};
}, [ getDropIndicatorIndent, targetElement ] );
}, [ getDropIndicatorIndent, getDropIndicatorWidth, targetElement ] );

const popoverAnchor = useMemo( () => {
const isValidDropPosition =
Expand All @@ -81,10 +123,8 @@ export default function ListViewDropIndicator( {
ownerDocument: targetElement.ownerDocument,
getBoundingClientRect() {
const rect = targetElement.getBoundingClientRect();
const indent = getDropIndicatorIndent();

const indent = getDropIndicatorIndent( rect );
const left = rect.left + indent;
const right = rect.right;
let top = 0;
let bottom = 0;

Expand All @@ -97,13 +137,18 @@ export default function ListViewDropIndicator( {
bottom = rect.bottom;
}

const width = right - left;
const width = getDropIndicatorWidth( rect, indent );
const height = bottom - top;

return new window.DOMRect( left, top, width, height );
},
};
}, [ targetElement, dropPosition, getDropIndicatorIndent ] );
}, [
targetElement,
dropPosition,
getDropIndicatorIndent,
getDropIndicatorWidth,
] );

if ( ! targetElement ) {
return null;
Expand Down