Skip to content

Commit

Permalink
Merge branch 'develop' into chore/change-app-request-notify-admins-me…
Browse files Browse the repository at this point in the history
…ssage
  • Loading branch information
kodiakhq[bot] committed Mar 1, 2023
2 parents db369bf + e6a9645 commit 912a01a
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ Meteor.methods({
name: file.name,
type: file.type,
},
files: [
{
_id: file._id,
name: file.name,
type: file.type,
},
],
groupable: false,
attachments: [attachment],
token: visitorToken,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ export const MessageActionMenu = ({ options, ...props }: MessageActionMenuProps)
<MessageToolboxItem
ref={ref}
icon='kebab'
onClick={(e): void => {
e.stopPropagation();
onClick={(): void => {
setVisible(!visible);
}}
data-qa-id='menu'
Expand Down
146 changes: 100 additions & 46 deletions apps/meteor/client/providers/TooltipProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,80 +1,134 @@
import { useMediaQuery } from '@rocket.chat/fuselage-hooks';
import { useDebouncedState, useMediaQuery } from '@rocket.chat/fuselage-hooks';
import { TooltipComponent } from '@rocket.chat/ui-client';
import { TooltipContext } from '@rocket.chat/ui-contexts';
import type { FC, ReactNode } from 'react';
import React, { useEffect, useState, useMemo, useRef, memo } from 'react';
import React, { useEffect, useMemo, useRef, memo, useCallback, useState } from 'react';

import TooltipPortal from '../components/TooltipPortal';

const TooltipProvider: FC = ({ children }) => {
const lastAnchor = useRef<HTMLElement>();
const hasHover = !useMediaQuery('(hover: none)');

const [tooltip, setTooltip] = useState<ReactNode>(null);
const [tooltip, setTooltip] = useDebouncedState<ReactNode>(null, 300);

const restoreTitle = useCallback((previousAnchor: HTMLElement | undefined): void => {
setTimeout(() => {
if (previousAnchor && !previousAnchor.getAttribute('title')) {
previousAnchor.setAttribute('title', previousAnchor.getAttribute('data-title') ?? '');
previousAnchor.removeAttribute('data-title');
}
}, 0);
}, []);

const contextValue = useMemo(
() => ({
open: (tooltip: ReactNode, anchor: HTMLElement): void => {
const previousAnchor = lastAnchor.current;
setTooltip(<TooltipComponent key={new Date().toISOString()} title={tooltip} anchor={anchor} />);
lastAnchor.current = anchor;
previousAnchor && restoreTitle(previousAnchor);
},
close: (): void => {
const previousAnchor = lastAnchor.current;
setTooltip(null);
setTooltip.flush();
lastAnchor.current = undefined;
previousAnchor && restoreTitle(previousAnchor);
},
dismiss: (): void => {
setTooltip(null);
setTooltip.flush();
},
}),
[setTooltip, restoreTitle],
);

useEffect(() => {
if (!hasHover) {
return;
}
let timeout: ReturnType<typeof setTimeout> | undefined;

const handleMouseOver = (e: MouseEvent): void => {
const target = e.target as HTMLElement;
const anchor = target.title || target.dataset?.tooltip ? target : (target.closest('[title], [data-tooltip]') as HTMLElement);
if (lastAnchor.current === target) {
return;
}

const anchor = target.closest('[title], [data-tooltip]') as HTMLElement;

if (lastAnchor.current === anchor) {
return;
}

if (timeout) {
clearTimeout(timeout);
if (!anchor) {
contextValue.close();
return;
}
lastAnchor.current = undefined;

timeout = setTimeout(() => {
if (!anchor) {
return;
}
const title = anchor.getAttribute('title') || anchor.getAttribute('data-tooltip');
if (!title) {
anchor.removeAttribute('data-title');
return;
}
anchor.setAttribute('data-title', title);
anchor.setAttribute('data-tooltip', title);
lastAnchor.current = anchor;
setTooltip(<TooltipComponent title={title} anchor={anchor} />);
}, 300);
setTooltip(null);

const title = anchor.getAttribute('title') ?? anchor.getAttribute('data-tooltip') ?? '';
if (!title) {
contextValue.close();
return;
}

// eslint-disable-next-line react/no-multi-comp
const Handler = () => {
const [state, setState] = useState(title);
useEffect(() => {
const close = (): void => contextValue.close();
// store the title in a data attribute
anchor.setAttribute('data-title', title);
// Removes the title attribute to prevent the browser's tooltip from showing
anchor.setAttribute('title', '');

anchor.addEventListener('mouseleave', close);

const observer = new MutationObserver(() => {
const title = anchor.getAttribute('title') ?? anchor.getAttribute('data-tooltip') ?? '';

if (title === '') {
return;
}

// store the title in a data attribute
anchor.setAttribute('data-title', title);
// Removes the title attribute to prevent the browser's tooltip from showing
anchor.setAttribute('title', '');

setState(title);
});

observer.observe(anchor, {
attributes: true,
attributeFilter: ['title', 'data-tooltip'],
});

return () => {
anchor.removeEventListener('mouseleave', close);
observer.disconnect();
};
}, []);
return <>{state}</>;
};
contextValue.open(<Handler />, anchor);
};

const handleClick = (): void => {
setTooltip(null);
clearTimeout(timeout);
const dismissOnClick = (): void => {
contextValue.dismiss();
};

document.body.addEventListener('mouseover', handleMouseOver);
document.body.addEventListener('click', handleClick);
document.body.addEventListener('mouseover', handleMouseOver, {
passive: true,
});
document.body.addEventListener('click', dismissOnClick);

return (): void => {
if (timeout) {
clearTimeout(timeout);
}
contextValue.close();
document.body.removeEventListener('mouseover', handleMouseOver);
document.body.removeEventListener('click', handleClick);
document.body.removeEventListener('click', dismissOnClick);
};
}, [hasHover]);

const contextValue = useMemo(
() => ({
open: (tooltip: ReactNode, anchor: HTMLElement): void => {
setTooltip(<TooltipComponent title={tooltip} anchor={anchor} />);
},
close: (): void => {
setTooltip(null);
},
}),
[],
);
}, [contextValue, setTooltip, hasHover]);

return (
<TooltipContext.Provider value={contextValue}>
Expand Down
6 changes: 3 additions & 3 deletions apps/meteor/client/views/meet/CallPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ const CallPage: FC<CallPageProps> = ({
<Button
id='mic'
square
data-title={isMicOn ? t('Mute_microphone') : t('Unmute_microphone')}
title={isMicOn ? t('Mute_microphone') : t('Unmute_microphone')}
onClick={(): any => toggleButton('mic')}
className={isMicOn ? 'On' : 'Off'}
size={Number(buttonSize)}
Expand All @@ -209,7 +209,7 @@ const CallPage: FC<CallPageProps> = ({
<Button
id='camera'
square
data-title={isCameraOn ? t('Turn_off_video') : t('Turn_on_video')}
title={isCameraOn ? t('Turn_off_video') : t('Turn_on_video')}
onClick={(): void => toggleButton('camera')}
className={isCameraOn ? 'On' : 'Off'}
size={parseInt(buttonSize)}
Expand All @@ -228,7 +228,7 @@ const CallPage: FC<CallPageProps> = ({
<Icon name='arrow-expand' size={iconSize} color='white' />
</Button>
)}
<Button square danger data-title={t('End_call')} onClick={closeWindow} size={parseInt(buttonSize)}>
<Button square danger title={t('End_call')} onClick={closeWindow} size={parseInt(buttonSize)}>
<Icon name='phone-off' size={iconSize} color='white' />
</Button>
</ButtonGroup>
Expand Down
11 changes: 10 additions & 1 deletion apps/meteor/client/views/room/components/body/RoomBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -503,11 +503,20 @@ const RoomBody = (): ReactElement => {

const handleCloseFlexTab: MouseEventHandler<HTMLElement> = useCallback(
(e): void => {
const checkIfElementOrParentIsInstanceOfButton = (element: HTMLElement | null): boolean => {
if (!element) {
return false;
}
if (element instanceof HTMLButtonElement) {
return true;
}
return checkIfElementOrParentIsInstanceOfButton(element.parentElement);
};
if (!hideFlexTab) {
return;
}

if (e.target instanceof HTMLButtonElement) {
if (checkIfElementOrParentIsInstanceOfButton(e.target as HTMLElement)) {
return;
}

Expand Down

0 comments on commit 912a01a

Please sign in to comment.