diff --git a/package.json b/package.json index 552b5858..a57b6aa0 100644 --- a/package.json +++ b/package.json @@ -11,12 +11,12 @@ }, "dependencies": { "@tanstack/react-virtual": "3.5.1", + "framer-motion": "^11.2.12", "react": "^18.3.1", "react-bootstrap": "^2.2.2", "react-dom": "^18.3.1", "react-icons": "^5.2.1", "react-slider": "^2.0.6", - "react-transition-group": "^4.4.5", "react-youtube": "^7.13.1", "use-between": "^1.3.5" }, diff --git a/src/common/index.ts b/src/common/index.ts index 3fc8c599..03eed926 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -18,6 +18,5 @@ export * from './classNames'; export * from './draggable-window'; export * from './layout'; export * from './layout/limited-edition'; -export * from './transitions'; export * from './types'; export * from './utils'; diff --git a/src/common/layout/LayoutNotificationBubbleView.tsx b/src/common/layout/LayoutNotificationBubbleView.tsx index 4a265929..62d84e42 100644 --- a/src/common/layout/LayoutNotificationBubbleView.tsx +++ b/src/common/layout/LayoutNotificationBubbleView.tsx @@ -1,6 +1,6 @@ +import { AnimatePresence, motion } from 'framer-motion'; import { FC, useEffect, useMemo, useState } from 'react'; import { Flex, FlexProps } from '../Flex'; -import { TransitionAnimation, TransitionAnimationTypes } from '../transitions'; export interface LayoutNotificationBubbleViewProps extends FlexProps { @@ -45,8 +45,14 @@ export const LayoutNotificationBubbleView: FC }, [ fadesOut, timeoutMs, onClose ]); return ( - - - + + { isVisible && + + + } + ); }; diff --git a/src/common/transitions/TransitionAnimation.tsx b/src/common/transitions/TransitionAnimation.tsx deleted file mode 100644 index 1287eda4..00000000 --- a/src/common/transitions/TransitionAnimation.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { FC, ReactNode, useEffect, useState } from 'react'; -import { Transition } from 'react-transition-group'; -import { getTransitionAnimationStyle } from './TransitionAnimationStyles'; - -export const TransitionAnimation: FC<{ - type: string; - inProp: boolean; - timeout?: number; - className?: string; - children?: ReactNode; -}> = props => -{ - const { type = null, inProp = false, timeout = 300, className = null, children = null } = props; - - const [ isChildrenVisible, setChildrenVisible ] = useState(false); - - useEffect(() => - { - let timeoutData: ReturnType = null; - - if(inProp) - { - setChildrenVisible(true); - } - else - { - timeoutData = setTimeout(() => - { - setChildrenVisible(false); - clearTimeout(timeout); - }, timeout); - } - - return () => - { - if(timeoutData) clearTimeout(timeoutData); - }; - }, [ inProp, timeout ]); - - return ( - - { state => ( -
- { isChildrenVisible && children } -
- ) } -
- ); -}; diff --git a/src/common/transitions/TransitionAnimationStyles.ts b/src/common/transitions/TransitionAnimationStyles.ts deleted file mode 100644 index feebdcca..00000000 --- a/src/common/transitions/TransitionAnimationStyles.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { CSSProperties } from 'react'; -import { TransitionStatus } from 'react-transition-group'; -import { ENTERING, EXITING } from 'react-transition-group/Transition'; -import { TransitionAnimationTypes } from './TransitionAnimationTypes'; - -export function getTransitionAnimationStyle(type: string, transition: TransitionStatus, timeout: number = 300): Partial -{ - switch(type) - { - case TransitionAnimationTypes.BOUNCE: - switch(transition) - { - default: - return {}; - case ENTERING: - return { - animationName: 'bounceIn', - animationDuration: `${ timeout }ms` - }; - case EXITING: - return { - animationName: 'bounceOut', - animationDuration: `${ timeout }ms` - }; - } - case TransitionAnimationTypes.SLIDE_LEFT: - switch(transition) - { - default: - return {}; - case ENTERING: - return { - animationName: 'slideInLeft', - animationDuration: `${ timeout }ms` - }; - case EXITING: - return { - animationName: 'slideOutLeft', - animationDuration: `${ timeout }ms` - }; - } - case TransitionAnimationTypes.SLIDE_RIGHT: - switch(transition) - { - default: - return {}; - case ENTERING: - return { - animationName: 'slideInRight', - animationDuration: `${ timeout }ms` - }; - case EXITING: - return { - animationName: 'slideOutRight', - animationDuration: `${ timeout }ms` - }; - } - case TransitionAnimationTypes.FLIP_X: - switch(transition) - { - default: - return {}; - case ENTERING: - return { - animationName: 'flipInX', - animationDuration: `${ timeout }ms` - }; - case EXITING: - return { - animationName: 'flipOutX', - animationDuration: `${ timeout }ms` - }; - } - case TransitionAnimationTypes.FADE_UP: - switch(transition) - { - default: - return {}; - case ENTERING: - return { - animationName: 'fadeInUp', - animationDuration: `${ timeout }ms` - }; - case EXITING: - return { - animationName: 'fadeOutDown', - animationDuration: `${ timeout }ms` - }; - } - case TransitionAnimationTypes.FADE_IN: - switch(transition) - { - default: - return {}; - case ENTERING: - return { - animationName: 'fadeIn', - animationDuration: `${ timeout }ms` - }; - case EXITING: - return { - animationName: 'fadeOut', - animationDuration: `${ timeout }ms` - }; - } - case TransitionAnimationTypes.FADE_DOWN: - switch(transition) - { - default: - return {}; - case ENTERING: - return { - animationName: 'fadeInDown', - animationDuration: `${ timeout }ms` - }; - case EXITING: - return { - animationName: 'fadeOutUp', - animationDuration: `${ timeout }ms` - }; - } - case TransitionAnimationTypes.HEAD_SHAKE: - switch(transition) - { - default: - return {}; - case ENTERING: - return { - animationName: 'headShake', - animationDuration: `${ timeout }ms` - }; - } - } - - return null; -} diff --git a/src/common/transitions/TransitionAnimationTypes.ts b/src/common/transitions/TransitionAnimationTypes.ts deleted file mode 100644 index 4ecc23be..00000000 --- a/src/common/transitions/TransitionAnimationTypes.ts +++ /dev/null @@ -1,11 +0,0 @@ -export class TransitionAnimationTypes -{ - public static BOUNCE: string = 'bounce'; - public static SLIDE_LEFT: string = 'slideLeft'; - public static SLIDE_RIGHT: string = 'slideRight'; - public static FLIP_X: string = 'flipX'; - public static FADE_IN: string = 'fadeIn'; - public static FADE_DOWN: string = 'fadeDown'; - public static FADE_UP: string = 'fadeUp'; - public static HEAD_SHAKE: string = 'headShake'; -} diff --git a/src/common/transitions/index.ts b/src/common/transitions/index.ts deleted file mode 100644 index 283a0058..00000000 --- a/src/common/transitions/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './TransitionAnimation'; -export * from './TransitionAnimationStyles'; -export * from './TransitionAnimationTypes'; diff --git a/src/components/main/MainView.tsx b/src/components/main/MainView.tsx index 884a9f5f..5e04b78c 100644 --- a/src/components/main/MainView.tsx +++ b/src/components/main/MainView.tsx @@ -1,6 +1,7 @@ import { AddLinkEventTracker, GetCommunication, HabboWebTools, ILinkEventTracker, RemoveLinkEventTracker, RoomSessionEvent } from '@nitrots/nitro-renderer'; +import { AnimatePresence, motion } from 'framer-motion'; import { FC, useEffect, useState } from 'react'; -import { Base, TransitionAnimation, TransitionAnimationTypes } from '../../common'; +import { Base } from '../../common'; import { useNitroEvent } from '../../hooks'; import { AchievementsView } from '../achievements/AchievementsView'; import { AvatarEditorView } from '../avatar-editor'; @@ -80,9 +81,15 @@ export const MainView: FC<{}> = props => return ( - - - + + { landingViewVisible && + + + } + diff --git a/src/components/room/RoomView.tsx b/src/components/room/RoomView.tsx index 06ae1b55..4f9061bf 100644 --- a/src/components/room/RoomView.tsx +++ b/src/components/room/RoomView.tsx @@ -1,7 +1,7 @@ -import { GetRenderer } from '@nitrots/nitro-renderer'; +import { GetRenderer, RoomSession } from '@nitrots/nitro-renderer'; +import { AnimatePresence, motion } from 'framer-motion'; import { FC, useEffect, useRef } from 'react'; import { DispatchMouseEvent, DispatchTouchEvent } from '../../api'; -import { Base } from '../../common'; import { useRoom } from '../../hooks'; import { RoomSpectatorView } from './spectator/RoomSpectatorView'; import { RoomWidgetsView } from './widgets/RoomWidgetsView'; @@ -13,6 +13,8 @@ export const RoomView: FC<{}> = props => useEffect(() => { + if(!roomSession) return; + const canvas = GetRenderer().canvas; if(!canvas) return; @@ -32,15 +34,23 @@ export const RoomView: FC<{}> = props => if(!element) return; element.appendChild(canvas); - }, []); + }, [ roomSession ]); return ( - - { roomSession && - <> - - { roomSession.isSpectator && } - } - + + { !!roomSession && + +
+ { roomSession instanceof RoomSession && + <> + + { roomSession.isSpectator && } + } +
+
} +
); }; diff --git a/src/components/room/widgets/furniture/FurnitureCraftingView.tsx b/src/components/room/widgets/furniture/FurnitureCraftingView.tsx index 585ff8e9..c2e5be06 100644 --- a/src/components/room/widgets/furniture/FurnitureCraftingView.tsx +++ b/src/components/room/widgets/furniture/FurnitureCraftingView.tsx @@ -12,9 +12,10 @@ export const FurnitureCraftingView: FC<{}> = props => const isOwner = useMemo(() => { + if(!roomSession) return false; const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, objectId, RoomObjectCategory.FLOOR); return IsOwnerOfFurniture(roomObject); - }, [ objectId, roomSession.roomId ]); + }, [ objectId, roomSession ]); const canCraft = useMemo(() => { diff --git a/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx index 95859268..14c670d2 100644 --- a/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx +++ b/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx @@ -1,7 +1,8 @@ import { CreateLinkEvent, GetGuestRoomResultEvent, GetRoomEngine, NavigatorSearchComposer, RateFlatMessageComposer } from '@nitrots/nitro-renderer'; +import { AnimatePresence, motion } from 'framer-motion'; import { FC, useEffect, useState } from 'react'; import { LocalizeText, SendMessageComposer } from '../../../../api'; -import { Base, Column, Flex, Text, TransitionAnimation, TransitionAnimationTypes, classNames } from '../../../../common'; +import { Base, Column, Flex, Text, classNames } from '../../../../common'; import { useMessageEvent, useNavigator, useRoom } from '../../../../hooks'; export const RoomToolsWidgetView: FC<{}> = props => @@ -80,20 +81,26 @@ export const RoomToolsWidgetView: FC<{}> = props => handleToolClick('like_room') } className="icon icon-like-room" /> } - - - - - { roomName } - { roomOwner } - - { roomTags && roomTags.length > 0 && + + { isOpen && + + + + + { roomName } + { roomOwner } + + { roomTags && roomTags.length > 0 && { roomTags.map((tag, index) => handleToolClick('navigator_search_tag', tag) }>#{ tag }) } } - - - + + + } + ); diff --git a/src/components/toolbar/ToolbarMeView.tsx b/src/components/toolbar/ToolbarMeView.tsx index 5dad9c73..4062b950 100644 --- a/src/components/toolbar/ToolbarMeView.tsx +++ b/src/components/toolbar/ToolbarMeView.tsx @@ -4,14 +4,11 @@ import { DispatchUiEvent, GetConfigurationValue, GetRoomSession, GetUserProfile import { Base, Flex, LayoutItemCountView } from '../../common'; import { GuideToolEvent } from '../../events'; -interface ToolbarMeViewProps -{ +export const ToolbarMeView: FC>; -} - -export const ToolbarMeView: FC> = props => +}>> = props => { const { useGuideTool = false, unseenAchievementCount = 0, setMeExpanded = null, children = null, ...rest } = props; const elementRef = useRef(); diff --git a/src/components/toolbar/ToolbarView.tsx b/src/components/toolbar/ToolbarView.tsx index 6784ff6a..07c3d6f6 100644 --- a/src/components/toolbar/ToolbarView.tsx +++ b/src/components/toolbar/ToolbarView.tsx @@ -1,7 +1,8 @@ import { CreateLinkEvent, Dispose, DropBounce, EaseOut, GetSessionDataManager, JumpBy, Motions, NitroToolbarAnimateIconEvent, PerkAllowancesMessageEvent, PerkEnum, Queue, Wait } from '@nitrots/nitro-renderer'; +import { AnimatePresence, motion } from 'framer-motion'; import { FC, useState } from 'react'; import { GetConfigurationValue, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api'; -import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes } from '../../common'; +import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView } from '../../common'; import { useAchievements, useFriends, useInventoryUnseenTracker, useMessageEvent, useMessenger, useNitroEvent, useSessionInfo } from '../../hooks'; import { ToolbarMeView } from './ToolbarMeView'; @@ -65,13 +66,23 @@ export const ToolbarView: FC<{ isInRoom: boolean }> = props => return ( <> - - - + + { isMeExpanded && + + + } + - setMeExpanded(!isMeExpanded) }> + + { + setMeExpanded(!isMeExpanded); + event.stopPropagation(); + } }> { (getTotalUnseen > 0) && } diff --git a/src/hooks/rooms/widgets/useAvatarInfoWidget.ts b/src/hooks/rooms/widgets/useAvatarInfoWidget.ts index f0421f95..eec6ba13 100644 --- a/src/hooks/rooms/widgets/useAvatarInfoWidget.ts +++ b/src/hooks/rooms/widgets/useAvatarInfoWidget.ts @@ -346,6 +346,8 @@ const useAvatarInfoWidgetState = () => useEffect(() => { + if(!roomSession) return; + roomSession.isDecorating = isDecorating; }, [ roomSession, isDecorating ]); diff --git a/yarn.lock b/yarn.lock index 33aaa3ef..9d9f7072 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1519,6 +1519,13 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" +framer-motion@^11.2.12: + version "11.2.12" + resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-11.2.12.tgz#ca5c49f8a1c70163cbadabcbd318acdcfea569fb" + integrity sha512-lCjkV4nA9rWOy2bhR4RZzkp2xpB++kFmUZ6D44V9VQaxk+JDmbDd5lq+u58DjJIIllE8AZEXp9OG/TyDN4FB/w== + dependencies: + tslib "^2.4.0" + fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"