diff --git a/web/chat/message-reply-button.react.js b/web/chat/message-reply-button.react.js deleted file mode 100644 index c74cdbfd8..000000000 --- a/web/chat/message-reply-button.react.js +++ /dev/null @@ -1,36 +0,0 @@ -// @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 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-timestamp-tooltip.css b/web/chat/message-timestamp-tooltip.css deleted file mode 100644 index 3a45decb1..000000000 --- a/web/chat/message-timestamp-tooltip.css +++ /dev/null @@ -1,53 +0,0 @@ -div.messageLeftTooltip:after { - top: 7px; - right: -14px; - border-color: transparent transparent transparent var(--tool-tip-bg); -} -div.messageRightTooltip:after { - top: 7px; - left: -14px; - border-color: transparent var(--tool-tip-bg) transparent transparent; -} -div.messageTopLeftTooltip:after { - bottom: -14px; - left: 4px; - border-color: var(--tool-tip-bg) transparent transparent transparent; -} -div.messageTopRightTooltip:after { - bottom: -14px; - right: 4px; - border-color: var(--tool-tip-bg) transparent transparent transparent; -} -div.messageBottomLeftTooltip:after { - top: -14px; - left: 4px; - border-color: transparent transparent var(--tool-tip-bg) transparent; -} -div.messageBottomRightTooltip:after { - top: -14px; - right: 4px; - border-color: transparent transparent var(--tool-tip-bg) transparent; -} - -div.messageActionActiveArea { - position: absolute; - display: flex; - top: 0; - bottom: 0; - align-items: center; - padding: 0 12px; -} - -div.viewerMessageActionActiveArea { - right: 100%; -} -div.nonViewerMessageActiveArea { - left: 100%; -} -div.messageActionActiveArea > div + div { - margin-left: 4px; -} - -div.messageActionLinkIcon:hover { - cursor: pointer; -} diff --git a/web/chat/message-timestamp-tooltip.react.js b/web/chat/message-timestamp-tooltip.react.js deleted file mode 100644 index 24a741892..000000000 --- a/web/chat/message-timestamp-tooltip.react.js +++ /dev/null @@ -1,148 +0,0 @@ -// @flow - -import invariant from 'invariant'; -import * as React from 'react'; - -import { isComposableMessageType } from 'lib/types/message-types'; -import { longAbsoluteDate } from 'lib/utils/date-utils'; - -import css from './message-timestamp-tooltip.css'; -import type { OnMessagePositionWithContainerInfo } from './position-types'; -import { - type TooltipPosition, - tooltipPositions, - sizeOfTooltipArrow, -} from './tooltip-utils'; -import { - TooltipMenu, - type TooltipStyle, - TooltipTextItem, -} from './tooltip.react'; - -const availablePositionsForComposedViewerMessage = [tooltipPositions.LEFT]; -const availablePositionsForNonComposedOrNonViewerMessage = [ - tooltipPositions.RIGHT_BOTTOM, -]; - -type Props = { - +messagePositionInfo: OnMessagePositionWithContainerInfo, - +timeZone: ?string, -}; -function MessageTimestampTooltip(props: Props): React.Node { - const { messagePositionInfo, timeZone } = props; - const { time, creator, type } = messagePositionInfo.item.messageInfo; - - const text = React.useMemo(() => longAbsoluteDate(time, timeZone), [ - time, - timeZone, - ]); - const availableTooltipPositions = React.useMemo(() => { - const { isViewer } = creator; - const isComposed = isComposableMessageType(type); - return isComposed && isViewer - ? availablePositionsForComposedViewerMessage - : availablePositionsForNonComposedOrNonViewerMessage; - }, [creator, type]); - - const { messagePosition, containerPosition } = messagePositionInfo; - const pointingToInfo = React.useMemo(() => { - return { - containerPosition, - itemPosition: messagePosition, - }; - }, [messagePosition, containerPosition]); - - const getTooltipStyle = React.useCallback( - (tooltipPosition: TooltipPosition) => - getTimestampTooltipStyle(messagePositionInfo, tooltipPosition), - [messagePositionInfo], - ); - return ( - - - - ); -} - -function getTimestampTooltipStyle( - messagePositionInfo: OnMessagePositionWithContainerInfo, - tooltipPosition: TooltipPosition, -): TooltipStyle { - const { messagePosition, containerPosition } = messagePositionInfo; - const { height: containerHeight, width: containerWidth } = containerPosition; - - let style, className; - if (tooltipPosition === tooltipPositions.LEFT) { - const centerOfMessage = messagePosition.top + messagePosition.height / 2; - const tooltipPointing = Math.max( - Math.min(centerOfMessage, containerHeight), - 0, - ); - style = { - right: containerWidth - messagePosition.left + sizeOfTooltipArrow + 2, - bottom: containerHeight - tooltipPointing - 5 * sizeOfTooltipArrow, - }; - className = css.messageLeftTooltip; - } else if (tooltipPosition === tooltipPositions.RIGHT) { - const centerOfMessage = messagePosition.top + messagePosition.height / 2; - const tooltipPointing = Math.max( - Math.min(centerOfMessage, containerHeight), - 0, - ); - style = { - left: messagePosition.right + sizeOfTooltipArrow, - top: tooltipPointing, - }; - className = css.messageRightTooltip; - } else if (tooltipPosition === tooltipPositions.LEFT_TOP) { - const tooltipPointing = Math.min( - containerHeight - messagePosition.top, - containerHeight, - ); - style = { - left: messagePosition.left, - bottom: tooltipPointing + sizeOfTooltipArrow, - }; - className = css.messageTopLeftTooltip; - } else if (tooltipPosition === tooltipPositions.RIGHT_TOP) { - const tooltipPointing = Math.min( - containerHeight - messagePosition.top, - containerHeight, - ); - style = { - right: containerWidth - messagePosition.right, - bottom: tooltipPointing + sizeOfTooltipArrow, - }; - className = css.messageTopRightTooltip; - } else if (tooltipPosition === tooltipPositions.LEFT_BOTTOM) { - const tooltipPointing = Math.min(messagePosition.bottom, containerHeight); - style = { - left: messagePosition.left, - top: tooltipPointing + sizeOfTooltipArrow, - }; - className = css.messageBottomLeftTooltip; - } else if (tooltipPosition === tooltipPositions.RIGHT_BOTTOM) { - const centerOfMessage = messagePosition.top + messagePosition.height / 2; - const tooltipPointing = Math.max( - Math.min(centerOfMessage, containerHeight), - 0, - ); - style = { - left: messagePosition.right + sizeOfTooltipArrow + 2, - bottom: containerHeight - tooltipPointing - 5 * sizeOfTooltipArrow, - }; - className = css.messageBottomRightTooltip; - } - invariant( - className && style, - `${tooltipPosition} is not valid for timestamp tooltip`, - ); - return { className, style }; -} - -export default MessageTimestampTooltip; diff --git a/web/chat/tooltip-utils.js b/web/chat/tooltip-utils.js index f8adf8bcb..dc6b1eaf8 100644 --- a/web/chat/tooltip-utils.js +++ b/web/chat/tooltip-utils.js @@ -1,522 +1,520 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors'; import { createMessageReply } from 'lib/shared/message-utils'; import { threadHasPermission, useSidebarExistsOrCanBeCreated, } from 'lib/shared/thread-utils'; import { isComposableMessageType } from 'lib/types/message-types'; import type { ThreadInfo } from 'lib/types/thread-types'; import { threadPermissions } from 'lib/types/thread-types'; import { longAbsoluteDate } from 'lib/utils/date-utils'; import CommIcon from '../CommIcon.react'; import { InputStateContext } from '../input/input-state'; import { useSelector } from '../redux/redux-utils'; import { useOnClickPendingSidebar, useOnClickThread, } from '../selectors/nav-selectors'; import { calculateMaxTextWidth } from '../utils/text-utils'; import { tooltipButtonStyle, tooltipLabelStyle, tooltipStyle, } from './chat-constants'; import MessageTooltip from './message-tooltip.react'; import type { PositionInfo } from './position-types'; import { useTooltipContext } from './tooltip-provider'; export const tooltipPositions = Object.freeze({ LEFT: 'left', RIGHT: 'right', LEFT_BOTTOM: 'left-bottom', RIGHT_BOTTOM: 'right-bottom', LEFT_TOP: 'left-top', RIGHT_TOP: 'right-top', TOP: 'top', BOTTOM: 'bottom', }); type TooltipSize = { +height: number, +width: number, }; export type TooltipPositionStyle = { +xCoord: number, +yCoord: number, +verticalPosition: 'top' | 'bottom', +horizontalPosition: 'left' | 'right', +alignment: 'left' | 'center' | 'right', }; export type TooltipPosition = $Values; export type MessageTooltipAction = { +label: string, +onClick: (SyntheticEvent) => mixed, +actionButtonContent: React.Node, }; -const sizeOfTooltipArrow = 10; // 7px arrow + 3px extra const appTopBarHeight = 65; const font = '14px "Inter", -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", ' + '"Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", ui-sans-serif'; type FindTooltipPositionArgs = { +sourcePositionInfo: PositionInfo, +tooltipSize: TooltipSize, +availablePositions: $ReadOnlyArray, +defaultPosition: TooltipPosition, +preventDisplayingBelowSource?: boolean, }; function findTooltipPosition({ sourcePositionInfo, tooltipSize, availablePositions, defaultPosition, preventDisplayingBelowSource, }: FindTooltipPositionArgs): TooltipPosition { if (!window) { return defaultPosition; } const appContainerPositionInfo: PositionInfo = { height: window.innerHeight - appTopBarHeight, width: window.innerWidth, top: appTopBarHeight, bottom: window.innerHeight, left: 0, right: window.innerWidth, }; const pointingTo = sourcePositionInfo; const { top: containerTop, left: containerLeft, right: containerRight, bottom: containerBottom, } = appContainerPositionInfo; const tooltipWidth = tooltipSize.width; const tooltipHeight = tooltipSize.height; const canBeDisplayedOnLeft = containerLeft + tooltipWidth <= pointingTo.left; const canBeDisplayedOnRight = tooltipWidth + pointingTo.right <= containerRight; const willCoverSidebarOnTopSideways = preventDisplayingBelowSource && pointingTo.top + tooltipHeight > pointingTo.bottom; const canBeDisplayedOnTopSideways = pointingTo.top >= containerTop && pointingTo.top + tooltipHeight <= containerBottom && !willCoverSidebarOnTopSideways; const canBeDisplayedOnBottomSideways = pointingTo.bottom <= containerBottom && pointingTo.bottom - tooltipHeight >= containerTop; const verticalCenterOfPointingTo = pointingTo.top + pointingTo.height / 2; const horizontalCenterOfPointingTo = pointingTo.left + pointingTo.width / 2; const willCoverSidebarInTheMiddleSideways = preventDisplayingBelowSource && verticalCenterOfPointingTo + tooltipHeight / 2 > pointingTo.bottom; const canBeDisplayedInTheMiddleSideways = verticalCenterOfPointingTo - tooltipHeight / 2 >= containerTop && verticalCenterOfPointingTo + tooltipHeight / 2 <= containerBottom && !willCoverSidebarInTheMiddleSideways; const canBeDisplayedOnTop = pointingTo.top - tooltipHeight >= containerTop && horizontalCenterOfPointingTo - tooltipWidth / 2 >= containerLeft && horizontalCenterOfPointingTo + tooltipWidth / 2 <= containerRight; const canBeDisplayedOnBottom = pointingTo.bottom + tooltipHeight <= containerBottom && horizontalCenterOfPointingTo - tooltipWidth / 2 >= containerLeft && horizontalCenterOfPointingTo + tooltipWidth / 2 <= containerRight && !preventDisplayingBelowSource; for (const tooltipPosition of availablePositions) { if ( tooltipPosition === tooltipPositions.RIGHT && canBeDisplayedOnRight && canBeDisplayedInTheMiddleSideways ) { return tooltipPosition; } else if ( tooltipPosition === tooltipPositions.RIGHT_BOTTOM && canBeDisplayedOnRight && canBeDisplayedOnBottomSideways ) { return tooltipPosition; } else if ( tooltipPosition === tooltipPositions.LEFT && canBeDisplayedOnLeft && canBeDisplayedInTheMiddleSideways ) { return tooltipPosition; } else if ( tooltipPosition === tooltipPositions.LEFT_BOTTOM && canBeDisplayedOnLeft && canBeDisplayedOnBottomSideways ) { return tooltipPosition; } else if ( tooltipPosition === tooltipPositions.LEFT_TOP && canBeDisplayedOnLeft && canBeDisplayedOnTopSideways ) { return tooltipPosition; } else if ( tooltipPosition === tooltipPositions.RIGHT_TOP && canBeDisplayedOnRight && canBeDisplayedOnTopSideways ) { return tooltipPosition; } else if ( tooltipPosition === tooltipPositions.TOP && canBeDisplayedOnTop ) { return tooltipPosition; } else if ( tooltipPosition === tooltipPositions.BOTTOM && canBeDisplayedOnBottom ) { return tooltipPosition; } } return defaultPosition; } type GetMessageActionTooltipStyleParams = { +sourcePositionInfo: PositionInfo, +tooltipSize: TooltipSize, +tooltipPosition: TooltipPosition, }; function getMessageActionTooltipStyle({ sourcePositionInfo, tooltipSize, tooltipPosition, }: GetMessageActionTooltipStyleParams): TooltipPositionStyle { if (tooltipPosition === tooltipPositions.RIGHT_TOP) { return { xCoord: sourcePositionInfo.right, yCoord: sourcePositionInfo.top, horizontalPosition: 'right', verticalPosition: 'bottom', alignment: 'left', }; } else if (tooltipPosition === tooltipPositions.LEFT_TOP) { return { xCoord: sourcePositionInfo.left, yCoord: sourcePositionInfo.top, horizontalPosition: 'left', verticalPosition: 'bottom', alignment: 'right', }; } else if (tooltipPosition === tooltipPositions.RIGHT_BOTTOM) { return { xCoord: sourcePositionInfo.right, yCoord: sourcePositionInfo.bottom, horizontalPosition: 'right', verticalPosition: 'top', alignment: 'left', }; } else if (tooltipPosition === tooltipPositions.LEFT_BOTTOM) { return { xCoord: sourcePositionInfo.left, yCoord: sourcePositionInfo.bottom, horizontalPosition: 'left', verticalPosition: 'top', alignment: 'right', }; } else if (tooltipPosition === tooltipPositions.LEFT) { return { xCoord: sourcePositionInfo.left, yCoord: sourcePositionInfo.top + sourcePositionInfo.height / 2 - tooltipSize.height / 2, horizontalPosition: 'left', verticalPosition: 'bottom', alignment: 'right', }; } else if (tooltipPosition === tooltipPositions.RIGHT) { return { xCoord: sourcePositionInfo.right, yCoord: sourcePositionInfo.top + sourcePositionInfo.height / 2 - tooltipSize.height / 2, horizontalPosition: 'right', verticalPosition: 'bottom', alignment: 'left', }; } else if (tooltipPosition === tooltipPositions.TOP) { return { xCoord: sourcePositionInfo.left + sourcePositionInfo.width / 2 - tooltipSize.width / 2, yCoord: sourcePositionInfo.top, horizontalPosition: 'right', verticalPosition: 'top', alignment: 'center', }; } else if (tooltipPosition === tooltipPositions.BOTTOM) { return { xCoord: sourcePositionInfo.left + sourcePositionInfo.width / 2 - tooltipSize.width / 2, yCoord: sourcePositionInfo.bottom, horizontalPosition: 'right', verticalPosition: 'bottom', alignment: 'center', }; } invariant(false, `Unexpected tooltip position value: ${tooltipPosition}`); } type CalculateTooltipSizeArgs = { +tooltipLabels: $ReadOnlyArray, +timestamp: string, }; function calculateTooltipSize({ tooltipLabels, timestamp, }: CalculateTooltipSizeArgs): { +width: number, +height: number, } { const textWidth = calculateMaxTextWidth([...tooltipLabels, timestamp], font) + 2 * tooltipLabelStyle.padding; const buttonsWidth = tooltipLabels.length * (tooltipButtonStyle.width + tooltipButtonStyle.paddingLeft + tooltipButtonStyle.paddingRight); const width = Math.max(textWidth, buttonsWidth) + tooltipStyle.paddingLeft + tooltipStyle.paddingRight; const height = (tooltipLabelStyle.height + 2 * tooltipLabelStyle.padding) * 2 + tooltipStyle.rowGap * 2 + tooltipButtonStyle.height; return { width, height, }; } function useMessageTooltipSidebarAction( item: ChatMessageInfoItem, threadInfo: ThreadInfo, ): ?MessageTooltipAction { const { threadCreatedFromMessage, messageInfo } = item; const sidebarExists = !!threadCreatedFromMessage; const sidebarExistsOrCanBeCreated = useSidebarExistsOrCanBeCreated( threadInfo, item, ); const openThread = useOnClickThread(threadCreatedFromMessage); const openPendingSidebar = useOnClickPendingSidebar(messageInfo, threadInfo); return React.useMemo(() => { if (!sidebarExistsOrCanBeCreated) { return null; } const buttonContent = ; const onClick = (event: SyntheticEvent) => { if (threadCreatedFromMessage) { openThread(event); } else { openPendingSidebar(event); } }; return { actionButtonContent: buttonContent, onClick, label: sidebarExists ? 'Go to thread' : 'Create thread', }; }, [ openPendingSidebar, openThread, sidebarExists, sidebarExistsOrCanBeCreated, threadCreatedFromMessage, ]); } function useMessageTooltipReplyAction( item: ChatMessageInfoItem, threadInfo: ThreadInfo, ): ?MessageTooltipAction { const { messageInfo } = item; const inputState = React.useContext(InputStateContext); invariant(inputState, 'inputState is required'); const { addReply } = inputState; return React.useMemo(() => { if ( !isComposableMessageType(item.messageInfo.type) || !threadHasPermission(threadInfo, threadPermissions.VOICED) ) { return null; } const buttonContent = ; const onClick = () => { if (!messageInfo.text) { return; } addReply(createMessageReply(messageInfo.text)); }; return { actionButtonContent: buttonContent, onClick, label: 'Reply', }; }, [addReply, item.messageInfo.type, messageInfo, threadInfo]); } function useMessageTooltipActions( item: ChatMessageInfoItem, threadInfo: ThreadInfo, ): $ReadOnlyArray { const sidebarAction = useMessageTooltipSidebarAction(item, threadInfo); const replyAction = useMessageTooltipReplyAction(item, threadInfo); return React.useMemo(() => [replyAction, sidebarAction].filter(Boolean), [ replyAction, sidebarAction, ]); } type UseMessageTooltipArgs = { +availablePositions: $ReadOnlyArray, +item: ChatMessageInfoItem, +threadInfo: ThreadInfo, }; type UseMessageTooltipResult = { onMouseEnter: (event: SyntheticEvent) => void, onMouseLeave: ?() => mixed, }; function useMessageTooltip({ availablePositions, item, threadInfo, }: UseMessageTooltipArgs): UseMessageTooltipResult { const [onMouseLeave, setOnMouseLeave] = React.useState mixed>(null); const { renderTooltip } = useTooltipContext(); const tooltipActions = useMessageTooltipActions(item, threadInfo); const containsInlineSidebar = !!item.threadCreatedFromMessage; const timeZone = useSelector(state => state.timeZone); const messageTimestamp = React.useMemo(() => { const time = item.messageInfo.time; return longAbsoluteDate(time, timeZone); }, [item.messageInfo.time, timeZone]); const tooltipSize = React.useMemo(() => { if (typeof document === 'undefined') { return { width: 0, height: 0, }; } const tooltipLabels = tooltipActions.map(action => action.label); return calculateTooltipSize({ tooltipLabels, timestamp: messageTimestamp, }); }, [messageTimestamp, tooltipActions]); const onMouseEnter = React.useCallback( (event: SyntheticEvent) => { if (!renderTooltip) { return; } const rect = event.currentTarget.getBoundingClientRect(); const { top, bottom, left, right, height, width } = rect; const messagePosition = { top, bottom, left, right, height, width }; const tooltipPosition = findTooltipPosition({ sourcePositionInfo: messagePosition, tooltipSize, availablePositions, defaultPosition: availablePositions[0], preventDisplayingBelowSource: containsInlineSidebar, }); if (!tooltipPosition) { return; } const tooltipPositionStyle = getMessageActionTooltipStyle({ tooltipPosition, sourcePositionInfo: messagePosition, tooltipSize: tooltipSize, }); const { alignment } = tooltipPositionStyle; const tooltip = ( ); const renderTooltipResult = renderTooltip({ newNode: tooltip, tooltipPositionStyle, }); if (renderTooltipResult) { const { onMouseLeaveCallback: callback } = renderTooltipResult; setOnMouseLeave((() => callback: () => () => mixed)); } }, [ availablePositions, containsInlineSidebar, messageTimestamp, renderTooltip, tooltipActions, tooltipSize, ], ); return { onMouseEnter, onMouseLeave, }; } export { findTooltipPosition, calculateTooltipSize, getMessageActionTooltipStyle, useMessageTooltipSidebarAction, useMessageTooltipReplyAction, useMessageTooltipActions, useMessageTooltip, - sizeOfTooltipArrow, }; diff --git a/web/chat/tooltip.css b/web/chat/tooltip.css index 2f2f190b8..e3b69a7d1 100644 --- a/web/chat/tooltip.css +++ b/web/chat/tooltip.css @@ -1,68 +1,31 @@ -div.messageTooltipMenu { - position: absolute; - background-color: var(--tool-tip-bg); - color: var(--tool-tip-color); - padding: 5px; - border-radius: 5px; - font-size: 14px; - z-index: 1; - white-space: nowrap; -} -div.messageTooltipMenu ul { - list-style: none; -} -div.messageTooltipMenu li:not(:last-child) { - padding-bottom: 5px; -} -div.messageTooltipMenu button { - border: none; - cursor: pointer; - font-size: 14px; - outline: none; - background-color: black; - color: white; - text-decoration: underline; -} -div.messageTooltipMenu button:hover { - background-color: black; - color: #129aff; +div.leftTooltipAlign > div { + align-items: flex-start; } -div.messageLeftTooltip { - transform: translate(0%, -50%); -} -div.messageRightTooltip { - transform: translate(0%, -50%); +div.centerTooltipAlign > div { + align-items: center; } -div.messageTimestampTooltip { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - padding: 6px; - background-color: var(--message-action-tooltip-bg); - border-radius: 8px; - overflow: auto; - min-width: 72px; +div.rightTooltipAlign > div { + align-items: flex-end; } div.tooltipAbsolute { position: absolute; } div.tooltipAbsoluteLeft { left: 0; } div.tooltipAbsoluteRight { right: 0; } div.tooltipAbsoluteTop { top: 0; } div.tooltipAbsoluteBottom { bottom: 0; } diff --git a/web/chat/tooltip.react.js b/web/chat/tooltip.react.js deleted file mode 100644 index 46c346ad4..000000000 --- a/web/chat/tooltip.react.js +++ /dev/null @@ -1,86 +0,0 @@ -// @flow - -import classNames from 'classnames'; -import * as React from 'react'; - -import type { ItemAndContainerPositionInfo } from './position-types'; -import { type TooltipPosition, tooltipPositions } from './tooltip-utils'; -import css from './tooltip.css'; - -type Style = { - +left?: number, - +right?: number, - +top?: number, - +bottom?: number, -}; -export type TooltipStyle = { +className: string, +style?: Style }; - -type TooltipMenuProps = { - +availableTooltipPositions: $ReadOnlyArray, - +targetPositionInfo: ItemAndContainerPositionInfo, - +layoutPosition: 'relative' | 'absolute', - +getStyle: (tooltipPosition: TooltipPosition) => TooltipStyle, - +children: React.ChildrenArray< - React.Element, - >, -}; -function TooltipMenu(props: TooltipMenuProps): React.Node { - const { getStyle, children } = props; - - // eslint-disable-next-line no-unused-vars - const tooltipTexts = React.useMemo( - () => React.Children.map(children, item => item.props.text), - [children], - ); - - const tooltipPosition = React.useMemo(() => tooltipPositions.LEFT, []); - - const tooltipStyle = React.useMemo(() => getStyle(tooltipPosition), [ - getStyle, - tooltipPosition, - ]); - - const className = React.useMemo( - () => - classNames( - css.messageTooltipMenu, - tooltipStyle.className, - css.messageTimestampTooltip, - ), - [tooltipStyle], - ); - - const style = tooltipStyle.style ? tooltipStyle.style : null; - - return ( -
-
    {children}
-
- ); -} - -type TooltipButtonProps = { - +onClick: (event: SyntheticEvent) => void, - +text: string, -}; -function TooltipButton(props: TooltipButtonProps): React.Node { - const { onClick, text } = props; - return ( -
  • - -
  • - ); -} - -type TooltipTextItemProps = { - +text: string, -}; -function TooltipTextItem(props: TooltipTextItemProps): React.Node { - return ( -
  • - {props.text} -
  • - ); -} - -export { TooltipMenu, TooltipButton, TooltipTextItem };