diff --git a/packages/elements/package.json b/packages/elements/package.json
index b2bd04e76c..bb0fdf5b30 100644
--- a/packages/elements/package.json
+++ b/packages/elements/package.json
@@ -48,6 +48,7 @@
"papaparse": "^5.1.1",
"pell": "^1.0.6",
"prop-types": "^15.7.2",
+ "rc-notification": "^4.0.0",
"react-datasheet": "^1.4.0",
"react-datepicker": "^2.9.6",
"react-google-map": "^3.1.1",
@@ -83,4 +84,3 @@
"react-router-dom": "^5.1.2"
}
}
-
diff --git a/packages/elements/src/components/Notification/__tests__/index.tsx b/packages/elements/src/components/Notification/__tests__/index.tsx
new file mode 100644
index 0000000000..46999308fc
--- /dev/null
+++ b/packages/elements/src/components/Notification/__tests__/index.tsx
@@ -0,0 +1,149 @@
+import React from 'react'
+import ReactDOM from 'react-dom'
+import NotificationApi, { getPlacementStyle } from '../'
+
+describe('Notification', () => {
+ beforeAll(() => {
+ jest.useFakeTimers()
+ })
+
+ afterAll(() => {
+ jest.useRealTimers()
+ })
+
+ afterEach(() => {
+ NotificationApi.destroy()
+ })
+
+ describe('NotificationApi', () => {
+ it('not duplicate create holder', () => {
+ const originRender = ReactDOM.render
+ const argsList = []
+ const spyRender = jest.spyOn(ReactDOM, 'render').mockImplementation((...args) => {
+ argsList.push(args as never)
+ })
+ for (let i = 0; i < 5; i += 1) {
+ NotificationApi.open({
+ message: 'Notification Title',
+ duration: 0,
+ prefixCls: 'additional-holder',
+ })
+ }
+
+ argsList.forEach(args => {
+ originRender(args[0], args[1], args[2])
+ })
+
+ const count = document.querySelectorAll('.additional-holder').length
+ expect(count).toEqual(1)
+
+ spyRender.mockRestore()
+ })
+ })
+
+ it('should be able to hide manually', async () => {
+ NotificationApi.open({
+ message: 'Notification Title',
+ duration: 0,
+ key: '1',
+ })
+ NotificationApi.open({
+ message: 'Notification Title',
+ duration: 0,
+ key: '2',
+ })
+
+ await Promise.resolve()
+ expect(document.querySelectorAll('.reapit-notification-notice').length).toBe(2)
+ NotificationApi.close('1')
+ await Promise.resolve()
+ jest.runAllTimers()
+ expect(document.querySelectorAll('.reapit-notification-notice').length).toBe(1)
+ NotificationApi.close('2')
+ await Promise.resolve()
+ jest.runAllTimers()
+ expect(document.querySelectorAll('.reapit-notification-notice').length).toBe(0)
+ })
+
+ it('should be able to destroy globally', async () => {
+ NotificationApi.open({
+ message: 'Notification Title',
+ duration: 0,
+ })
+ NotificationApi.open({
+ message: 'Notification Title',
+ duration: 0,
+ })
+ await Promise.resolve()
+ expect(document.querySelectorAll('.reapit-notification').length).toBe(1)
+ expect(document.querySelectorAll('.reapit-notification-notice').length).toBe(2)
+ NotificationApi.destroy()
+ await Promise.resolve()
+ expect(document.querySelectorAll('.reapit-notification').length).toBe(0)
+ expect(document.querySelectorAll('.reapit-notification-notice').length).toBe(0)
+ })
+
+ it('should be able to destroy after config', () => {
+ NotificationApi.config({
+ bottom: 100,
+ })
+ NotificationApi.destroy()
+ })
+
+ it('trigger onClick', () => {
+ NotificationApi.open({
+ message: 'Notification Title',
+ duration: 0,
+ })
+ expect(document.querySelectorAll('.reapit-notification').length).toBe(1)
+ })
+
+ it('support closeIcon', () => {
+ NotificationApi.open({
+ message: 'Notification Title',
+ duration: 0,
+ closeIcon: ,
+ })
+ expect(document.querySelectorAll('.test-customize-icon').length).toBe(1)
+ })
+
+ it('support config closeIcon', () => {
+ NotificationApi.config({
+ closeIcon: ,
+ })
+ NotificationApi.open({
+ message: 'Notification Title',
+ duration: 0,
+ closeIcon: ,
+ })
+ expect(document.querySelectorAll('.test-customize-icon').length).toBe(1)
+ })
+
+ describe('getPlacementStyle', () => {
+ it('should run correctly', () => {
+ expect(getPlacementStyle('topLeft', 10, 20)).toEqual({
+ left: 0,
+ top: 10,
+ bottom: 'auto',
+ })
+
+ expect(getPlacementStyle('topRight', 10, 20)).toEqual({
+ right: 0,
+ top: 10,
+ bottom: 'auto',
+ })
+
+ expect(getPlacementStyle('bottomLeft', 10, 20)).toEqual({
+ left: 0,
+ bottom: 20,
+ top: 'auto',
+ })
+
+ expect(getPlacementStyle('bottomRight', 10, 20)).toEqual({
+ right: 0,
+ bottom: 20,
+ top: 'auto',
+ })
+ })
+ })
+})
diff --git a/packages/elements/src/components/Notification/__tests__/useNotification.tsx b/packages/elements/src/components/Notification/__tests__/useNotification.tsx
new file mode 100644
index 0000000000..0d4d7424dd
--- /dev/null
+++ b/packages/elements/src/components/Notification/__tests__/useNotification.tsx
@@ -0,0 +1,48 @@
+import React from 'react'
+import { mount } from 'enzyme'
+import NotificationApi from '../'
+
+describe('notification.hooks', () => {
+ beforeAll(() => {
+ jest.useFakeTimers()
+ })
+
+ afterAll(() => {
+ jest.useRealTimers()
+ })
+
+ afterEach(() => {
+ NotificationApi.destroy()
+ })
+
+ it('should run correctly', () => {
+ const Context = React.createContext('light')
+
+ const Demo = () => {
+ const [api, holder] = NotificationApi.useNotification()
+
+ return (
+
+
+ )
+ }
+
+ const wrapper = mount()
+ wrapper.find('button').simulate('click')
+ expect(document.querySelectorAll('.reapit-notification-notice').length).toBe(1)
+ const messageEl = document.querySelector('.hook-test-result')
+ expect(messageEl?.innerHTML).toEqual('bamboo')
+ })
+})
diff --git a/packages/elements/src/components/Notification/index.tsx b/packages/elements/src/components/Notification/index.tsx
new file mode 100644
index 0000000000..8c983612bc
--- /dev/null
+++ b/packages/elements/src/components/Notification/index.tsx
@@ -0,0 +1,222 @@
+import * as React from 'react'
+import Notification from 'rc-notification'
+import { NotificationInstance as RCNotificationInstance } from 'rc-notification/lib/Notification'
+import createUseNotification from './useNotification'
+
+export type NotificationPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'
+
+export type NotificationType = 'success' | 'info' | 'error' | 'warn'
+
+const notificationInstance: {
+ [key: string]: Promise
+} = {}
+let defaultDuration = 3
+let defaultTop = 24
+let defaultBottom = 24
+let defaultPlacement: NotificationPlacement = 'topRight'
+let defaultGetContainer: () => HTMLElement
+let defaultCloseIcon: React.ReactNode
+
+export interface ConfigProps {
+ top?: number
+ bottom?: number
+ duration?: number
+ placement?: NotificationPlacement
+ getContainer?: () => HTMLElement
+ closeIcon?: React.ReactNode
+}
+
+function setNotificationConfig(options: ConfigProps) {
+ const { duration, placement, bottom, top, getContainer, closeIcon } = options
+ if (duration !== undefined) {
+ defaultDuration = duration
+ }
+ if (placement !== undefined) {
+ defaultPlacement = placement
+ }
+ if (bottom !== undefined) {
+ defaultBottom = bottom
+ }
+ if (top !== undefined) {
+ defaultTop = top
+ }
+ if (getContainer !== undefined) {
+ defaultGetContainer = getContainer
+ }
+ if (closeIcon !== undefined) {
+ defaultCloseIcon = closeIcon
+ }
+}
+
+export function getPlacementStyle(
+ placement: NotificationPlacement,
+ top: number = defaultTop,
+ bottom: number = defaultBottom,
+) {
+ let style
+ switch (placement) {
+ case 'topLeft':
+ style = {
+ left: 0,
+ top,
+ bottom: 'auto',
+ }
+ break
+ case 'topRight':
+ style = {
+ right: 0,
+ top,
+ bottom: 'auto',
+ }
+ break
+ case 'bottomLeft':
+ style = {
+ left: 0,
+ top: 'auto',
+ bottom,
+ }
+ break
+ default:
+ style = {
+ right: 0,
+ top: 'auto',
+ bottom,
+ }
+ break
+ }
+ return style
+}
+
+function getNotificationInstance(
+ args: ArgsProps,
+ callback: (info: { prefixCls: string; instance: RCNotificationInstance }) => void,
+) {
+ const {
+ placement = defaultPlacement,
+ top,
+ bottom,
+ getContainer = defaultGetContainer,
+ closeIcon = defaultCloseIcon,
+ } = args
+ const outerPrefixCls = args.prefixCls || 'reapit-notification'
+ const prefixCls = `${outerPrefixCls}-notice`
+
+ const cacheKey = `${outerPrefixCls}-${placement}`
+ const cacheInstance = notificationInstance[cacheKey]
+ if (cacheInstance) {
+ Promise.resolve(cacheInstance).then(instance => {
+ callback({ prefixCls, instance })
+ })
+ return
+ }
+
+ const closeIconToRender = {closeIcon || }
+
+ notificationInstance[cacheKey] = new Promise(resolve => {
+ Notification.newInstance(
+ {
+ prefixCls: outerPrefixCls,
+ className: `${outerPrefixCls}-${placement}`,
+ style: getPlacementStyle(placement, top, bottom),
+ getContainer,
+ closeIcon: closeIconToRender,
+ },
+ notification => {
+ resolve(notification)
+ callback({
+ prefixCls,
+ instance: notification,
+ })
+ },
+ )
+ })
+}
+
+export interface ArgsProps {
+ message: React.ReactNode
+ btn?: React.ReactNode
+ key?: string
+ onClose?: () => void
+ duration?: number | null
+ placement?: NotificationPlacement
+ style?: React.CSSProperties
+ prefixCls?: string
+ className?: string
+ readonly type?: NotificationType
+ top?: number
+ bottom?: number
+ getContainer?: () => HTMLElement
+ closeIcon?: React.ReactNode
+}
+
+function getRCNoticeProps(args: ArgsProps) {
+ const duration = args.duration === undefined ? defaultDuration : args.duration
+
+ const variant =
+ args.type === 'success'
+ ? 'is-success'
+ : args.type === 'info'
+ ? 'is-info'
+ : args.type === 'error'
+ ? 'is-danger'
+ : 'is-warning'
+
+ return {
+ content: {args.message}
,
+ duration,
+ closable: true,
+ onClose: args.onClose,
+ key: args.key,
+ style: args.style || {},
+ className: args.className,
+ }
+}
+
+const api = {
+ open: (args: ArgsProps) => {
+ getNotificationInstance(args, ({ instance }) => {
+ instance.notice(getRCNoticeProps(args))
+ })
+ },
+ close(key: string) {
+ Object.keys(notificationInstance).forEach(cacheKey =>
+ Promise.resolve(notificationInstance[cacheKey]).then(instance => {
+ instance.removeNotice(key)
+ }),
+ )
+ },
+ config: setNotificationConfig,
+ destroy() {
+ Object.keys(notificationInstance).forEach(cacheKey => {
+ Promise.resolve(notificationInstance[cacheKey]).then(instance => {
+ instance.destroy()
+ })
+ delete notificationInstance[cacheKey]
+ })
+ },
+ useNotification: createUseNotification(getNotificationInstance, getRCNoticeProps),
+}
+;['success', 'info', 'error', 'warn'].forEach(type => {
+ api[type] = (args: ArgsProps) =>
+ api.open({
+ ...args,
+ type: type as NotificationType,
+ })
+})
+
+export interface NotificationInstance {
+ success(args: ArgsProps): void
+ error(args: ArgsProps): void
+ info(args: ArgsProps): void
+ warm(args: ArgsProps): void
+ open(args: ArgsProps): void
+}
+
+export interface NotificationApi extends NotificationInstance {
+ close(key: string): void
+ config(options: ConfigProps): void
+ destroy(): void
+ useNotification: () => [NotificationInstance, React.ReactElement]
+}
+
+export default api as NotificationApi
diff --git a/packages/elements/src/components/Notification/notification.stories.tsx b/packages/elements/src/components/Notification/notification.stories.tsx
new file mode 100644
index 0000000000..e02bd18097
--- /dev/null
+++ b/packages/elements/src/components/Notification/notification.stories.tsx
@@ -0,0 +1,103 @@
+import React from 'react'
+
+import { storiesOf } from '@storybook/react'
+import NotificationApi, { NotificationPlacement } from '.'
+import { Button } from '../Button'
+
+const stories = storiesOf('Notification', module)
+
+const longText =
+ 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Non sint voluptas qui amet architecto, ' +
+ 'maxime laudantium voluptatibus, laborum beatae explicabo minima voluptatum, doloremque blanditiis ' +
+ 'ipsum reiciendis quasi fugit eveniet perferendis!'
+
+type FunctionName = 'open' | 'success' | 'error' | 'info' | 'warn'
+
+const showNotification = (fnName: FunctionName = 'open', placement: NotificationPlacement = 'bottomRight') => {
+ const fn = NotificationApi[fnName]
+ fn({
+ message: longText,
+ onClick: () => {
+ console.log('Notification Clicked!')
+ },
+ placement,
+ })
+}
+
+const Apis = () => {
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+const Placement = () => {
+ return (
+
+
+
+
+
+
+ )
+}
+
+const Context = React.createContext({ name: 'Default' })
+
+const Hooks = () => {
+ const [instance, contextHolder] = NotificationApi.useNotification()
+
+ const openNotification = placement => {
+ instance.info({
+ message: {({ name }) => `Hello, ${name}! - ${placement}`},
+ placement,
+ })
+ }
+
+ return (
+
+
+ {contextHolder}
+
+
+
+
+
+
+ )
+}
+
+stories.add('Api', () => )
+stories.add('Placement', () => )
+stories.add('Hooks', () => )
diff --git a/packages/elements/src/components/Notification/useNotification.tsx b/packages/elements/src/components/Notification/useNotification.tsx
new file mode 100644
index 0000000000..ac8f0f96bd
--- /dev/null
+++ b/packages/elements/src/components/Notification/useNotification.tsx
@@ -0,0 +1,57 @@
+import * as React from 'react'
+import useRCNotification from 'rc-notification/lib/useNotification'
+import {
+ NotificationInstance as RCNotificationInstance,
+ NoticeContent as RCNoticeContent,
+ HolderReadyCallback as RCHolderReadyCallback,
+} from 'rc-notification/lib/Notification'
+import { NotificationInstance, ArgsProps } from '.'
+
+export default function createUseNotification(
+ getNotificationInstance: (
+ args: ArgsProps,
+ callback: (info: { prefixCls: string; instance: RCNotificationInstance }) => void,
+ ) => void,
+ getRCNoticeProps: (args: ArgsProps, prefixCls: string) => RCNoticeContent,
+) {
+ const useNotification = (): [NotificationInstance, React.ReactElement] => {
+ // We create a proxy to handle delay created instance
+ let innerInstance: RCNotificationInstance | null = null
+ const proxy = {
+ add: (noticeProps: RCNoticeContent, holderCallback?: RCHolderReadyCallback) => {
+ innerInstance?.component.add(noticeProps, holderCallback)
+ },
+ } as any
+
+ const [hookNotify, holder] = useRCNotification(proxy)
+
+ function notify(args: ArgsProps) {
+ getNotificationInstance(
+ {
+ ...args,
+ prefixCls: 'reapit-notification',
+ },
+ ({ prefixCls, instance }) => {
+ innerInstance = instance
+ hookNotify(getRCNoticeProps(args, prefixCls))
+ },
+ )
+ }
+
+ // Fill functions
+ const hookAPI: any = {
+ open: notify,
+ }
+ ;['success', 'info', 'warn', 'error'].forEach(type => {
+ hookAPI[type] = (args: ArgsProps) =>
+ hookAPI.open({
+ ...args,
+ type,
+ })
+ })
+
+ return [hookAPI, holder]
+ }
+
+ return useNotification
+}
diff --git a/packages/elements/src/index.tsx b/packages/elements/src/index.tsx
index 0a28b8e801..7ba33e8e41 100644
--- a/packages/elements/src/index.tsx
+++ b/packages/elements/src/index.tsx
@@ -44,6 +44,7 @@ export * from './components/Helper'
export * from './components/Spreadsheet'
export * from './components/HelpGuide'
export * from './components/HelpGuide/context'
+export * from './components/Notification'
// Utils
export * from './utils/validators'
diff --git a/packages/elements/src/styles/components/notification.scss b/packages/elements/src/styles/components/notification.scss
new file mode 100644
index 0000000000..4a2c608604
--- /dev/null
+++ b/packages/elements/src/styles/components/notification.scss
@@ -0,0 +1,131 @@
+$notification-width: 400px;
+$notification-padding-vertical: 16px;
+$notification-padding-horizontal: 24px;
+$notification-padding: $notification-padding-vertical $notification-padding-horizontal;
+$notification-margin-bottom: 16px;
+
+.reapit-notification {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ position: fixed;
+ z-index: 99;
+ width: $notification-width;
+ margin-right: 24px;
+ margin-left: 24px;
+
+ &-topLeft,
+ &-bottomLeft {
+ .reapit-notification-fade-enter.reapit-notification-fade-enter-active,
+ .reapit-notification-fade-appear.reapit-notification-fade-appear-active {
+ animation-name: NotificationLeftFadeIn;
+ }
+ }
+
+ &-hook-holder,
+ &-notice {
+ position: relative;
+ margin-bottom: $notification-margin-bottom;
+ overflow: hidden;
+ background: white;
+ }
+
+ &-hook-holder > &-notice {
+ margin-bottom: 0;
+ box-shadow: none;
+ }
+
+ &-notice {
+ &-close {
+ position: absolute;
+ top: 12px;
+ right: 12px;
+ color: rgba(0, 0, 0, 0.45);
+ outline: none;
+ }
+
+ &-btn {
+ float: right;
+ margin-top: 16px;
+ }
+ }
+
+ %notification-fade-effect {
+ animation-duration: 0.24s;
+ animation-timing-function: ease-in-out;
+ animation-fill-mode: both;
+ }
+
+ .notification-fade-effect {
+ @extend %notification-fade-effect;
+ }
+
+ &-fade-enter,
+ &-fade-appear {
+ opacity: 0;
+ @extend %notification-fade-effect;
+ }
+
+ &-fade-leave {
+ @extend %notification-fade-effect;
+ animation-duration: 0.2s;
+ animation-play-state: paused;
+ }
+
+ &-fade-enter,
+ &-fade-enter-active,
+ &-fade-appear,
+ &-fade-appear-active {
+ animation-name: NotificationFadeIn;
+ animation-play-state: running;
+ }
+
+ &-fade-leave,
+ &-fade-leave-active {
+ animation-name: NotificationFadeOut;
+ animation-play-state: running;
+ }
+
+ &-content {
+ padding: 24px;
+ }
+}
+
+@keyframes NotificationFadeIn {
+ 0% {
+ left: $notification-width;
+ opacity: 0;
+ }
+ 100% {
+ left: 0;
+ opacity: 1;
+ }
+}
+
+@keyframes NotificationLeftFadeIn {
+ 0% {
+ right: $notification-width;
+ opacity: 0;
+ }
+ 100% {
+ right: 0;
+ opacity: 1;
+ }
+}
+
+@keyframes NotificationFadeOut {
+ 0% {
+ max-height: 150px;
+ margin-bottom: $notification-margin-bottom;
+ padding-top: $notification-padding;
+ padding-bottom: $notification-padding;
+ opacity: 1;
+ }
+ 100% {
+ max-height: 0;
+ margin-bottom: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+ opacity: 0;
+ }
+}
diff --git a/packages/elements/src/styles/index.scss b/packages/elements/src/styles/index.scss
index 56bc89c8dc..9c80b35e89 100644
--- a/packages/elements/src/styles/index.scss
+++ b/packages/elements/src/styles/index.scss
@@ -29,3 +29,4 @@
@import './components/helper.scss';
@import './components/spreadsheet.scss';
@import './components/help-guide.scss';
+@import './components/notification.scss';
diff --git a/yarn.lock b/yarn.lock
index a5da6eaeb7..23b24003d4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5512,6 +5512,13 @@ acorn@^3.1.0, acorn@^4.0.4, acorn@^5.5.3, acorn@^6.0.1, acorn@^6.2.1, acorn@^6.4
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
+add-dom-event-listener@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310"
+ integrity sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==
+ dependencies:
+ object-assign "4.x"
+
address@1.1.2, address@^1.0.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6"
@@ -6974,7 +6981,7 @@ babel-preset-jest@^25.1.0:
babel-plugin-transform-undefined-to-void "^6.9.4"
lodash "^4.17.11"
-babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
+babel-runtime@6.x, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
@@ -8113,7 +8120,7 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
-classnames@^2.2.5, classnames@^2.2.6:
+classnames@2.x, classnames@^2.2.5, classnames@^2.2.6:
version "2.2.6"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
@@ -8560,11 +8567,23 @@ compare-versions@^3.5.1:
resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62"
integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==
+component-classes@^1.2.5:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/component-classes/-/component-classes-1.2.6.tgz#c642394c3618a4d8b0b8919efccbbd930e5cd691"
+ integrity sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE=
+ dependencies:
+ component-indexof "0.0.3"
+
component-emitter@^1.2.0, component-emitter@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
+component-indexof@0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/component-indexof/-/component-indexof-0.0.3.tgz#11d091312239eb8f32c8f25ae9cb002ffe8d3c24"
+ integrity sha1-EdCRMSI5648yyPJa6csAL/6NPCQ=
+
compress-commons@^1.2.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.2.tgz#524a9f10903f3a813389b0225d27c48bb751890f"
@@ -9188,6 +9207,14 @@ crypto-random-string@^1.0.0:
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
+css-animation@^1.3.2:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/css-animation/-/css-animation-1.6.1.tgz#162064a3b0d51f958b7ff37b3d6d4de18e17039e"
+ integrity sha512-/48+/BaEaHRY6kNQ2OIPzKf9A6g8WjZYjhiNDNuIVbsm5tXCGIAsHDjB4Xu1C4vXJtUWZo26O68OQkDpNBaPog==
+ dependencies:
+ babel-runtime "6.x"
+ component-classes "^1.2.5"
+
css-color-keywords@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
@@ -18048,7 +18075,7 @@ oauth-sign@~0.9.0:
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
-object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
+object-assign@4.x, object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
@@ -19504,7 +19531,7 @@ prop-types-exact@^1.2.0:
object.assign "^4.1.0"
reflect.ownkeys "^0.2.0"
-prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
+prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -19826,7 +19853,7 @@ quick-lru@^1.0.0:
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8"
integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=
-raf@^3.1.0, raf@^3.4.1:
+raf@^3.1.0, raf@^3.4.0, raf@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
@@ -19920,6 +19947,40 @@ raw-loader@^3.1.0:
loader-utils "^1.1.0"
schema-utils "^2.0.1"
+rc-animate@2.x:
+ version "2.10.3"
+ resolved "https://registry.yarnpkg.com/rc-animate/-/rc-animate-2.10.3.tgz#163d5e29281a4ff82d53ee7918eeeac856b756f9"
+ integrity sha512-A9qQ5Y8BLlM7EhuCO3fWb/dChndlbWtY/P5QvPqBU7h4r5Q2QsvsbpTGgdYZATRDZbTRnJXXfVk9UtlyS7MBLg==
+ dependencies:
+ babel-runtime "6.x"
+ classnames "^2.2.6"
+ css-animation "^1.3.2"
+ prop-types "15.x"
+ raf "^3.4.0"
+ rc-util "^4.15.3"
+ react-lifecycles-compat "^3.0.4"
+
+rc-notification@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/rc-notification/-/rc-notification-4.0.0.tgz#ffe59783d6738003972dde8b9658f1acd469cd2c"
+ integrity sha512-In9FimkJY+JSIq3/eopPfBpQQr2Zugq5i9Aw9vdiNCGCsAsSO9bGq2dPsn8bamOydNrhc3djljGfmxUUMbcZnA==
+ dependencies:
+ classnames "2.x"
+ rc-animate "2.x"
+ rc-util "^4.0.4"
+
+rc-util@^4.0.4, rc-util@^4.15.3:
+ version "4.20.1"
+ resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.20.1.tgz#a5976eabfc3198ed9b8e79ffb8c53c231db36e77"
+ integrity sha512-EGlDg9KPN0POzmAR2hk9ZyFc3DmJIrXwlC8NoDxJguX2LTINnVqwadLIVauLfYgYISMiFYFrSHiFW+cqUhZ5dA==
+ dependencies:
+ add-dom-event-listener "^1.1.0"
+ babel-runtime "6.x"
+ prop-types "^15.5.10"
+ react-is "^16.12.0"
+ react-lifecycles-compat "^3.0.4"
+ shallowequal "^1.1.0"
+
rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"