diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_profile.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_profile.tsx
index 9bc47a2435..7ed691d2e9 100644
--- a/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_profile.tsx
+++ b/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_profile.tsx
@@ -71,7 +71,6 @@ export function TeamProfile({team, isArchived, onToggleArchive, isDisabled, save
hint={defineMessage({id: 'workspace_limits.teams_limit_reached.tool_tip', defaultMessage: 'You\'ve reached the team limit for your current plan. Consider upgrading to unarchive this team or archive your other teams'})}
placement='bottom'
>
- {/* OverlayTrigger doesn't play nicely with `disabled` buttons, because the :hover events don't fire. This is a workaround to ensure the popover appears see: https://github.com/react-bootstrap/react-bootstrap/issues/1588*/}
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 4794972a9f..20072704ea 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
@@ -24,6 +24,8 @@ import type {LinkInfo} from '../types';
import './file_preview_modal_main_actions.scss';
+const COPIED_TOOLTIP_DURATION = 2000;
+
interface Props {
usedInside?: 'Header' | 'Footer';
showOnlyClose?: boolean;
@@ -52,6 +54,15 @@ const FilePreviewModalMainActions: React.FC
= (props: Props) => {
dispatch(getFilePublicLink(props.fileInfo.id));
}
}, [props.fileInfo, props.enablePublicLink]);
+
+ useEffect(() => {
+ if (publicLinkCopied) {
+ setTimeout(() => {
+ setPublicLinkCopied(false);
+ }, COPIED_TOOLTIP_DURATION);
+ }
+ }, [publicLinkCopied]);
+
const copyPublicLink = () => {
copyToClipboard(selectedFilePublicLink ?? '');
setPublicLinkCopied(true);
@@ -96,8 +107,6 @@ const FilePreviewModalMainActions: React.FC = (props: Props) => {
key='filePreviewPublicLink'
placement={tooltipPlacement}
title={publicTooltipMessage}
- shouldUpdatePosition={true}
- onExit={() => setPublicLinkCopied(false)}
>
+
-
- Jump to recents
+
+
+
+
+
+
+ Jump to recents
+
+
+ child
+
-
- child
-
-
-
}
- placement="bottom"
- trigger={
- Array [
- "hover",
- "focus",
- ]
- }
- >
-
+
`;
exports[`components/Toast should match snapshot for showing toast 1`] = `
-
+
-
- Jump to recents
-
-
- child
-
-
-
-
-
-
-
-
- }
- placement="bottom"
- trigger={
- Array [
- "hover",
- "focus",
- ]
- }
- >
-
-
+
+
+
+
+
+ Jump to recents
+
+
+ child
+
-
+
+
`;
exports[`components/Toast should match snapshot for toast width less than 780px 1`] = `
-
+
-
- Jump to recents
-
-
- child
-
-
-
-
-
-
-
-
- }
- placement="bottom"
- trigger={
- Array [
- "hover",
- "focus",
- ]
- }
- >
-
-
+
+
+
+
+
+ Jump to recents
+
+
+ child
+
-
+
+
`;
exports[`components/Toast should match snapshot to have extraClasses 1`] = `
-
+
-
-
-
-
-
-
- }
- placement="bottom"
- trigger={
- Array [
- "hover",
- "focus",
- ]
- }
- >
-
-
+
+
+
+
+
+ Jump to recents
+
+
+ child
+
-
+
+
`;
exports[`components/Toast should match snapshot to not have actions 1`] = `
-
+
-
- child
-
-
-
}
- placement="bottom"
- trigger={
- Array [
- "hover",
- "focus",
- ]
- }
+ class="toast toast__visible"
>
-
+
+ child
+
-
+
+
`;
diff --git a/webapp/channels/src/components/toast/toast.test.tsx b/webapp/channels/src/components/toast/toast.test.tsx
index 26d44f2ed3..aaa548f0d2 100644
--- a/webapp/channels/src/components/toast/toast.test.tsx
+++ b/webapp/channels/src/components/toast/toast.test.tsx
@@ -1,11 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {shallow} from 'enzyme';
import React from 'react';
+import {FormattedMessage} from 'react-intl';
import {renderWithContext, screen} from 'tests/react_testing_utils';
-import * as Utils from 'utils/utils';
import Toast from './toast';
import type {Props} from './toast';
@@ -15,30 +14,34 @@ describe('components/Toast', () => {
onClick: jest.fn(),
show: true,
showActions: true,
- onClickMessage: Utils.localizeMessage('postlist.toast.scrollToBottom', 'Jump to recents'),
+ onClickMessage: (
+
+ ),
width: 1000,
};
test('should match snapshot for showing toast', () => {
- const wrapper = shallow({'child'} );
- expect(wrapper).toMatchSnapshot();
+ const {container} = renderWithContext({'child'} );
+ expect(container).toMatchSnapshot();
+ expect(screen.getByTestId('dismissToast')).toBeInTheDocument();
});
test('should match snapshot for hiding toast', () => {
- const wrapper = shallow({'child'} );
- expect(wrapper).toMatchSnapshot();
- expect(wrapper.find('.toast__visible').length).toBe(0);
+ const {container} = renderWithContext({'child'} );
+ expect(container).toMatchSnapshot();
});
test('should match snapshot for toast width less than 780px', () => {
- const wrapper = shallow({'child'} );
- expect(wrapper).toMatchSnapshot();
+ const {container} = renderWithContext({'child'} );
+ expect(container).toMatchSnapshot();
});
test('should match snapshot to not have actions', () => {
- const wrapper = shallow({'child'} );
- expect(wrapper).toMatchSnapshot();
- expect(wrapper.find('.toast__pointer').length).toBe(0);
+ const {container} = renderWithContext({'child'} );
+ expect(container).toMatchSnapshot();
});
test('should dismiss', () => {
@@ -56,7 +59,7 @@ describe('components/Toast', () => {
});
test('should match snapshot to have extraClasses', () => {
- const wrapper = shallow({'child'} );
- expect(wrapper).toMatchSnapshot();
+ const {container} = renderWithContext({'child'} );
+ expect(container).toMatchSnapshot();
});
});
diff --git a/webapp/channels/src/components/toast/toast.tsx b/webapp/channels/src/components/toast/toast.tsx
index 9ce0011cc3..efe4f64476 100644
--- a/webapp/channels/src/components/toast/toast.tsx
+++ b/webapp/channels/src/components/toast/toast.tsx
@@ -1,16 +1,15 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
+import classNames from 'classnames';
import React from 'react';
import type {ReactNode, MouseEventHandler} from 'react';
-import type {OverlayTriggerProps} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl';
-import OverlayTrigger from 'components/overlay_trigger';
-import Tooltip from 'components/tooltip';
import CloseIcon from 'components/widgets/icons/close_icon';
import UnreadAboveIcon from 'components/widgets/icons/unread_above_icon';
import UnreadBelowIcon from 'components/widgets/icons/unread_below_icon';
+import WithTooltip from 'components/with_tooltip';
import Constants from 'utils/constants';
@@ -18,111 +17,88 @@ import './toast.scss';
export type Props = {
onClick?: MouseEventHandler;
- onClickMessage?: string;
+ onClickMessage?: ReactNode;
onDismiss?: () => void;
children?: ReactNode;
show: boolean;
showActions?: boolean; //used for showing jump actions
width: number;
extraClasses?: string;
- overlayPlacement?: OverlayTriggerProps['placement'];
+ overlayPlacement?: string;
jumpDirection?: 'up' | 'down';
-}
+};
-export default class Toast extends React.PureComponent {
- private mounted!: boolean;
-
- static defaultProps = {
- overlayPlacement: 'bottom',
- jumpDirection: 'down',
- };
-
- componentDidMount() {
- this.mounted = true;
+export default function Toast({
+ onClick,
+ onClickMessage,
+ onDismiss,
+ children,
+ show,
+ showActions,
+ width,
+ extraClasses = '',
+ overlayPlacement = 'bottom',
+ jumpDirection = 'down',
+}: Props) {
+ function handleDismiss() {
+ if (typeof onDismiss === 'function') {
+ onDismiss();
+ }
}
- componentWillUnmount() {
- this.mounted = false;
- }
+ const toastClass = classNames('toast', {
+ toast__visible: show,
+ [extraClasses]: extraClasses.length > 0,
+ });
- handleDismiss = () => {
- if (typeof this.props.onDismiss == 'function') {
- this.props.onDismiss();
- }
- };
+ const toastActionClass = classNames('toast__message', {
+ toast__pointer: showActions,
+ });
- render() {
- let toastClass = 'toast';
- const {show, extraClasses, showActions, width, overlayPlacement, jumpDirection} = this.props;
-
- if (extraClasses) {
- toastClass += ` ${extraClasses}`;
- }
-
- if (show) {
- toastClass += ' toast__visible';
- }
-
- let toastActionClass = 'toast__message';
- if (showActions) {
- toastActionClass += ' toast__pointer';
- }
-
- const jumpSection = () => {
- return (
-
- {jumpDirection === 'down' ? : }
- {width > Constants.MOBILE_SCREEN_WIDTH && this.props.onClickMessage}
-
- );
- };
-
- let closeTooltip = (
);
- if (showActions && show) {
- closeTooltip = (
-
-
-
-
+ return (
+
+
+ {showActions && (
+
+ {jumpDirection === 'down' ? ( ) : ( )}
+ {width > Constants.MOBILE_SCREEN_WIDTH && onClickMessage}
-
- );
- }
-
- return (
-
-
- {showActions && jumpSection()}
- {this.props.children}
-
-
-
-
-
-
+ )}
+ {children}
- );
- }
+
+
+
+
+
+ >
+ }
+ disabled={!showActions || !show}
+ >
+
+
+
+
+
+ );
}
diff --git a/webapp/channels/src/components/toast_wrapper/toast_wrapper.tsx b/webapp/channels/src/components/toast_wrapper/toast_wrapper.tsx
index a4e9d07d4b..72c8102a06 100644
--- a/webapp/channels/src/components/toast_wrapper/toast_wrapper.tsx
+++ b/webapp/channels/src/components/toast_wrapper/toast_wrapper.tsx
@@ -393,7 +393,12 @@ export class ToastWrapperClass extends React.PureComponent
{
width,
onDismiss: this.hideUnreadToast,
onClick: this.scrollToLatestMessages,
- onClickMessage: localizeMessage('postlist.toast.scrollToBottom', 'Jump to recents'),
+ onClickMessage: (
+
+ ),
showActions: !atLatestPost || (atLatestPost && (atBottom === false)),
};
@@ -410,7 +415,12 @@ export class ToastWrapperClass extends React.PureComponent {
width,
onDismiss: this.hideUnreadWithBottomStartToast,
onClick: this.scrollToUnreadMessages,
- onClickMessage: localizeMessage('postlist.toast.scrollToUnread', 'Jump to unreads'),
+ onClickMessage: (
+
+ ),
showActions: true,
jumpDirection: 'up' as const,
};
@@ -427,7 +437,12 @@ export class ToastWrapperClass extends React.PureComponent {
const showNewMessagesToastOverrides = {
onDismiss: this.hideNewMessagesToast,
onClick: this.scrollToNewMessage,
- onClickMessage: localizeMessage('postlist.toast.scrollToLatest', 'Jump to new messages'),
+ onClickMessage: (
+
+ ),
};
return (
diff --git a/webapp/channels/src/components/widgets/simple_tooltip/index.ts b/webapp/channels/src/components/widgets/simple_tooltip/index.ts
index 763cc9068d..2557ec70ca 100644
--- a/webapp/channels/src/components/widgets/simple_tooltip/index.ts
+++ b/webapp/channels/src/components/widgets/simple_tooltip/index.ts
@@ -3,5 +3,4 @@
export {
default,
- useSynchronizedImmediate,
} from './simple_tooltip';
diff --git a/webapp/channels/src/components/widgets/simple_tooltip/simple_tooltip.tsx b/webapp/channels/src/components/widgets/simple_tooltip/simple_tooltip.tsx
index e5fc59b57d..562e18193a 100644
--- a/webapp/channels/src/components/widgets/simple_tooltip/simple_tooltip.tsx
+++ b/webapp/channels/src/components/widgets/simple_tooltip/simple_tooltip.tsx
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import React, {useState, useMemo} from 'react';
+import React from 'react';
import type {ReactNode, ComponentProps, CSSProperties} from 'react';
import OverlayTrigger from 'components/overlay_trigger';
@@ -48,16 +48,3 @@ const SimpleTooltip = ({
};
export default SimpleTooltip;
-
-export function useSynchronizedImmediate(): [Partial>, (isImmediate: boolean) => void] {
- const [isImmediate, setImmediate] = useState(false);
-
- return [
- useMemo((): Partial> => ({
- onEntered: () => setImmediate(true),
- animation: !isImmediate,
- delayShow: isImmediate ? 0 : undefined,
- }), [isImmediate, setImmediate]),
- setImmediate,
- ];
-}
diff --git a/webapp/channels/src/components/with_tooltip/create_tooltip.tsx b/webapp/channels/src/components/with_tooltip/create_tooltip.tsx
index f3817b1218..7446f95b45 100644
--- a/webapp/channels/src/components/with_tooltip/create_tooltip.tsx
+++ b/webapp/channels/src/components/with_tooltip/create_tooltip.tsx
@@ -20,7 +20,6 @@ export type CommonTooltipProps = {
shortcut?: ShortcutDefinition;
emoji?: string;
emojiStyle?: EmojiStyle;
- shouldUpdatePosition?: boolean;
}
export function createTooltip(commonTooltipProps: CommonTooltipProps) {
diff --git a/webapp/channels/src/components/with_tooltip/index.tsx b/webapp/channels/src/components/with_tooltip/index.tsx
index 2ee215ac6d..84a603ea9c 100644
--- a/webapp/channels/src/components/with_tooltip/index.tsx
+++ b/webapp/channels/src/components/with_tooltip/index.tsx
@@ -18,7 +18,6 @@ type WithTooltipProps = {
placement: OverlayTriggerProps['placement'];
onShow?: () => void;
delayHide?: number;
- onExit?: () => void;
disabled?: boolean;
} & CommonTooltipProps;
const WithTooltip = ({
@@ -32,8 +31,6 @@ const WithTooltip = ({
onShow,
delayHide,
children,
- onExit,
- shouldUpdatePosition,
disabled = false,
}: WithTooltipProps) => {
const ThisTooltip = useMemo(() => createTooltip({
@@ -52,8 +49,6 @@ const WithTooltip = ({
placement={placement}
onEnter={onShow}
delayHide={delayHide}
- onExit={onExit}
- shouldUpdatePosition={shouldUpdatePosition}
disabled={disabled}
>
{children}
diff --git a/webapp/channels/src/types/external/react-bootstrap.d.ts b/webapp/channels/src/types/external/react-bootstrap.d.ts
deleted file mode 100644
index 310768cd79..0000000000
--- a/webapp/channels/src/types/external/react-bootstrap.d.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-// Here we are extending the Interface defined by @types/react-bootstrap to include out own
-// additional types, this soon will be not needed when we upgrade React-Bootstrap version to latest
-// Until that happens this is the fix
-
-import * as React from 'react';
-import type {OverlayTriggerProps} from 'react-bootstrap';
-
-export interface AdditionalOverlayTriggerProps extends React.ComponentPropsWithRef {
-
- className?: string;
- overlay: any;
-}
-
-declare class OverlayTrigger extends React.Component {}
-
-declare module 'react-bootstrap' {
- export {OverlayTrigger};
-}