diff --git a/web/chat/message-reply-button.react.js b/web/chat/message-reply-button.react.js index 38600c47b..c74cdbfd8 100644 --- a/web/chat/message-reply-button.react.js +++ b/web/chat/message-reply-button.react.js @@ -1,36 +1,36 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { createMessageReply } from 'lib/shared/message-utils'; +import CommIcon from '../CommIcon.react.js'; import type { InputState } from '../input/input-state'; -import SWMansionIcon from '../SWMansionIcon.react'; import css from './chat-message-list.css'; import type { OnMessagePositionWithContainerInfo } from './position-types'; type Props = { +messagePositionInfo: OnMessagePositionWithContainerInfo, +onReplyClick: () => void, +inputState: InputState, }; function MessageReplyButton(props: Props): React.Node { const { inputState, onReplyClick, messagePositionInfo } = props; const { addReply } = inputState; const { item } = messagePositionInfo; const replyClicked = React.useCallback(() => { invariant(item.messageInfo.text, 'text should be set in message clicked'); addReply(createMessageReply(item.messageInfo.text)); onReplyClick(); }, [addReply, item, onReplyClick]); return (
- +
); } export default MessageReplyButton; diff --git a/web/chat/message-tooltip.react.js b/web/chat/message-tooltip.react.js index 1cf32e00f..b6297db06 100644 --- a/web/chat/message-tooltip.react.js +++ b/web/chat/message-tooltip.react.js @@ -1,264 +1,264 @@ // @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 SWMansionIcon from '../SWMansionIcon.react'; 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'; type MessageTooltipProps = { +threadInfo: ThreadInfo, +item: ChatMessageInfoItem, +availableTooltipPositions: $ReadOnlyArray, +setMouseOverMessagePosition?: ( messagePositionInfo: MessagePositionInfo, ) => void, +mouseOverMessagePosition: OnMessagePositionWithContainerInfo, +canReply?: boolean, +inputState?: ?InputState, }; function MessageTooltip(props: MessageTooltipProps): React.Node { const { threadInfo, item, availableTooltipPositions, setMouseOverMessagePosition, mouseOverMessagePosition, canReply, inputState, } = props; const { containerPosition } = mouseOverMessagePosition; const [activeTooltip, setActiveTooltip] = React.useState(); 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) => { const rect = event.currentTarget.getBoundingClientRect(); const iconPosition = getIconPosition(rect, containerPosition); showTooltip('sidebar', iconPosition); }, [containerPosition, showTooltip], ); const showReplyTooltip = React.useCallback( (event: SyntheticEvent) => { const rect = event.currentTarget.getBoundingClientRect(); const iconPosition = getIconPosition(rect, containerPosition); showTooltip('reply', iconPosition); }, [containerPosition, showTooltip], ); const { threadCreatedFromMessage, messageInfo } = item; const onThreadOpen = useOnClickThread(threadCreatedFromMessage); const onPendingSidebarOpen = useOnClickPendingSidebar( messageInfo, threadInfo, ); const onSidebarButtonClick = React.useCallback( (event: SyntheticEvent) => { if (threadCreatedFromMessage) { onThreadOpen(event); } else { onPendingSidebarOpen(event); } }, [onPendingSidebarOpen, onThreadOpen, threadCreatedFromMessage], ); const onReplyButtonClick = React.useCallback(() => { invariant( setMouseOverMessagePosition, 'setMouseOverMessagePosition should be set if replyButton exists', ); setMouseOverMessagePosition({ type: 'off', item: item }); }, [item, setMouseOverMessagePosition]); let tooltipText = ''; if (activeTooltip === 'reply') { tooltipText = 'Reply'; } else if (activeTooltip === 'sidebar') { tooltipText = threadCreatedFromMessage ? openSidebarText : createSidebarText; } let tooltipMenu = null; if (pointingTo && activeTooltip) { tooltipMenu = ( ); } let replyButton; if (canReply) { invariant(inputState, 'inputState must be set if replyButton exists'); invariant( mouseOverMessagePosition, 'mouseOverMessagePosition must be set if replyButton exists', ); replyButton = (
{activeTooltip === 'reply' ? tooltipMenu : null}
); } const sidebarExistsOrCanBeCreated = useSidebarExistsOrCanBeCreated( threadInfo, item, ); let sidebarButton; if (sidebarExistsOrCanBeCreated) { sidebarButton = (
- + {activeTooltip === 'sidebar' ? tooltipMenu : null}
); } const { isViewer } = messageInfo.creator; const messageActionButtonsContainerClassName = classNames({ [css.messageActionContainer]: true, [css.messageActionButtons]: true, [css.messageActionButtonsViewer]: isViewer, [css.messageActionButtonsNonViewer]: !isViewer, }); return (
{sidebarButton} {replyButton}
); } 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;