From e0e24aaa6f24a7074abc0c10510d918f123d4711 Mon Sep 17 00:00:00 2001 From: M-ZubairAhmed Date: Tue, 7 Jan 2025 18:40:01 +0530 Subject: [PATCH] [MM-62390] Combine the floating and transition styles into one in WithTooltip and other related minor improvements (#29730) --- .../send_button/send_post_options/index.tsx | 1 - .../announcement_bar.tsx | 3 +- .../default_announcement_bar.scss | 2 +- .../channel_bookmarks_menu.tsx | 1 - .../__snapshots__/dot_menu.test.tsx.snap | 1 - .../src/components/dot_menu/dot_menu.tsx | 1 - webapp/channels/src/components/menu/menu.tsx | 1 - .../profile_popover_controller.tsx | 16 ++- ...idebar_category_sorting_menu.test.tsx.snap | 1 - .../sidebar_category_generic_menu.tsx | 1 - .../sidebar_category_sorting_menu.tsx | 1 - .../sidebar_channel_menu.test.tsx.snap | 10 -- .../sidebar_channel_menu.tsx | 1 - .../user_group_popover.scss | 5 +- .../src/components/with_tooltip/index.tsx | 121 +++++++++--------- .../src/components/with_tooltip/tooltip.scss | 70 ---------- .../components/with_tooltip/with_tooltip.scss | 68 ++++++++++ .../channels/src/sass/utils/_variables.scss | 6 + webapp/channels/src/utils/constants.tsx | 10 +- 19 files changed, 158 insertions(+), 162 deletions(-) delete mode 100644 webapp/channels/src/components/with_tooltip/tooltip.scss create mode 100644 webapp/channels/src/components/with_tooltip/with_tooltip.scss diff --git a/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/index.tsx b/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/index.tsx index 5951a22d87..aa6453ae13 100644 --- a/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/index.tsx +++ b/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/index.tsx @@ -64,7 +64,6 @@ export function SendPostOptions({disabled, onSelect, channelId}: Props) { return ( { barContent = ( {barContent} diff --git a/webapp/channels/src/components/announcement_bar/default_announcement_bar/default_announcement_bar.scss b/webapp/channels/src/components/announcement_bar/default_announcement_bar/default_announcement_bar.scss index 46205a5e2f..4315f1e327 100644 --- a/webapp/channels/src/components/announcement_bar/default_announcement_bar/default_announcement_bar.scss +++ b/webapp/channels/src/components/announcement_bar/default_announcement_bar/default_announcement_bar.scss @@ -1,5 +1,5 @@ .announcementBarTooltip { min-width: 50vw; - max-width: 100vw; + max-width: 90vw; pointer-events: auto; } diff --git a/webapp/channels/src/components/channel_bookmarks/channel_bookmarks_menu.tsx b/webapp/channels/src/components/channel_bookmarks/channel_bookmarks_menu.tsx index bffc4047c4..2e2d031e81 100644 --- a/webapp/channels/src/components/channel_bookmarks/channel_bookmarks_menu.tsx +++ b/webapp/channels/src/components/channel_bookmarks/channel_bookmarks_menu.tsx @@ -82,7 +82,6 @@ function BookmarksMenu({ id: 'channelBookmarksPlusMenuDropdown', }} menuButtonTooltip={addBookmarkTooltipText ? { - id: 'channelBookmarksPlusMenuButtonTooltip', text: addBookmarkTooltipText, } : undefined} > diff --git a/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap b/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap index 264cf3fa55..c87388ca68 100644 --- a/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap +++ b/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap @@ -352,7 +352,6 @@ exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = ` menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "PostDotMenu-ButtonTooltip-post_id_1", "text": "More", } } diff --git a/webapp/channels/src/components/dot_menu/dot_menu.tsx b/webapp/channels/src/components/dot_menu/dot_menu.tsx index 4637fa6083..791f2aecb7 100644 --- a/webapp/channels/src/components/dot_menu/dot_menu.tsx +++ b/webapp/channels/src/components/dot_menu/dot_menu.tsx @@ -507,7 +507,6 @@ export class DotMenuClass extends React.PureComponent { onToggle: this.handleMenuToggle, }} menuButtonTooltip={{ - id: `PostDotMenu-ButtonTooltip-${this.props.post.id}`, text: formatMessage({id: 'post_info.dot_menu.tooltip.more', defaultMessage: 'More'}), class: 'hidden-xs', }} diff --git a/webapp/channels/src/components/menu/menu.tsx b/webapp/channels/src/components/menu/menu.tsx index 06c0d29b86..76f0a8d2a1 100644 --- a/webapp/channels/src/components/menu/menu.tsx +++ b/webapp/channels/src/components/menu/menu.tsx @@ -44,7 +44,6 @@ type MenuButtonProps = { } type MenuButtonTooltipProps = { - id: string; isVertical?: boolean; class?: string; text: string; diff --git a/webapp/channels/src/components/profile_popover/profile_popover_controller.tsx b/webapp/channels/src/components/profile_popover/profile_popover_controller.tsx index 4f873b5dad..133c32ece8 100644 --- a/webapp/channels/src/components/profile_popover/profile_popover_controller.tsx +++ b/webapp/channels/src/components/profile_popover/profile_popover_controller.tsx @@ -85,13 +85,7 @@ export function ProfilePopoverController middleware: [autoPlacement()], }); - const {isMounted, styles: transitionStyles} = useTransitionStyles(floatingContext, { - duration: { - open: OverlaysTimings.FADE_IN_DURATION, - close: OverlaysTimings.FADE_OUT_DURATION, - }, - initial: OverlayTransitionStyles.START, - }); + const {isMounted, styles: transitionStyles} = useTransitionStyles(floatingContext, TRANSITION_STYLE_PROPS); const clickInteractions = useClick(floatingContext); const dismissInteraction = useDismiss(floatingContext); @@ -154,3 +148,11 @@ export function ProfilePopoverController ); } + +const TRANSITION_STYLE_PROPS = { + duration: { + open: OverlaysTimings.FADE_IN_DURATION, + close: OverlaysTimings.FADE_OUT_DURATION, + }, + initial: OverlayTransitionStyles.START, +}; diff --git a/webapp/channels/src/components/sidebar/sidebar_category/__snapshots__/sidebar_category_sorting_menu.test.tsx.snap b/webapp/channels/src/components/sidebar/sidebar_category/__snapshots__/sidebar_category_sorting_menu.test.tsx.snap index 168253624a..e94e02383f 100644 --- a/webapp/channels/src/components/sidebar/sidebar_category/__snapshots__/sidebar_category_sorting_menu.test.tsx.snap +++ b/webapp/channels/src/components/sidebar/sidebar_category/__snapshots__/sidebar_category_sorting_menu.test.tsx.snap @@ -25,7 +25,6 @@ exports[`components/sidebar/sidebar_category/sidebar_category_sorting_menu shoul menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "SidebarCategorySortingMenu-ButtonTooltip-category_id", "text": "Category options", } } diff --git a/webapp/channels/src/components/sidebar/sidebar_category/sidebar_category_menu/sidebar_category_generic_menu.tsx b/webapp/channels/src/components/sidebar/sidebar_category/sidebar_category_menu/sidebar_category_generic_menu.tsx index 6f778997ea..5806f84792 100644 --- a/webapp/channels/src/components/sidebar/sidebar_category/sidebar_category_menu/sidebar_category_generic_menu.tsx +++ b/webapp/channels/src/components/sidebar/sidebar_category/sidebar_category_menu/sidebar_category_generic_menu.tsx @@ -47,7 +47,6 @@ const SidebarCategoryGenericMenu = ({ children: , }} menuButtonTooltip={{ - id: `SidebarCategoryMenu-ButtonTooltip-${id}`, text: formatMessage({id: 'sidebar_left.sidebar_category_menu.editCategory', defaultMessage: 'Category options'}), class: 'hidden-xs', }} diff --git a/webapp/channels/src/components/sidebar/sidebar_category/sidebar_category_sorting_menu.tsx b/webapp/channels/src/components/sidebar/sidebar_category/sidebar_category_sorting_menu.tsx index 5ca3ad11f7..293ab78f01 100644 --- a/webapp/channels/src/components/sidebar/sidebar_category/sidebar_category_sorting_menu.tsx +++ b/webapp/channels/src/components/sidebar/sidebar_category/sidebar_category_sorting_menu.tsx @@ -198,7 +198,6 @@ const SidebarCategorySortingMenu = ({ children: , }} menuButtonTooltip={{ - id: `SidebarCategorySortingMenu-ButtonTooltip-${category.id}`, text: formatMessage({id: 'sidebar_left.sidebar_category_menu.editCategory', defaultMessage: 'Category options'}), class: 'hidden-xs', }} diff --git a/webapp/channels/src/components/sidebar/sidebar_channel/sidebar_channel_menu/__snapshots__/sidebar_channel_menu.test.tsx.snap b/webapp/channels/src/components/sidebar/sidebar_channel/sidebar_channel_menu/__snapshots__/sidebar_channel_menu.test.tsx.snap index e46d135600..067f2bffcf 100644 --- a/webapp/channels/src/components/sidebar/sidebar_channel/sidebar_channel_menu/__snapshots__/sidebar_channel_menu.test.tsx.snap +++ b/webapp/channels/src/components/sidebar/sidebar_channel/sidebar_channel_menu/__snapshots__/sidebar_channel_menu.test.tsx.snap @@ -22,7 +22,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should match sn menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "SidebarChannelMenu-ButtonTooltip-channel_id", "text": "Channel options", } } @@ -168,7 +167,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should match sn menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "SidebarChannelMenu-ButtonTooltip-channel_id", "text": "Channel options", } } @@ -314,7 +312,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should match sn menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "SidebarChannelMenu-ButtonTooltip-channel_id", "text": "Channel options", } } @@ -460,7 +457,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "SidebarChannelMenu-ButtonTooltip-channel_id", "text": "Channel options", } } @@ -574,7 +570,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "SidebarChannelMenu-ButtonTooltip-channel_id", "text": "Channel options", } } @@ -703,7 +698,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "SidebarChannelMenu-ButtonTooltip-channel_id", "text": "Channel options", } } @@ -849,7 +843,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "SidebarChannelMenu-ButtonTooltip-channel_id", "text": "Channel options", } } @@ -995,7 +988,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "SidebarChannelMenu-ButtonTooltip-channel_id", "text": "Channel options", } } @@ -1141,7 +1133,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "SidebarChannelMenu-ButtonTooltip-channel_id", "text": "Channel options", } } @@ -1287,7 +1278,6 @@ exports[`components/sidebar/sidebar_channel/sidebar_channel_menu should show cor menuButtonTooltip={ Object { "class": "hidden-xs", - "id": "SidebarChannelMenu-ButtonTooltip-channel_id", "text": "Channel options", } } diff --git a/webapp/channels/src/components/sidebar/sidebar_channel/sidebar_channel_menu/sidebar_channel_menu.tsx b/webapp/channels/src/components/sidebar/sidebar_channel/sidebar_channel_menu/sidebar_channel_menu.tsx index 6687733201..14c4ace952 100644 --- a/webapp/channels/src/components/sidebar/sidebar_channel/sidebar_channel_menu/sidebar_channel_menu.tsx +++ b/webapp/channels/src/components/sidebar/sidebar_channel/sidebar_channel_menu/sidebar_channel_menu.tsx @@ -297,7 +297,6 @@ const SidebarChannelMenu = ({ children: , }} menuButtonTooltip={{ - id: `SidebarChannelMenu-ButtonTooltip-${channel.id}`, class: 'hidden-xs', text: formatMessage({id: 'sidebar_left.sidebar_channel_menu.editChannel', defaultMessage: 'Channel options'}), }} diff --git a/webapp/channels/src/components/user_group_popover/user_group_popover.scss b/webapp/channels/src/components/user_group_popover/user_group_popover.scss index 928860c4c5..2a1ba96858 100644 --- a/webapp/channels/src/components/user_group_popover/user_group_popover.scss +++ b/webapp/channels/src/components/user_group_popover/user_group_popover.scss @@ -1,8 +1,9 @@ +@use 'utils/variables'; + #user-group-popover .popover-content { padding: 0; } .user-group-popover-floating-overlay { - // 99 being the z-index of the global header - z-index: 1060; + z-index: variables.$z-index-user-group-popover; } diff --git a/webapp/channels/src/components/with_tooltip/index.tsx b/webapp/channels/src/components/with_tooltip/index.tsx index a9785359dd..4f2decbfcf 100644 --- a/webapp/channels/src/components/with_tooltip/index.tsx +++ b/webapp/channels/src/components/with_tooltip/index.tsx @@ -24,21 +24,17 @@ import type {ReactElement, ReactNode} from 'react'; import type {MessageDescriptor} from 'react-intl'; import {defineMessage} from 'react-intl'; -import {Constants} from 'utils/constants'; +import {OverlayArrow, OverlaysTimings, OverlayTransitionStyles, RootHtmlPortalId} from 'utils/constants'; import TooltipContent from './tooltip_content'; import type {ShortcutDefinition} from './tooltip_shortcut'; -import './tooltip.scss'; - -const ARROW_WIDTH = 10; // in px -const ARROW_HEIGHT = 6; // in px -const ARROW_OFFSET = 8; // in px - -const TOOLTIP_REST_TIME_BEFORE_OPEN = 400; // in ms -const TOOLTIP_APPEAR_DURATION = 250; // in ms -const TOOLTIP_DISAPPEAR_DURATION = 200; // in ms +import './with_tooltip.scss'; +/** + * Shortcut keys map to translations that can be used in the tooltip + * when shortcut definition is provided + */ export const ShortcutKeys = { alt: defineMessage({ id: 'shortcuts.generic.alt', @@ -68,7 +64,17 @@ interface Props { * This doesn't always guarantee the tooltip will be vertical, it just determines the initial placement and fallback placements */ isVertical?: boolean; - tooltipContentContainerClassName?: string; + + /** + * If closing of the tooltip should be delayed, + * Useful if tooltips contains links that need to be clicked + */ + delayClose?: boolean; + + /** + * Additional class name to be added to the tooltip container + */ + className?: string; disabled?: boolean; /** @@ -79,7 +85,7 @@ interface Props { children: ReactElement; } -function WithTooltip({ +export default function WithTooltip({ children, title, emoji, @@ -87,7 +93,8 @@ function WithTooltip({ hint, shortcut, isVertical = true, - tooltipContentContainerClassName, + delayClose = false, + className, onOpen, disabled, }: Props) { @@ -116,13 +123,13 @@ function WithTooltip({ return {initial, fallback}; }, [isVertical]); - const {refs: {setReference, setFloating}, floatingStyles, context} = useFloating({ + const {refs: {setReference, setFloating}, floatingStyles, context: floatingContext} = useFloating({ open: disabled ? false : open, onOpenChange: handleChange, whileElementsMounted: autoUpdate, placement: placements.initial, middleware: [ - offset(ARROW_OFFSET), + offset(OverlayArrow.OFFSET), flip({ fallbackPlacements: placements.fallback, }), @@ -132,75 +139,61 @@ function WithTooltip({ ], }); - const hover = useHover(context, { - restMs: TOOLTIP_REST_TIME_BEFORE_OPEN, + const {isMounted, styles: transitionStyles} = useTransitionStyles(floatingContext, TRANSITION_STYLE_PROPS); + + const hover = useHover(floatingContext, { + restMs: OverlaysTimings.CURSOR_REST_TIME_BEFORE_OPEN, delay: { - open: Constants.OVERLAY_TIME_DELAY, + open: OverlaysTimings.CURSOR_MOUSEOVER_TO_OPEN, + close: delayClose ? OverlaysTimings.CURSOR_MOUSEOUT_TO_CLOSE_WITH_DELAY : OverlaysTimings.CURSOR_MOUSEOUT_TO_CLOSE, }, }); - const focus = useFocus(context); - const dismiss = useDismiss(context); - const role = useRole(context, {role: 'tooltip'}); + const focus = useFocus(floatingContext); + const dismiss = useDismiss(floatingContext); + const role = useRole(floatingContext, {role: 'tooltip'}); const {getReferenceProps, getFloatingProps} = useInteractions([hover, focus, dismiss, role]); - const {isMounted, styles: transitionStyles} = useTransitionStyles(context, { - duration: { - open: TOOLTIP_APPEAR_DURATION, - close: TOOLTIP_DISAPPEAR_DURATION, - }, - initial: { - opacity: 0, - }, - common: { - opacity: 1, - }, - }); if (!isValidElement(children)) { // eslint-disable-next-line no-console console.error('Children must be a valid React element for WithTooltip'); } - const mergedRefs = useMergeRefs([(children as any)?.ref, setReference]); + const mergedRefs = useMergeRefs([setReference, (children as any)?.ref]); - const trigger = cloneElement(children, { - ...getReferenceProps({ + const trigger = cloneElement( + children, + getReferenceProps({ ref: mergedRefs, ...children.props, }), - }); + ); return ( <> {trigger} + {isMounted && ( - +
-
- - -
+ +
)} @@ -208,4 +201,10 @@ function WithTooltip({ ); } -export default WithTooltip; +const TRANSITION_STYLE_PROPS = { + duration: { + open: OverlaysTimings.FADE_IN_DURATION, + close: OverlaysTimings.FADE_OUT_DURATION, + }, + initial: OverlayTransitionStyles.START, +}; diff --git a/webapp/channels/src/components/with_tooltip/tooltip.scss b/webapp/channels/src/components/with_tooltip/tooltip.scss deleted file mode 100644 index 5508d1f971..0000000000 --- a/webapp/channels/src/components/with_tooltip/tooltip.scss +++ /dev/null @@ -1,70 +0,0 @@ -.tooltipContainer { - z-index: 1070; - - > .tooltipContentContainer { - z-index: 1070; - max-width: 220px; - padding: 4px 8px; - border-radius: 4px; - background: rgba(0, 0, 0, 1); - box-shadow: 0 6px 14px rgba(0, 0, 0, 0.12); - line-height: 18px; - pointer-events: none; - text-align: center; - word-break: break-word; - - > .tooltipContent { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-family: "Open Sans", sans-serif; - - > .tooltipContentTitleContainer { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - gap: 6px; - - &.isEmojiLarge { - flex-direction: column; - gap: 2px; - - > .tooltipContentEmoji { - padding-top: 1px; - } - } - - > .tooltipContentEmoji { - display: flex; - align-items: center; - justify-content: center; - } - - > .tooltipContentTitle { - color: #ffffff; - font-size: 12px; - font-weight: 600; - line-height: 15px; - } - } - - > .tooltipContentShortcut { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - padding: 4px 0; - gap: 2px; - } - - > .tooltipContentHint { - color: rgba(255, 255, 255, 0.64); - font-size: 11px; - font-weight: 600; - line-height: 16px; - } - } - } -} diff --git a/webapp/channels/src/components/with_tooltip/with_tooltip.scss b/webapp/channels/src/components/with_tooltip/with_tooltip.scss new file mode 100644 index 0000000000..78b18ea455 --- /dev/null +++ b/webapp/channels/src/components/with_tooltip/with_tooltip.scss @@ -0,0 +1,68 @@ +@use 'utils/variables'; + +.tooltipContainer { + z-index: variables.$z-index-popover; + max-width: 220px; + padding: 4px 8px; + border-radius: 4px; + background: rgba(0, 0, 0, 1); + box-shadow: 0 6px 14px rgba(0, 0, 0, 0.12); + line-height: 18px; + pointer-events: none; + text-align: center; + word-break: break-word; + + > .tooltipContent { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-family: "Open Sans", sans-serif; + + > .tooltipContentTitleContainer { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + gap: 6px; + + &.isEmojiLarge { + flex-direction: column; + gap: 2px; + + > .tooltipContentEmoji { + padding-top: 1px; + } + } + + > .tooltipContentEmoji { + display: flex; + align-items: center; + justify-content: center; + } + + > .tooltipContentTitle { + color: #ffffff; + font-size: 12px; + font-weight: 600; + line-height: 15px; + } + } + + > .tooltipContentShortcut { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + padding: 4px 0; + gap: 2px; + } + + > .tooltipContentHint { + color: rgba(255, 255, 255, 0.64); + font-size: 11px; + font-weight: 600; + line-height: 16px; + } + } +} diff --git a/webapp/channels/src/sass/utils/_variables.scss b/webapp/channels/src/sass/utils/_variables.scss index 1a74907c7b..ac823ea3bc 100644 --- a/webapp/channels/src/sass/utils/_variables.scss +++ b/webapp/channels/src/sass/utils/_variables.scss @@ -36,3 +36,9 @@ $elevation-3: var(--elevation-3); $elevation-4: var(--elevation-4); $elevation-5: var(--elevation-5); $elevation-6: var(--elevation-6); + +// Z-Index +// Central place to manage z-index values for the app, providing a consistent way to manage stacking order. +$z-index-popover: 1070; +$z-index-user-group-popover: 1060; +$z-index-global-header: 99; diff --git a/webapp/channels/src/utils/constants.tsx b/webapp/channels/src/utils/constants.tsx index b2da43fe4e..9e5c8f02b6 100644 --- a/webapp/channels/src/utils/constants.tsx +++ b/webapp/channels/src/utils/constants.tsx @@ -2240,6 +2240,9 @@ export const RootHtmlPortalId = 'root-portal'; export const OverlaysTimings = { CURSOR_REST_TIME_BEFORE_OPEN: 400, // in ms + CURSOR_MOUSEOVER_TO_OPEN: 400, // in ms + CURSOR_MOUSEOUT_TO_CLOSE: 0, + CURSOR_MOUSEOUT_TO_CLOSE_WITH_DELAY: 200, // in ms FADE_IN_DURATION: 250, // in ms FADE_OUT_DURATION: 150, // in ms }; @@ -2250,5 +2253,10 @@ export const OverlayTransitionStyles = { }, }; -export default Constants; +export const OverlayArrow = { + WIDTH: 10, // in px + HEIGHT: 6, // in px + OFFSET: 8, // in px +}; +export default Constants;