From fd6a662d769b75359f11cb33f2d3c96136f2afd6 Mon Sep 17 00:00:00 2001 From: M-ZubairAhmed Date: Thu, 19 Dec 2024 03:26:30 +0530 Subject: [PATCH] [MM-62074] Move tooltips with withTooltip to new Tooltip component (#29528) * replace inside of comp/withtooltip * remove overlay trigger eslint rl * update location of prev migrated new tooltips * copy button * shared_channel_indicator, shared_user_indicator.tsx, size_aware_image * actions_menu, old_admin_settings, schema_admin_settings, admin_settings * billing_summary, brand_image_setting, edit_section_edit_table_row, elapsed_duration_cell * permissions_scheme_summary,secure_connections/controls,system_users_column_toggler_menu,system_users_export,group/group_users/users_to_remove_groups * team_profile,user_grid_role_dropdown,priority_labels,toggle_formatting_bar,use_emoji_picker,formatting_icon * show_formatting,alert_banner others * more * snap fix * add disabled prop to menu * test fix for avatar feat: Add id to WithTooltip in Avatars component to fix test failures * combine refs in withtooltip * channel header title favorite test fix * priority label comp changes * types check for children * Update avatar.tsx * e2e fixes * fix E2E tests * Remove memo from WithTooltip I found that the web app leaks a fair bit less memory when this is removed. See https://community.mattermost.com/core/pl/gwyyoww9gtbg8fddoic9meq84y for more information * e2e lint fixes * e2e fixes * Fix test style issue --------- Co-authored-by: yasserfaraazkhan Co-authored-by: Harrison Healey Co-authored-by: Mattermost Build --- .../channels/channel/channel_info_rhs_spec.ts | 24 +- .../channel/channel_members_rhs_spec.ts | 2 + .../channel/channel_name_tooltips_spec.ts | 44 +- .../custom_status_expiry_2_spec.ts | 14 +- .../file_preview_audio_spec.js | 12 +- .../file_preview_generic_spec.js | 10 +- .../file_preview_image_spec.js | 10 +- .../file_preview_video_spec.js | 10 +- .../upload_files_not_cloud_spec.js | 8 +- .../upload_files_spec.js | 30 +- .../playbooks/channels/app_bar_spec.js | 4 +- .../cypress/tests/support/ui/file_preview.js | 8 +- e2e-tests/cypress/tests/support/ui/tooltip.js | 2 +- .../setting_picture.test.tsx.snap | 4 - .../size_aware_image.test.tsx.snap | 12 - .../__snapshots__/actions_menu.test.tsx.snap | 6 - .../components/actions_menu/actions_menu.tsx | 2 - .../bleve_settings.test.tsx.snap | 4 - .../cluster_settings.test.tsx.snap | 8 - .../database_settings.test.tsx.snap | 2 - .../elasticsearch_settings.test.tsx.snap | 4 - .../message_export_settings.test.tsx.snap | 8 - .../__snapshots__/push_settings.test.tsx.snap | 4 - .../schema_admin_settings.test.tsx.snap | 2 - .../admin_settings/admin_settings.tsx | 2 - .../billing_summary/billing_summary.tsx | 2 - .../brand_image_setting.tsx | 8 +- .../custom_plugin_settings.test.tsx.snap | 6 - ...om_terms_of_service_settings.test.tsx.snap | 8 - .../edit_section_edit_table_row.tsx | 4 - .../list_table/elapsed_duration_cell.tsx | 2 - .../admin_console/old_admin_settings.tsx | 2 - .../permission_description.test.tsx.snap | 134 +- .../permission_description.tsx | 2 - .../permissions_scheme_summary.test.tsx.snap | 2 - .../permissions_scheme_summary.tsx | 2 - .../plugin_management.test.tsx.snap | 30 - .../admin_console/schema_admin_settings.tsx | 2 - .../secure_connections/controls.tsx | 2 - .../system_user_detail/system_user_detail.tsx | 2 - .../system_users/system_users.tsx | 2 - .../index.tsx | 3 +- .../system_users_export/index.tsx | 2 - .../users_to_remove_groups.test.tsx.snap | 2 - .../group_users/users_to_remove_groups.tsx | 2 - .../team/details/team_profile.tsx | 6 +- .../user_grid/user_grid_role_dropdown.tsx | 2 - .../formatting_bar/formatting_icon.tsx | 2 - .../index.tsx} | 100 +- .../priority_labels/priority_labels.scss | 45 + .../send_button/send_button.tsx | 6 +- .../send_button/send_post_options/index.tsx | 2 +- .../show_formatting/show_formatting.tsx | 2 - .../toggle_formatting_bar.tsx | 2 - .../advanced_text_editor/use_emoji_picker.tsx | 2 - .../src/components/alert_banner/index.tsx | 3 +- .../__snapshots__/table_chart.test.tsx.snap | 4 - .../analytics/activated_users_card/title.tsx | 2 - .../src/components/analytics/table_chart.tsx | 2 - .../announcement_bar.tsx | 6 +- .../default_announcement_bar.scss | 6 +- .../components/app_bar/app_bar_binding.tsx | 3 +- .../app_bar/app_bar_marketplace.tsx | 3 +- .../app_bar/app_bar_plugin_component.tsx | 3 +- .../channel_header.test.tsx.snap | 4 - .../channel_header/channel_header.tsx | 3 - .../channel_header/channel_header_title.tsx | 2 - .../channel_header_title_favorite.test.tsx | 35 +- .../channel_header_title_favorite.tsx | 3 - .../components/header_icon_wrapper.tsx | 4 +- .../components/channel_info_rhs/header.tsx | 2 - .../channel_info_rhs/top_buttons.tsx | 8 - .../group_option/group_option.tsx | 2 - .../team_warning_banner.test.tsx.snap | 222 +-- .../team_warning_banner.tsx | 4 - .../components/channel_members_rhs/header.tsx | 2 - .../components/channel_members_rhs/member.tsx | 2 - .../src/components/common/comment_icon.tsx | 2 +- .../multi_select_cards/multi_select_card.tsx | 2 - .../channels/src/components/copy_button.tsx | 7 +- webapp/channels/src/components/copy_text.tsx | 6 +- .../__snapshots__/team_url.test.tsx.snap | 2 - .../components/team_url/team_url.tsx | 2 - .../custom_status_emoji.test.tsx.snap | 1 - .../custom_status_suggestion.test.tsx.snap | 2 - .../custom_status_text.test.tsx.snap | 2 - .../custom_status_emoji.test.tsx | 1 - .../custom_status/custom_status_emoji.tsx | 35 +- .../custom_status/custom_status_modal.tsx | 1 - .../custom_status_suggestion.tsx | 3 - .../custom_status/custom_status_text.test.tsx | 1 - .../custom_status/custom_status_text.tsx | 6 +- .../__snapshots__/action.test.tsx.snap | 2 - .../drafts/draft_actions/action.tsx | 2 - .../drafts/drafts_link/drafts_link.tsx | 2 - .../__snapshots__/panel_body.test.tsx.snap | 249 +-- .../__snapshots__/panel_header.test.tsx.snap | 2 - .../components/drafts/panel/panel_body.scss | 4 + .../components/drafts/panel/panel_body.tsx | 1 - .../components/drafts/panel/panel_header.tsx | 2 - .../placeholder_scheduled_posts_title.tsx | 2 - .../components/emoji_picker_category.tsx | 2 - .../components/emoji_picker_skin.tsx | 2 - .../file_attachment.test.tsx.snap | 16 - .../filename_overlay.test.tsx.snap | 20 +- .../file_attachment/file_attachment.tsx | 4 - .../file_attachment/filename_overlay.tsx | 7 +- .../file_preview_modal_footer.test.tsx.snap | 2 - .../file_preview_modal_footer.tsx | 1 - .../file_preview_modal_header.test.tsx.snap | 2 - .../file_preview_modal_header.tsx | 1 - .../file_preview_modal_main_actions.tsx | 10 - .../file_preview_modal_main_nav.test.tsx.snap | 4 - .../file_preview_modal_main_nav.tsx | 4 - .../__snapshots__/popover_bar.test.tsx.snap | 6 - .../popover_bar/popover_bar.tsx | 6 - .../file_search_result_item.test.tsx.snap | 36 +- .../file_search_result_item.tsx | 10 +- .../__snapshots__/file_upload.test.tsx.snap | 2 - .../components/file_upload/file_upload.tsx | 4 - .../user_guide_dropdown.test.tsx.snap | 6 - .../user_guide_dropdown.tsx | 2 - .../history_buttons/history_buttons.tsx | 4 - .../at_mentions_button.test.tsx.snap | 2 - .../at_mentions_button/at_mentions_button.tsx | 2 - .../plan_upgrade_button/index.tsx | 2 - .../saved_posts_button.test.tsx.snap | 2 - .../saved_posts_button/saved_posts_button.tsx | 2 - .../settings_button/settings_button.tsx | 2 - .../integrations/bots/add_bot/add_bot.tsx | 2 - webapp/channels/src/components/menu/menu.tsx | 9 +- .../new_channel_modal/new_channel_modal.tsx | 2 - .../new_replies_banner/new_replies_banner.tsx | 1 - .../marketplace_item/marketplace_item.tsx | 4 - .../src/components/post/post_component.tsx | 2 - .../edited_post_item.test.tsx.snap | 2 - .../edited_post_item/edited_post_item.tsx | 2 - .../src/components/post_emoji/post_emoji.tsx | 4 +- .../post_priority_picker_overlay.tsx | 2 - .../post_attachment_opengraph.tsx | 2 - .../post_edited_indicator.tsx | 2 - .../post_flag_icon.test.tsx.snap | 8 +- .../post_flag_icon/post_flag_icon.tsx | 2 +- .../__snapshots__/post_reaction.test.tsx.snap | 4 +- .../post_view/post_reaction/post_reaction.tsx | 2 +- .../post_recent_reactions.tsx | 2 +- .../post_view/post_time/post_time.tsx | 2 - .../reaction_tooltip/reaction_tooltip.tsx | 6 +- .../reactions_list.test.tsx.snap | 2 - .../post_view/reaction_list/reaction_list.tsx | 2 - .../profile_popover_add_to_channel.tsx | 2 - .../index.tsx | 2 - .../profile_popover_custom_status.tsx | 1 - .../profile_popover_full_name.tsx | 1 - .../profile_popover_self_user_row.tsx | 2 - .../components/quick_input/quick_input.tsx | 8 - .../rename_channel_modal.test.tsx.snap | 2 - .../rename_channel_modal.tsx | 2 - .../rhs_card_header/rhs_card_header.tsx | 6 - .../rhs_header_post/rhs_header_post.tsx | 6 - .../channels/src/components/search/search.tsx | 2 +- .../user_guide_dropdown.test.tsx.snap | 4 - .../user_guide_dropdown.tsx | 2 - .../files_filter_menu.test.tsx.snap | 16 - .../search_results/files_filter_menu.tsx | 2 - .../search_results_header.tsx | 4 - .../src/components/seats_calculator/index.tsx | 3 +- .../select_team_item.test.tsx.snap | 2 - .../components/select_team_item.tsx | 2 - .../src/components/setting_picture.tsx | 2 - .../components/shared_channel_indicator.tsx | 2 - .../src/components/shared_user_indicator.tsx | 4 - .../sidebar/add_channel_dropdown.tsx | 2 - .../channel_filter.test.tsx.snap | 4 - .../sidebar/channel_filter/channel_filter.tsx | 7 +- .../contents/contents.tsx | 3 - .../sidebar_category.test.tsx.snap | 4 - .../sidebar_category/sidebar_category.tsx | 2 - .../sidebar_channel_link.test.tsx.snap | 2 - .../sidebar_channel_link.tsx | 2 - .../sidebar_header/sidebar_header.scss | 26 + .../sidebar/sidebar_header/sidebar_header.tsx | 37 +- .../src/components/size_aware_image.tsx | 4 - .../status_dropdown.test.tsx.snap | 19 - .../status_dropdown/status_dropdown.tsx | 3 - .../at_mention_suggestion.test.tsx.snap | 8 +- .../at_mention_suggestion.tsx | 1 - .../suggestion/search_user_provider.tsx | 1 - .../team_sidebar/components/team_button.tsx | 8 +- .../__snapshots__/thread_footer.test.tsx.snap | 1205 ++++--------- .../thread_footer/thread_footer.tsx | 2 - .../__snapshots__/thread_item.test.tsx.snap | 6 - .../thread_item/thread_item.tsx | 2 - .../__snapshots__/thread_list.test.tsx.snap | 2 - .../thread_list/thread_list.tsx | 2 - .../__snapshots__/thread_pane.test.tsx.snap | 2 - .../thread_pane/thread_pane.tsx | 2 - .../channels/src/components/toast/toast.tsx | 4 - .../user_group_popover.test.tsx.snap | 615 ++----- .../group_member_list.test.tsx.snap | 615 ++----- .../group_member_list/group_member_list.tsx | 2 - .../components/user_profile/user_profile.tsx | 1 - .../custom_theme_chooser.test.tsx.snap | 2 - .../custom_theme_chooser.tsx | 2 - .../components/widgets/inputs/input/input.tsx | 2 - .../widgets/inputs/url_input/url_input.tsx | 2 - .../menu/menu_items/restricted_indicator.tsx | 2 - .../public-private-selector.tsx | 2 - .../widgets/users/avatar/avatar.tsx | 15 +- .../__snapshots__/avatars.test.tsx.snap | 1519 +++++------------ .../widgets/users/avatars/avatars.test.tsx | 20 +- .../widgets/users/avatars/avatars.tsx | 4 - .../tooltip_content.test.tsx.snap | 0 .../with_tooltip/create_tooltip.tsx | 101 -- .../{with_tooltip_new => }/index.test.tsx | 0 .../src/components/with_tooltip/index.tsx | 246 ++- .../with_tooltip/overlay_trigger.tsx | 66 - .../src/components/with_tooltip/shortcut.tsx | 70 - .../{with_tooltip_new => }/tooltip.scss | 0 .../src/components/with_tooltip/tooltip.tsx | 32 - .../tooltip_content.test.tsx | 0 .../tooltip_content.tsx | 9 +- .../tooltip_shortcut.test.tsx | 0 .../tooltip_shortcut.tsx | 21 +- .../with_tooltip/with_tooltip_new/index.tsx | 204 --- .../channel_header_plug.tsx | 2 - .../eslint-plugin/configs/.eslintrc.json | 5 - 227 files changed, 1676 insertions(+), 4835 deletions(-) rename webapp/channels/src/components/advanced_text_editor/{priority_labels.tsx => priority_labels/index.tsx} (59%) create mode 100644 webapp/channels/src/components/advanced_text_editor/priority_labels/priority_labels.scss create mode 100644 webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.scss rename webapp/channels/src/components/with_tooltip/{with_tooltip_new => }/__snapshots__/tooltip_content.test.tsx.snap (100%) delete mode 100644 webapp/channels/src/components/with_tooltip/create_tooltip.tsx rename webapp/channels/src/components/with_tooltip/{with_tooltip_new => }/index.test.tsx (100%) delete mode 100644 webapp/channels/src/components/with_tooltip/overlay_trigger.tsx delete mode 100644 webapp/channels/src/components/with_tooltip/shortcut.tsx rename webapp/channels/src/components/with_tooltip/{with_tooltip_new => }/tooltip.scss (100%) delete mode 100644 webapp/channels/src/components/with_tooltip/tooltip.tsx rename webapp/channels/src/components/with_tooltip/{with_tooltip_new => }/tooltip_content.test.tsx (100%) rename webapp/channels/src/components/with_tooltip/{with_tooltip_new => }/tooltip_content.tsx (89%) rename webapp/channels/src/components/with_tooltip/{with_tooltip_new => }/tooltip_shortcut.test.tsx (100%) rename webapp/channels/src/components/with_tooltip/{with_tooltip_new => }/tooltip_shortcut.tsx (74%) delete mode 100644 webapp/channels/src/components/with_tooltip/with_tooltip_new/index.tsx diff --git a/e2e-tests/cypress/tests/integration/channels/channel/channel_info_rhs_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel/channel_info_rhs_spec.ts index 8657d687d4..88ae7cda0e 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel/channel_info_rhs_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel/channel_info_rhs_spec.ts @@ -99,21 +99,21 @@ describe('Channel Info RHS', () => { cy.get('#channel-info-btn').click(); // * Verify tooltips appear with correct text - cy.uiGetRHS().findByText('Favorite').trigger('mouseover'); - cy.get('#favorite-tooltip').should('be.visible').and('have.text', 'Add this channel to favorites'); - cy.uiGetRHS().findByText('Favorite').trigger('mouseout'); + cy.uiGetRHS().findByText('Favorite').trigger('mouseenter'); + cy.findByText('Add this channel to favorites').should('be.visible'); + cy.uiGetRHS().findByText('Favorite').trigger('mouseleave'); - cy.uiGetRHS().findByText('Mute').trigger('mouseover'); - cy.get('#mute-tooltip').should('be.visible').and('have.text', 'Mute notifications for this channel'); - cy.uiGetRHS().findByText('Mute').trigger('mouseout'); + cy.uiGetRHS().findByText('Mute').trigger('mouseenter'); + cy.findByText('Mute notifications for this channel').should('be.visible'); + cy.uiGetRHS().findByText('Mute').trigger('mouseleave'); - cy.uiGetRHS().findByText('Add People').trigger('mouseover'); - cy.get('#add-people-tooltip').should('be.visible').and('have.text', 'Add team members to this channel'); - cy.uiGetRHS().findByText('Add People').trigger('mouseout'); + cy.uiGetRHS().findByText('Add People').trigger('mouseenter'); + cy.findByText('Add team members to this channel').should('be.visible'); + cy.uiGetRHS().findByText('Add People').trigger('mouseleave'); - cy.uiGetRHS().findByText('Copy Link').trigger('mouseover'); - cy.get('#copy-link-tooltip').should('be.visible').and('have.text', 'Copy link to this channel'); - cy.uiGetRHS().findByText('Copy Link').trigger('mouseout'); + cy.uiGetRHS().findByText('Copy Link').trigger('mouseenter'); + cy.findByText('Copy link to this channel').should('be.visible'); + cy.uiGetRHS().findByText('Copy Link').trigger('mouseleave'); }); it('should be able to toggle favorite on a channel', () => { diff --git a/e2e-tests/cypress/tests/integration/channels/channel/channel_members_rhs_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel/channel_members_rhs_spec.ts index 8d310a7a62..5bece26d45 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel/channel_members_rhs_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel/channel_members_rhs_spec.ts @@ -235,6 +235,8 @@ describe('Channel members RHS', () => { // # Click on the Manage button cy.uiGetRHS().findByText('Manage').should('be.visible').click(); + cy.wait(500); + // * Can see user with their roles, and change it cy.uiGetRHS().findByTestId(`memberline-${user.id}`).should('be.visible').within(() => { cy.contains(`${user.username}`).should('be.visible'); diff --git a/e2e-tests/cypress/tests/integration/channels/channel/channel_name_tooltips_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel/channel_name_tooltips_spec.ts index aae9568166..50cb253df8 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel/channel_name_tooltips_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel/channel_name_tooltips_spec.ts @@ -17,26 +17,6 @@ import * as TIMEOUTS from '../../../fixtures/timeouts'; const timestamp = Date.now(); -function verifyChannel(channel: Channel, verifyExistence = true) { - // # Wait for Channel to be created - cy.wait(TIMEOUTS.HALF_SEC); - - // # Hover on the channel name - cy.get(`#sidebarItem_${channel.name}`).should('be.visible').trigger('mouseover'); - - // * Verify that the tooltip is displayed - if (verifyExistence) { - cy.get('div.tooltip-inner'). - should('be.visible'). - and('contain', channel.display_name); - } else { - cy.get('div.tooltip-inner').should('not.exist'); - } - - // # Move cursor away from channel - cy.get(`#sidebarItem_${channel.name}`).should('be.visible').trigger('mouseout'); -} - describe('channel name tooltips', () => { let loggedUser: UserProfile; let longUser: UserProfile; @@ -122,12 +102,30 @@ describe('channel name tooltips', () => { cy.uiGetButton('Go').click(); // # Hover on the channel name - cy.get(`#sidebarItem_${Cypress._.sortBy([loggedUser.id, longUser.id]).join('__')}`).scrollIntoView().should('be.visible').trigger('mouseover'); + cy.get(`#sidebarItem_${Cypress._.sortBy([loggedUser.id, longUser.id]).join('__')}`).scrollIntoView().should('be.visible').trigger('mouseenter'); // * Verify that the tooltip is displayed - cy.get('div.tooltip-inner').should('be.visible'); + cy.findByRole('tooltip').should('be.visible'); // # Move cursor away from channel - cy.get(`#sidebarItem_${Cypress._.sortBy([loggedUser.id, longUser.id]).join('__')}`).scrollIntoView().should('be.visible').trigger('mouseout'); + cy.get(`#sidebarItem_${Cypress._.sortBy([loggedUser.id, longUser.id]).join('__')}`).scrollIntoView().should('be.visible').trigger('mouseleave'); }); }); + +function verifyChannel(channel: Channel, verifyExistence = true) { + // # Wait for Channel to be created + cy.wait(TIMEOUTS.HALF_SEC); + + // # Hover on the channel name + cy.get(`#sidebarItem_${channel.name}`).should('be.visible').trigger('mouseenter'); + + // * Verify that the tooltip is displayed + if (verifyExistence) { + cy.findByRole('tooltip').should('be.visible').and('have.text', channel.display_name); + } else { + cy.findByRole('tooltip').should('not.exist'); + } + + // # Move cursor away from channel + cy.get(`#sidebarItem_${channel.name}`).should('be.visible').trigger('mouseleave'); +} diff --git a/e2e-tests/cypress/tests/integration/channels/custom_status/custom_status_expiry/custom_status_expiry_2_spec.ts b/e2e-tests/cypress/tests/integration/channels/custom_status/custom_status_expiry/custom_status_expiry_2_spec.ts index 9b6a11fb9f..a15928b29c 100644 --- a/e2e-tests/cypress/tests/integration/channels/custom_status/custom_status_expiry/custom_status_expiry_2_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/custom_status/custom_status_expiry/custom_status_expiry_2_spec.ts @@ -104,14 +104,16 @@ describe('MM-T4064 Status expiry visibility', () => { // # Post a message in the channel cy.postMessage('Hello World!'); - // # Hover on the custom status emoji present in the post header - cy.get('.post.current--user .post__header span.emoticon').trigger('mouseover'); + // # Get the last post + cy.getLastPostId().then((postId) => { + // # Hover on the custom status emoji present in the post header + cy.get(`#post_${postId}`).find('.emoticon').should('exist').trigger('mouseenter'); - // * Custom status tooltip should be visible - cy.get('#custom-status-tooltip').should('exist'); + // * Custom status tooltip should be visible and contain the correct custom status expiry time + cy.findByRole('tooltip').should('exist').and('contain.text', expiresAt.format(expiryTimeFormat)); - // * Tooltip should contain the correct custom status expiry time - cy.get('#custom-status-tooltip .custom-status-expiry time').should('have.text', expiresAt.format(expiryTimeFormat)); + cy.get(`#post_${postId}`).find('.emoticon').trigger('mouseleave'); + }); }); it('MM-T4064_7 should show custom status expiry time in the user popover', () => { diff --git a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_audio_spec.js b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_audio_spec.js index 4036f837a8..2466a93a9f 100644 --- a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_audio_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_audio_spec.js @@ -126,14 +126,16 @@ function testAudioFile(properties) { cy.get('@filePreviewModal').get('video').should('exist'); } + cy.get('.file-preview-modal__file-name').should('have.text', fileName); + // * Download button should exist cy.get('@filePreviewModal').uiGetDownloadFilePreviewModal().then((downloadLink) => { - expect(downloadLink.attr('download')).to.equal(fileName); + cy.wrap(downloadLink).parent().should('have.attr', 'download', fileName).then((link) => { + const fileAttachmentURL = link.attr('href'); - const fileAttachmentURL = downloadLink.attr('href'); - - // * Verify that download link has correct name - downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, fileName, 'attachment'); + // * Verify that download link has correct name + downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, fileName, 'attachment'); + }); }); // # Close modal diff --git a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_generic_spec.js b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_generic_spec.js index 4062912d3b..b7e989ff40 100644 --- a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_generic_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_generic_spec.js @@ -114,12 +114,12 @@ function testGenericFile(properties) { // * Download button should exist cy.get('@filePreviewModal').uiGetDownloadFilePreviewModal().then((downloadLink) => { - expect(downloadLink.attr('download')).to.equal(fileName); + cy.wrap(downloadLink).parent().should('have.attr', 'download', fileName).then((link) => { + const fileAttachmentURL = link.attr('href'); - const fileAttachmentURL = downloadLink.attr('href'); - - // * Verify that download link has correct name - downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, fileName, 'attachment'); + // * Verify that download link has correct name + downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, fileName, 'attachment'); + }); }); // # Close modal diff --git a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_image_spec.js b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_image_spec.js index 9fb644475e..2dfa97b554 100644 --- a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_image_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_image_spec.js @@ -145,12 +145,12 @@ function testImage(properties) { // * Download button should exist cy.get('@filePreviewModal').uiGetDownloadFilePreviewModal().then((downloadLink) => { - expect(downloadLink.attr('download')).to.equal(fileName); + cy.wrap(downloadLink).parent().should('have.attr', 'download', fileName).then((link) => { + const fileAttachmentURL = link.attr('href'); - const fileAttachmentURL = downloadLink.attr('href'); - - // * Verify that download link has correct name - downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, fileName, 'attachment'); + // * Verify that download link has correct name + downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, fileName, 'attachment'); + }); }); // # Close modal diff --git a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_video_spec.js b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_video_spec.js index 8a756981a8..4a697d3ac0 100644 --- a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_video_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/file_preview_video_spec.js @@ -126,12 +126,12 @@ export function testVideoFile(properties) { // * Download button should exist cy.get('@filePreviewModal').uiGetDownloadFilePreviewModal().then((downloadLink) => { - expect(downloadLink.attr('download')).to.equal(fileName); + cy.wrap(downloadLink).parent().should('have.attr', 'download', fileName).then((link) => { + const fileAttachmentURL = link.attr('href'); - const fileAttachmentURL = downloadLink.attr('href'); - - // * Verify that download link has correct name - downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, fileName, 'attachment'); + // * Verify that download link has correct name + downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, fileName, 'attachment'); + }); }); // # Close modal diff --git a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/upload_files_not_cloud_spec.js b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/upload_files_not_cloud_spec.js index 36e60d9490..7cdfc683db 100644 --- a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/upload_files_not_cloud_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/upload_files_not_cloud_spec.js @@ -71,8 +71,8 @@ describe('Upload Files', () => { cy.uiGetFilePreviewModal(); // # Hover over the downlink button and verify that tooltip is shown - cy.uiGetDownloadLinkFilePreviewModal().trigger('mouseover'); - cy.uiGetToolTip('Get a public link'); + cy.uiGetDownloadLinkFilePreviewModal().trigger('mouseenter'); + cy.findByText('Get a public link').should('exist'); // # Copy download link cy.uiGetDownloadLinkFilePreviewModal().click(); @@ -178,8 +178,8 @@ describe('Upload Files', () => { cy.uiGetFilePreviewModal(); // # Hover over the downlink button and verify that tooltip is shown - cy.uiGetDownloadLinkFilePreviewModal().trigger('mouseover'); - cy.uiGetToolTip('Get a public link'); + cy.uiGetDownloadLinkFilePreviewModal().trigger('mouseenter'); + cy.findByText('Get a public link').should('exist'); // # Click to copy download link cy.uiGetDownloadLinkFilePreviewModal().click({force: true}); diff --git a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/upload_files_spec.js b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/upload_files_spec.js index 88ba60c450..64ba261aac 100644 --- a/e2e-tests/cypress/tests/integration/channels/files_and_attachments/upload_files_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/files_and_attachments/upload_files_spec.js @@ -140,12 +140,12 @@ describe('Upload Files', () => { // * Download button should exist cy.get('@filePreviewModal').uiGetDownloadFilePreviewModal().then((downloadLink) => { - expect(downloadLink.attr('download')).to.equal(file.filename); + cy.wrap(downloadLink).parent().should('have.attr', 'download', file.filename).then((link) => { + const fileAttachmentURL = link.attr('href'); - const fileAttachmentURL = downloadLink.attr('href'); - - // * Verify that download link has correct name - downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, file.filename, 'attachment'); + // * Verify that download link has correct name + downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, file.filename, 'attachment'); + }); }); // # Close the modal @@ -174,12 +174,12 @@ describe('Upload Files', () => { // * Download button should exist cy.get('@filePreviewModal').uiGetDownloadFilePreviewModal().then((downloadLink) => { - expect(downloadLink.attr('download')).to.equal(filename); + cy.wrap(downloadLink).parent().should('have.attr', 'download', filename).then((link) => { + const fileAttachmentURL = link.attr('href'); - const fileAttachmentURL = downloadLink.attr('href'); - - // * Verify that download link has correct name - downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, filename, 'attachment'); + // * Verify that download link has correct name + downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, filename, 'attachment'); + }); }); // # Close the modal @@ -405,12 +405,12 @@ describe('Upload Files', () => { // * Download button should exist cy.get('@filePreviewModal').uiGetDownloadFilePreviewModal().then((downloadLink) => { - expect(downloadLink.attr('download')).to.equal(filename); + cy.wrap(downloadLink).parent().should('have.attr', 'download', filename).then((link) => { + const fileAttachmentURL = link.attr('href'); - const fileAttachmentURL = downloadLink.attr('href'); - - // * Verify that download link has correct name - downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, filename, 'attachment'); + // * Verify that download link has correct name + downloadAttachmentAndVerifyItsProperties(fileAttachmentURL, filename, 'attachment'); + }); }); // # Close modal diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/app_bar_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/app_bar_spec.js index cf31500902..c9b3883584 100644 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/app_bar_spec.js +++ b/e2e-tests/cypress/tests/integration/playbooks/channels/app_bar_spec.js @@ -60,10 +60,10 @@ describe('channels > App Bar', {testIsolation: true}, () => { cy.visit(`/${testTeam.name}/channels/town-square`); // # Hover over the channel header icon - cy.getPlaybooksAppBarIcon().trigger('mouseover'); + cy.getPlaybooksAppBarIcon().trigger('mouseenter'); // * Verify tooltip text - cy.findByRole('tooltip', {name: 'Playbooks'}).should('be.visible'); + cy.findByRole('tooltip').should('be.visible').and('contain', 'Playbooks'); }); }); }); diff --git a/e2e-tests/cypress/tests/support/ui/file_preview.js b/e2e-tests/cypress/tests/support/ui/file_preview.js index 0a58408cb6..67adfd0154 100644 --- a/e2e-tests/cypress/tests/support/ui/file_preview.js +++ b/e2e-tests/cypress/tests/support/ui/file_preview.js @@ -51,17 +51,17 @@ Cypress.Commands.add('uiGetContentFilePreviewModal', () => { }); Cypress.Commands.add('uiGetDownloadLinkFilePreviewModal', () => { - return cy.uiGetFilePreviewModal().find('.icon-link-variant').parent(); + return cy.uiGetFilePreviewModal().find('.icon-link-variant'); }); Cypress.Commands.add('uiGetDownloadFilePreviewModal', () => { - return cy.uiGetFilePreviewModal().find('.icon-download-outline').parent(); + return cy.uiGetFilePreviewModal().find('.icon-download-outline'); }); Cypress.Commands.add('uiGetArrowLeftFilePreviewModal', () => { - return cy.uiGetFilePreviewModal().find('.icon-chevron-left').parent(); + return cy.uiGetFilePreviewModal().find('.icon-chevron-left'); }); Cypress.Commands.add('uiGetArrowRightFilePreviewModal', () => { - return cy.uiGetFilePreviewModal().find('.icon-chevron-right').parent(); + return cy.uiGetFilePreviewModal().find('.icon-chevron-right'); }); diff --git a/e2e-tests/cypress/tests/support/ui/tooltip.js b/e2e-tests/cypress/tests/support/ui/tooltip.js index d74768d3a8..a24b922e31 100644 --- a/e2e-tests/cypress/tests/support/ui/tooltip.js +++ b/e2e-tests/cypress/tests/support/ui/tooltip.js @@ -2,5 +2,5 @@ // See LICENSE.txt for license information. Cypress.Commands.add('uiGetToolTip', (text) => { - cy.findByRole('tooltip').should('contain', text); + cy.findByRole('tooltip').should('exist').and('contain', text); }); diff --git a/webapp/channels/src/components/__snapshots__/setting_picture.test.tsx.snap b/webapp/channels/src/components/__snapshots__/setting_picture.test.tsx.snap index 529398379e..c708595594 100644 --- a/webapp/channels/src/components/__snapshots__/setting_picture.test.tsx.snap +++ b/webapp/channels/src/components/__snapshots__/setting_picture.test.tsx.snap @@ -763,8 +763,6 @@ exports[`components/SettingItemMin should match snapshot, team icon on source 1` { onToggle={this.handleDropdownOpened} > } - placement='top' > )} - + ); } diff --git a/webapp/channels/src/components/advanced_text_editor/priority_labels/priority_labels.scss b/webapp/channels/src/components/advanced_text_editor/priority_labels/priority_labels.scss new file mode 100644 index 0000000000..d1b5ca6337 --- /dev/null +++ b/webapp/channels/src/components/advanced_text_editor/priority_labels/priority_labels.scss @@ -0,0 +1,45 @@ +.priorityLabelsContainer { + display: flex; + align-items: center; + padding: 14px 16px 0; + gap: 6px; + + &:hover { + .priorityLabelsClose { + visibility: visible; + } + } + + .priorityLabelsClose { + display: flex; + align-items: center; + justify-content: center; + margin-top: -1px; + color: rgb(var(--center-channel-color)); + font-size: 17px; + opacity: 0.73; + visibility: hidden; + } + + span.icon { + font-size: 14px; + + &.icon-bell-ring-outline { + color: var(--dnd-indicator); + } + + &.icon-check-circle-outline { + color: var(--online-indicator); + + &.hasError { + color: var(--dnd-indicator); + } + } + } + + .priorityLabelsError { + color: var(--dnd-indicator); + font-size: 11px; + font-weight: 600; + } +} diff --git a/webapp/channels/src/components/advanced_text_editor/send_button/send_button.tsx b/webapp/channels/src/components/advanced_text_editor/send_button/send_button.tsx index d926b31fd5..edc4e57e8c 100644 --- a/webapp/channels/src/components/advanced_text_editor/send_button/send_button.tsx +++ b/webapp/channels/src/components/advanced_text_editor/send_button/send_button.tsx @@ -15,8 +15,8 @@ import {isSendOnCtrlEnter} from 'selectors/preferences'; import {SendPostOptions} from 'components/advanced_text_editor/send_button/send_post_options'; import WithTooltip from 'components/with_tooltip'; -import type {ShortcutDefinition} from 'components/with_tooltip/shortcut'; -import {ShortcutKeys} from 'components/with_tooltip/shortcut'; +import type {ShortcutDefinition} from 'components/with_tooltip/tooltip_shortcut'; +import {ShortcutKeys} from 'components/with_tooltip/tooltip_shortcut'; import './send_button.scss'; @@ -65,8 +65,6 @@ const SendButton = ({disabled, handleSubmit, channelId}: SendButtonProps) => { return (
{ return ( { isInsideTooltip={true} /> } - placement='left' > { return ( {onDismiss && closeBtnTooltip && ( {dismissButton} diff --git a/webapp/channels/src/components/analytics/__snapshots__/table_chart.test.tsx.snap b/webapp/channels/src/components/analytics/__snapshots__/table_chart.test.tsx.snap index ee7d600f03..753184f8e0 100644 --- a/webapp/channels/src/components/analytics/__snapshots__/table_chart.test.tsx.snap +++ b/webapp/channels/src/components/analytics/__snapshots__/table_chart.test.tsx.snap @@ -22,8 +22,6 @@ exports[`components/analytics/table_chart.tsx should match snapshot, loaded with > @@ -42,8 +40,6 @@ exports[`components/analytics/table_chart.tsx should match snapshot, loaded with > diff --git a/webapp/channels/src/components/analytics/activated_users_card/title.tsx b/webapp/channels/src/components/analytics/activated_users_card/title.tsx index 68b5a5a79d..d951a3da45 100644 --- a/webapp/channels/src/components/analytics/activated_users_card/title.tsx +++ b/webapp/channels/src/components/analytics/activated_users_card/title.tsx @@ -17,10 +17,8 @@ const Title = () => { const intl = useIntl(); return ( {item.name} diff --git a/webapp/channels/src/components/announcement_bar/default_announcement_bar/announcement_bar.tsx b/webapp/channels/src/components/announcement_bar/default_announcement_bar/announcement_bar.tsx index fbfa70df0b..81dbe172c6 100644 --- a/webapp/channels/src/components/announcement_bar/default_announcement_bar/announcement_bar.tsx +++ b/webapp/channels/src/components/announcement_bar/default_announcement_bar/announcement_bar.tsx @@ -44,8 +44,6 @@ type State = { isStringContainingUrl: boolean; } -const OVERLAY_ANNOUNCEMENT_HIDE_DELAY = 600; - export default class AnnouncementBar extends React.PureComponent { messageRef: React.RefObject; constructor(props: Props) { @@ -196,10 +194,8 @@ export default class AnnouncementBar extends React.PureComponent { if (this.state.showTooltip) { 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 f3790e673d..46205a5e2f 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 @@ -#announcement-bar__tooltip { - width: 50%; - max-width: 100%; +.announcementBarTooltip { + min-width: 50vw; + max-width: 100vw; pointer-events: auto; } diff --git a/webapp/channels/src/components/app_bar/app_bar_binding.tsx b/webapp/channels/src/components/app_bar/app_bar_binding.tsx index c85822bb02..aaaf05b383 100644 --- a/webapp/channels/src/components/app_bar/app_bar_binding.tsx +++ b/webapp/channels/src/components/app_bar/app_bar_binding.tsx @@ -84,9 +84,8 @@ const AppBarBinding = (props: BindingComponentProps) => { return (
{ return (
@@ -777,8 +706,6 @@ exports[`components/channel_invite_modal/team_warning_banner should match snapsh />, " and ", and - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] + - - - - 10 others - - + + 10 others - - + + to this channel once they are members of the { ), others: ( { ), others: ( { {!editing && ( actions.openDirectMessage(member.user)}> diff --git a/webapp/channels/src/components/common/comment_icon.tsx b/webapp/channels/src/components/common/comment_icon.tsx index 91522ea6cb..b63818ec08 100644 --- a/webapp/channels/src/components/common/comment_icon.tsx +++ b/webapp/channels/src/components/common/comment_icon.tsx @@ -5,7 +5,7 @@ import React from 'react'; import {useIntl} from 'react-intl'; import ReplyIcon from 'components/widgets/icons/reply_icon'; -import WithTooltip from 'components/with_tooltip/with_tooltip_new'; +import WithTooltip from 'components/with_tooltip'; import type {Locations} from 'utils/constants'; diff --git a/webapp/channels/src/components/common/multi_select_cards/multi_select_card.tsx b/webapp/channels/src/components/common/multi_select_cards/multi_select_card.tsx index 57e8f8f335..68224aed54 100644 --- a/webapp/channels/src/components/common/multi_select_cards/multi_select_card.tsx +++ b/webapp/channels/src/components/common/multi_select_cards/multi_select_card.tsx @@ -46,8 +46,6 @@ const MultiSelectCard = (props: Props) => { if (props.tooltip) { button = ( {button} diff --git a/webapp/channels/src/components/copy_button.tsx b/webapp/channels/src/components/copy_button.tsx index 6eda797966..6e2d1eeadc 100644 --- a/webapp/channels/src/components/copy_button.tsx +++ b/webapp/channels/src/components/copy_button.tsx @@ -5,14 +5,13 @@ import classNames from 'classnames'; import React, {useRef, useState} from 'react'; import {FormattedMessage, defineMessages, useIntl} from 'react-intl'; -import {copyToClipboard} from 'utils/utils'; +import WithTooltip from 'components/with_tooltip'; -import WithTooltip from './with_tooltip'; +import {copyToClipboard} from 'utils/utils'; type Props = { content: string; isForText?: boolean; - placement?: string; className?: string; }; @@ -54,8 +53,6 @@ const CopyButton: React.FC = (props: Props) => { return ( + `; @@ -43,7 +42,6 @@ exports[`components/custom_status/custom_status_emoji should match snapshot with `; @@ -12,6 +11,5 @@ exports[`components/custom_status/custom_status_text should match snapshot with `; diff --git a/webapp/channels/src/components/custom_status/custom_status_emoji.test.tsx b/webapp/channels/src/components/custom_status/custom_status_emoji.test.tsx index c58cc4706d..da13903bf4 100644 --- a/webapp/channels/src/components/custom_status/custom_status_emoji.test.tsx +++ b/webapp/channels/src/components/custom_status/custom_status_emoji.test.tsx @@ -32,7 +32,6 @@ describe('components/custom_status/custom_status_emoji', () => { , {wrappingComponent: Provider, wrappingComponentProps: {store}}, ); diff --git a/webapp/channels/src/components/custom_status/custom_status_emoji.tsx b/webapp/channels/src/components/custom_status/custom_status_emoji.tsx index efaf070134..daa932298c 100644 --- a/webapp/channels/src/components/custom_status/custom_status_emoji.tsx +++ b/webapp/channels/src/components/custom_status/custom_status_emoji.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {memo, useEffect, useMemo, useRef, useState} from 'react'; +import React, {memo, useMemo, useRef} from 'react'; import {useSelector} from 'react-redux'; import {CustomStatusDuration} from '@mattermost/types/users'; @@ -20,7 +20,6 @@ import ExpiryTime from './expiry_time'; interface Props { emojiSize?: number; showTooltip?: boolean; - tooltipDirection?: 'top' | 'right' | 'bottom' | 'left'; spanStyle?: React.CSSProperties; emojiStyle?: React.CSSProperties; userID?: string; @@ -46,36 +45,8 @@ function CustomStatusEmoji({ const customStatusExpired = useSelector((state: GlobalState) => isCustomStatusExpired(state, customStatus)); const customStatusEnabled = useSelector(isCustomStatusEnabled); - const [placement, setPlacement] = useState('bottom'); const emojiRef = useRef(null); - useEffect(() => { - function handleMouseEnter() { - if (emojiRef.current) { - const boundingRect = emojiRef.current.getBoundingClientRect(); - const windowHeight = window.innerHeight; - const threshold = windowHeight * 0.8; - - if (boundingRect.bottom >= threshold) { - setPlacement('top'); - } else { - setPlacement('bottom'); - } - } - } - - const emojiElement = emojiRef.current; - if (emojiElement) { - emojiElement.addEventListener('mouseenter', handleMouseEnter); - } - - return () => { - if (emojiElement) { - emojiElement.removeEventListener('mouseenter', handleMouseEnter); - } - }; - }, []); - if (!customStatusEnabled || !customStatus?.emoji || customStatusExpired) { return null; } @@ -95,7 +66,6 @@ function CustomStatusEmoji({ return (
@@ -120,8 +90,7 @@ function CustomStatusEmoji({ } emoji={customStatus.emoji} - emojiStyle='large' - placement={placement} + isEmojiLarge={true} > = (props: Props) => { onClear={clearHandle} className='emoji-quick-input form-control' clearClassName='StatusModal__clear-container' - tooltipPosition='top' onChange={handleTextChange} placeholder={formatMessage({id: 'custom_status.set_status', defaultMessage: 'Set a status'})} autoFocus={true} diff --git a/webapp/channels/src/components/custom_status/custom_status_suggestion.tsx b/webapp/channels/src/components/custom_status/custom_status_suggestion.tsx index 43ca8f6ea6..d2cb1eb47d 100644 --- a/webapp/channels/src/components/custom_status/custom_status_suggestion.tsx +++ b/webapp/channels/src/components/custom_status/custom_status_suggestion.tsx @@ -43,14 +43,12 @@ const CustomStatusSuggestion: React.FC = (props: Props) => { const clearButton = handleClear ? (
} - id='clear-recent-custom-status' >
{ it('should match snapshot with props', () => { const wrapper = mount( , {wrappingComponent: Provider, wrappingComponentProps: {store}}, diff --git a/webapp/channels/src/components/custom_status/custom_status_text.tsx b/webapp/channels/src/components/custom_status/custom_status_text.tsx index 52ccdf7260..60b4005bde 100644 --- a/webapp/channels/src/components/custom_status/custom_status_text.tsx +++ b/webapp/channels/src/components/custom_status/custom_status_text.tsx @@ -11,13 +11,12 @@ import WithTooltip from 'components/with_tooltip'; import type {GlobalState} from 'types/store'; interface ComponentProps { - tooltipDirection?: 'top' | 'right' | 'bottom' | 'left'; text: string; className?: string; } const CustomStatusText = (props: ComponentProps) => { - const {tooltipDirection, text, className} = props; + const {text, className} = props; const customStatusEnabled = useSelector((state: GlobalState) => { return isCustomStatusEnabled(state); }); @@ -49,8 +48,6 @@ const CustomStatusText = (props: ComponentProps) => { return ( {customStatusTextComponent} @@ -59,7 +56,6 @@ const CustomStatusText = (props: ComponentProps) => { }; CustomStatusText.defaultProps = { - tooltipDirection: 'bottom', text: '', className: '', }; diff --git a/webapp/channels/src/components/drafts/draft_actions/__snapshots__/action.test.tsx.snap b/webapp/channels/src/components/drafts/draft_actions/__snapshots__/action.test.tsx.snap index 95ab53b53b..3d33920ffb 100644 --- a/webapp/channels/src/components/drafts/draft_actions/__snapshots__/action.test.tsx.snap +++ b/webapp/channels/src/components/drafts/draft_actions/__snapshots__/action.test.tsx.snap @@ -5,8 +5,6 @@ exports[`components/drafts/draft_actions/action should match snapshot 1`] = ` className="DraftAction" >
diff --git a/webapp/channels/src/components/drafts/panel/__snapshots__/panel_body.test.tsx.snap b/webapp/channels/src/components/drafts/panel/__snapshots__/panel_body.test.tsx.snap index 026c6d632e..1eaaa3d21d 100644 --- a/webapp/channels/src/components/drafts/panel/__snapshots__/panel_body.test.tsx.snap +++ b/webapp/channels/src/components/drafts/panel/__snapshots__/panel_body.test.tsx.snap @@ -64,7 +64,7 @@ exports[`components/drafts/panel/panel_body should have called handleFormattedTe - - + @@ -290,7 +290,7 @@ exports[`components/drafts/panel/panel_body should match snapshot 1`] = ` - - + @@ -522,7 +522,7 @@ exports[`components/drafts/panel/panel_body should match snapshot for priority 1 - - + @@ -614,64 +614,59 @@ exports[`components/drafts/panel/panel_body should match snapshot for priority 1 - -
- - - -
- - - - - - - - Important - - -
-
-
-
-
-
+ + + + + + Important + + +
+ + + +
- - + @@ -908,135 +903,39 @@ exports[`components/drafts/panel/panel_body should match snapshot for requested_ -
- -
- - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - - - - - - - - - - Request acknowledgement - - -
-
+ + + + + Request acknowledgement + +
-
+
diff --git a/webapp/channels/src/components/emoji_picker/components/emoji_picker_category.tsx b/webapp/channels/src/components/emoji_picker/components/emoji_picker_category.tsx index 1bb82a88ab..2427119bb4 100644 --- a/webapp/channels/src/components/emoji_picker/components/emoji_picker_category.tsx +++ b/webapp/channels/src/components/emoji_picker/components/emoji_picker_category.tsx @@ -38,8 +38,6 @@ function EmojiPickerCategory({category, categoryRowIndex, selected, enable, onCl return ( } diff --git a/webapp/channels/src/components/emoji_picker/components/emoji_picker_skin.tsx b/webapp/channels/src/components/emoji_picker/components/emoji_picker_skin.tsx index 229bfece1e..1e7646ef3b 100644 --- a/webapp/channels/src/components/emoji_picker/components/emoji_picker_skin.tsx +++ b/webapp/channels/src/components/emoji_picker/components/emoji_picker_skin.tsx @@ -173,8 +173,6 @@ export class EmojiPickerSkin extends React.PureComponent { return (
`; diff --git a/webapp/channels/src/components/file_preview_modal/file_preview_modal_footer/file_preview_modal_footer.tsx b/webapp/channels/src/components/file_preview_modal/file_preview_modal_footer/file_preview_modal_footer.tsx index 532950a6e0..4a9e5320fe 100644 --- a/webapp/channels/src/components/file_preview_modal/file_preview_modal_footer/file_preview_modal_footer.tsx +++ b/webapp/channels/src/components/file_preview_modal/file_preview_modal_footer/file_preview_modal_footer.tsx @@ -37,7 +37,6 @@ const FilePreviewModalFooter: React.FC = ({post, ...actionProps}: Props)
diff --git a/webapp/channels/src/components/file_preview_modal/file_preview_modal_header/__snapshots__/file_preview_modal_header.test.tsx.snap b/webapp/channels/src/components/file_preview_modal/file_preview_modal_header/__snapshots__/file_preview_modal_header.test.tsx.snap index e4f883a48a..23ca45c7e9 100644 --- a/webapp/channels/src/components/file_preview_modal/file_preview_modal_header/__snapshots__/file_preview_modal_header.test.tsx.snap +++ b/webapp/channels/src/components/file_preview_modal/file_preview_modal_header/__snapshots__/file_preview_modal_header.test.tsx.snap @@ -48,7 +48,6 @@ exports[`components/file_preview_modal/file_preview_modal_header/FilePreviewModa onGetPublicLink={[MockFunction]} showOnlyClose={false} showPublicLink={false} - usedInside="Header" /> `; @@ -90,7 +89,6 @@ exports[`components/file_preview_modal/file_preview_modal_header/FilePreviewModa onGetPublicLink={[MockFunction]} showOnlyClose={true} showPublicLink={false} - usedInside="Header" /> = ({post, totalFiles, fileIndex, . ); return (
diff --git a/webapp/channels/src/components/file_preview_modal/file_preview_modal_main_actions/file_preview_modal_main_actions.tsx b/webapp/channels/src/components/file_preview_modal/file_preview_modal_main_actions/file_preview_modal_main_actions.tsx index 20072704ea..ea089e3430 100644 --- a/webapp/channels/src/components/file_preview_modal/file_preview_modal_main_actions/file_preview_modal_main_actions.tsx +++ b/webapp/channels/src/components/file_preview_modal/file_preview_modal_main_actions/file_preview_modal_main_actions.tsx @@ -27,7 +27,6 @@ import './file_preview_modal_main_actions.scss'; const COPIED_TOOLTIP_DURATION = 2000; interface Props { - usedInside?: 'Header' | 'Footer'; showOnlyClose?: boolean; showClose?: boolean; showPublicLink?: boolean; @@ -44,7 +43,6 @@ interface Props { const FilePreviewModalMainActions: React.FC = (props: Props) => { const intl = useIntl(); - const tooltipPlacement = props.usedInside === 'Header' ? 'bottom' : 'top'; const selectedFilePublicLink = useSelector((state: GlobalState) => selectFilePublicLink(state)?.link); const dispatch = useDispatch(); const [publicLinkCopied, setPublicLinkCopied] = useState(false); @@ -74,9 +72,7 @@ const FilePreviewModalMainActions: React.FC = (props: Props) => { }); const closeButton = (
{this.props.fileInfo.post_id && ( )}
{ bodyAction = (
{ /> { onToggle={this.buttonToggleState} > { return ( { /> { return ( { return ( { return ( } - placement='bottom' > { return ( } - placement='bottom' > { let imageURL = ''; let removeImageIcon: JSX.Element | null = ( {triggerElement} diff --git a/webapp/channels/src/components/new_channel_modal/new_channel_modal.tsx b/webapp/channels/src/components/new_channel_modal/new_channel_modal.tsx index 1e7a1c6764..105bac64bd 100644 --- a/webapp/channels/src/components/new_channel_modal/new_channel_modal.tsx +++ b/webapp/channels/src/components/new_channel_modal/new_channel_modal.tsx @@ -221,7 +221,6 @@ const NewChannelModal = () => { const newBoardInfoIcon = (
@@ -238,7 +237,6 @@ const NewChannelModal = () => {
} - placement='right' >
diff --git a/webapp/channels/src/components/new_replies_banner/new_replies_banner.tsx b/webapp/channels/src/components/new_replies_banner/new_replies_banner.tsx index e533d2d5d1..ecbba0aaaf 100644 --- a/webapp/channels/src/components/new_replies_banner/new_replies_banner.tsx +++ b/webapp/channels/src/components/new_replies_banner/new_replies_banner.tsx @@ -62,7 +62,6 @@ function NewRepliesBanner({ onClick={onClick} onDismiss={onDismiss} onClickMessage={onClickMessage} - overlayPlacement='top' width={156} > {tag}
@@ -137,9 +135,7 @@ export default class MarketplaceItem extends React.PureComponent {description}
diff --git a/webapp/channels/src/components/post/post_component.tsx b/webapp/channels/src/components/post/post_component.tsx index 85e2e02fb2..482760e2e6 100644 --- a/webapp/channels/src/components/post/post_component.tsx +++ b/webapp/channels/src/components/post/post_component.tsx @@ -594,14 +594,12 @@ const PostComponent = (props: Props): JSX.Element => { {priority} {post.props && post.props.card && } - placement='top' >
{ return ( {rest.currentUserId === post.user_id && !isInPermalink && ( - + `; exports[`components/post_view/PostFlagIcon should match snapshot 2`] = ` - - + `; diff --git a/webapp/channels/src/components/post_view/post_flag_icon/post_flag_icon.tsx b/webapp/channels/src/components/post_view/post_flag_icon/post_flag_icon.tsx index 0ccc6da973..9ea1264f64 100644 --- a/webapp/channels/src/components/post_view/post_flag_icon/post_flag_icon.tsx +++ b/webapp/channels/src/components/post_view/post_flag_icon/post_flag_icon.tsx @@ -7,7 +7,7 @@ import {FormattedMessage, useIntl} from 'react-intl'; import FlagIcon from 'components/widgets/icons/flag_icon'; import FlagIconFilled from 'components/widgets/icons/flag_icon_filled'; -import WithTooltip from 'components/with_tooltip/with_tooltip_new'; +import WithTooltip from 'components/with_tooltip'; import {Locations, A11yCustomEventTypes} from 'utils/constants'; diff --git a/webapp/channels/src/components/post_view/post_reaction/__snapshots__/post_reaction.test.tsx.snap b/webapp/channels/src/components/post_view/post_reaction/__snapshots__/post_reaction.test.tsx.snap index b360916525..ff24080843 100644 --- a/webapp/channels/src/components/post_view/post_reaction/__snapshots__/post_reaction.test.tsx.snap +++ b/webapp/channels/src/components/post_view/post_reaction/__snapshots__/post_reaction.test.tsx.snap @@ -17,7 +17,7 @@ exports[`components/post_view/PostReaction should match snapshot 1`] = ` target={[MockFunction]} topOffset={-7} /> - - + `; diff --git a/webapp/channels/src/components/post_view/post_reaction/post_reaction.tsx b/webapp/channels/src/components/post_view/post_reaction/post_reaction.tsx index c63d5b3032..06812ba73d 100644 --- a/webapp/channels/src/components/post_view/post_reaction/post_reaction.tsx +++ b/webapp/channels/src/components/post_view/post_reaction/post_reaction.tsx @@ -14,7 +14,7 @@ import {getEmojiName} from 'mattermost-redux/utils/emoji_utils'; import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay'; import ChannelPermissionGate from 'components/permissions_gates/channel_permission_gate'; import EmojiIcon from 'components/widgets/icons/emoji_icon'; -import WithTooltip from 'components/with_tooltip/with_tooltip_new'; +import WithTooltip from 'components/with_tooltip'; import {Locations} from 'utils/constants'; diff --git a/webapp/channels/src/components/post_view/post_recent_reactions/post_recent_reactions.tsx b/webapp/channels/src/components/post_view/post_recent_reactions/post_recent_reactions.tsx index 84bc317279..cb445b201d 100644 --- a/webapp/channels/src/components/post_view/post_recent_reactions/post_recent_reactions.tsx +++ b/webapp/channels/src/components/post_view/post_recent_reactions/post_recent_reactions.tsx @@ -9,7 +9,7 @@ import Permissions from 'mattermost-redux/constants/permissions'; import {getEmojiName} from 'mattermost-redux/utils/emoji_utils'; import ChannelPermissionGate from 'components/permissions_gates/channel_permission_gate'; -import WithTooltip from 'components/with_tooltip/with_tooltip_new'; +import WithTooltip from 'components/with_tooltip'; import {Locations} from 'utils/constants'; diff --git a/webapp/channels/src/components/post_view/post_time/post_time.tsx b/webapp/channels/src/components/post_view/post_time/post_time.tsx index 470ff931c8..9443c3ec58 100644 --- a/webapp/channels/src/components/post_view/post_time/post_time.tsx +++ b/webapp/channels/src/components/post_view/post_time/post_time.tsx @@ -94,8 +94,6 @@ export default class PostTime extends React.PureComponent { return ( = (props: Props) => { }); } + if (!React.isValidElement(children)) { + return null; + } + return ( { permissions={[Permissions.ADD_REACTION]} >
diff --git a/webapp/channels/src/components/profile_popover/profile_popover_full_name.tsx b/webapp/channels/src/components/profile_popover/profile_popover_full_name.tsx index f1ad3a5d00..a3c5d7f9df 100644 --- a/webapp/channels/src/components/profile_popover/profile_popover_full_name.tsx +++ b/webapp/channels/src/components/profile_popover/profile_popover_full_name.tsx @@ -23,7 +23,6 @@ const ProfilePopoverFullName = ({ if (remoteId) { sharedIcon = ( diff --git a/webapp/channels/src/components/profile_popover/profile_popover_self_user_row.tsx b/webapp/channels/src/components/profile_popover/profile_popover_self_user_row.tsx index 59ad907df4..312ef8b3d4 100644 --- a/webapp/channels/src/components/profile_popover/profile_popover_self_user_row.tsx +++ b/webapp/channels/src/components/profile_popover/profile_popover_self_user_row.tsx @@ -67,9 +67,7 @@ const ProfilePopoverSelfUserRow = ({ /> } - placement={'top'} >
- +
{ ); const copyLink = ( @@ -228,113 +161,46 @@ exports[`components/threading/channel_threads/thread_footer should report total onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - + } + tabIndex={-1} + /> + @@ -366,222 +232,88 @@ exports[`components/threading/channel_threads/thread_footer should report total onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - - - - - - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - -
- - - + tabIndex={-1} + url="/api/v4/users/3/image?_=0" + > + user profile image + + + + + + + +
+
@@ -799,8 +531,6 @@ exports[`components/threading/channel_threads/thread_footer should show unread i className="ThreadFooter" > } > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } +
- - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > -
-
-
- - +
+
- } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - + } + tabIndex={-1} + /> + @@ -1076,113 +672,46 @@ exports[`components/threading/channel_threads/thread_footer should show unread i onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - + } + tabIndex={-1} + /> + @@ -1214,222 +743,88 @@ exports[`components/threading/channel_threads/thread_footer should show unread i onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - - - - - - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - -
- - - + tabIndex={-1} + url="/api/v4/users/3/image?_=0" + > + user profile image + + + + + + + +
+
diff --git a/webapp/channels/src/components/threading/channel_threads/thread_footer/thread_footer.tsx b/webapp/channels/src/components/threading/channel_threads/thread_footer/thread_footer.tsx index 3aa0f8a35c..32ba2a3064 100644 --- a/webapp/channels/src/components/threading/channel_threads/thread_footer/thread_footer.tsx +++ b/webapp/channels/src/components/threading/channel_threads/thread_footer/thread_footer.tsx @@ -85,8 +85,6 @@ function ThreadFooter({
) : (
- - +
@@ -1097,102 +1097,37 @@ exports[`component/user_group_popover should match snapshot 1`] = ` className="DMContainer-ilPVMc Cnskx group-member-list_dm-button" > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - - + + +
@@ -1265,7 +1200,7 @@ exports[`component/user_group_popover should match snapshot 1`] = ` - - + @@ -1341,102 +1276,37 @@ exports[`component/user_group_popover should match snapshot 1`] = ` className="DMContainer-ilPVMc Cnskx group-member-list_dm-button" > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - -
+ + +
@@ -1509,7 +1379,7 @@ exports[`component/user_group_popover should match snapshot 1`] = ` - - + @@ -1585,102 +1455,37 @@ exports[`component/user_group_popover should match snapshot 1`] = ` className="DMContainer-ilPVMc Cnskx group-member-list_dm-button" > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - -
+ + +
@@ -1753,7 +1558,7 @@ exports[`component/user_group_popover should match snapshot 1`] = ` - - +
@@ -1829,102 +1634,37 @@ exports[`component/user_group_popover should match snapshot 1`] = ` className="DMContainer-ilPVMc Cnskx group-member-list_dm-button" > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - - + + +
@@ -1997,7 +1737,7 @@ exports[`component/user_group_popover should match snapshot 1`] = ` - - + @@ -2073,102 +1813,37 @@ exports[`component/user_group_popover should match snapshot 1`] = ` className="DMContainer-ilPVMc Cnskx group-member-list_dm-button" > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - -
+ + +
diff --git a/webapp/channels/src/components/user_group_popover/group_member_list/__snapshots__/group_member_list.test.tsx.snap b/webapp/channels/src/components/user_group_popover/group_member_list/__snapshots__/group_member_list.test.tsx.snap index 6de127da9c..e8bf00e2bf 100644 --- a/webapp/channels/src/components/user_group_popover/group_member_list/__snapshots__/group_member_list.test.tsx.snap +++ b/webapp/channels/src/components/user_group_popover/group_member_list/__snapshots__/group_member_list.test.tsx.snap @@ -406,7 +406,7 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1` - - + @@ -482,102 +482,37 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1` className="DMContainer-ilPVMc Cnskx group-member-list_dm-button" > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - - + + + @@ -650,7 +585,7 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1` - - + @@ -726,102 +661,37 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1` className="DMContainer-ilPVMc Cnskx group-member-list_dm-button" > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - - + + + @@ -894,7 +764,7 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1` - - + @@ -970,102 +840,37 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1` className="DMContainer-ilPVMc Cnskx group-member-list_dm-button" > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - - + + + @@ -1138,7 +943,7 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1` - - + @@ -1214,102 +1019,37 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1` className="DMContainer-ilPVMc Cnskx group-member-list_dm-button" > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - - + + + @@ -1382,7 +1122,7 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1` - - + @@ -1458,102 +1198,37 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1` className="DMContainer-ilPVMc Cnskx group-member-list_dm-button" > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } + - - - + + + diff --git a/webapp/channels/src/components/user_group_popover/group_member_list/group_member_list.tsx b/webapp/channels/src/components/user_group_popover/group_member_list/group_member_list.tsx index 04249dd22c..b76163ede6 100644 --- a/webapp/channels/src/components/user_group_popover/group_member_list/group_member_list.tsx +++ b/webapp/channels/src/components/user_group_popover/group_member_list/group_member_list.tsx @@ -197,9 +197,7 @@ const GroupMemberList = (props: Props) => { {userIsRemote && diff --git a/webapp/channels/src/components/user_settings/display/user_settings_theme/custom_theme_chooser/__snapshots__/custom_theme_chooser.test.tsx.snap b/webapp/channels/src/components/user_settings/display/user_settings_theme/custom_theme_chooser/__snapshots__/custom_theme_chooser.test.tsx.snap index de04fa45a9..4eed442c91 100644 --- a/webapp/channels/src/components/user_settings/display/user_settings_theme/custom_theme_chooser/__snapshots__/custom_theme_chooser.test.tsx.snap +++ b/webapp/channels/src/components/user_settings/display/user_settings_theme/custom_theme_chooser/__snapshots__/custom_theme_chooser.test.tsx.snap @@ -428,8 +428,6 @@ exports[`components/user_settings/display/CustomThemeChooser should match, init { {codeThemeOptions} diff --git a/webapp/channels/src/components/widgets/inputs/url_input/url_input.tsx b/webapp/channels/src/components/widgets/inputs/url_input/url_input.tsx index 64f1c7fd5b..d2b3f4717e 100644 --- a/webapp/channels/src/components/widgets/inputs/url_input/url_input.tsx +++ b/webapp/channels/src/components/widgets/inputs/url_input/url_input.tsx @@ -92,9 +92,7 @@ function UrlInput({
{isShortenedURL ? ( {urlInputLabel} diff --git a/webapp/channels/src/components/widgets/menu/menu_items/restricted_indicator.tsx b/webapp/channels/src/components/widgets/menu/menu_items/restricted_indicator.tsx index 8af881cd4a..046cab0880 100644 --- a/webapp/channels/src/components/widgets/menu/menu_items/restricted_indicator.tsx +++ b/webapp/channels/src/components/widgets/menu/menu_items/restricted_indicator.tsx @@ -88,7 +88,6 @@ const RestrictedIndicator = ({ return ( @@ -103,7 +102,6 @@ const RestrictedIndicator = ({
} - placement='right' > {useModal && blocked ? ( diff --git a/webapp/channels/src/components/widgets/public-private-selector/public-private-selector.tsx b/webapp/channels/src/components/widgets/public-private-selector/public-private-selector.tsx index b6299a8a71..e209f13f95 100644 --- a/webapp/channels/src/components/widgets/public-private-selector/public-private-selector.tsx +++ b/webapp/channels/src/components/widgets/public-private-selector/public-private-selector.tsx @@ -80,8 +80,6 @@ const BigButtonSelector = ({ return ( {button} diff --git a/webapp/channels/src/components/widgets/users/avatar/avatar.tsx b/webapp/channels/src/components/widgets/users/avatar/avatar.tsx index 8627adebe6..d784c1f3ce 100644 --- a/webapp/channels/src/components/widgets/users/avatar/avatar.tsx +++ b/webapp/channels/src/components/widgets/users/avatar/avatar.tsx @@ -2,8 +2,8 @@ // See LICENSE.txt for license information. import classNames from 'classnames'; -import React, {memo} from 'react'; -import type {HTMLAttributes, SyntheticEvent} from 'react'; +import React, {memo, forwardRef} from 'react'; +import type {HTMLAttributes, RefObject, SyntheticEvent} from 'react'; import {useIntl} from 'react-intl'; import {Client4} from 'mattermost-redux/client'; @@ -50,13 +50,13 @@ type Attrs = HTMLAttributes; const isURLForUser = (url: string) => url.startsWith(Client4.getUsersRoute()); const replaceURLWithDefaultImageURL = (url: string) => url.replace(/\?_=(\w+)/, '/default'); -const Avatar = ({ +const Avatar = forwardRef(({ url, username, size = 'md', text, ...attrs -}: Props & Attrs) => { +}, ref) => { const {formatMessage} = useIntl(); const classes = classNames(`Avatar Avatar-${size}`, attrs.className); @@ -65,6 +65,7 @@ const Avatar = ({ return (
} className={classNames(classes, 'Avatar-plain')} data-content={text} /> @@ -82,6 +83,7 @@ const Avatar = ({ return ( } className={classes} alt={formatMessage({id: 'avatar.alt', defaultMessage: '{username} profile image'}, { username: username || 'user', @@ -91,5 +93,8 @@ const Avatar = ({ onError={handleOnError} /> ); -}; +}); + +Avatar.displayName = 'Avatar'; + export default memo(Avatar); diff --git a/webapp/channels/src/components/widgets/users/avatars/__snapshots__/avatars.test.tsx.snap b/webapp/channels/src/components/widgets/users/avatars/__snapshots__/avatars.test.tsx.snap index 1cb2cc7aa6..d9db0a7678 100644 --- a/webapp/channels/src/components/widgets/users/avatars/__snapshots__/avatars.test.tsx.snap +++ b/webapp/channels/src/components/widgets/users/avatars/__snapshots__/avatars.test.tsx.snap @@ -44,113 +44,46 @@ exports[`components/widgets/users/Avatars should fetch missing users 1`] = ` onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - + } + tabIndex={-1} + /> + @@ -182,113 +115,46 @@ exports[`components/widgets/users/Avatars should fetch missing users 1`] = ` onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - + } + tabIndex={-1} + /> + @@ -320,222 +186,88 @@ exports[`components/widgets/users/Avatars should fetch missing users 1`] = ` onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - - - - - - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - -
- - - + tabIndex={-1} + url="/api/v4/users/7/image?_=0" + > + user profile image + + + + + + + +
+
@@ -584,113 +316,46 @@ exports[`components/widgets/users/Avatars should properly count overflow 1`] = ` onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - + } + tabIndex={-1} + /> +
@@ -722,113 +387,46 @@ exports[`components/widgets/users/Avatars should properly count overflow 1`] = ` onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - + } + tabIndex={-1} + /> + @@ -860,222 +458,88 @@ exports[`components/widgets/users/Avatars should properly count overflow 1`] = ` onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - - - - - - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - -
- - - + tabIndex={-1} + url="/api/v4/users/3/image?_=1620680333191" + > + user profile image + + + + + + + +
+
@@ -1122,113 +586,46 @@ exports[`components/widgets/users/Avatars should support userIds 1`] = ` onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - + } + tabIndex={-1} + /> +
@@ -1260,113 +657,46 @@ exports[`components/widgets/users/Avatars should support userIds 1`] = ` onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - + } + tabIndex={-1} + /> + @@ -1398,113 +728,46 @@ exports[`components/widgets/users/Avatars should support userIds 1`] = ` onPointerDown={[Function]} > - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] + - - } - placement="top" - trigger={ - Array [ - "hover", - "focus", - ] - } - > - - user profile image - - - + } + tabIndex={-1} + /> + diff --git a/webapp/channels/src/components/widgets/users/avatars/avatars.test.tsx b/webapp/channels/src/components/widgets/users/avatars/avatars.test.tsx index 8d7bebc388..d187e61fbb 100644 --- a/webapp/channels/src/components/widgets/users/avatars/avatars.test.tsx +++ b/webapp/channels/src/components/widgets/users/avatars/avatars.test.tsx @@ -4,6 +4,14 @@ import {mount} from 'enzyme'; import React from 'react'; +import WithTooltip from 'components/with_tooltip'; + +import {mockStore} from 'tests/test_store'; + +import Avatars from './avatars'; + +import Avatar from '../avatar'; + jest.mock('mattermost-redux/actions/users', () => { return { ...jest.requireActual('mattermost-redux/actions/users'), @@ -16,14 +24,6 @@ jest.mock('mattermost-redux/actions/users', () => { }; }); -import WithTooltip from 'components/with_tooltip'; - -import {mockStore} from 'tests/test_store'; - -import Avatars from './avatars'; - -import Avatar from '../avatar'; - describe('components/widgets/users/Avatars', () => { const state = { entities: { @@ -149,7 +149,7 @@ describe('components/widgets/users/Avatars', () => { mountOptions, ); - expect(wrapper.find(WithTooltip).find({id: 'names-overflow'}).prop('title')).toBe('first.last4, first.last5'); + expect(wrapper.find(WithTooltip).find({title: 'first.last4, first.last5'})).toBeDefined(); }); test('should fetch missing users', () => { @@ -178,6 +178,6 @@ describe('components/widgets/users/Avatars', () => { expect(wrapper.find(Avatar).find({url: '/api/v4/users/1/image?_=1620680333191'}).exists()).toBe(true); expect(wrapper.find(Avatar).find({url: '/api/v4/users/6/image?_=0'}).exists()).toBe(true); expect(wrapper.find(Avatar).find({url: '/api/v4/users/7/image?_=0'}).exists()).toBe(true); - expect(wrapper.find(WithTooltip).find({id: 'names-overflow'}).prop('title')).toBe('first.last2, Someone, Someone'); + expect(wrapper.find(WithTooltip).find({title: 'first.last2, Someone, Someone'}).exists()).toBe(true); }); }); diff --git a/webapp/channels/src/components/widgets/users/avatars/avatars.tsx b/webapp/channels/src/components/widgets/users/avatars/avatars.tsx index 5ff2e7a0d9..e538ac606a 100644 --- a/webapp/channels/src/components/widgets/users/avatars/avatars.tsx +++ b/webapp/channels/src/components/widgets/users/avatars/avatars.tsx @@ -68,9 +68,7 @@ function UserAvatar({ src={profilePictureURL} > , 'children' | 'id'>) => { - const contents = []; - - if (commonTooltipProps.emoji && commonTooltipProps.emojiStyle === 'large') { - contents.push( -
- -
, - ); - } - - const title = formatAsComponent(commonTooltipProps.title); - if (commonTooltipProps.emoji && commonTooltipProps.emojiStyle !== 'large') { - contents.push( -
- - {title} -
, - ); - } else { - contents.push( -
- {title} -
, - ); - } - - if (commonTooltipProps.shortcut) { - contents.push( -
- -
, - ); - } - - const hint = formatAsComponent(commonTooltipProps.hint); - if (commonTooltipProps.hint) { - contents.push( -
- {hint} -
, - ); - } - - return ( - - {contents} - - ); - }; -} diff --git a/webapp/channels/src/components/with_tooltip/with_tooltip_new/index.test.tsx b/webapp/channels/src/components/with_tooltip/index.test.tsx similarity index 100% rename from webapp/channels/src/components/with_tooltip/with_tooltip_new/index.test.tsx rename to webapp/channels/src/components/with_tooltip/index.test.tsx diff --git a/webapp/channels/src/components/with_tooltip/index.tsx b/webapp/channels/src/components/with_tooltip/index.tsx index e446097195..a9785359dd 100644 --- a/webapp/channels/src/components/with_tooltip/index.tsx +++ b/webapp/channels/src/components/with_tooltip/index.tsx @@ -1,59 +1,211 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useMemo} from 'react'; -import type {ComponentProps} from 'react'; +import type {Placement} from '@floating-ui/react'; +import { + useFloating, + autoUpdate, + offset, + useHover, + useFocus, + useDismiss, + useRole, + useInteractions, + arrow, + FloatingPortal, + useTransitionStyles, + FloatingArrow, + flip, + useMergeRefs, +} from '@floating-ui/react'; +import classNames from 'classnames'; +import React, {useRef, useState, useMemo, cloneElement, isValidElement} from 'react'; +import type {ReactElement, ReactNode} from 'react'; +import type {MessageDescriptor} from 'react-intl'; +import {defineMessage} from 'react-intl'; -import Constants from 'utils/constants'; +import {Constants} from 'utils/constants'; -import type {CommonTooltipProps} from './create_tooltip'; -import {createTooltip} from './create_tooltip'; -import OverlayTrigger from './overlay_trigger'; +import TooltipContent from './tooltip_content'; +import type {ShortcutDefinition} from './tooltip_shortcut'; -type OverlayTriggerProps = ComponentProps; +import './tooltip.scss'; -type WithTooltipProps = { - children: OverlayTriggerProps['children']; - placement: OverlayTriggerProps['placement']; - onShow?: () => void; - delayHide?: number; - disabled?: boolean; -} & CommonTooltipProps; +const ARROW_WIDTH = 10; // in px +const ARROW_HEIGHT = 6; // in px +const ARROW_OFFSET = 8; // in px -const WithTooltip = ({ - id, - title, - emoji, - emojiStyle, - hint, - shortcut, - placement, - onShow, - delayHide, - children, - disabled = false, -}: WithTooltipProps) => { - const ThisTooltip = useMemo(() => createTooltip({ - id, - title, - emoji, - emojiStyle, - hint, - shortcut, - }), [id, title, emoji, emojiStyle, hint, shortcut]); +const TOOLTIP_REST_TIME_BEFORE_OPEN = 400; // in ms +const TOOLTIP_APPEAR_DURATION = 250; // in ms +const TOOLTIP_DISAPPEAR_DURATION = 200; // in ms - return ( - } - placement={placement} - onEnter={onShow} - delayHide={delayHide} - disabled={disabled} - > - {children} - - ); +export const ShortcutKeys = { + alt: defineMessage({ + id: 'shortcuts.generic.alt', + defaultMessage: 'Alt', + }), + cmd: '⌘', + ctrl: defineMessage({ + id: 'shortcuts.generic.ctrl', + defaultMessage: 'Ctrl', + }), + option: '⌥', + shift: defineMessage({ + id: 'shortcuts.generic.shift', + defaultMessage: 'Shift', + }), }; +interface Props { + title: string | ReactNode | MessageDescriptor; + emoji?: string; + isEmojiLarge?: boolean; + hint?: string | ReactNode | MessageDescriptor; + shortcut?: ShortcutDefinition; + + /** + * Whether the tooltip should be vertical or horizontal, by default it is vertical + * This doesn't always guarantee the tooltip will be vertical, it just determines the initial placement and fallback placements + */ + isVertical?: boolean; + tooltipContentContainerClassName?: string; + disabled?: boolean; + + /** + * @deprecated Do not use this except for special cases + * Callback when the tooltip appears + */ + onOpen?: () => void; + children: ReactElement; +} + +function WithTooltip({ + children, + title, + emoji, + isEmojiLarge = false, + hint, + shortcut, + isVertical = true, + tooltipContentContainerClassName, + onOpen, + disabled, +}: Props) { + const [open, setOpen] = useState(false); + + const arrowRef = useRef(null); + + function handleChange(open: boolean) { + setOpen(open); + + if (onOpen && open) { + onOpen(); + } + } + + const placements = useMemo<{initial: Placement; fallback: Placement[]}>(() => { + let initial: Placement; + let fallback: Placement[]; + if (isVertical) { + initial = 'top'; + fallback = ['bottom', 'right', 'left']; + } else { + initial = 'right'; + fallback = ['left', 'top', 'bottom']; + } + return {initial, fallback}; + }, [isVertical]); + + const {refs: {setReference, setFloating}, floatingStyles, context} = useFloating({ + open: disabled ? false : open, + onOpenChange: handleChange, + whileElementsMounted: autoUpdate, + placement: placements.initial, + middleware: [ + offset(ARROW_OFFSET), + flip({ + fallbackPlacements: placements.fallback, + }), + arrow({ + element: arrowRef, + }), + ], + }); + + const hover = useHover(context, { + restMs: TOOLTIP_REST_TIME_BEFORE_OPEN, + delay: { + open: Constants.OVERLAY_TIME_DELAY, + }, + }); + const focus = useFocus(context); + const dismiss = useDismiss(context); + const role = useRole(context, {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 trigger = cloneElement(children, { + ...getReferenceProps({ + ref: mergedRefs, + ...children.props, + }), + }); + + return ( + <> + {trigger} + {isMounted && ( + +
+
+ + +
+
+
+ )} + + ); +} + export default WithTooltip; diff --git a/webapp/channels/src/components/with_tooltip/overlay_trigger.tsx b/webapp/channels/src/components/with_tooltip/overlay_trigger.tsx deleted file mode 100644 index 927cc14067..0000000000 --- a/webapp/channels/src/components/with_tooltip/overlay_trigger.tsx +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React from 'react'; -import {OverlayTrigger as OriginalOverlayTrigger} from 'react-bootstrap'; // eslint-disable-line no-restricted-imports -import type {OverlayTriggerProps} from 'react-bootstrap'; -import {IntlContext} from 'react-intl'; -import type {IntlShape} from 'react-intl'; -import {Provider, useStore} from 'react-redux'; - -export type BaseOverlayTrigger = OriginalOverlayTrigger & { - hide: () => void; -}; - -type Props = OverlayTriggerProps & { - disabled?: boolean; - className?: string; -}; - -/** - * @deprecated Use (and expand when strictly needed) WithTooltip instead - */ -const OverlayTrigger = React.forwardRef((props: Props, ref?: React.Ref) => { - const {overlay, disabled, ...otherProps} = props; - - const store = useStore(); - - // The overlay is rendered outside of the regular React context, and our version react-bootstrap can't forward - // that context itself, so we have to manually forward the react-intl context to this component's child. - const OverlayWrapper = ({intl, ...overlayProps}: {intl: IntlShape}) => ( - - {React.cloneElement(overlay, overlayProps)} - - ); - - return ( - - {(intl): React.ReactNode => { - const overlayProps = {...overlay.props}; - if (disabled) { - overlayProps.style = {visibility: 'hidden', ...overlayProps.style}; - } - return ( - - } - /> - ); - }} - - ); -}); - -OverlayTrigger.defaultProps = { - defaultOverlayShown: false, - trigger: ['hover', 'focus'], -}; -OverlayTrigger.displayName = 'OverlayTrigger'; - -export default OverlayTrigger; diff --git a/webapp/channels/src/components/with_tooltip/shortcut.tsx b/webapp/channels/src/components/with_tooltip/shortcut.tsx deleted file mode 100644 index 4e628f401f..0000000000 --- a/webapp/channels/src/components/with_tooltip/shortcut.tsx +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React from 'react'; -import type {MessageDescriptor} from 'react-intl'; -import {FormattedMessage, defineMessage} from 'react-intl'; - -import {ShortcutKey, ShortcutKeyVariant} from 'components/shortcut_key'; - -import {isMessageDescriptor} from 'utils/i18n'; -import {isMac} from 'utils/user_agent'; - -export type ShortcutDefinition = { - default: ShortcutKeyDescriptor[]; - mac?: ShortcutKeyDescriptor[]; -} -export type ShortcutKeyDescriptor = string | MessageDescriptor; - -export const ShortcutKeys = { - alt: defineMessage({ - id: 'shortcuts.generic.alt', - defaultMessage: 'Alt', - }), - cmd: '⌘', - ctrl: defineMessage({ - id: 'shortcuts.generic.ctrl', - defaultMessage: 'Ctrl', - }), - option: '⌥', - shift: defineMessage({ - id: 'shortcuts.generic.shift', - defaultMessage: 'Shift', - }), -}; - -type Props = { - shortcut: ShortcutDefinition; -} - -export function TooltipShortcutSequence(props: Props) { - let shortcut = props.shortcut.default; - if (props.shortcut.mac && isMac()) { - shortcut = props.shortcut.mac; - } - - return ( - <> - {shortcut.map((v) => { - let key; - let content; - if (isMessageDescriptor(v)) { - key = v.id; - content = ; - } else { - key = v; - content = v; - } - - return ( - - {content} - - ); - })} - - ); -} diff --git a/webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip.scss b/webapp/channels/src/components/with_tooltip/tooltip.scss similarity index 100% rename from webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip.scss rename to webapp/channels/src/components/with_tooltip/tooltip.scss diff --git a/webapp/channels/src/components/with_tooltip/tooltip.tsx b/webapp/channels/src/components/with_tooltip/tooltip.tsx deleted file mode 100644 index a013193988..0000000000 --- a/webapp/channels/src/components/with_tooltip/tooltip.tsx +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React from 'react'; -import type {CSSProperties} from 'react'; -import {Tooltip as RBTooltip} from 'react-bootstrap'; - -type Props = { - id?: string; - className?: string; - style?: CSSProperties; - children?: React.ReactNode; - positionLeft?: number; - placement?: string; -}; - -/** - * @deprecated Use (and expand when extrictly needed) WithTooltip instead - */ -export default function Tooltip(props: Props) { - return ( - - {props.children} - - ); -} diff --git a/webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip_content.test.tsx b/webapp/channels/src/components/with_tooltip/tooltip_content.test.tsx similarity index 100% rename from webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip_content.test.tsx rename to webapp/channels/src/components/with_tooltip/tooltip_content.test.tsx diff --git a/webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip_content.tsx b/webapp/channels/src/components/with_tooltip/tooltip_content.tsx similarity index 89% rename from webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip_content.tsx rename to webapp/channels/src/components/with_tooltip/tooltip_content.tsx index 35c4552aa5..c865916e71 100644 --- a/webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip_content.tsx +++ b/webapp/channels/src/components/with_tooltip/tooltip_content.tsx @@ -21,7 +21,7 @@ interface Props { title: string | ReactNode | MessageDescriptor; emoji?: string; isEmojiLarge?: boolean; - hint?: string; + hint?: string | ReactNode | MessageDescriptor; shortcut?: ShortcutDefinition; } @@ -33,6 +33,11 @@ function TooltipContent(props: Props) { title = formatMessage(title); } + let hint = props.hint; + if (isMessageDescriptor(hint)) { + hint = formatMessage(hint); + } + return (
{title} {props.hint && ( - {props.hint} + {hint} )} {props.shortcut && ( diff --git a/webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip_shortcut.test.tsx b/webapp/channels/src/components/with_tooltip/tooltip_shortcut.test.tsx similarity index 100% rename from webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip_shortcut.test.tsx rename to webapp/channels/src/components/with_tooltip/tooltip_shortcut.test.tsx diff --git a/webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip_shortcut.tsx b/webapp/channels/src/components/with_tooltip/tooltip_shortcut.tsx similarity index 74% rename from webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip_shortcut.tsx rename to webapp/channels/src/components/with_tooltip/tooltip_shortcut.tsx index e18de69495..2674be3ac8 100644 --- a/webapp/channels/src/components/with_tooltip/with_tooltip_new/tooltip_shortcut.tsx +++ b/webapp/channels/src/components/with_tooltip/tooltip_shortcut.tsx @@ -3,14 +3,31 @@ import React, {memo} from 'react'; import type {MessageDescriptor} from 'react-intl'; -import {FormattedMessage} from 'react-intl'; +import {defineMessage, FormattedMessage} from 'react-intl'; import {ShortcutKey, ShortcutKeyVariant} from 'components/shortcut_key'; import {isMessageDescriptor} from 'utils/i18n'; import {isMac} from 'utils/user_agent'; -export type ShortcutKeyDescriptor = string | MessageDescriptor; +export const ShortcutKeys = { + alt: defineMessage({ + id: 'shortcuts.generic.alt', + defaultMessage: 'Alt', + }), + cmd: '⌘', + ctrl: defineMessage({ + id: 'shortcuts.generic.ctrl', + defaultMessage: 'Ctrl', + }), + option: '⌥', + shift: defineMessage({ + id: 'shortcuts.generic.shift', + defaultMessage: 'Shift', + }), +}; + +type ShortcutKeyDescriptor = string | MessageDescriptor; export type ShortcutDefinition = { default: ShortcutKeyDescriptor[]; diff --git a/webapp/channels/src/components/with_tooltip/with_tooltip_new/index.tsx b/webapp/channels/src/components/with_tooltip/with_tooltip_new/index.tsx deleted file mode 100644 index 8db8fa98c0..0000000000 --- a/webapp/channels/src/components/with_tooltip/with_tooltip_new/index.tsx +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import type {Placement} from '@floating-ui/react'; -import { - useFloating, - autoUpdate, - offset, - useHover, - useFocus, - useDismiss, - useRole, - useInteractions, - arrow, - FloatingPortal, - useTransitionStyles, - FloatingArrow, - flip, -} from '@floating-ui/react'; -import React, {useRef, useState, memo, useMemo, cloneElement, isValidElement} from 'react'; -import type {ReactNode} from 'react'; -import type {MessageDescriptor} from 'react-intl'; -import {defineMessage} from 'react-intl'; - -import {Constants} 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 - -export const ShortcutKeys = { - alt: defineMessage({ - id: 'shortcuts.generic.alt', - defaultMessage: 'Alt', - }), - cmd: '⌘', - ctrl: defineMessage({ - id: 'shortcuts.generic.ctrl', - defaultMessage: 'Ctrl', - }), - option: '⌥', - shift: defineMessage({ - id: 'shortcuts.generic.shift', - defaultMessage: 'Shift', - }), -}; - -interface Props { - title: string | ReactNode | MessageDescriptor; - emoji?: string; - isEmojiLarge?: boolean; - hint?: string; - shortcut?: ShortcutDefinition; - - /** - * Whether the tooltip should be vertical or horizontal, by default it is vertical - * This doesn't always guarantee the tooltip will be vertical, it just determines the initial placement and fallback placements - */ - isVertical?: boolean; - - /** - * @deprecated Do not use this except for special cases - * Callback when the tooltip appears - */ - onOpen?: () => void; - children: ReactNode; -} - -function WithTooltip({ - children, - title, - emoji, - isEmojiLarge = false, - hint, - shortcut, - isVertical = true, - onOpen, -}: Props) { - const [open, setOpen] = useState(false); - - const arrowRef = useRef(null); - - function handleChange(open: boolean) { - setOpen(open); - - if (onOpen && open) { - onOpen(); - } - } - - const placements = useMemo<{initial: Placement; fallback: Placement[]}>(() => { - let initial: Placement; - let fallback: Placement[]; - if (isVertical) { - initial = 'top'; - fallback = ['bottom', 'right', 'left']; - } else { - initial = 'right'; - fallback = ['left', 'top', 'bottom']; - } - return {initial, fallback}; - }, [isVertical]); - - const {refs: {setReference, setFloating}, floatingStyles, context} = useFloating({ - open, - onOpenChange: handleChange, - whileElementsMounted: autoUpdate, - placement: placements.initial, - middleware: [ - offset(ARROW_OFFSET), - flip({ - fallbackPlacements: placements.fallback, - }), - arrow({ - element: arrowRef, - }), - ], - }); - - const hover = useHover(context, { - restMs: TOOLTIP_REST_TIME_BEFORE_OPEN, - delay: { - open: Constants.OVERLAY_TIME_DELAY, - }, - }); - const focus = useFocus(context); - const dismiss = useDismiss(context); - const role = useRole(context, {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'); - return null; - } - - const trigger = cloneElement(children, { - ...getReferenceProps({ - ref: setReference, - ...children.props, - }), - }); - - return ( - <> - {trigger} - {isMounted && ( - -
-
- - -
-
-
- )} - - ); -} - -export default memo(WithTooltip); diff --git a/webapp/channels/src/plugins/channel_header_plug/channel_header_plug.tsx b/webapp/channels/src/plugins/channel_header_plug/channel_header_plug.tsx index e724d84ff7..28dfac9350 100644 --- a/webapp/channels/src/plugins/channel_header_plug/channel_header_plug.tsx +++ b/webapp/channels/src/plugins/channel_header_plug/channel_header_plug.tsx @@ -329,8 +329,6 @@ class ChannelHeaderPlug extends React.PureComponent