mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-01-14 08:58:02 -05:00
* beginning ESM transition: Ceramic libraries, Next.js, & TypeScript configuration 🇭🇰 * updating Chakra, React, & Next image `import`s 👔 * upgrading `@types/react`, import extensions for Node, & b64 SVG to PNG ⛹🏿♀️ * fixing relative import names & upddating @types packages 📻 * removoing WYSIWYG editor, draft-js, & updating express ⛹🏿♀️ * updating OpenSea 🚲 * ¡@metafam/utils is building! 📰 * ¡Discord bot is building! 👘 * ¡backend is building! 🛩 * fixed everything but Ceramic DID update 🏍 * switching to DID:PKH 📦 * fixing "only one child allowed" error 🙇🏿♀️ * importing `React` as required by tsc's `isolatedModules` 🇲🇰 * disabling testing rather than taking the time to fix jest ⚜ * removing set `types` from `tsconfig` to fix compilation error 🥦 * printing tests disabled warning, hopefully 🙀 * setting file to be copied to the new resolver 👁️🗨️ * "paths-resolver" not "paths-resolve" 🦴 * switching back to relative paths rather than trying to fix `paths` ⏳ * `yarn backend:dev` not working, testing GitHub build 🎺 * removing design system build & fixing some images ✊🏿 * fixed "expected function got string" error & trying to address undefined HTMLElement 🐡 * fixing @emotion/react tree shaking by making external 🏏 * including eslint config in Dockerfile 🌾 * fixing more images 🎯 * updating DIDs & switching back to an updated DID:3 ❇ * switching to w3s.link gateway & fixing early termination of storage endpoint 🔭 * switching back to ipfs.io gateway b/c w3s.link serves SVGs as application/xml which are CORB blocked 🥾 * fixing node config name in eslint ignore & shortening some paths 🧰 * fixing ts-node not handling project references 🥁
173 lines
4.4 KiB
TypeScript
173 lines
4.4 KiB
TypeScript
import type { PanInfo } from '@metafam/ds';
|
|
import {
|
|
Flex,
|
|
motion,
|
|
useAnimation,
|
|
useBreakpointValue,
|
|
useMotionValue,
|
|
VStack,
|
|
} from '@metafam/ds';
|
|
import type { PropsWithChildren } from 'react';
|
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
|
|
import { useCarouselContext } from './CarouselContext';
|
|
|
|
const MotionFlex = motion(Flex);
|
|
|
|
const transitionProps = {
|
|
stiffness: 400,
|
|
type: 'spring',
|
|
damping: 60,
|
|
mass: 3,
|
|
};
|
|
|
|
export const Track: React.FC<PropsWithChildren> = ({ children }) => {
|
|
const {
|
|
setDragging,
|
|
setTrackIsActive,
|
|
trackIsActive,
|
|
isSubmittingProof,
|
|
setActiveItem,
|
|
activeItem,
|
|
constraint,
|
|
multiplier,
|
|
itemWidth,
|
|
positions,
|
|
} = useCarouselContext();
|
|
|
|
const [dragStartPosition, setDragStartPosition] = useState(0);
|
|
const controls = useAnimation();
|
|
const x = useMotionValue(0);
|
|
const node = useRef<HTMLDivElement>(null);
|
|
const isMobile = useBreakpointValue({ base: true, lg: false });
|
|
|
|
const handleDragStart = () => {
|
|
setDragging(true);
|
|
setDragStartPosition(positions[activeItem]);
|
|
};
|
|
|
|
// 2022-10-25: This method relied on on a type imported from
|
|
// Framer that no longer exists.
|
|
const handleDragEnd = (_evt: DragEvent, info: PanInfo) => {
|
|
const distance = info.offset.x;
|
|
const velocity = info.velocity.x * multiplier;
|
|
const direction = velocity < 0 || distance < 0 ? 1 : -1;
|
|
|
|
const extrapolatedPosition =
|
|
dragStartPosition +
|
|
(direction === 1
|
|
? Math.min(velocity, distance)
|
|
: Math.max(velocity, distance));
|
|
|
|
const closestPosition = positions.reduce(
|
|
(prev: number, curr: number) =>
|
|
Math.abs(curr - extrapolatedPosition) <
|
|
Math.abs(prev - extrapolatedPosition)
|
|
? curr
|
|
: prev,
|
|
0,
|
|
);
|
|
|
|
if (!(closestPosition < positions[positions.length - constraint])) {
|
|
setActiveItem(positions.indexOf(closestPosition));
|
|
controls.start({
|
|
x: closestPosition,
|
|
transition: {
|
|
velocity: info.velocity.x,
|
|
...transitionProps,
|
|
},
|
|
});
|
|
} else {
|
|
setActiveItem(positions.length - constraint);
|
|
controls.start({
|
|
x: positions[positions.length - constraint],
|
|
transition: {
|
|
velocity: info.velocity.x,
|
|
...transitionProps,
|
|
},
|
|
});
|
|
}
|
|
setDragging(false);
|
|
};
|
|
|
|
const handleResize = useCallback(
|
|
() =>
|
|
controls.start({
|
|
x: positions[activeItem],
|
|
transition: {
|
|
...transitionProps,
|
|
},
|
|
}),
|
|
[activeItem, controls, positions],
|
|
);
|
|
|
|
const handleClick = useCallback(
|
|
(event: MouseEvent) =>
|
|
node?.current?.contains(event.target as Node)
|
|
? setTrackIsActive(true)
|
|
: setTrackIsActive(false),
|
|
[setTrackIsActive],
|
|
);
|
|
|
|
const handleKeyDown = useCallback(
|
|
(event: KeyboardEvent) => {
|
|
if (trackIsActive && !isSubmittingProof) {
|
|
if (activeItem < positions.length - constraint) {
|
|
if (event.key === 'ArrowRight' || event.key === 'ArrowUp') {
|
|
event.preventDefault();
|
|
setActiveItem((prev: number) => prev + 1);
|
|
}
|
|
}
|
|
if (activeItem > positions.length - positions.length) {
|
|
if (event.key === 'ArrowLeft' || event.key === 'ArrowDown') {
|
|
event.preventDefault();
|
|
setActiveItem((prev: number) => prev - 1);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
[
|
|
trackIsActive,
|
|
isSubmittingProof,
|
|
activeItem,
|
|
positions.length,
|
|
constraint,
|
|
setActiveItem,
|
|
],
|
|
);
|
|
|
|
useEffect(() => {
|
|
handleResize();
|
|
|
|
document.addEventListener('keydown', handleKeyDown);
|
|
document.addEventListener('mousedown', handleClick);
|
|
return () => {
|
|
document.removeEventListener('keydown', handleKeyDown);
|
|
document.removeEventListener('mousedown', handleClick);
|
|
};
|
|
}, [handleClick, handleResize, handleKeyDown, positions]);
|
|
|
|
return (
|
|
<>
|
|
{itemWidth && (
|
|
<VStack ref={node} spacing={5} alignItems="stretch">
|
|
<MotionFlex
|
|
dragConstraints={node}
|
|
onDragStart={isMobile ? undefined : handleDragStart}
|
|
onDragEnd={isMobile ? undefined : handleDragEnd}
|
|
animate={controls}
|
|
style={{ x }}
|
|
drag="x"
|
|
_active={{ cursor: 'grabbing' }}
|
|
minWidth="min-content"
|
|
flexWrap="nowrap"
|
|
cursor="grab"
|
|
>
|
|
{children}
|
|
</MotionFlex>
|
|
</VStack>
|
|
)}
|
|
</>
|
|
);
|
|
};
|