Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BD-46] feat: add new toast #2959

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions src/Toast/BaseToast.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/* eslint-disable react/prop-types */
import React, { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import classNames from 'classnames';

import Icon from '../Icon';
import IconButton from '../IconButton';
import Button from '../Button';
import { Close } from '../../icons';

function Toast({
id, message, onDismiss, actions, className, duration, ...rest
}) {
const intl = useIntl();
const intlCloseLabel = intl.formatMessage({
id: 'pgn.Toast.closeLabel',
defaultMessage: 'Close',
description: 'Close label for Toast component',
});

const timerRef = useRef();

useEffect(() => {
timerRef.current = setTimeout(() => onDismiss(id), duration);

return () => clearTimeout(timerRef.current);
}, [id, onDismiss, duration]);

const clearTimer = () => {
clearTimeout(timerRef.current);
};

const startTimer = () => {
clearTimer();
timerRef.current = setTimeout(() => onDismiss(id), duration);
};

return (
<div
className={classNames('pgn__toast', className)}
onMouseOver={clearTimer}
onMouseOut={startTimer}
onFocus={clearTimer}
onBlur={startTimer}
{...rest}
>
<div className="pgn__toast__header small">
<p className="pgn__toast__message">{message}</p>
<IconButton
iconAs={Icon}
alt={intlCloseLabel}
className="pgn__toast__close-btn align-self-start"
src={Close}
onClick={() => onDismiss(id)}

Check warning on line 55 in src/Toast/BaseToast.jsx

View check run for this annotation

Codecov / codecov/patch

src/Toast/BaseToast.jsx#L55

Added line #L55 was not covered by tests
variant="primary"
invertColors
/>
</div>
{actions
? (
<div className="pgn__toast__optional-actions">
{actions.map((action) => (
<Button
as={action.href ? 'a' : 'button'}
href={action.href}
onClick={action.onClick}
size="sm"
variant="inverse-outline-primary"
>
{action.label}
</Button>
))}
</div>
)
: null}
</div>
);
}

export default Toast;

Toast.propTypes = {
id: PropTypes.number.isRequired,
message: PropTypes.string.isRequired,
onDismiss: PropTypes.func,
actions: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string.isRequired,
onClick: PropTypes.func,
href: PropTypes.string,
}),
),
className: PropTypes.string,
duration: PropTypes.number,
};

Toast.defaultProps = {
onDismiss: () => {},

Check warning on line 99 in src/Toast/BaseToast.jsx

View check run for this annotation

Codecov / codecov/patch

src/Toast/BaseToast.jsx#L99

Added line #L99 was not covered by tests
actions: null,
className: '',
duration: 5000,
};
112 changes: 45 additions & 67 deletions src/Toast/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'Toast'
type: 'component'
components:
- Toast
- ToastContainer
categories:
- Overlays
status: 'New'
Expand All @@ -11,85 +11,63 @@ devStatus: 'Done'
notes: ''
---

``Toast`` is a pop-up style message that shows the user a brief, fleeting, dismissible message about a successful app process.

``Toasts`` sit fixed to the bottom left of the window.
`Toast` is a pop-up style message that shows the user a brief, fleeting, dismissible message about a successful app process.

## Behaviors

<ul>
<li>Auto-dismiss: Toast automatically dismisses after 5 seconds by default.</li>
<li>Disable timer: On hover of the Toast container. On hover or focus of dismiss icon or optional button</li>
<li>Re-enable timer: On mouse leave of the Toast container. On blur of dismiss icon or option button</li>
<li>Auto-dismiss timer: 5 - 15 second range.</li>
</ul>
- **Customizable Appearance**: Choose the window position for toast.
- **Auto-dismiss**: Toast automatically dismisses after a default duration of 5 seconds.
- **Disable timer**: Pause the auto-dismiss timer on hover or focus of the Toast or the dismiss icon.
- **Re-enable timer**: Resume the auto-dismiss timer on mouse leave or blur of the Toast component.

## Basic Usage

```jsx live
() => {
const [show, setShow] = useState(false);

return (
<>
<Toast
onClose={() => setShow(false)}
show={show}
>
Example of a basic Toast.
</Toast>

<Button variant="primary" onClick={() => setShow(true)}>Show Toast</Button>
</>
);
}
```

## With Button

```jsx live
() => {
const [show, setShow] = useState(false);

return (
<>
<Toast
action={{
label: "Optional Button",
onClick: () => console.log('You clicked the action button.')
}}
onClose={() => setShow(false)}
show={show}
>
Success! Example of a Toast with a button.
</Toast>

<Button variant="primary" onClick={() => setShow(true)}>Show Toast</Button>
</>
);
}
```
const [position, setPosition] = useState('bottom-left');
const [timer, setTimer] = useState(5000);
const [message, setMessage] = useState('Example of a basic Toast.');
const [withActions, setWithActions] = useState('false');

## With Link

```jsx live
() => {
const [show, setShow] = useState(false);
const testAction = {
label: "Optional Button",
onClick: () => console.log('You clicked the action button.')
};

return (
<>
<Toast
action={{
label: "Optional Link",
href: "#"
}}
onClose={() => setShow(false)}
show={show}
>
Success! Example of a Toast with a link.
</Toast>

<Button variant="primary" onClick={() => setShow(true)}>Show Toast</Button>
{/* start example form block */}
<ExamplePropsForm
inputs={[
{ value: position, setValue: (value) => setPosition(value), name: 'Position', options: [
{ value: "top-left", name: "top-left" },
{ value: "top-right", name: "top-right" },
{ value: "bottom-left", name: "bottom-left" },
{ value: "bottom-right", name: "bottom-right" }]
},
{ value: timer, setValue: (value) => setTimer(value), name: 'Duration (ms)', range: { min: 1000 , max: 10000, step: 1000 } },
{ value: withActions, setValue: (value) => setWithActions(value), name: 'With actions', options: [
{ value: 'true', name: "True" },
{ value: 'false', name: "False" },
]},
]}
/>
{/* end example form block */}

<div className="mt-3 mb-3">
Message:
<Form.Control
className="mt-1"
as="textarea"
value={message}
onChange={(e) => setMessage(e.target.value)}
/>
</div>

<Button onClick={() => toast({ message, duration: timer, actions: withActions === 'true' ? [testAction] : [], position })}>
Show Toast
</Button>
</>
);
}
Expand Down
92 changes: 0 additions & 92 deletions src/Toast/Toast.test.jsx

This file was deleted.

40 changes: 0 additions & 40 deletions src/Toast/ToastContainer.jsx

This file was deleted.

Loading