fixes,todo:product list animations,showreel modal,etc

This commit is contained in:
2024-08-15 19:34:48 +05:00
parent 41bd0d96b9
commit 775e01253f
24 changed files with 291 additions and 187 deletions
+2
View File
@@ -19,6 +19,7 @@
"react-input-mask": "^2.0.4",
"react-rangeslider": "^2.2.0",
"react-swipeable": "^7.0.1",
"react-transition-group": "^4.4.5",
"react-usestateref": "^1.0.9",
"usehooks-ts": "^3.1.0",
"zustand": "^4.5.4"
@@ -29,6 +30,7 @@
"@types/react-dom": "^18",
"@types/react-input-mask": "^3.0.5",
"@types/react-rangeslider": "^2.2.7",
"@types/react-transition-group": "^4.4.11",
"autoprefixer": "^10.4.19",
"eslint": "^8",
"eslint-config-next": "14.2.5",
@@ -0,0 +1,12 @@
<svg width="345" height="304" viewBox="0 0 345 304" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_f_3894_14794)">
<ellipse cx="0.372531" cy="-3.79121e-05" rx="154.894" ry="104.153" transform="rotate(135 0.372531 -3.79121e-05)" fill="#5545AC"/>
</g>
<defs>
<filter id="filter0_f_3894_14794" x="-343.626" y="-343.998" width="687.996" height="687.996" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="106" result="effect1_foregroundBlur_3894_14794"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.
+2 -2
View File
@@ -38,7 +38,7 @@ export function Header() {
{width >= 1280 && <LogoWithTextIcon />}
</Link>
</div>
<div className="flex border-x border-[#3D425C] max-xl:hidden">
<div className="flex border-x border-[#3D425C] max-xl:hidden relative">
<ProductsList />
<NavLink href="/about">О компании</NavLink>
<NavLink href="/blog">Блог</NavLink>
@@ -48,7 +48,7 @@ export function Header() {
<div className="flex">
<Button
onClick={() => setModal(<ModalWithForm />)}
className="rounded-none btn-text font-bold max-sm:hidden px-10"
className="rounded-none btn-text font-bold max-sm:hidden px-10 outline-none"
>
Оставить заявку
</Button>
+4 -4
View File
@@ -7,10 +7,10 @@ export function ModalContainer() {
return (
modal && (
<div className="fixed top-0 left-0 z-50 w-full h-full flex justify-center items-center bg-black bg-opacity-40 transition-opacity">
<div onClick={e => e.stopPropagation()} className="cursor-default">
{modal}
</div>
<div className="fixed top-0 left-0 z-10 w-full h-full flex justify-center items-start bg-black bg-opacity-40 transition-opacity">
{/* <div onClick={e => e.stopPropagation()} className="cursor-default"> */}
{modal}
{/* </div> */}
</div>
)
);
+63 -29
View File
@@ -1,7 +1,9 @@
import Products from '@/consts/products.json';
import { useModalStore } from '@/stores/useModalStore';
import { AnimatePresence, motion } from 'framer-motion';
import Image from 'next/image';
import { useEffect } from 'react';
import { useEffect, useRef, useState } from 'react';
import { useOnClickOutside } from 'usehooks-ts';
import { CloseIcon } from '../icons/CloseIcon';
interface IProduct {
@@ -11,40 +13,66 @@ interface IProduct {
image: string;
}
export default function ModalWithProducts() {
export function ModalWithProducts() {
const { setModal } = useModalStore();
const [show, setShow] = useState(true);
const ref = useRef<HTMLDivElement>(null);
useOnClickOutside(ref, () => setShow(false));
useEffect(() => {
const listener = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
setModal(false);
}
if (e.key === 'Escape') setShow(false);
};
document.addEventListener('keydown', listener);
return () => document.removeEventListener('keydown', listener);
}, [setModal]);
}, []);
return (
<div className="p-6 bg-[#14161F] z-100 aspect-[1600/600] max-h-[calc(100vw/1600*600)] relative top-0 space-y-6">
<h4 className="h4 font-medium flex justify-between items-center">
GRAFF.estate
<button
onClick={() => setModal(null)}
className="hover:bg-[#3D425C] rounded-full p-2"
<AnimatePresence onExitComplete={() => setModal(null)}>
{show && (
<motion.div
ref={ref}
key={'products'}
initial={{
opacity: 0,
// scaleY: 0,
// originY: 0,
}}
animate={{
opacity: 1,
// scaleY: 1,
// originY: 0,
}}
transition={{ duration: 0.75, type: 'spring' }}
exit={{
opacity: 0,
// scaleY: 0,
// originY: 0,
}}
className="pt-10 p-6 bg-[#14161F] bg-opacity-90 -z-20 aspect-[1600/720] top-[76px] relative space-y-6 transition-all backdrop-blur-3xl"
>
<CloseIcon />
</button>
</h4>
<div className="grid grid-col-3 grid-rows-2 mt-px ml-px">
{Products.map((product, index) => (
<ProductItem
key={product.id}
{...product}
className={`col-start-${(index % 3) + 1} row-start-${index < 3 ? 1 : 2}`}
/>
))}
</div>
</div>
<h4 className="h4 font-medium flex justify-between items-center">
GRAFF.estate
<button
onClick={() => setShow(false)}
className="hover:bg-[#3D425C] rounded-full p-2"
>
<CloseIcon />
</button>
</h4>
<div className="grid grid-col-3 grid-rows-2 mt-px ml-px">
{Products.map((product, index) => (
<ProductItem
key={product.id}
{...product}
className={`col-start-${(index % 3) + 1} row-start-${index < 3 ? 1 : 2}`}
/>
))}
</div>
</motion.div>
)}
</AnimatePresence>
);
}
@@ -55,9 +83,13 @@ function ProductItem({
className,
}: Omit<IProduct, 'id'> & { className?: string }) {
return (
<div
<motion.div
whileHover={{
backgroundSize: '100% 100%',
}}
transition={{ duration: 0.2, type: 'just', delay: 0.1 }}
className={
'border border-[#3D425C] -mt-px -ml-px p-6 flex col-span-1 row-span-1 ' +
'border border-[#3D425C] -mt-px -ml-px p-6 flex col-span-1 row-span-1 aspect-[517/304] bg-[url(/img/components/products/highlight.svg)] bg-[length:0px_0px] bg-left-top bg-no-repeat ' +
className
}
>
@@ -76,9 +108,11 @@ function ProductItem({
src={image}
alt={title}
fill
className="object-contain object-bottom !relative"
priority
sizes="100% 100%"
className="object-contain !relative object-bottom"
/>
</div>
</div>
</motion.div>
);
}
+15 -3
View File
@@ -1,17 +1,29 @@
'use client';
import { useModalStore } from '@/stores/useModalStore';
import { useEffect, useState } from 'react';
import { ChevronDownIcon } from '../icons/ChevronDownIcon';
import { ChevronUpIcon } from '../icons/ChevronUpIcon';
import ModalWithProducts from './ModalWithProducts';
import { ModalWithProducts } from './ModalWithProducts';
export function ProductsList() {
const { setModal, modal } = useModalStore();
const [show, setShow] = useState(false);
useEffect(() => {
setShow(!!modal);
}, [modal]);
return (
<button
onClick={() => setModal(modal ? null : <ModalWithProducts />)}
className="btn-text font-medium px-8 py-6 flex gap-x-2 items-center border-r border-[#3D425C] hover:bg-[#3D425C]"
onClick={() => {
setModal(modal ? null : <ModalWithProducts />);
setShow(prev => !prev);
}}
className={
'btn-text font-medium px-8 py-6 flex gap-x-2 items-center border-r border-[#3D425C] hover:bg-[#3D425C] outline-none' +
(show ? ' relative z-[101]' : '')
}
>
Продукты
{modal ? <ChevronUpIcon /> : <ChevronDownIcon />}
+29
View File
@@ -0,0 +1,29 @@
import { CloseIcon } from '@/components/icons/CloseIcon';
import { useModalStore } from '@/stores/useModalStore';
interface VideoModalProps {
link: string;
}
export function VideoModal({ link }: VideoModalProps) {
const { setModal } = useModalStore();
const handleOnCloseClick = () => {
setModal(null);
console.log('aboba');
};
return (
<div className="w-screen h-screen absolute top-0 left-0 overflow-hidden flex justify-center items-center">
<div className="aspect-video w-full flex items-center justify-center">
<button
className="p-4 rounded-full border border-[#3D425C] absolute z-100 top-4 right-4 cursor-pointer"
onClick={handleOnCloseClick}
>
<CloseIcon />
</button>
<video src={link} className="aspect-video h-full" />
</div>
</div>
);
}
+2 -2
View File
@@ -8,8 +8,8 @@ export function ChevronUpIcon() {
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fill-Rule="evenodd"
clip-Rule="evenodd"
d="M12.0001 6.58594L19.7072 14.293L18.293 15.7073L12.0001 9.41436L5.70718 15.7073L4.29297 14.293L12.0001 6.58594Z"
fill="white"
/>
@@ -26,7 +26,7 @@ export const AvailableItem = forwardRef<HTMLDivElement, IAvailable>(
minHeight: '17.6vw',
}
}
transition={{ duration: 1, type: 'just' }}
transition={{ duration: 1, type: 'just', delay: 0.5 }}
exit={{
minWidth: '31.6vw',
minHeight: '17.6vw',
@@ -9,38 +9,66 @@ export interface IIntegration {
company: string;
}
export const IntegrationItem = forwardRef<HTMLDivElement, IIntegration>(
({ img, title, year, company }, ref) => {
return (
<AnimatePresence>
<motion.div
key={title}
ref={ref}
initial={{ minWidth: '31.6vw', minHeight: '31.8vw' }}
// exit={{ minWidth: '31.6vw', minHeight: '31.8vw' }}
transition={{ duration: 0.5, type: 'just' }}
animate={!!ref && { minWidth: '48vw', minHeight: '48vw' }}
className="flex flex-col relative duration-500 pointer-events-none"
>
<Image
src={img}
alt={''}
fill
priority
sizes="auto"
className="!relative flex-1 object-cover"
/>
<div className="mt-4">
<div className={`flex justify-between mb-${!ref ? 1 : 2}`}>
<h4 className="h4 font-medium">{title}</h4>
<h4 className="h4 font-medium">{year}</h4>
</div>
<p className="m-caption font-medium text-[#737AA1]">{company}</p>
export const IntegrationItem = forwardRef<
HTMLDivElement,
IIntegration & { index: number }
>(({ img, title, year, company, index }, ref) => {
// const transitionStyles: Map<TransitionStatus, CSSProperties> = new Map([
// ['entering', { minWidth: '48vw', minHeight: '48vw' }],
// ['entered', { minWidth: '48vw', minHeight: '48vw' }],
// ['exiting', { minWidth: '31.6vw', minHeight: '31.8vw' }],
// ['exited', { minWidth: '31.6vw', minHeight: '31.8vw' }],
// ]);
return (
// <Transition
// nodeRef={ref}
// timeout={500}
// in={!!ref}
// exit={!ref}
// appear
// onEnter={() => console.log('enter')}
// onEntering={() => console.log('entering')}
// onEntered={() => console.log('entered')}
// onExit={() => console.log('exit')}
// onExiting={() => console.log('exiting')}
// onExited={() => console.log('exited')}
// >
// {state => (
<AnimatePresence onExitComplete={() => console.log('exit')}>
<motion.div
ref={ref}
key={title + (index < 1 ? '123' : index > 3 ? '456' : '')}
initial={{ minWidth: '31.6vw', minHeight: '31.8vw' }}
transition={{ duration: 0.5, type: 'just', delay: 0.5 }}
animate={!!ref && { minWidth: '48vw', minHeight: '48vw' }}
// exit={{ minWidth: '31.6vw', minHeight: '31.8vw' }}
className={'flex flex-col relative transition-all pointer-events-none'}
// style={{
// transition: 'all 0.5s ease-out',
// ...transitionStyles.get(state),
// }}
>
<Image
src={img}
alt={''}
fill
priority
sizes="auto"
className="!relative flex-1 object-cover"
/>
<div className="mt-4">
<div className={`flex justify-between mb-${!ref ? 1 : 2}`}>
<h4 className="h4 font-medium">{title}</h4>
<h4 className="h4 font-medium">{year}</h4>
</div>
</motion.div>
</AnimatePresence>
);
},
);
<p className="m-caption font-medium text-[#737AA1]">{company}</p>
</div>
</motion.div>
</AnimatePresence>
// )}
// </Transition>
);
});
IntegrationItem.displayName = 'IntegrationItem';
@@ -1,7 +1,6 @@
'use client';
import { SliderWithScaling } from '@/ui/SliderWithScaling';
import 'react-circular-progressbar/dist/styles.css';
import { IIntegration, IntegrationItem } from './IntegrationItem';
export function IntegrationsSlider({
+20 -62
View File
@@ -1,77 +1,35 @@
'use client';
import { LoadingIcon } from '@/components/icons/LoadingIcon';
import { PauseIcon } from '@/components/icons/PauseIcon';
import { PlayIcon } from '@/components/icons/PlayIcon';
import { VideoModal } from '@/components/Layout/VideoModal';
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
import { useRef, useState } from 'react';
import { useHover } from 'usehooks-ts';
import { useModalStore } from '@/stores/useModalStore';
export function Showreel() {
const [isPlaying, setIsPlaying] = useState(true);
const [isBuffering, setIsBuffering] = useState(false);
function handleOnPlaying() {
setIsBuffering(false);
}
function handleOnWaiting() {
setIsBuffering(true);
}
const ref = useRef<HTMLDivElement>(null);
const videoRef = useRef<HTMLVideoElement>(null);
const hovered = useHover(ref);
const { modal, setModal } = useModalStore();
return (
<div className="lg:mb-[200px]">
<div ref={ref} className="relative flex justify-center items-center">
<video
ref={videoRef}
src="/videos/pages/home/showreel_1080p_4000k_h264.mp4"
muted
autoPlay
loop
className="w-full object-cover"
onPlaying={handleOnPlaying}
onWaiting={handleOnWaiting}
/>
{(hovered || !isPlaying) && (
<button
onClick={() => {
if (!isPlaying) {
videoRef.current?.play();
setIsPlaying(true);
} else {
videoRef.current?.pause();
setIsPlaying(false);
}
}}
className="absolute z-10 mx-auto p-8 rounded-full border"
>
<ClassNameWrapper
className="w-10 h-10"
element={isPlaying ? <PauseIcon /> : <PlayIcon />}
/>
</button>
)}
<div
className={
'absolute aspect-video w-full h-full flex justify-center items-center bg-black bg-opacity-50 transition-opacity ' +
(isBuffering ? 'opacity-100' : 'opacity-0')
<div className="w-full bg-cover bg-no-repeat bg-[url(/img/pages/home/showreel/preview.png)] aspect-[1551/616] relative flex justify-center items-center">
<button
className="absolute z-10 mx-auto p-8 rounded-full border"
onClick={() =>
setModal(<VideoModal link={'/videos/pages/home/showreel.mp4'} />)
}
>
<div className="flex gap-4 items-center">
<span>
<ClassNameWrapper
className="animate-spin w-5 h-5"
element={<LoadingIcon />}
/>
</span>
<span>Загружаем шоурил...</span>
</div>
<ClassNameWrapper className="w-10 h-10" element={<PlayIcon />} />
</button>
</div>
<div className="absolute aspect-video w-full h-full flex justify-center items-center bg-black bg-opacity-50 transition-opacity">
<div className="flex gap-4 items-center">
<span>
<ClassNameWrapper
className="animate-spin w-5 h-5"
element={<LoadingIcon />}
/>
</span>
<span>Загружаем шоурил...</span>
</div>
</div>
</div>
+5 -3
View File
@@ -1,5 +1,4 @@
import { Descriptor } from '@/ui/Descriptor';
import { LineThrow } from '@/ui/LineThrow';
import { Title } from '@/ui/Title';
import { Manrope } from 'next/font/google';
import Image from 'next/image';
@@ -9,10 +8,13 @@ const manrope = Manrope({ subsets: ['latin'] });
export function Statistics() {
return (
<section>
<Title className="mb-20">
<Title className="mb-20 leading-[-2em]">
Продавайте недвижимость <br />
<span className="text-gradient">проще и </span>
<LineThrow>быстрее</LineThrow>
<span className="relative">
<span className="text-[#52587A]">быстрее</span>
<span className="absolute top-[55%] -left-[2.5%] 2xl:h-1.5 h-1 w-[105%] bg-white" />
</span>
<span className="text-gradient"> дороже</span>
</Title>
<div className="grid grid-cols-4 border-t border-[#3D425C]">
+1 -8
View File
@@ -1,7 +1,6 @@
import { ArrowMoreIcon } from '@/components/icons/ArrowMoreIcon';
import { PlusIcon } from '@/components/icons/PlusIcon';
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
import Image from 'next/image';
import Link from 'next/link';
export function Technology() {
@@ -33,13 +32,7 @@ export function Technology() {
презентовать объект покупателю из любой точки мира
</p>
<div className="col-start-4 col-span-6 rounded-lg [box-shadow:1.04px_1.04px_4.18px_0px_rgba(45,79,0,0.3)] relative">
<Image
src={'/img/pages/home/technology/Content.png'}
fill
alt={''}
sizes="100%"
className="!relative rounded-lg border-[8.36px] border-transparent [background:linear-gradient(72.18deg,#575A6C_1.53%,#616476_98.43%)_border-box] [-webkit-mask:linear-gradient(#fff_0_0)_padding-box,linear-gradient(#fff_0_0)] [-webkit-mask-composite:xor]"
/>
<video src="/img/pages/home/technology/content.mp4" autoPlay loop />
</div>
<div className="flex justify-between items-start col-start-4 col-span-6 mt-10">
<h4 className="h4 font-medium w-2/3">
+5 -5
View File
@@ -4,14 +4,14 @@
"text": "«Эффективность инструмента была подтверждена буквально в первый день после его внедрения»",
"author": "Егор Бобров, Коммерческий директор авторского квартала «Машаров»"
},
{
"image": "/img/pages/home/reviews/2.jpg",
"text": "«Клиенты особенно ценят возможность легко выбрать квартиру с помощью 3D-модель жилого комплекса»",
"author": "Олег Бондорев, Ведущий менеджер компании «ЭНКО»"
},
{
"image": "/img/pages/home/reviews/3.jpg",
"text": "«Клиенты особенно ценят возможность легко выбрать квартиру с помощью 3D-модель жилого комплекса»",
"author": "Алина Веселова, Ведущий специалист отдела продаж"
},
{
"image": "/img/pages/home/reviews/2.jpg",
"text": "«Клиенты особенно ценят возможность легко выбрать квартиру с помощью 3D-модель жилого комплекса»",
"author": "Олег Бондорев, Ведущий менеджер компании «ЭНКО»"
}
]
-14
View File
@@ -1,14 +0,0 @@
import { PropsWithChildren } from 'react';
export function LineThrow({
className = '',
children,
}: PropsWithChildren<{ className?: string }>) {
return (
<span
className={'line-through decoration-white text-[#52587A]' + className}
>
{children}
</span>
);
}
-7
View File
@@ -1,7 +1,6 @@
'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
export function NavLink({
href,
@@ -12,8 +11,6 @@ export function NavLink({
children: React.ReactNode;
className?: string;
}) {
const pathname = usePathname();
return (
<Link
href={href}
@@ -22,10 +19,6 @@ export function NavLink({
className
}
>
{/* <ClassNameWrapper
element={<ActiveCubeIcon />}
className={pathname.startsWith(href) ? '' : 'invisible'}
/> */}
{children}
</Link>
);
+17 -13
View File
@@ -22,7 +22,9 @@ export function SliderWithScaling<T>({
controlsPosition,
}: {
slides: T[];
SlideElement: ForwardRefExoticComponent<T & RefAttributes<HTMLDivElement>>;
SlideElement: ForwardRefExoticComponent<
T & { index: number } & RefAttributes<HTMLDivElement>
>;
className?: string;
alignItems?: 'start' | 'center' | 'end';
title: string;
@@ -32,7 +34,6 @@ export function SliderWithScaling<T>({
const width = useWindowWidth();
const baseoffset = (-width / 1600) * 507 + 8;
// const [itemRef, scale] = useAnimate<HTMLDivElement>();
const itemRef = useRef<HTMLDivElement>(null);
const [slide, setSlide] = useState(0);
@@ -57,8 +58,6 @@ export function SliderWithScaling<T>({
);
const nextSlide = () => {
// itemRef.current!.style.minWidth = minWidth;
// itemRef.current!.style.minHeight = minHeight;
dispatch('next');
};
@@ -66,7 +65,9 @@ export function SliderWithScaling<T>({
setSliderOffset(baseoffset);
}, [baseoffset, order, slide]);
const prevSlide = () => {};
const prevSlide = () => {
dispatch('prev');
};
const handlers = useSwipeable({
onSwipedLeft: nextSlide,
@@ -84,20 +85,23 @@ export function SliderWithScaling<T>({
<div className="overflow-hidden -mx-6">
<div {...handlers}>
<div
// ref={sliderRef}
className={`flex items-${alignItems} gap-x-4 -mr-6 relative select-none`}
style={{
transform: `translateX(${sliderOffset}px)`,
transitionDuration: `${sliderOffset !== 0 && sliderOffset !== 2 * baseoffset ? 1 : 0}s`,
// transitionDelay: `${sliderOffset !== 0 && sliderOffset !== 2 * baseoffset ? 1 : 0}s`,
}}
>
{order.map((slide, index) => (
<SlideElement
ref={index === 1 ? itemRef : null}
key={index}
{...slide}
/>
))}
{order.map((slide, index) => {
return (
<SlideElement
ref={index === 1 ? itemRef : null}
index={index}
key={index}
{...slide}
/>
);
})}
</div>
</div>
</div>
+15
View File
@@ -14,12 +14,27 @@ const config: Config = {
},
animation: {
'infinite-scroll': 'infinite-scroll 25s linear infinite',
'highlight-product': 'highlight-product 0.1s ease-in 0s',
},
keyframes: {
'infinite-scroll': {
from: { transform: 'translateX(0)' },
to: { transform: 'translateX(-100%)' },
},
'highlight-product': {
'100%': {
backgroundImage: 'url(/img/components/products/highlight.svg)',
},
},
scaling: {
'0%': {
transform: 'min-width 31.6vw min-height 31.8vw',
transition: 'transform 500ms',
},
'100%': {
transform: 'min-width 48vw min-height 48vw',
},
},
},
},
},
+38 -1
View File
@@ -7,6 +7,13 @@
resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
"@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
version "7.25.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb"
integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==
dependencies:
regenerator-runtime "^0.14.0"
"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@@ -241,6 +248,13 @@
dependencies:
"@types/react" "*"
"@types/react-transition-group@^4.4.11":
version "4.4.11"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.11.tgz#d963253a611d757de01ebb241143b1017d5d63d5"
integrity sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^18":
version "18.3.3"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f"
@@ -795,6 +809,14 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
dom-helpers@^5.0.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
dependencies:
"@babel/runtime" "^7.8.7"
csstype "^3.0.2"
eastasianwidth@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
@@ -2230,7 +2252,7 @@ prettier@^3.3.3:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105"
integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==
prop-types@^15.8.1:
prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -2288,6 +2310,16 @@ react-swipeable@^7.0.1:
resolved "https://registry.yarnpkg.com/react-swipeable/-/react-swipeable-7.0.1.tgz#cd299f5986c5e4a7ee979839658c228f660e1e0c"
integrity sha512-RKB17JdQzvECfnVj9yDZsiYn3vH0eyva/ZbrCZXZR0qp66PBRhtg4F9yJcJTWYT5Adadi+x4NoG53BxKHwIYLQ==
react-transition-group@^4.4.5:
version "4.4.5"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
dependencies:
"@babel/runtime" "^7.5.5"
dom-helpers "^5.0.1"
loose-envify "^1.4.0"
prop-types "^15.6.2"
react-usestateref@^1.0.9:
version "1.0.9"
resolved "https://registry.yarnpkg.com/react-usestateref/-/react-usestateref-1.0.9.tgz#d40bc54db116e786b6b2bb1cd20fe06e7f8187f3"
@@ -2327,6 +2359,11 @@ reflect.getprototypeof@^1.0.4:
globalthis "^1.0.3"
which-builtin-type "^1.1.3"
regenerator-runtime@^0.14.0:
version "0.14.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334"