Skip to content
Snippets Groups Projects
Unverified Commit fbe67d8d authored by Anton Kulyk's avatar Anton Kulyk Committed by GitHub
Browse files

Expand collections on drag-n-drop hover (#21795)


* Split SidebarCollectionLink

* Expand collection on DND hover

* Increase time before expanding

Co-authored-by: default avatarMaz Ameli <maz@metabase.com>

Co-authored-by: default avatarMaz Ameli <maz@metabase.com>
parent b42119c0
Branches
Tags
No related merge requests found
/* eslint-disable react/prop-types */
import React, { useCallback, KeyboardEvent } from "react";
import React, { useEffect, useCallback, useRef, KeyboardEvent } from "react";
import _ from "underscore";
import { Collection } from "metabase-types/api";
......@@ -8,6 +7,7 @@ import { TreeNode } from "metabase/components/tree/TreeNode";
import { TreeNodeProps } from "metabase/components/tree/types";
import CollectionDropTarget from "metabase/containers/dnd/CollectionDropTarget";
import { usePrevious } from "metabase/hooks/use-previous";
import { PLUGIN_COLLECTIONS } from "metabase/plugins";
import { getCollectionIcon } from "metabase/entities/collections";
......@@ -21,23 +21,49 @@ import {
SidebarIcon,
} from "./SidebarItems.styled";
// eslint-disable-next-line react/display-name
const SidebarCollectionLink = React.forwardRef<HTMLLIElement, TreeNodeProps>(
type DroppableProps = {
hovered: boolean;
highlighted: boolean;
};
type Props = DroppableProps &
Omit<TreeNodeProps, "item"> & {
collection: Collection;
};
const TIME_BEFORE_EXPANDING_ON_HOVER = 600;
const SidebarCollectionLink = React.forwardRef<HTMLLIElement, Props>(
function SidebarCollectionLink(
{
item,
collection,
hovered: isHovered,
depth,
onSelect,
isExpanded,
isSelected,
hasChildren,
onToggleExpand,
},
}: Props,
ref,
) {
const collection = (item as unknown) as Collection;
const wasHovered = usePrevious(isHovered);
const timeoutId = useRef<any>(null);
useEffect(() => {
const justHovered = !wasHovered && isHovered;
if (justHovered && !isExpanded) {
timeoutId.current = setTimeout(() => {
if (isHovered) {
onToggleExpand();
}
}, TIME_BEFORE_EXPANDING_ON_HOVER);
}
return () => clearTimeout(timeoutId.current);
}, [wasHovered, isHovered, isExpanded, onToggleExpand]);
const { name } = collection;
const url = Urls.collection(collection);
const onKeyDown = useCallback(
......@@ -63,37 +89,55 @@ const SidebarCollectionLink = React.forwardRef<HTMLLIElement, TreeNodeProps>(
);
return (
<div data-testid="sidebar-collection-link-root">
<CollectionDropTarget collection={collection}>
{({ hovered }: { hovered: boolean }) => (
<CollectionNodeRoot
role="treeitem"
depth={depth}
isSelected={isSelected}
hovered={hovered}
onClick={onToggleExpand}
hasDefaultIconStyle={isRegularCollection}
ref={ref}
>
<ExpandToggleButton hidden={!hasChildren}>
<TreeNode.ExpandToggleIcon
isExpanded={isExpanded}
name="chevronright"
size={12}
/>
</ExpandToggleButton>
<FullWidthLink to={url} onClick={onSelect} onKeyDown={onKeyDown}>
<TreeNode.IconContainer transparent={false}>
<SidebarIcon {...icon} isSelected={isSelected} />
</TreeNode.IconContainer>
<NameContainer>{name}</NameContainer>
</FullWidthLink>
</CollectionNodeRoot>
)}
</CollectionDropTarget>
</div>
<CollectionNodeRoot
role="treeitem"
depth={depth}
isSelected={isSelected}
hovered={isHovered}
onClick={onToggleExpand}
hasDefaultIconStyle={isRegularCollection}
ref={ref}
>
<ExpandToggleButton hidden={!hasChildren}>
<TreeNode.ExpandToggleIcon
isExpanded={isExpanded}
name="chevronright"
size={12}
/>
</ExpandToggleButton>
<FullWidthLink to={url} onClick={onSelect} onKeyDown={onKeyDown}>
<TreeNode.IconContainer transparent={false}>
<SidebarIcon {...icon} isSelected={isSelected} />
</TreeNode.IconContainer>
<NameContainer>{collection.name}</NameContainer>
</FullWidthLink>
</CollectionNodeRoot>
);
},
);
export default SidebarCollectionLink;
const DroppableSidebarCollectionLink = React.forwardRef<
HTMLLIElement,
TreeNodeProps
>(function DroppableSidebarCollectionLink(
{ item, ...props }: TreeNodeProps,
ref,
) {
const collection = (item as unknown) as Collection;
return (
<div data-testid="sidebar-collection-link-root">
<CollectionDropTarget collection={collection}>
{(droppableProps: DroppableProps) => (
<SidebarCollectionLink
{...props}
{...droppableProps}
collection={collection}
ref={ref}
/>
)}
</CollectionDropTarget>
</div>
);
});
export default DroppableSidebarCollectionLink;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment