V 0.06
parent
4d7b3dd8cd
commit
3afcb45816
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,42 @@
|
||||
import { FC, useRef, useEffect } from 'react'
|
||||
import { MdOutlineEdit } from '@react-icons/all-files/md/MdOutlineEdit'
|
||||
import { BsArrow90DegLeft } from '@react-icons/all-files/bs/BsArrow90DegLeft'
|
||||
import { BsArrow90DegRight } from '@react-icons/all-files/bs/BsArrow90DegRight'
|
||||
import { MdContentCopy } from '@react-icons/all-files/md/MdContentCopy'
|
||||
import { AiOutlineDelete } from '@react-icons/all-files/ai/AiOutlineDelete'
|
||||
import { AiOutlineCheckCircle } from '@react-icons/all-files/ai/AiOutlineCheckCircle'
|
||||
import MessageMenuItem from './MessageMenuItem';
|
||||
import { IContext } from '../../../../models/IContext'
|
||||
import { clickOuter } from '../../../../utils/clickOuter'
|
||||
|
||||
interface MessageMenuProps {
|
||||
context: IContext;
|
||||
setContext: (obj: IContext) => void;
|
||||
}
|
||||
|
||||
const MessageMenu: FC<MessageMenuProps> = ({ context, setContext }) => {
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
useEffect(() => {
|
||||
if(menuRef.current) {
|
||||
return clickOuter(menuRef.current, ()=>setContext({...context, active: false}));
|
||||
}
|
||||
}, [context, setContext]);
|
||||
return (
|
||||
<>
|
||||
{context.active &&
|
||||
<div ref={menuRef} style={{left: context.x, top: context.y}} className={['bg-gray-800 rounded-sm h-auto absolute', context.y < 280 ? '' : '-translate-y-full'].join(' ')}>
|
||||
<ul className='flex flex-col'>
|
||||
<MessageMenuItem icon={<BsArrow90DegLeft/>}>Reply</MessageMenuItem>
|
||||
<MessageMenuItem icon={<MdOutlineEdit/>}>Edit</MessageMenuItem>
|
||||
<MessageMenuItem icon={<BsArrow90DegRight/>}>Resend</MessageMenuItem>
|
||||
<MessageMenuItem icon={<MdContentCopy/>}>Copy text</MessageMenuItem>
|
||||
<MessageMenuItem icon={<AiOutlineDelete/>}>Delete</MessageMenuItem>
|
||||
<MessageMenuItem icon={<AiOutlineCheckCircle/>}>Select</MessageMenuItem>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default MessageMenu;
|
||||
@ -0,0 +1,14 @@
|
||||
import { FC, PropsWithChildren } from 'react'
|
||||
|
||||
interface MessageMenuItemProps {
|
||||
icon: React.JSX.Element;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const MessageMenuItem: FC<PropsWithChildren<MessageMenuItemProps>> = ({children, icon, className}) => {
|
||||
return (
|
||||
<button className={['hover:bg-gray-700 py-3 px-5 rounded-sm transition-all flex items-center text-white text-sm', className].join(' ')}><span className='text-xl mr-3'>{icon}</span>{children}</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default MessageMenuItem;
|
||||
@ -0,0 +1,36 @@
|
||||
import { FC, useRef, useEffect } from 'react'
|
||||
import Picker, { EmojiStyle, Theme } from 'emoji-picker-react';
|
||||
import { EmojiClickData } from 'emoji-picker-react';
|
||||
import { clickOuter } from '../../utils/clickOuter';
|
||||
|
||||
interface EmojiPickerProps {
|
||||
msg: string;
|
||||
setMsg: (val: string) => void;
|
||||
active: boolean;
|
||||
setActive: (bool: boolean) => void;
|
||||
button: HTMLButtonElement | null;
|
||||
}
|
||||
|
||||
const EmojiPicker: FC<EmojiPickerProps> = ({msg, setMsg, active, setActive, button}) => {
|
||||
|
||||
const onEmojiClick = (emojiObject: EmojiClickData ) => {
|
||||
setMsg(msg + emojiObject.emoji)
|
||||
}
|
||||
const pickerRef = useRef<HTMLDivElement>(null);
|
||||
useEffect(() => {
|
||||
if(pickerRef.current && button) {
|
||||
return clickOuter(pickerRef.current, ()=>setActive(false), button);
|
||||
}
|
||||
}, [active, setActive, button]);
|
||||
return (
|
||||
<>
|
||||
{active &&
|
||||
<div ref={pickerRef} className="absolute bottom-16">
|
||||
<Picker theme={Theme.DARK} emojiStyle={EmojiStyle.NATIVE} onEmojiClick={onEmojiClick} skinTonesDisabled={true}/>
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default EmojiPicker;
|
||||
@ -1,14 +1,16 @@
|
||||
import { FC } from 'react'
|
||||
import { FC, forwardRef, ForwardedRef } from 'react'
|
||||
|
||||
interface IcoButton {
|
||||
icon: React.JSX.Element;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
ref?: ForwardedRef<HTMLButtonElement>
|
||||
}
|
||||
|
||||
const IcoButton: FC<IcoButton> = ({icon, className}) => {
|
||||
const IcoButton: FC<IcoButton> = forwardRef(({icon, className, onClick}, ref) => {
|
||||
return (
|
||||
<button className={['hover:bg-gray-700 py-3 px-5 rounded-sm transition-all mr-2 text-white text-xl', className].join(' ')}>{icon}</button>
|
||||
<button ref={ref} className={['hover:bg-gray-700 py-3 px-5 rounded-sm transition-all mr-2 text-white text-xl', className].join(' ')} onClick={onClick}>{icon}</button>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default IcoButton;
|
||||
@ -0,0 +1,6 @@
|
||||
export interface IContext {
|
||||
active: boolean;
|
||||
x: number;
|
||||
y: number;
|
||||
message_id: string;
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
export const clickOuter = (ref: HTMLDivElement, callback: () => void, button: HTMLButtonElement | null = null) => {
|
||||
const onClick = (e: MouseEvent) => {
|
||||
const target = e.target as HTMLDivElement;
|
||||
if(button) {
|
||||
if(!(ref.contains(target) || button.contains(target))) {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
ref.contains(target) || callback();
|
||||
}
|
||||
}
|
||||
document.addEventListener('mousedown', onClick);
|
||||
return () => document.removeEventListener('mousedown', onClick);
|
||||
}
|
||||
Loading…
Reference in New Issue