Skip to content

Commit

Permalink
Merge pull request #182 from minop1205/fix-167
Browse files Browse the repository at this point in the history
Improved performance of opening and closing animation
  • Loading branch information
minop1205 authored Dec 31, 2022
2 parents 14e9ff2 + 86feef9 commit 09b90ee
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 35 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Change Log

## 3.4.1

_Dec 31, 2022_

- Improved performance when `enableAnimateExpand` is `true`.

## 3.4.0

_Nov 29, 2022_
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@minoru/react-dnd-treeview",
"description": "A draggable / droppable React-based treeview component.",
"version": "3.4.0",
"version": "3.4.1",
"license": "MIT",
"repository": {
"type": "git",
Expand Down
53 changes: 40 additions & 13 deletions src/AnimateHeight.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useEffect } from "react";
import { ResizeObserver } from "@juggle/resize-observer";
import type { Target, Tween } from "framer-motion";
import { motion } from "framer-motion";
Expand Down Expand Up @@ -26,34 +27,60 @@ export function AnimateHeight(props: AnimateHeightProps) {
},
children,
} = props;

const [ref, { height }] = useMeasure({ polyfill: ResizeObserver });
const [animating, setAnimating] = useState(false);
const onAnimationStart = () => {
setAnimating(true);
};
const [isVisibleChildren, setIsVisibleChildren] = useState(isVisible);
const [isVisibleContainer, setIsVisibleContainer] = useState(isVisible);
const [transition, setTransition] = useState(false);

const onAnimationComplete = () => {
setAnimating(false);
setTransition(false);

if (!isVisible) {
setIsVisibleChildren(false);
}
};

useEffect(() => {
setTransition(true);

if (isVisible) {
setIsVisibleChildren(true);
} else {
setIsVisibleContainer(false);
}
}, [isVisible]);

useEffect(() => {
if (isVisibleChildren) {
setIsVisibleContainer(true);
}
}, [height]);

return (
<motion.div
style={isVisible && !animating ? {} : { overflow: "hidden" }}
style={transition ? { overflow: "hidden" } : undefined}
onAnimationComplete={onAnimationComplete}
onAnimationStart={onAnimationStart}
initial={isVisible ? "open" : "close"}
animate={isVisible ? "open" : "close"}
initial={isVisibleContainer ? "open" : "close"}
animate={isVisibleContainer ? "open" : "close"}
inherit={false}
variants={variants}
transition={{ ease, duration: computeDuration(height, duration) }}
>
<div ref={ref}>{children}</div>
<div ref={ref}>{isVisibleChildren && children}</div>
</motion.div>
);
}

/** Auto compute the duration by dynamic height. */
function computeDuration(height: number, fixedDuration?: number) {
if (fixedDuration) return fixedDuration;
if (!height) return 0;
if (fixedDuration) {
return fixedDuration;
}

if (!height) {
return 0;
}

const constant = height / 36;
// ??? don't know why use below computed expression (just copy it from somewhere)
return Math.round((4 + 10 * constant ** 0.25 + constant / 5) * 10) / 1500;
Expand Down
26 changes: 10 additions & 16 deletions src/Node.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import React, {
useEffect,
useRef,
useContext,
PropsWithChildren,
ReactElement,
} from "react";
import React, { useEffect, useRef, useContext, ReactElement } from "react";
import { getEmptyImage } from "react-dnd-html5-backend";
import { AnimateHeight } from "./AnimateHeight";
import { Container } from "./Container";
Expand All @@ -19,10 +13,10 @@ import { PlaceholderContext } from "./providers";
import { NodeModel, RenderParams } from "./types";
import { isDroppable } from "./utils";

type Props = PropsWithChildren<{
type Props = {
id: NodeModel["id"];
depth: number;
}>;
};

export const Node = <T,>(props: Props): ReactElement | null => {
const treeContext = useTreeContext<T>();
Expand Down Expand Up @@ -70,15 +64,15 @@ export const Node = <T,>(props: Props): ReactElement | null => {

const draggable = treeContext.canDrag ? treeContext.canDrag(props.id) : true;
const isDropTarget = placeholderContext.dropTargetId === props.id;
const hasChild = !!treeContext.tree.find((node) => node.parent === props.id);
const children = treeContext.tree.filter((node) => node.parent === props.id);

const params: RenderParams = {
depth: props.depth,
isOpen: open,
isDragging,
isDropTarget,
draggable,
hasChild,
hasChild: children.length > 0,
containerRef,
handleRef,
onToggle: handleToggle,
Expand All @@ -87,13 +81,13 @@ export const Node = <T,>(props: Props): ReactElement | null => {
return (
<Component ref={containerRef} className={className} role="listitem">
{treeContext.render(item, params)}
{enableAnimateExpand ? (
<AnimateHeight isVisible={open && hasChild}>
{enableAnimateExpand && params.hasChild && (
<AnimateHeight isVisible={open}>
<Container parentId={props.id} depth={props.depth + 1} />
</AnimateHeight>
) : (
open &&
hasChild && <Container parentId={props.id} depth={props.depth + 1} />
)}
{!enableAnimateExpand && params.hasChild && open && (
<Container parentId={props.id} depth={props.depth + 1} />
)}
</Component>
);
Expand Down
6 changes: 3 additions & 3 deletions src/stories/examples/AnimateExpand/AnimateExpand.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ if (!interactionsDisabled) {
AnimateExpandStory.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);

// If enableAnimateExpand is true, hidden nodes are rendered.
expect(canvas.getByText("File 1-01")).toBeInTheDocument();
expect(canvas.getByText("File 2-1-1")).toBeInTheDocument();
// Do not render hidden nodes.
expect(canvas.queryByText("File 1-01")).toBe(null);
expect(canvas.queryByText("File 2-1-1")).toBe(null);

// Check style attributes before and after opening a node.
const animateContainer =
Expand Down

0 comments on commit 09b90ee

Please sign in to comment.