editor: get rid of framer-motion

This commit is contained in:
Abdullah Atta
2024-11-12 13:18:52 +05:00
committed by Abdullah Atta
parent b7aaa382b1
commit 6671a97181
4 changed files with 147 additions and 80 deletions

View File

@@ -92,7 +92,6 @@
"@types/react-dom": "^18.3.0",
"@types/react-modal": "^3.16.3 ",
"@types/tinycolor2": "^1.4.6",
"framer-motion": "^11.5.4",
"happy-dom": "^15.7.4",
"isomorphic-fetch": "^3.0.0",
"nodemon": "^3.1.7",
@@ -110,7 +109,6 @@
"@mdi/js": ">=7.2.96",
"@theme-ui/components": ">=0.16.0",
"@theme-ui/core": ">=0.16.0",
"framer-motion": ">=11",
"react": ">=18",
"react-dom": ">=18",
"react-modal": ">=3",

View File

@@ -28,29 +28,13 @@ import { MenuItem, Icon, MenuButton, MenuSeparator } from "@notesnook/ui";
import { Box, Button, Flex, Text } from "@theme-ui/components";
import { Icons } from "../../toolbar/icons.js";
import Modal from "react-modal";
import {
motion,
PanInfo,
useMotionValue,
useTransform,
useAnimation
} from "framer-motion";
import { useTheme } from "@emotion/react";
import { EmotionThemeProvider, Theme } from "@notesnook/theme";
const AnimatedFlex = motion.create(Flex);
type ActionSheetHistoryItem = {
title?: string;
items?: MenuItem[];
};
const TRANSITION = {
type: "spring",
stiffness: 300,
damping: 30,
mass: 0.2,
duration: 300
};
function useHistory<T>(initial: T) {
const [current, setCurrent] = useState<T | undefined>(initial);
@@ -101,25 +85,127 @@ export function ActionSheetPresenter(
} = props;
const theme = useTheme() as Theme;
const contentRef = useRef<HTMLDivElement>();
const pressed = useRef(false);
const startY = useRef(0);
const reverse = false;
const threshold = 50;
const sheetTransition = "transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1)";
const animationRef = useRef(0);
const masterOffset = useRef(0);
const sheetRef = useRef<HTMLDivElement>(null);
const overlayRef = useRef<HTMLDivElement>(null);
const y = useMotionValue(0);
const opacity = useTransform(
y,
[0, contentRef.current?.offsetHeight || window.innerHeight],
[1, 0]
);
const animation = useAnimation();
const onSwipeMove = (event: React.TouchEvent<HTMLDivElement>): void => {
if (pressed.current) {
const offset = event.touches[0].clientY - startY.current;
move(offset);
}
};
const onMouseMove = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>
): void => {
event.stopPropagation();
if (pressed.current) {
if (reverse) {
const offset = event.clientY - startY.current;
move(offset);
} else {
const offset = event.clientY - startY.current;
move(offset);
}
}
};
const move = (offset: number): boolean => {
if (!reverse && offset > 0) {
masterOffset.current = offset;
animationRef.current = requestAnimationFrame(updatePosition);
return true;
} else if (reverse && offset < 0) {
masterOffset.current = offset;
animationRef.current = requestAnimationFrame(updatePosition);
return true;
}
return false;
};
const updatePosition = (): boolean => {
if (animationRef.current !== undefined) {
if (sheetRef.current) {
sheetRef.current.style.transform = `translate3d(0, ${masterOffset.current}px, 0)`;
if (overlayRef.current)
overlayRef.current.style.opacity = `${
1 - masterOffset.current / sheetRef.current.offsetHeight
}`;
return true;
}
return false;
}
return false;
};
const onSwipeStart = (event: React.TouchEvent<HTMLDivElement>): void => {
if (sheetRef?.current) sheetRef.current.style.transition = "none";
startY.current = event.touches[0].clientY;
changePressed(true);
};
const onMouseStart = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>
): void => {
if (sheetRef?.current) sheetRef.current.style.transition = "none";
startY.current = event.clientY;
changePressed(true);
};
const changePressed = (x: boolean): void => {
pressed.current = x;
};
const requestSheetDown = React.useCallback((): boolean => {
if (sheetRef.current) {
sheetRef.current.style.transition = sheetTransition;
sheetRef.current.style.transform = reverse
? "translate3d(0, -101%, 0)"
: "translate3d(0, 101%, 0)";
if (overlayRef.current) overlayRef.current.style.opacity = `0`;
return true;
}
return false;
}, [reverse, sheetTransition]);
const requestSheetUp = React.useCallback((): boolean => {
if (sheetRef.current) {
sheetRef.current.style.transform = `translate3d(0, 0%, 0)`;
if (overlayRef.current) overlayRef.current.style.opacity = `1`;
return true;
}
return false;
}, []);
const onSwipeEnd = (): void => {
cancelAnimationFrame(animationRef.current);
changePressed(false);
if (Math.abs(masterOffset.current) > threshold) {
// setShow(false);
requestSheetDown();
console.log("CLSOING", masterOffset.current);
setTimeout(() => {
if (onClose) onClose();
}, 300);
} else {
requestSheetUp();
}
masterOffset.current = 0;
};
const onBeforeClose = useCallback(() => {
const height = contentRef.current?.offsetHeight || window.innerHeight;
requestSheetDown();
setTimeout(() => {
onClose?.();
}, TRANSITION.duration - 50);
animation.start({
transition: TRANSITION,
y: height + 100
});
}, [animation, onClose]);
if (onClose) onClose();
}, 300);
}, [onClose, requestSheetDown]);
const handleBackPress = useCallback(
(event: Event) => {
@@ -156,7 +242,7 @@ export function ActionSheetPresenter(
onRequestClose={() => onBeforeClose()}
portalClassName={"bottom-sheet-presenter-portal"}
onAfterOpen={() => {
setTimeout(() => animation.start({ transition: TRANSITION, y: 0 }));
setTimeout(() => requestSheetUp());
}}
overlayElement={(overlayElementProps, contentEl) => {
return (
@@ -172,12 +258,13 @@ export function ActionSheetPresenter(
tabIndex={-1}
>
{blocking && (
<motion.div
id="action-sheet-overlay"
<div
ref={overlayRef}
style={{
height: "100%",
width: "100%",
opacity,
zIndex: 1000,
transition: "opacity 0.3s ease-out",
position: "absolute",
backgroundColor: "var(--backdrop)"
}}
@@ -212,14 +299,12 @@ export function ActionSheetPresenter(
</Box>
)}
>
<AnimatedFlex
animate={animation}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
style={{ y }}
initial={{ y: 1000 }}
<Flex
ref={sheetRef}
sx={{
bg: "background",
transform: "translate3d(0, 101%, 0)",
transition: sheetTransition,
borderTopLeftRadius: 15,
borderTopRightRadius: 15,
boxShadow: theme?.shadows.menu || "none",
@@ -228,34 +313,13 @@ export function ActionSheetPresenter(
}}
>
{draggable && (
<AnimatedFlex
drag="y"
onDrag={(_, { delta }: PanInfo) => {
y.set(Math.max(y.get() + delta.y, 0));
}}
onDragEnd={(_, { velocity }: PanInfo) => {
if (velocity.y >= 500) {
onClose?.();
return;
}
const sheetEl = contentRef.current;
if (!sheetEl) return;
const contentHeight = sheetEl.offsetHeight;
const threshold = 30;
const closingHeight = (contentHeight * threshold) / 100;
if (y.get() >= closingHeight) {
onBeforeClose();
} else {
setTimeout(() =>
animation.start({ transition: TRANSITION, y: 0 })
);
}
}}
dragConstraints={{ top: 0, bottom: 0 }}
dragMomentum={false}
dragElastic={false}
<Flex
onMouseDown={onMouseStart}
onMouseMove={onMouseMove}
onMouseUp={onSwipeEnd}
onTouchStart={onSwipeStart}
onTouchMove={onSwipeMove}
onTouchEnd={onSwipeEnd}
sx={{
bg: "transparent",
alignItems: "center",
@@ -272,12 +336,12 @@ export function ActionSheetPresenter(
borderRadius: 100
}}
/>
</AnimatedFlex>
</Flex>
)}
<ContentContainer items={items} title={title} onClose={onClose}>
{children}
</ContentContainer>
</AnimatedFlex>
</Flex>
</Modal>
);
}

View File

@@ -38,13 +38,10 @@ import {
toBlobURL,
toDataURL
} from "../../utils/downloader.js";
import { motion } from "framer-motion";
import { useObserver } from "../../hooks/use-observer.js";
import { Attachment, ImageAlignmentOptions } from "../attachment/index.js";
import { DataURL } from "@notesnook/common";
export const AnimatedImage = motion.create(Image);
export function ImageComponent(
props: ReactNodeViewProps<Partial<ImageAttributes>>
) {
@@ -252,11 +249,8 @@ export function ImageComponent(
/>
</Flex>
)}
<AnimatedImage
<Image
as={isSVG ? "object" : "img"}
initial={{ opacity: 0 }}
animate={{ opacity: bloburl || src ? 1 : 0 }}
transition={{ duration: 0.2, ease: "easeIn" }}
data-drag-image
ref={imageRef}
alt={alt}
@@ -271,6 +265,8 @@ export function ImageComponent(
})}
title={title}
sx={{
animation: bloburl || src ? "0.2s ease-in 0s 1 fadeIn" : "none",
opacity: 0,
objectFit: "contain",
width: editor.isEditable ? "100%" : size.width,
height: editor.isEditable ? "100%" : size.height,

View File

@@ -1,3 +1,12 @@
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.ProseMirror p span {
font-family: inherit;
}