Page MenuHomePhabricator

D4912.id16054.diff
No OneTemporary

D4912.id16054.diff

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

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)

Event Timeline