Shadis/src/FileView/views/FVSidebar/FVSidebar.tsx

152 lines
4.1 KiB
TypeScript
Executable File

import React, { useEffect, useContext } from "react";
import { FVSidebarProps, FVSidebarClassNameContract } from "./FVSidebar.props";
import {
DesignSystem,
neutralLayerL1,
neutralOutlineActive,
applyPillCornerRadius,
} from "@microsoft/fast-components-styles-msft";
import manageJss, { ComponentStyles } from "@microsoft/fast-jss-manager-react";
import { motion, useTransform } from "framer-motion";
import { tween } from "popmotion";
import { cubicBezier } from "@popmotion/easing";
import { Heading, HeadingSize, HeadingTag } from "@microsoft/fast-components-react-msft";
import { SidebarData } from "./FVSidebarContext";
import FVSidebarContent from "./FVSidebarContent";
import FVSidebarFooter from "./FVSidebarFooter";
import { useTranslation } from "react-i18next";
/**
* The position where on the x-axis the button is placed by default
*/
const defaultButtonPos = 17;
/**
* The width of the sidebar by default
*/
const defaultSidebarWidth = 400;
const styles: ComponentStyles<FVSidebarClassNameContract, DesignSystem> = {
fv_sidebar_button: {
zIndex: "63",
position: "absolute",
right: defaultButtonPos + "px",
top: "14px",
...applyPillCornerRadius(),
},
fv_sidebar: {
display: "flex",
flexDirection: "column",
width: defaultSidebarWidth + "px",
height: "100%",
background: neutralLayerL1,
borderInlineStart: "1px solid",
borderInlineStartColor: neutralOutlineActive,
zIndex: "60",
position: "absolute",
top: "0",
right: "0",
"& > h1": {
padding: "19px 25px 17px 75px",
},
},
fv_sidebar_container: {
overflow: "auto",
display: "flex",
flexDirection: "column",
flexGrow: "1",
},
};
const FVSidebar: React.ComponentType<FVSidebarProps> = ({ managedClasses, fileData }) => {
const { sidebarWidth, sidebarPos, isSidebarVisible } = useContext(SidebarData);
const { t } = useTranslation("fileview");
// const [isPresent, safeToRemove] = usePresence();
/**
* The transitionX position of the sidebar.
*
* We need to invert the values, as this value
* is relative to the initial position of the
* sidebar, which is inside the viewport.
*/
const sidebarContainerX = useTransform(
sidebarPos,
pos => -1 * (pos - sidebarWidth.get())
);
/**
* Custom tween animator for opening and closing
*/
useEffect(() => {
sidebarPos.start(complete => {
const anim = tween({
from: sidebarPos.get(),
to: isSidebarVisible ? defaultSidebarWidth : 0,
duration: isSidebarVisible ? 400 : 300,
ease: isSidebarVisible
? cubicBezier(0.2, 0.66, 0, 1)
: cubicBezier(0.0, 0.0, 0.85, 0.05),
}).start({
complete,
update: (val: number) => sidebarPos.set(val),
});
return anim.stop;
});
}, [sidebarPos, isSidebarVisible]);
/**
* Close sidebar while unmounting component.
* We set a timeout for the image repositoning animation to kick in.
*
* TODO: Find a way to close sidebar BEFORE unmounting
* ! Maybe call an upper safeToRemove prop?
*/
/*
const allowUnmount = useCallback(
(pos: number) => {
if (!isPresent && pos === 0) {
setTimeout(safeToRemove, 200);
}
},
[isPresent, safeToRemove]
);
/**
* Listen to isPresent for starting closing animation.
*
useEffect(() => {
if (!safeToRemove) return;
if (!isPresent) {
if (isSidebarVisible) setVisibility(false);
else if (!sidebarPos.isAnimating()) {
safeToRemove();
return;
}
return sidebarPos.onChange(allowUnmount);
}
}, [allowUnmount, isPresent, safeToRemove, sidebarPos, isSidebarVisible]);*/
return (
<>
<motion.div
className={managedClasses.fv_sidebar}
style={{
x: sidebarContainerX,
}}
>
<Heading size={HeadingSize._5} tag={HeadingTag.h1}>
{t("inspector")}
</Heading>
<div className={managedClasses.fv_sidebar_container}>
<FVSidebarContent fileData={fileData} />
<FVSidebarFooter fileData={fileData} />
</div>
</motion.div>
</>
);
};
export default manageJss(styles)(FVSidebar);