Skip to content

Commit

Permalink
feat(notification-manager): add component (#565)
Browse files Browse the repository at this point in the history
* feat(notification): add usePortal prop

* feat(notification-manager): add component

* feat(notification-manager): add base of component

* feat(notification-manager): updates

* feat(notification-manager): updates

* test(notification-manager): add tests

* docs(notification-manager): fix license

* test(notification-manager): update snapshot

* feat(notification-manager): fix animation duration

* feat(notification): change animation-duration to 0.4s
  • Loading branch information
dmitrsavk committed Mar 24, 2021
1 parent 576d896 commit ad6ffab
Show file tree
Hide file tree
Showing 13 changed files with 662 additions and 4 deletions.
24 changes: 24 additions & 0 deletions packages/notification-manager/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@alfalab/core-components-notification-manager",
"version": "1.0.0",
"description": "Notification manager",
"keywords": [],
"license": "MIT",
"main": "dist/index.js",
"module": "./dist/modern/index.js",
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"react": "^16.9.0 || ^17.0.1"
},
"dependencies": {
"@alfalab/core-components-notification": "^2.0.8",
"@alfalab/core-components-portal": "^1.4.2",
"classnames": "^2.2.6",
"react-transition-group": "^4.3.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`NotificationManager Snapshots tests should match empty snapshot 1`] = `
<body>
<div />
<div
alfa-portal-container=""
>
<div
class="component"
/>
</div>
</body>
`;

exports[`NotificationManager Snapshots tests should match snapshot 1`] = `
<body>
<div
alfa-portal-container=""
>
<div
class="component"
>
<div>
<div
class="component hasCloser notificationComponent isVisible notification"
id="1"
role="alert"
style="top: 0px;"
>
<div
class="contentWrap"
>
<div
class="toastContent content"
>
<div>
<div
class="title"
>
title
</div>
</div>
</div>
<button
aria-label="закрыть"
class="component ghost m iconOnly closeButton"
type="button"
>
<span
class="addons"
>
<svg
fill="currentColor"
focusable="false"
height="24"
viewBox="0 0 24 24"
width="24"
>
<path
d="M10.586 12L6 16.5 7.5 18l4.5-4.586L16.5 18l1.5-1.5-4.586-4.5L18 7.5 16.5 6 12 10.586 7.5 6 6 7.5l4.586 4.5z"
/>
</svg>
</span>
</button>
</div>
</div>
</div>
<div>
<div
class="component hasCloser notificationComponent isVisible notification"
id="2"
role="alert"
style="top: 0px;"
>
<div
class="contentWrap"
>
<div
class="toastContent content"
>
<div>
<div
class="title"
>
title
</div>
</div>
</div>
<button
aria-label="закрыть"
class="component ghost m iconOnly closeButton"
type="button"
>
<span
class="addons"
>
<svg
fill="currentColor"
focusable="false"
height="24"
viewBox="0 0 24 24"
width="24"
>
<path
d="M10.586 12L6 16.5 7.5 18l4.5-4.586L16.5 18l1.5-1.5-4.586-4.5L18 7.5 16.5 6 12 10.586 7.5 6 6 7.5l4.586 4.5z"
/>
</svg>
</span>
</button>
</div>
</div>
</div>
<div>
<div
class="component hasCloser notificationComponent isVisible notification"
id="3"
role="alert"
style="top: 0px;"
>
<div
class="contentWrap"
>
<div
class="toastContent content"
>
<div>
<div
class="title"
>
title
</div>
</div>
</div>
<button
aria-label="закрыть"
class="component ghost m iconOnly closeButton"
type="button"
>
<span
class="addons"
>
<svg
fill="currentColor"
focusable="false"
height="24"
viewBox="0 0 24 24"
width="24"
>
<path
d="M10.586 12L6 16.5 7.5 18l4.5-4.586L16.5 18l1.5-1.5-4.586-4.5L18 7.5 16.5 6 12 10.586 7.5 6 6 7.5l4.586 4.5z"
/>
</svg>
</span>
</button>
</div>
</div>
</div>
</div>
</div>
<div />
</body>
`;
127 changes: 127 additions & 0 deletions packages/notification-manager/src/component.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
import { select, text, boolean, number } from '@storybook/addon-knobs';
import { ComponentHeader } from 'storybook/blocks/component-header';
import { Button } from '@alfalab/core-components-button';
import { Notification } from '@alfalab/core-components-notification';

import { NotificationManager } from './component';
import { name, version } from '../package.json';

<Meta title='Компоненты' component={NotificationManager} />

<!-- Canvas -->

<Story name='NotificationManager'>
{React.createElement(() => {
const [notifications, setNotifications] = React.useState([]);
const [count, setCount] = React.useState(0);
const addNotification = () => {
const newNotification = (
<Notification
badge='positive'
title={`Нотификация #${count}`}
autoCloseDelay={3000}
id={count.toString()}
key={count.toString()}
/>
);
notifications.unshift(newNotification);
setNotifications([...notifications]);
setCount(val => val + 1);
};
const removeNotification = React.useCallback(id => {
/**
* Обратите внимание, что актуальный массив нотификаций
* нужно брать из аргументов функции обновления состояния.
*/
setNotifications(actualNotifications =>
actualNotifications.filter(notification => notification.props.id !== id),
);
}, []);
return (
<div>
<Button onClick={addNotification}>Добавить нотификацию</Button>
<NotificationManager
notifications={notifications}
onRemoveNotification={removeNotification}
/>
</div>
);
})}
</Story>

<!-- Docs -->

<ComponentHeader
name='NotificationManager'
version={version}
package='@alfalab/core-components-notification-manager'
stage={2}
/>

```tsx
import { NotificationManager } from '@alfalab/core-components-notification-manager';
```

Менеджер нотификаций.
Рендерит массив нотификаций:

- Располагает нотификации друг под другом, новые нотификации появляются выше старых
- Скрывает/показывает нотификации с анимацией
- В качестве нотификации может быть прокинут любой компонент со схожим API

**При реализации функции onRemoveNotification, актуальный массив нотификаций следует брать
из аргументов функции обновления состояния:**

```tsx
const removeNotification = React.useCallback(id => {
/**
* Обратите внимание, что актуальный массив нотификаций
* нужно брать из аргументов функции обновления состояния.
*/
setNotifications(actualNotifications =>
actualNotifications.filter(notification => notification.props.id !== id),
);
}, []);
```

<Preview>
{React.createElement(() => {
const [notifications, setNotifications] = React.useState([]);
const [count, setCount] = React.useState(0);
const addNotification = () => {
const newNotification = (
<Notification
badge='positive'
title={`Нотификация #${count}`}
autoCloseDelay={3000}
id={count.toString()}
key={count.toString()}
/>
);
notifications.unshift(newNotification);
setNotifications([...notifications]);
setCount(val => val + 1);
};
const removeNotification = React.useCallback(id => {
/**
* Обратите внимание, что актуальный массив нотификаций
* нужно брать из аргументов функции обновления состояния.
*/
setNotifications(actualNotifications =>
actualNotifications.filter(notification => notification.props.id !== id),
);
}, []);
return (
<div>
<Button onClick={addNotification}>Добавить нотификацию</Button>
<NotificationManager
notifications={notifications}
onRemoveNotification={removeNotification}
/>
</div>
);
})}
</Preview>

<Props of={NotificationManager} />

0 comments on commit ad6ffab

Please sign in to comment.