Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3345813
D4912.id16054.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
14 KB
Referenced Files
None
Subscribers
None
D4912.id16054.diff
View Options
diff --git a/web/chat/composed-message.react.js b/web/chat/composed-message.react.js
--- a/web/chat/composed-message.react.js
+++ b/web/chat/composed-message.react.js
@@ -124,21 +124,12 @@
this.props.mouseOverMessagePosition.item.messageInfo.id === id &&
(this.props.sidebarExistsOrCanBeCreated || this.props.canReply)
) {
+ // eslint-disable-next-line no-unused-vars
const availableTooltipPositions = isViewer
? availableTooltipPositionsForViewerMessage
: availableTooltipPositionsForNonViewerMessage;
- messageTooltip = (
- <MessageTooltip
- threadInfo={threadInfo}
- item={item}
- availableTooltipPositions={availableTooltipPositions}
- setMouseOverMessagePosition={this.props.setMouseOverMessagePosition}
- mouseOverMessagePosition={this.props.mouseOverMessagePosition}
- canReply={this.props.canReply}
- inputState={this.props.inputState}
- />
- );
+ messageTooltip = <MessageTooltip messageTimestamp="" actions={[]} />;
}
let messageTooltipLinks;
diff --git a/web/chat/message-tooltip.css b/web/chat/message-tooltip.css
--- a/web/chat/message-tooltip.css
+++ b/web/chat/message-tooltip.css
@@ -1,3 +1,12 @@
+div.messageTooltipContainer {
+ display: flex;
+ flex-direction: column;
+ gap: 3px;
+ align-items: center;
+ font-size: var(--s-font-14);
+ padding: 0 5px;
+}
+
div.messageActionContainer {
display: flex;
flex-direction: row;
@@ -21,62 +30,21 @@
cursor: pointer;
color: var(--fg);
}
-div.messageActionButtonsViewer {
- flex-direction: row;
- margin-left: auto;
- margin-right: 0;
-}
-div.messageActionButtonsNonViewer {
- flex-direction: row-reverse;
- margin-left: 0;
- margin-right: auto;
-}
-div.messageActionLinkIcon {
- margin: 0 3px;
- position: relative;
-}
-div.messageActionExtraAreaTop:before {
- height: 15px;
- width: 55px;
- content: '';
- position: absolute;
- bottom: -15px;
-}
-div.messageActionExtraAreaTopRight:before {
- right: 0;
-}
-div.messageActionExtraAreaTopLeft:before {
- left: 0;
-}
-div.messageActionExtraArea:before {
- height: 30px;
- width: 20px;
- content: '';
- position: absolute;
-}
-div.messageActionExtraAreaRight:before {
- left: -20px;
-}
-div.messageActionExtraAreaLeft:before {
- right: -20px;
-}
-div.messageActionTopRightTooltip {
- bottom: 100%;
- margin-bottom: 1px;
- right: 0;
-}
-div.messageActionTopLeftTooltip {
- bottom: 100%;
- margin-bottom: 1px;
- left: 0;
-}
-div.messageActionLeftTooltip {
- top: 50%;
- right: 100%;
- margin-right: 7px;
+
+div.messageTooltipTopLabel {
+ height: 32px;
}
-div.messageActionRightTooltip {
- top: 50%;
- left: 100%;
- margin-left: 7px;
+
+div.messageTooltipLabel {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ height: 20px;
+ padding: 6px;
+ background-color: var(--message-action-tooltip-bg);
+ color: var(--tool-tip-color);
+ border-radius: 8px;
+ overflow: auto;
+ white-space: nowrap;
}
diff --git a/web/chat/message-tooltip.react.js b/web/chat/message-tooltip.react.js
--- a/web/chat/message-tooltip.react.js
+++ b/web/chat/message-tooltip.react.js
@@ -1,264 +1,72 @@
// @flow
import classNames from 'classnames';
-import invariant from 'invariant';
import * as React from 'react';
-import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors';
-import { useSidebarExistsOrCanBeCreated } from 'lib/shared/thread-utils';
-import type { ThreadInfo } from 'lib/types/thread-types';
-
-import CommIcon from '../CommIcon.react.js';
-import type { InputState } from '../input/input-state';
-import {
- useOnClickThread,
- useOnClickPendingSidebar,
-} from '../selectors/nav-selectors';
-import MessageReplyButton from './message-reply-button.react';
import css from './message-tooltip.css';
-import type {
- ItemAndContainerPositionInfo,
- MessagePositionInfo,
- OnMessagePositionWithContainerInfo,
- PositionInfo,
-} from './position-types';
-import { tooltipPositions, type TooltipPosition } from './tooltip-utils';
-import {
- TooltipMenu,
- type TooltipStyle,
- TooltipTextItem,
-} from './tooltip.react';
-
-const messageActionIconExcessVerticalWhitespace = 10;
-
-const openSidebarText = 'Go to thread';
-const createSidebarText = 'Create thread';
-
-type TooltipType = 'sidebar' | 'reply';
+import { type MessageTooltipAction } from './tooltip-utils';
type MessageTooltipProps = {
- +threadInfo: ThreadInfo,
- +item: ChatMessageInfoItem,
- +availableTooltipPositions: $ReadOnlyArray<TooltipPosition>,
- +setMouseOverMessagePosition?: (
- messagePositionInfo: MessagePositionInfo,
- ) => void,
- +mouseOverMessagePosition: OnMessagePositionWithContainerInfo,
- +canReply?: boolean,
- +inputState?: ?InputState,
+ +actions: $ReadOnlyArray<MessageTooltipAction>,
+ +messageTimestamp: string,
};
function MessageTooltip(props: MessageTooltipProps): React.Node {
- const {
- threadInfo,
- item,
- availableTooltipPositions,
- setMouseOverMessagePosition,
- mouseOverMessagePosition,
- canReply,
- inputState,
- } = props;
-
- const { containerPosition } = mouseOverMessagePosition;
-
- const [activeTooltip, setActiveTooltip] = React.useState<?TooltipType>();
- const [pointingTo, setPointingTo] = React.useState();
-
- const showTooltip = React.useCallback(
- (tooltipType: TooltipType, iconPosition: ItemAndContainerPositionInfo) => {
- if (activeTooltip) {
- return;
- }
- setActiveTooltip(tooltipType);
- setPointingTo(iconPosition);
- },
- [activeTooltip],
- );
-
- const hideTooltip = React.useCallback(() => {
- setActiveTooltip(null);
- }, []);
-
- const showSidebarTooltip = React.useCallback(
- (event: SyntheticEvent<HTMLDivElement>) => {
- const rect = event.currentTarget.getBoundingClientRect();
- const iconPosition = getIconPosition(rect, containerPosition);
- showTooltip('sidebar', iconPosition);
- },
- [containerPosition, showTooltip],
- );
-
- const showReplyTooltip = React.useCallback(
- (event: SyntheticEvent<HTMLDivElement>) => {
- const rect = event.currentTarget.getBoundingClientRect();
- const iconPosition = getIconPosition(rect, containerPosition);
- showTooltip('reply', iconPosition);
- },
- [containerPosition, showTooltip],
+ const { actions, messageTimestamp } = props;
+ const [activeTooltipLabel, setActiveTooltipLabel] = React.useState<?string>();
+ const messageActionButtonsContainerClassName = classNames(
+ css.messageActionContainer,
+ css.messageActionButtons,
);
- const { threadCreatedFromMessage, messageInfo } = item;
-
- const onThreadOpen = useOnClickThread(threadCreatedFromMessage);
- const onPendingSidebarOpen = useOnClickPendingSidebar(
- messageInfo,
- threadInfo,
- );
- const onSidebarButtonClick = React.useCallback(
- (event: SyntheticEvent<HTMLButtonElement>) => {
- if (threadCreatedFromMessage) {
- onThreadOpen(event);
- } else {
- onPendingSidebarOpen(event);
- }
- },
- [onPendingSidebarOpen, onThreadOpen, threadCreatedFromMessage],
- );
-
- const onReplyButtonClick = React.useCallback(() => {
- invariant(
- setMouseOverMessagePosition,
- 'setMouseOverMessagePosition should be set if replyButton exists',
+ const tooltipButtons = React.useMemo(() => {
+ if (!actions || actions.length === 0) {
+ return null;
+ }
+ const buttons = actions.map(({ label, onClick, actionButtonContent }) => {
+ const onMouseEnter = () => {
+ setActiveTooltipLabel(label);
+ };
+ const onMouseLeave = () =>
+ setActiveTooltipLabel(oldLabel =>
+ label === oldLabel ? null : oldLabel,
+ );
+
+ return (
+ <div
+ onMouseEnter={onMouseEnter}
+ onMouseLeave={onMouseLeave}
+ key={label}
+ onClick={onClick}
+ >
+ {actionButtonContent}
+ </div>
+ );
+ });
+ return (
+ <div className={messageActionButtonsContainerClassName}>{buttons}</div>
);
- setMouseOverMessagePosition({ type: 'off', item: item });
- }, [item, setMouseOverMessagePosition]);
+ }, [actions, messageActionButtonsContainerClassName]);
+ const tooltipLabel = React.useMemo(() => {
+ if (!activeTooltipLabel) {
+ return null;
+ }
+ return <div className={css.messageTooltipLabel}>{activeTooltipLabel} </div>;
+ }, [activeTooltipLabel]);
+
+ const tooltipTimestamp = React.useMemo(() => {
+ if (!messageTimestamp) {
+ return null;
+ }
+ return <div className={css.messageTooltipLabel}>{messageTimestamp} </div>;
+ }, [messageTimestamp]);
- let tooltipText = '';
- if (activeTooltip === 'reply') {
- tooltipText = 'Reply';
- } else if (activeTooltip === 'sidebar') {
- tooltipText = threadCreatedFromMessage
- ? openSidebarText
- : createSidebarText;
- }
-
- let tooltipMenu = null;
- if (pointingTo && activeTooltip) {
- tooltipMenu = (
- <TooltipMenu
- availableTooltipPositions={availableTooltipPositions}
- targetPositionInfo={pointingTo}
- layoutPosition="relative"
- getStyle={getMessageActionTooltipStyle}
- >
- <TooltipTextItem text={tooltipText} />
- </TooltipMenu>
- );
- }
-
- let replyButton;
- if (canReply) {
- invariant(inputState, 'inputState must be set if replyButton exists');
- invariant(
- mouseOverMessagePosition,
- 'mouseOverMessagePosition must be set if replyButton exists',
- );
- replyButton = (
- <div
- className={css.messageActionLinkIcon}
- onMouseEnter={showReplyTooltip}
- onMouseLeave={hideTooltip}
- >
- <MessageReplyButton
- messagePositionInfo={mouseOverMessagePosition}
- onReplyClick={onReplyButtonClick}
- inputState={inputState}
- />
- {activeTooltip === 'reply' ? tooltipMenu : null}
- </div>
- );
- }
-
- const sidebarExistsOrCanBeCreated = useSidebarExistsOrCanBeCreated(
- threadInfo,
- item,
- );
-
- let sidebarButton;
- if (sidebarExistsOrCanBeCreated) {
- sidebarButton = (
- <div
- className={css.messageActionLinkIcon}
- onMouseEnter={showSidebarTooltip}
- onMouseLeave={hideTooltip}
- onClick={onSidebarButtonClick}
- >
- <CommIcon icon="sidebar-filled" size={16} />
- {activeTooltip === 'sidebar' ? tooltipMenu : null}
- </div>
- );
- }
-
- const { isViewer } = messageInfo.creator;
- const messageActionButtonsContainerClassName = classNames({
- [css.messageActionContainer]: true,
- [css.messageActionButtons]: true,
- [css.messageActionButtonsViewer]: isViewer,
- [css.messageActionButtonsNonViewer]: !isViewer,
- });
return (
- <div>
- <div className={messageActionButtonsContainerClassName}>
- {sidebarButton}
- {replyButton}
- </div>
+ <div className={css.messageTooltipContainer}>
+ <div className={css.messageTooltipTopLabel}>{tooltipLabel}</div>
+ {tooltipButtons}
+ {tooltipTimestamp}
</div>
);
}
-function getIconPosition(
- rect: ClientRect,
- containerPosition: PositionInfo,
-): ItemAndContainerPositionInfo {
- const { top, bottom, left, right, width, height } = rect;
- return {
- containerPosition,
- itemPosition: {
- top:
- top - containerPosition.top + messageActionIconExcessVerticalWhitespace,
- bottom:
- bottom -
- containerPosition.top -
- messageActionIconExcessVerticalWhitespace,
- left: left - containerPosition.left,
- right: right - containerPosition.left,
- width,
- height: height - messageActionIconExcessVerticalWhitespace * 2,
- },
- };
-}
-
-function getMessageActionTooltipStyle(
- tooltipPosition: TooltipPosition,
-): TooltipStyle {
- let className;
- if (tooltipPosition === tooltipPositions.TOP_RIGHT) {
- className = classNames(
- css.messageActionTopRightTooltip,
- css.messageActionExtraAreaTop,
- css.messageActionExtraAreaTopRight,
- );
- } else if (tooltipPosition === tooltipPositions.TOP_LEFT) {
- className = classNames(
- css.messageActionTopLeftTooltip,
- css.messageActionExtraAreaTop,
- css.messageActionExtraAreaTopLeft,
- );
- } else if (tooltipPosition === tooltipPositions.RIGHT) {
- className = classNames(
- css.messageActionRightTooltip,
- css.messageActionExtraArea,
- css.messageActionExtraAreaRight,
- );
- } else if (tooltipPosition === tooltipPositions.LEFT) {
- className = classNames(
- css.messageActionLeftTooltip,
- css.messageActionExtraArea,
- css.messageActionExtraAreaLeft,
- );
- }
-
- invariant(className, `${tooltipPosition} is not valid for message tooltip`);
- return { className };
-}
-
export default MessageTooltip;
diff --git a/web/chat/robotext-message.react.js b/web/chat/robotext-message.react.js
--- a/web/chat/robotext-message.react.js
+++ b/web/chat/robotext-message.react.js
@@ -24,6 +24,7 @@
import css from './robotext-message.css';
import { tooltipPositions } from './tooltip-utils';
+// eslint-disable-next-line no-unused-vars
const availableTooltipPositionsForRobotext = [
tooltipPositions.TOP_RIGHT,
tooltipPositions.RIGHT,
@@ -57,7 +58,7 @@
);
}
- const { item, threadInfo, sidebarExistsOrCanBeCreated } = this.props;
+ const { item, sidebarExistsOrCanBeCreated } = this.props;
const { id } = item.messageInfo;
let messageTooltip;
if (
@@ -65,14 +66,7 @@
this.props.mouseOverMessagePosition.item.messageInfo.id === id &&
sidebarExistsOrCanBeCreated
) {
- messageTooltip = (
- <MessageTooltip
- threadInfo={threadInfo}
- item={item}
- mouseOverMessagePosition={this.props.mouseOverMessagePosition}
- availableTooltipPositions={availableTooltipPositionsForRobotext}
- />
- );
+ messageTooltip = <MessageTooltip messageTimestamp="" actions={[]} />;
}
let messageTooltipLinks;
diff --git a/web/chat/tooltip-utils.js b/web/chat/tooltip-utils.js
--- a/web/chat/tooltip-utils.js
+++ b/web/chat/tooltip-utils.js
@@ -1,6 +1,7 @@
// @flow
import invariant from 'invariant';
+import * as React from 'react';
import { calculateMaxTextWidth } from '../utils/text-utils';
import type { ItemAndContainerPositionInfo } from './position-types';
@@ -24,6 +25,12 @@
export type TooltipPosition = $Values<typeof tooltipPositions>;
+export type MessageTooltipAction = {
+ +label: string,
+ +onClick: (SyntheticEvent<HTMLDivElement>) => mixed,
+ +actionButtonContent: React.Node,
+};
+
const sizeOfTooltipArrow = 10; // 7px arrow + 3px extra
const tooltipMenuItemHeight = 22; // 17px line-height + 5px padding bottom
const tooltipInnerTopPadding = 5; // 5px bottom is included in last item
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 23, 7:10 AM (18 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2569560
Default Alt Text
D4912.id16054.diff (14 KB)
Attached To
Mode
D4912: [web] Refactor `MessageTooltip` component
Attached
Detach File
Event Timeline
Log In to Comment