Skip to content

Commit

Permalink
Merge pull request #259 from abhinavkrin/new/toastbar-components
Browse files Browse the repository at this point in the history
[New] toastbar components
  • Loading branch information
abhinavkrin authored Oct 6, 2023
2 parents f372531 + 125a75d commit 4926a14
Show file tree
Hide file tree
Showing 24 changed files with 296 additions and 24 deletions.
2 changes: 1 addition & 1 deletion packages/react/src/components/Button/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const Button = ({
}
&.ghost {
background: none;
color: ${theme?.palette?.[color]?.main || '#1A2027'};
color: ${theme?.palette?.[color]?.main || 'currentColor'};
border: none;
}
&.disabled.ghost {
Expand Down
3 changes: 1 addition & 2 deletions packages/react/src/components/ChatInput/ChatInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import React, {
useEffect,
useCallback,
} from 'react';
import { useToastBarDispatch } from '@rocket.chat/fuselage-toastbar';
import { css } from '@emotion/react';
import styles from './ChatInput.module.css';
import RCContext from '../../context/RCInstance';
Expand All @@ -29,6 +28,7 @@ import { Icon } from '../Icon';
import { CommandsList } from '../CommandList';
import { ActionButton } from '../ActionButton';
import useComponentOverrides from '../../theme/useComponentOverrides';
import { useToastBarDispatch } from '../../hooks/useToastBarDispatch';

const ChatInput = () => {
const { styleOverrides, classNames } = useComponentOverrides('ChatInput');
Expand Down Expand Up @@ -158,7 +158,6 @@ const ChatInput = () => {
dispatchToastMessage({
type: 'error',
message: 'Error sending message, login again',
position: toastPosition,
});
} else {
replaceMessage(pendingMessage._id, res.message);
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/components/Icon/Icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const Icon = ({ size = 24, name, className = '', style = {}, ...props }) => {
y="0"
width={size}
height={size}
color="inherit"
color="currentColor"
className={`ec-icon ${classNames}`}
style={styleOverrides}
{...props}
Expand Down
14 changes: 14 additions & 0 deletions packages/react/src/components/Icon/icons/Check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

const Check = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 32 32"
fill="currentColor"
{...props}
>
<path d="M26.7033 7.28911C27.0959 7.67753 27.0993 8.31069 26.7109 8.7033L11.871 23.7033C11.6831 23.8932 11.427 24.0001 11.1599 24C10.8927 23.9999 10.6367 23.8929 10.4489 23.7029L5.28872 18.4814C4.90052 18.0886 4.90426 17.4554 5.29709 17.0672C5.68991 16.679 6.32307 16.6827 6.71128 17.0756L11.1605 21.5777L25.2891 7.2967C25.6775 6.90408 26.3107 6.90069 26.7033 7.28911Z" />
</svg>
);

export default Check;
14 changes: 14 additions & 0 deletions packages/react/src/components/Icon/icons/ErrorCircle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

const ErrorCircle = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 32 32"
fill="currentColor"
{...props}
>
<path d="M29 16C29 23.1797 23.1797 29 16 29C8.8203 29 3 23.1797 3 16C3 8.8203 8.8203 3 16 3C23.1797 3 29 8.8203 29 16ZM20.7071 11.2929C20.3166 10.9024 19.6834 10.9024 19.2929 11.2929L16 14.5858L12.7071 11.2929C12.3166 10.9024 11.6834 10.9024 11.2929 11.2929C10.9024 11.6834 10.9024 12.3166 11.2929 12.7071L14.5858 16L11.2929 19.2929C10.9024 19.6834 10.9024 20.3166 11.2929 20.7071C11.6834 21.0976 12.3166 21.0976 12.7071 20.7071L16 17.4142L19.2929 20.7071C19.6834 21.0976 20.3166 21.0976 20.7071 20.7071C21.0976 20.3166 21.0976 19.6834 20.7071 19.2929L17.4142 16L20.7071 12.7071C21.0976 12.3166 21.0976 11.6834 20.7071 11.2929Z" />
</svg>
);

export default ErrorCircle;
4 changes: 4 additions & 0 deletions packages/react/src/components/Icon/icons/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import Italic from './Italic';
import StarFilled from './StarFilled';
import Trash from './Trash';
import Kebab from './Kebab';
import Check from './Check';
import ErrorCircle from './ErrorCircle';

const icons = {
file: File,
Expand Down Expand Up @@ -68,6 +70,8 @@ const icons = {
'star-filled': StarFilled,
trash: Trash,
kebab: Kebab,
check: Check,
'error-circle': ErrorCircle,
};

export default icons;
8 changes: 1 addition & 7 deletions packages/react/src/components/Message/Message.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useContext, useMemo } from 'react';
import PropTypes from 'prop-types';
import Cookies from 'js-cookie';
import { useToastBarDispatch } from '@rocket.chat/fuselage-toastbar';
import { format } from 'date-fns';
import { css } from '@emotion/react';
import { Attachments } from '../Attachments';
Expand All @@ -22,6 +21,7 @@ import { MessageMetrics } from './MessageMetrics';
import { MessageToolbox } from './MessageToolbox';
import { Avatar } from '../Avatar';
import { MessageDivider } from './MessageDivider';
import { useToastBarDispatch } from '../../hooks/useToastBarDispatch';

const MessageCss = css`
display: flex;
Expand Down Expand Up @@ -77,14 +77,12 @@ const Message = ({
dispatchToastMessage({
type: 'success',
message: 'Message starred',
position: toastPosition,
});
} else {
await RCInstance.unstarMessage(msg._id);
dispatchToastMessage({
type: 'success',
message: 'Message unstarred',
position: toastPosition,
});
}
};
Expand All @@ -98,13 +96,11 @@ const Message = ({
dispatchToastMessage({
type: 'error',
message: 'Error pinning message',
position: toastPosition,
});
} else {
dispatchToastMessage({
type: 'success',
message: isPinned ? 'Message unpinned' : 'Message pinned',
position: toastPosition,
});
}
};
Expand All @@ -116,13 +112,11 @@ const Message = ({
dispatchToastMessage({
type: 'success',
message: 'Message deleted successfully',
position: toastPosition,
});
} else {
dispatchToastMessage({
type: 'error',
message: 'Error in deleting message',
position: toastPosition,
});
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { useContext } from 'react';
import { useToastBarDispatch } from '@rocket.chat/fuselage-toastbar';
import PropTypes from 'prop-types';
import { useMessageStore, useToastStore } from '../../store';
import RCContext from '../../context/RCInstance';
import { Button } from '../Button';
import { Icon } from '../Icon';
import { Modal } from '../Modal';
import { useToastBarDispatch } from '../../hooks/useToastBarDispatch';

const ReportWindowButtons = ({ children, reportDescription, messageId }) => {
const [toggleReportMessage, setMessageToReport] = useMessageStore((state) => [
Expand All @@ -28,13 +28,11 @@ const ReportWindowButtons = ({ children, reportDescription, messageId }) => {
dispatchToastMessage({
type: 'success',
message: 'Message reported successfully',
position: toastPosition,
});
} else {
dispatchToastMessage({
type: 'error',
message: 'Error in reporting message',
position: toastPosition,
});
}

Expand Down
86 changes: 86 additions & 0 deletions packages/react/src/components/ToastBar/ToastBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* eslint-disable no-shadow */
import React, { useMemo, useRef, useEffect } from 'react';
import { css, useTheme, keyframes } from '@emotion/react';
import alpha from 'color-alpha';
import { appendClassNames } from '../../lib/appendClassNames';
import useComponentOverrides from '../../theme/useComponentOverrides';
import { Box } from '../Box';
import { Icon } from '../Icon';
import { ActionButton } from '../ActionButton';

const ToastBar = ({ toast, onClose }) => {
const { type, message, time = 2000 } = toast;
const toastRef = useRef();
const theme = useTheme();
const { classNames, styleOverrides } = useComponentOverrides('ToastBar');
const { iconName, bgColor, color } = useMemo(() => {
const color = theme.palette?.[type]?.main;
const bgColor = alpha(color, 0.3);
let iconName = 'success';
switch (type) {
case 'info':
iconName = 'info';
break;
case 'warning':
iconName = 'report';
break;
case 'error':
iconName = 'error-circle';
break;
case 'success':
default:
iconName = 'check';
}
return { iconName, color, bgColor };
}, [theme.palette, type]);

const animation = keyframes`
0% {
opacity: 0;
}
20% {
opacity: 1;
}
80% {
opacity: 1;
}
100% {
opacity: 0;
}
`;

const ToastBarCSS = css`
display: flex;
flex-direction: row;
gap: 1em;
align-items: center;
justify-content: space-between;
width: fit-content;
max-width: 20rem;
color: ${color};
background-color: ${bgColor};
border-radius: 0.25em;
padding: 0.75em 1em;
z-index: ${theme.zIndex?.toastbar};
animation: ${animation} ${time}ms ease-in-out forwards;
`;

useEffect(() => {
setTimeout(onClose, time);
}, [onClose, time]);

return (
<Box
ref={toastRef}
css={ToastBarCSS}
className={appendClassNames('ec-toast-bar', classNames)}
style={styleOverrides}
>
<Icon size="1em" name={iconName} />
{message}
<ActionButton icon="cross" size="small" onClick={onClose} ghost />
</Box>
);
};

export default ToastBar;
76 changes: 76 additions & 0 deletions packages/react/src/components/ToastBar/ToastBar.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from 'react';
import { ThemeProvider } from '@emotion/react';
import { ToastBar, ToastBarProvider } from '.';
import DefaultTheme from '../../theme/DefaultTheme';
import { Button } from '../Button';
import { useToastBarDispatch } from '../../hooks/useToastBarDispatch';

export default {
title: 'Components/ToastBar',
component: ToastBar,
};

const ToastBarContainer = () => {
const dispatchToast = useToastBarDispatch();
return (
<>
<Button
onClick={() =>
dispatchToast({
message: 'Success Message',
type: 'success',
})
}
color="success"
>
Show Success Toast
</Button>
<Button
color="error"
onClick={() =>
dispatchToast({
message: 'Error Message',
type: 'error',
})
}
>
Show Error Toast
</Button>
<Button
color="info"
onClick={() =>
dispatchToast({
message: 'Info Message',
type: 'info',
})
}
>
Show Info Toast
</Button>
<Button
color="warning"
onClick={() =>
dispatchToast({
message: 'Warning Message',
type: 'warning',
})
}
>
Show Warning Toast
</Button>
</>
);
};

const Template = (args) => (
<ThemeProvider theme={DefaultTheme}>
<ToastBarProvider {...args}>
<ToastBarContainer />
</ToastBarProvider>
</ThemeProvider>
);

export const Default = Template.bind({});
Default.args = {
position: 'bottom right',
};
30 changes: 30 additions & 0 deletions packages/react/src/components/ToastBar/ToastBarProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { useState, useCallback, useMemo } from 'react';
import ToastContext from '../../context/ToastContext';
import ToastContainer from './ToastContainer';

const ToastBarProvider = ({ position = 'bottom left', children }) => {
const [toasts, setToasts] = useState([]);
const dispatchToast = useCallback(
(toast) => {
setToasts((prevToasts) => [toast, ...prevToasts]);
},
[setToasts]
);
const contextValue = useMemo(
() => ({
toasts,
dispatchToast,
position,
setToasts,
}),
[toasts, dispatchToast, position, setToasts]
);
return (
<ToastContext.Provider value={contextValue}>
{children}
<ToastContainer />
</ToastContext.Provider>
);
};

export default ToastBarProvider;
Loading

0 comments on commit 4926a14

Please sign in to comment.