Skip to content

Commit

Permalink
Fix #3272: Toast do not timeout while mouse has focus (#3273)
Browse files Browse the repository at this point in the history
  • Loading branch information
melloware authored Sep 9, 2022
1 parent 3b817f0 commit fd07f37
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 14 deletions.
22 changes: 22 additions & 0 deletions api-generator/components/toast.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,28 @@ const ToastEvents = [
name: 'onHide',
description: 'Callback to invoke when message becomes hidden.',
arguments: []
},
{
name: 'onMouseEnter',
description: 'Callback to invoke when a message gets focus with mouse.',
arguments: [
{
name: 'event',
type: 'MouseEvent',
description: 'Mouse Event'
}
]
},
{
name: 'onMouseLeave',
description: 'Callback to invoke when a message loses focus with mouse.',
arguments: [
{
name: 'event',
type: 'MouseEvent',
description: 'Mouse Event'
}
]
}
];

Expand Down
16 changes: 13 additions & 3 deletions components/doc/toast/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { memo } from 'react';
import Link from 'next/link';
import { TabView, TabPanel } from '../../lib/tabview/TabView';
import { useLiveEditorTabs } from '../common/liveeditor';
import React, { memo } from 'react';
import { TabPanel, TabView } from '../../lib/tabview/TabView';
import { CodeHighlight } from '../common/codehighlight';
import { DevelopmentSection } from '../common/developmentsection';
import { useLiveEditorTabs } from '../common/liveeditor';

const ToastDoc = memo(() => {
const sources = {
Expand Down Expand Up @@ -827,6 +827,16 @@ toast.current.replace(newMessages);
<td>-</td>
<td>Callback to invoke when message becomes hidden.</td>
</tr>
<tr>
<td>onMouseEnter</td>
<td>event: Mouse Event </td>
<td>Callback to invoke when a message gets focus with mouse.</td>
</tr>
<tr>
<td>onMouseLeave</td>
<td>event: Mouse Event </td>
<td>Callback to invoke when a message loses focus with mouse.</td>
</tr>
</tbody>
</table>
</div>
Expand Down
1 change: 1 addition & 0 deletions components/lib/api/Locale.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ let locales = {
dateAfter: 'Date is after',
custom: 'Custom',
clear: 'Clear',
close: 'Close',
apply: 'Apply',
matchAll: 'Match All',
matchAny: 'Match Any',
Expand Down
6 changes: 4 additions & 2 deletions components/lib/toast/Toast.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export const Toast = React.memo(

return (
<CSSTransition nodeRef={messageRef} key={messageInfo._pId} classNames="p-toast-message" unmountOnExit timeout={{ enter: 300, exit: 300 }} onEntered={onEntered} onExited={onExited} options={props.transitionOptions}>
<ToastMessage ref={messageRef} messageInfo={messageInfo} onClick={props.onClick} onClose={onClose} />
<ToastMessage ref={messageRef} messageInfo={messageInfo} onClick={props.onClick} onClose={onClose} onMouseEnter={props.onMouseEnter} onMouseLeave={props.onMouseLeave} />
</CSSTransition>
);
})}
Expand Down Expand Up @@ -126,5 +126,7 @@ Toast.defaultProps = {
onClick: null,
onRemove: null,
onShow: null,
onHide: null
onHide: null,
onMouseEnter: null,
onMouseLeave: null
};
44 changes: 35 additions & 9 deletions components/lib/toast/ToastMessage.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import * as React from 'react';
import { localeOption } from '../api/Locale';
import { Button } from '../button/Button';
import { useTimeout } from '../hooks/Hooks';
import { Ripple } from '../ripple/Ripple';
import { classNames, DomHandler, ObjectUtils } from '../utils/Utils';

export const ToastMessage = React.memo(
React.forwardRef((props, ref) => {
const messageInfo = props.messageInfo;
const { severity, content, summary, detail, closable, life, sticky, className: _className, style, contentClassName: _contentClassName, contentStyle } = messageInfo.message;

const [focused, setFocused] = React.useState(false);
const [clearTimer] = useTimeout(
() => {
onClose();
},
life || 3000,
!sticky
!sticky && !focused
);

const onClose = () => {
Expand All @@ -27,14 +29,38 @@ export const ToastMessage = React.memo(
}
};

const onMouseEnter = (event) => {
props.onMouseEnter && props.onMouseEnter(event);

// do not continue if the user has canceled the event
if (event.defaultPrevented) {
return;
}

// stop timer while user has focused message
if (!sticky) {
clearTimer();
setFocused(true);
}
};

const onMouseLeave = (event) => {
props.onMouseLeave && props.onMouseLeave(event);

// do not continue if the user has canceled the event
if (event.defaultPrevented) {
return;
}

// restart timer when user has left message
if (!sticky) {
setFocused(false);
}
};

const createCloseIcon = () => {
if (closable !== false) {
return (
<button type="button" className="p-toast-icon-close p-link" onClick={onClose}>
<span className="p-toast-icon-close-icon pi pi-times"></span>
<Ripple />
</button>
);
return <Button type="button" className="p-toast-icon-close p-link" icon="p-toast-icon-close-icon pi pi-times" onClick={onClose} aria-label={localeOption('close')} />;
}

return null;
Expand Down Expand Up @@ -78,7 +104,7 @@ export const ToastMessage = React.memo(
const closeIcon = createCloseIcon();

return (
<div ref={ref} className={className} style={style} role="alert" aria-live="assertive" aria-atomic="true" onClick={onClick}>
<div ref={ref} className={className} style={style} role="alert" aria-live="assertive" aria-atomic="true" onClick={onClick} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
<div className={contentClassName} style={contentStyle}>
{message}
{closeIcon}
Expand Down

0 comments on commit fd07f37

Please sign in to comment.