From 8e692f060265b6553cdda54acbc8019eb8e4b409 Mon Sep 17 00:00:00 2001 From: sam-m-m Date: Thu, 10 Dec 2020 13:15:11 -0800 Subject: [PATCH] feat #174 - NotificationsV2 updates --- package-lock.json | 29 ++++++++ package.json | 3 + rollup.config.ts | 9 ++- src/__snapshots__/storybook.test.ts.snap | 58 ++++++++++++++- .../NotificationV2/Notification.tsx | 71 +++++++++++-------- .../NotificationV2/NotificationContext.ts | 14 ++-- .../NotificationV2/NotificationV2.stories.tsx | 57 ++++++++++++--- src/components/NotificationV2/index.tsx | 10 +-- src/components/NotificationV2/utils.ts | 31 ++++++-- 9 files changed, 221 insertions(+), 61 deletions(-) diff --git a/package-lock.json b/package-lock.json index ebd7c576..54e6ae29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1581,6 +1581,35 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" }, + "@fortawesome/fontawesome-common-types": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.32.tgz", + "integrity": "sha512-ux2EDjKMpcdHBVLi/eWZynnPxs0BtFVXJkgHIxXRl+9ZFaHPvYamAfCzeeQFqHRjuJtX90wVnMRaMQAAlctz3w==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "1.2.32", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.32.tgz", + "integrity": "sha512-XjqyeLCsR/c/usUpdWcOdVtWFVjPbDFBTQkn2fQRrWhhUoxriQohO2RWDxLyUM8XpD+Zzg5xwJ8gqTYGDLeGaQ==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.32" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.1.tgz", + "integrity": "sha512-EFMuKtzRMNbvjab/SvJBaOOpaqJfdSap/Nl6hst7CgrJxwfORR1drdTV6q1Ib/JVzq4xObdTDcT6sqTaXMqfdg==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.32" + } + }, + "@fortawesome/react-fontawesome": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.13.tgz", + "integrity": "sha512-/HrLnIft5Ks2511Pz6TxHBIctC9QalVscAC64sufQ4sJH/sXaQlG3uR9LCu6VpEwkBemgcBLrz/QPNP/ddbjDg==", + "requires": { + "prop-types": "^15.7.2" + } + }, "@hapi/address": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", diff --git a/package.json b/package.json index fc40d69f..16b0cbf9 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,9 @@ "dependencies": { "@ant-design/icons": "^4.2.2", "@dassana-io/web-utils": "^0.7.2", + "@fortawesome/fontawesome-svg-core": "^1.2.32", + "@fortawesome/free-solid-svg-icons": "^5.15.1", + "@fortawesome/react-fontawesome": "^0.1.13", "@storybook/addon-cssresources": "^6.0.28", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", diff --git a/rollup.config.ts b/rollup.config.ts index 047009e7..c6955ad9 100644 --- a/rollup.config.ts +++ b/rollup.config.ts @@ -28,7 +28,14 @@ const rootImport = options => ({ }) export default { - external: ['antd', 'react', 'uuid'], + external: [ + 'antd', + '@fortawesome/fontawesome-svg-core', + '@fortawesome/free-solid-svg-icons', + '@fortawesome/react-fontawesome', + 'react', + 'uuid' + ], input: 'src/components/index.ts', output: [ { diff --git a/src/__snapshots__/storybook.test.ts.snap b/src/__snapshots__/storybook.test.ts.snap index 0367d0b6..2c6d284a 100644 --- a/src/__snapshots__/storybook.test.ts.snap +++ b/src/__snapshots__/storybook.test.ts.snap @@ -369,7 +369,7 @@ exports[`Storyshots Link Href 1`] = ` `; -exports[`Storyshots Notification Default 1`] = ` +exports[`Storyshots Notification Error 1`] = `
@@ -381,7 +381,61 @@ exports[`Storyshots Notification Default 1`] = ` type="button" > - Click + Error + + +
+`; + +exports[`Storyshots Notification Info 1`] = ` +
+ +
+`; + +exports[`Storyshots Notification Success 1`] = ` +
+ +
+`; + +exports[`Storyshots Notification Warning 1`] = ` +
+
diff --git a/src/components/NotificationV2/Notification.tsx b/src/components/NotificationV2/Notification.tsx index 78ac435a..5c9fc1f6 100644 --- a/src/components/NotificationV2/Notification.tsx +++ b/src/components/NotificationV2/Notification.tsx @@ -1,11 +1,20 @@ +import cn from 'classnames' import { createUseStyles } from 'react-jss' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { IconButton } from 'components/IconButton' import { motion } from 'framer-motion' -import { generateNotificationStyles, ProcessedNotification } from './utils' + +import { + generateNotificationStyles, + mappedTypesToIcons, + NotificationTypes, + ProcessedNotification +} from './utils' import React, { FC } from 'react' -import { styleguide, ThemeType } from 'components/assets/styles' +import { styleguide, themedStyles, ThemeType } from 'components/assets/styles' const { - colors: { blacks }, + colors: { oranges, reds, greens }, font, spacing } = styleguide @@ -13,30 +22,24 @@ const { const { dark, light } = ThemeType const useStyles = createUseStyles({ - closeButton: { - ...font.label, - '&:hover': { - color: blacks['lighten-30'] - }, - alignSelf: 'flex-end', - color: blacks['lighten-70'], - cursor: 'pointer', - lineHeight: 1, - position: 'absolute', - right: spacing.s, - top: spacing.s - }, container: generateNotificationStyles(light), + error: { color: reds.base }, + icon: { + ...font.h2 + }, + info: { color: themedStyles[light].base.color }, + message: { + alignSelf: 'center', + padding: `0 ${spacing.m}px`, + width: '100%' + }, + success: { color: greens.base }, + warning: { color: oranges.base }, // eslint-disable-next-line sort-keys '@global': { [`.${dark}`]: { - '& $closeButton': { - '&:hover': { - color: blacks['lighten-40'] - }, - color: blacks['lighten-20'] - }, - '& $container': generateNotificationStyles(dark) + '& $container': generateNotificationStyles(dark), + '& $info': { color: themedStyles[dark].base.color } } } }) @@ -46,9 +49,19 @@ export type NotificationProps = ProcessedNotification export const Notification: FC = ( props: NotificationProps ) => { - const { message, onClose } = props + const { error, info, success, warning } = NotificationTypes + + const { message, onClose, type } = props const classes = useStyles(props) + const iconClasses = cn({ + [classes.error]: type === error, + [classes.icon]: true, + [classes.info]: type === info, + [classes.success]: type === success, + [classes.warning]: type === warning + }) + return ( = ( type: 'spring' }} > - {message} -
- X -
+ +
{message}
+
) } diff --git a/src/components/NotificationV2/NotificationContext.ts b/src/components/NotificationV2/NotificationContext.ts index 7d7bf83e..2abdcfaa 100644 --- a/src/components/NotificationV2/NotificationContext.ts +++ b/src/components/NotificationV2/NotificationContext.ts @@ -1,15 +1,13 @@ +import { createCtx } from '@dassana-io/web-utils' import { NotificationConfig } from './utils' -import { createContext, useContext } from 'react' - export interface NotificationContextProps { generateNotification: (notification: NotificationConfig) => void } -const NotificationCtx = createContext( - {} as NotificationContextProps -) +const [useNotificationContext, NotificationCtxProvider] = createCtx< + NotificationContextProps +>() -const useNotification = (): NotificationContextProps => - useContext(NotificationCtx) +const useNotification = (): NotificationContextProps => useNotificationContext() -export { NotificationCtx, useNotification } +export { NotificationCtxProvider, useNotification } diff --git a/src/components/NotificationV2/NotificationV2.stories.tsx b/src/components/NotificationV2/NotificationV2.stories.tsx index 12003caa..486721d3 100644 --- a/src/components/NotificationV2/NotificationV2.stories.tsx +++ b/src/components/NotificationV2/NotificationV2.stories.tsx @@ -1,18 +1,37 @@ import { Button } from '../Button' import { generatePopupSelector } from '../utils' +import omit from 'lodash/omit' import React from 'react' import { SbTheme } from '../../../.storybook/preview' +import startCase from 'lodash/startCase' import { useTheme } from 'react-jss' import { Meta, Story } from '@storybook/react/types-6-0' import { + NotificationConfig, NotificationProvider, NotificationTypes, useNotification } from './index' +const { error, info, success, warning } = NotificationTypes + export default { argTypes: { - children: { control: 'text' } + duration: { + control: { max: 10000, min: 1000, step: 500, type: 'range' }, + defaultValue: 3000, + description: + 'Optional time in miliseconds before the Notification dissapears' + }, + message: { description: 'Notification message to display' }, + type: { + control: { + options: [error, info, success, warning], + type: 'select' + }, + description: + 'Notification type which can either be error, info, success or warning. Each type renders a different icon' + } }, decorators: [ Story => { @@ -30,21 +49,39 @@ export default { title: 'Notification' } as Meta -const Template: Story = () => { +const Template: Story = args => { const { generateNotification } = useNotification() return ( ) } -export const Default = Template.bind({}) +export const Error = Template.bind({}) +Error.args = { + message: 'Message for error notification', + type: error +} + +export const Info = Template.bind({}) +Info.args = { + message: 'Message for info notification', + type: info +} + +export const Success = Template.bind({}) +Success.args = { + message: 'Message for success notification', + type: success +} + +export const Warning = Template.bind({}) +Warning.args = { + message: 'Message for warning notification', + type: warning +} diff --git a/src/components/NotificationV2/index.tsx b/src/components/NotificationV2/index.tsx index ebe0abcc..f0c7637a 100644 --- a/src/components/NotificationV2/index.tsx +++ b/src/components/NotificationV2/index.tsx @@ -10,16 +10,16 @@ import { useCreateDomElement, useNotifications } from './utils' -import { NotificationCtx, useNotification } from './NotificationContext' +import { NotificationCtxProvider, useNotification } from './NotificationContext' import React, { FC, ReactNode } from 'react' -const { spacing } = styleguide +const { spacing, topNavHeight } = styleguide const useStyles = createUseStyles({ container: { position: 'fixed', right: spacing.m, - top: 64 + top: topNavHeight } }) @@ -42,9 +42,9 @@ const NotificationProvider: FC = ({ return ( <> - + {children} - + {rootElement && createPortal(
diff --git a/src/components/NotificationV2/utils.ts b/src/components/NotificationV2/utils.ts index 24799987..2cde8805 100644 --- a/src/components/NotificationV2/utils.ts +++ b/src/components/NotificationV2/utils.ts @@ -1,6 +1,13 @@ +import { ev as NotificationTypes } from '@dassana-io/web-utils' import omit from 'lodash/omit' import { styleguide } from 'components/assets/styles' import { v4 as uuidV4 } from 'uuid' +import { + faCheckCircle, + faExclamationCircle, + faExclamationTriangle, + faTimesCircle +} from '@fortawesome/free-solid-svg-icons' import { themedStyles, themes, ThemeType } from '../assets/styles/themes' import { useCallback, useEffect, useState } from 'react' @@ -32,13 +39,6 @@ export const useCreateDomElement = ( return domElement } -export enum NotificationTypes { - error = 'error', - info = 'info', - success = 'success', - warning = 'warning' -} - export interface NotificationConfig { duration?: number message: string @@ -101,3 +101,20 @@ export const generateNotificationStyles = (themeType: ThemeType) => { width: 384 } } + +export const mappedTypesToIcons = { + [NotificationTypes.error]: { + icon: faTimesCircle + }, + [NotificationTypes.info]: { + icon: faExclamationCircle + }, + [NotificationTypes.success]: { + icon: faCheckCircle + }, + [NotificationTypes.warning]: { + icon: faExclamationTriangle + } +} + +export { NotificationTypes }