Add fading to context menu

This commit is contained in:
Bill 2021-06-25 01:42:41 -04:00
parent 78c25c21ee
commit 083f5ff0f3
7 changed files with 67 additions and 36 deletions

View File

@ -174,13 +174,18 @@ export const AvatarInfoWidgetView: FC<AvatarInfoWidgetViewProps> = props =>
setInfoStandEvent(null); setInfoStandEvent(null);
}, []); }, []);
const clearName = useCallback(() =>
{
setName(null);
}, []);
const currentView = useMemo(() => const currentView = useMemo(() =>
{ {
if(isGameMode) return null; if(isGameMode) return null;
if(decorateView) return decorateView; if(decorateView) return decorateView;
if(name) return <AvatarInfoWidgetNameView event={ name } />; if(name) return <AvatarInfoWidgetNameView nameData={ name } close={ clearName } />;
if(infoStandEvent) if(infoStandEvent)
{ {

View File

@ -11,7 +11,7 @@ export const AvatarInfoWidgetDecorateView: FC<AvatarInfoWidgetDecorateViewProps>
const { userId = -1, userName = '', roomIndex = -1, setIsDecorating = null } = props; const { userId = -1, userName = '', roomIndex = -1, setIsDecorating = null } = props;
return ( return (
<ContextMenuView objectId={ roomIndex } category={ RoomObjectCategory.UNIT } onClose={ null }> <ContextMenuView objectId={ roomIndex } category={ RoomObjectCategory.UNIT } close={ null }>
<ContextMenuListView> <ContextMenuListView>
<ContextMenuListItemView onClick={ event => setIsDecorating(false) }> <ContextMenuListItemView onClick={ event => setIsDecorating(false) }>
{ LocalizeText('widget.avatar.stop_decorating') } { LocalizeText('widget.avatar.stop_decorating') }

View File

@ -1,21 +1,23 @@
import { FC, useCallback } from 'react'; import { FC, useMemo } from 'react';
import { GetSessionDataManager } from '../../../../../../api';
import { ContextMenuView } from '../../../context-menu/ContextMenuView'; import { ContextMenuView } from '../../../context-menu/ContextMenuView';
import { ContextMenuHeaderView } from '../../../context-menu/views/header/ContextMenuHeaderView';
import { AvatarInfoWidgetNameViewProps } from './AvatarInfoWidgetNameView.types'; import { AvatarInfoWidgetNameViewProps } from './AvatarInfoWidgetNameView.types';
export const AvatarInfoWidgetNameView: FC<AvatarInfoWidgetNameViewProps> = props => export const AvatarInfoWidgetNameView: FC<AvatarInfoWidgetNameViewProps> = props =>
{ {
const { event = null } = props; const { nameData = null, close = null } = props;
const onClose = useCallback(() => const fades = useMemo(() =>
{ {
return (nameData.id !== GetSessionDataManager().userId);
}, []); }, [ nameData ]);
return ( return (
<ContextMenuView objectId={ event.roomIndex } category={ event.category } onClose= { onClose }> <ContextMenuView objectId={ nameData.roomIndex } category={ nameData.category } fades={ fades } close= { close }>
<div className="d-flex justify-content-center align-items-center bg-dark border border-dark"> <ContextMenuHeaderView>
{ event.name } { nameData.name }
</div> </ContextMenuHeaderView>
</ContextMenuView> </ContextMenuView>
); );
} }

View File

@ -2,5 +2,6 @@ import { RoomWidgetObjectNameEvent } from '../../../../events';
export interface AvatarInfoWidgetNameViewProps export interface AvatarInfoWidgetNameViewProps
{ {
event: RoomWidgetObjectNameEvent; nameData: RoomWidgetObjectNameEvent;
close: () => void;
} }

View File

@ -106,7 +106,7 @@ export const AvatarInfoWidgetOwnAvatarView: FC<AvatarInfoWidgetOwnAvatarViewProp
const isRidingHorse = IsRidingHorse(); const isRidingHorse = IsRidingHorse();
return ( return (
<ContextMenuView objectId={ userData.roomIndex } category={ RoomObjectCategory.UNIT } onClose={ close }> <ContextMenuView objectId={ userData.roomIndex } category={ RoomObjectCategory.UNIT } close={ close }>
<ContextMenuHeaderView> <ContextMenuHeaderView>
{ userData.name } { userData.name }
</ContextMenuHeaderView> </ContextMenuHeaderView>

View File

@ -1,24 +1,45 @@
import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { GetRoomObjectBounds, GetRoomSession, GetTicker } from '../../../../api'; import { GetRoomObjectBounds, GetRoomSession, GetTicker } from '../../../../api';
import { ContextMenuViewFadeOptions, ContextMenuViewProps } from './ContextMenuView.types'; import { ContextMenuViewProps } from './ContextMenuView.types';
const fadeDelay = 3000;
const fadeLength = 75;
export const ContextMenuView: FC<ContextMenuViewProps> = props => export const ContextMenuView: FC<ContextMenuViewProps> = props =>
{ {
const { objectId = -1, category = -1, fades = false, onClose = null, children = null } = props; const { objectId = -1, category = -1, fades = false, close = null, children = null } = props;
const [ pos, setPos ] = useState<{ x: number, y: number }>({ x: -1, y: -1}); const [ pos, setPos ] = useState<{ x: number, y: number }>({ x: -1, y: -1});
const [ opacity, setOpacity ] = useState(1); const [ opacity, setOpacity ] = useState(1);
const [ fadeOptions, setFadeOptions ] = useState<ContextMenuViewFadeOptions>({ const [ isFading, setIsFading ] = useState(false);
firstFadeStarted: false, const [ fadeTime, setFadeTime ] = useState(0);
fadeAfterDelay: true,
fadeLength: 75,
fadeTime: 0,
fadeStartDelay: 3000,
fadingOut: false
});
const elementRef = useRef<HTMLDivElement>(); const elementRef = useRef<HTMLDivElement>();
const update = useCallback((time: number) => const update = useCallback((time: number) =>
{ {
let fadeTime = time;
let newOpacity = 1;
if(isFading)
{
setFadeTime(prevValue =>
{
fadeTime += prevValue;
return fadeTime;
});
newOpacity = ((1 - (fadeTime / fadeLength)) * 1);
if(newOpacity <= 0)
{
close();
return;
}
setOpacity(newOpacity);
}
const bounds = GetRoomObjectBounds(GetRoomSession().roomId, objectId, category); const bounds = GetRoomObjectBounds(GetRoomSession().roomId, objectId, category);
if(!bounds || !elementRef.current) return; if(!bounds || !elementRef.current) return;
@ -27,7 +48,7 @@ export const ContextMenuView: FC<ContextMenuViewProps> = props =>
x: Math.round(((bounds.left + (bounds.width / 2)) - (elementRef.current.offsetWidth / 2))), x: Math.round(((bounds.left + (bounds.width / 2)) - (elementRef.current.offsetWidth / 2))),
y: Math.round((bounds.top - elementRef.current.offsetHeight) + 10) y: Math.round((bounds.top - elementRef.current.offsetHeight) + 10)
}); });
}, [ objectId, category ]); }, [ objectId, category, isFading, close ]);
useEffect(() => useEffect(() =>
{ {
@ -39,8 +60,20 @@ export const ContextMenuView: FC<ContextMenuViewProps> = props =>
} }
}, [ update ]); }, [ update ]);
useEffect(() =>
{
if(!fades) return;
const timeout = setTimeout(() => setIsFading(true), fadeDelay);
return () =>
{
clearTimeout(timeout);
}
}, [ fades ]);
return ( return (
<div ref={ elementRef } className={ 'nitro-context-menu position-absolute ' + (pos.x > -1 ? 'visible' : 'invisible') } style={ { left: pos.x, top: pos.y } }> <div ref={ elementRef } className={ 'nitro-context-menu position-absolute ' + (pos.x > -1 ? 'visible' : 'invisible') } style={ { left: pos.x, top: pos.y, opacity: opacity } }>
{ children } { children }
</div> </div>
); );

View File

@ -3,15 +3,5 @@ export interface ContextMenuViewProps
objectId: number; objectId: number;
category: number; category: number;
fades?: boolean; fades?: boolean;
onClose: () => void; close: () => void;
}
export interface ContextMenuViewFadeOptions
{
firstFadeStarted: boolean;
fadeAfterDelay: boolean;
fadeLength: number;
fadeTime: number;
fadeStartDelay: number;
fadingOut: boolean;
} }