@snack-uikit/toaster 0.11.20 → 0.11.21-preview-83f569e2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,6 +6,160 @@
6
6
 
7
7
  [Changelog](./CHANGELOG.md)
8
8
 
9
+ ## Description
10
+
11
+ - Пакет `@snack-uikit/toaster` предоставляет систему уведомлений (тостеров) для отображения временных сообщений пользователю: системных событий, результатов действий пользователя и прогресса загрузки файлов.
12
+ - Компоненты автоматически управляют жизненным циклом уведомлений (автозакрытие, позиционирование, лимит количества), поддерживают программное создание, обновление и закрытие через объект `toaster`, а также работают с разными визуальными вариантами (appearance) для передачи типа сообщения.
13
+ - Каждый тип тостера предназначен для своего сценария: `ToastSystemEvent` — для важных системных уведомлений с заголовком и описанием, `ToastUserAction` — для кратких сообщений о результатах действий пользователя, `ToastUpload` — для отслеживания прогресса загрузки файлов с возможностью управления процессом.
14
+
15
+ ## ToastSystemEvent
16
+
17
+ ### Description
18
+
19
+ - `ToastSystemEvent` — компонент для отображения системных уведомлений о важных событиях приложения (успешные операции, ошибки, предупреждения, информационные сообщения).
20
+ - Поддерживает **разные типы статусов** через проп `appearance` (neutral, success, error, errorCritical, warning) с соответствующей иконкой и цветовой схемой.
21
+ - Позволяет задать **заголовок и описание** с автоматическим усечением длинных текстов (заголовок до 2 строк, описание до 4 строк).
22
+ - Может отображать **прогресс-бар** (`progressBar`), показывающий оставшееся время до автозакрытия уведомления.
23
+ - Поддерживает **кнопку закрытия** (`closable`) с возможностью кастомизации обработчика (`onCloseClick`).
24
+ - Позволяет добавить **текстовую ссылку** (`link`) и **кнопки действий в футере** (`action`) для выполнения связанных с уведомлением операций.
25
+ - Figma: [`ToastSystemEvent`](https://www.figma.com/file/jtGxAPvFJOMir7V0eQFukN/Snack-UI-Kit-1.1.0?node-id=41%3A196736&mode=design).
26
+
27
+ ### Example
28
+
29
+ ```tsx
30
+ import { toaster } from '@snack-uikit/toaster';
31
+
32
+ // Создание системного уведомления
33
+ const toastId = await toaster.systemEvent.success({
34
+ title: 'Настройки сохранены',
35
+ description: 'Новые параметры будут применены при следующем входе в систему.',
36
+ link: {
37
+ text: 'Изменить ещё раз',
38
+ href: '#',
39
+ },
40
+ action: [
41
+ { label: 'Отменить', onClick: () => console.log('Revert') },
42
+ { label: 'Подробнее', onClick: () => console.log('Details') },
43
+ ],
44
+ progressBar: true,
45
+ closable: true,
46
+ });
47
+
48
+ // Обновление существующего уведомления
49
+ toaster.systemEvent.update.error(toastId, {
50
+ title: 'Ошибка сохранения',
51
+ description: 'Не удалось сохранить изменения. Попробуйте ещё раз.',
52
+ });
53
+
54
+ // Закрытие уведомления
55
+ toaster.systemEvent.dismiss(toastId);
56
+ ```
57
+
58
+ ## ToastUserAction
59
+
60
+ ### Description
61
+
62
+ - `ToastUserAction` — компонент для отображения кратких уведомлений о результатах действий пользователя (успешное выполнение операции, ошибка, предупреждение).
63
+ - Поддерживает **разные типы статусов** через проп `appearance` (neutral, success, error, warning) с соответствующей иконкой и цветовой схемой.
64
+ - Отображает **краткий текст** (`label`) без описания, что делает уведомление компактным и ненавязчивым.
65
+ - Может показывать **состояние загрузки** (`loading`) с анимацией вместо иконки статуса.
66
+ - Поддерживает **текстовую ссылку** (`link`) для перехода к связанному контенту или действию.
67
+ - Отличается от `ToastSystemEvent` более компактным размером и отсутствием заголовка, описания и кнопок действий, что делает его подходящим для быстрых обратных связей на действия пользователя.
68
+ - Figma: [`ToastUserAction`](https://www.figma.com/file/jtGxAPvFJOMir7V0eQFukN/Snack-UI-Kit-1.1.0?node-id=41%3A197658&mode=design).
69
+
70
+ ### Example
71
+
72
+ ```tsx
73
+ import { toaster } from '@snack-uikit/toaster';
74
+
75
+ // Создание уведомления о действии пользователя
76
+ const toastId = await toaster.userAction.success({
77
+ label: 'Файл успешно загружен',
78
+ link: {
79
+ text: 'Открыть',
80
+ href: '#',
81
+ },
82
+ });
83
+
84
+ // Обновление уведомления с состоянием загрузки
85
+ toaster.userAction.update.neutral(toastId, {
86
+ label: 'Обработка файла...',
87
+ loading: true,
88
+ });
89
+
90
+ // Закрытие уведомления
91
+ toaster.userAction.dismiss(toastId);
92
+ ```
93
+
94
+ ## ToastUpload
95
+
96
+ ### Description
97
+
98
+ - `ToastUpload` — компонент для отображения прогресса загрузки одного или нескольких файлов с возможностью управления процессом (пауза, продолжение, повтор при ошибке, отмена).
99
+ - Отображает **список файлов** (`files`) с индивидуальным прогрессом каждого файла, его статусом (loading, pause, error, uploaded, errorUploaded) и возможностью управления через действия (`actions`).
100
+ - Показывает **общий прогресс загрузки** (`progress`) в виде счётчика (current/total) и процентов, а также прогресс-бар при свёрнутом состоянии.
101
+ - Поддерживает **разные статусы загрузки** (`status`) с соответствующим визуальным оформлением и доступными действиями (продолжить, приостановить, повторить).
102
+ - Позволяет **сворачивать и разворачивать** список файлов (`collapsed`, `onCollapsed`) для экономии места на экране.
103
+ - Может быть **перемещаемым** (`draggable`) с ограничениями области перемещения (`draggableBounds`).
104
+ - Поддерживает **кнопку отмены всей загрузки** (`cancelButton`) и **кнопку закрытия** (`closable`).
105
+ - Отображает **заголовок** (`title`) и **описание статуса** (`description`) для информирования пользователя о текущем состоянии загрузки.
106
+ - Figma: [`ToastUpload`](https://www.figma.com/design/jtGxAPvFJOMir7V0eQFukN/branch/qzePfVaHqZdDKogF2PYKRL/Snack-UI-Kit-5.0.0?node-id=17463-61268&t=O9Jb62r0iZv5zcdY-0).
107
+
108
+ ### Example
109
+
110
+ ```tsx
111
+ import { toaster } from '@snack-uikit/toaster';
112
+
113
+ // Создание или обновление уведомления о загрузке
114
+ const toastId = toaster.upload.startOrUpdate({
115
+ title: 'Загрузка файлов',
116
+ description: '3 минуты осталось',
117
+ status: 'loading',
118
+ progress: {
119
+ current: 4,
120
+ total: 10,
121
+ },
122
+ files: [
123
+ {
124
+ id: '1',
125
+ title: 'document.pdf',
126
+ formattedSize: '45 MB',
127
+ progress: 50,
128
+ status: 'loading',
129
+ statusLabel: 'Загрузка...',
130
+ actions: {
131
+ onPause: () => console.log('Pause file 1'),
132
+ onRetry: () => console.log('Retry file 1'),
133
+ },
134
+ },
135
+ {
136
+ id: '2',
137
+ title: 'image.jpg',
138
+ formattedSize: '12 MB',
139
+ progress: 100,
140
+ status: 'uploaded',
141
+ statusLabel: 'Загружено',
142
+ link: { href: '#', text: 'Открыть' },
143
+ },
144
+ ],
145
+ generalActions: {
146
+ onContinue: () => console.log('Continue all'),
147
+ onPause: () => console.log('Pause all'),
148
+ onRetry: () => console.log('Retry all'),
149
+ },
150
+ cancelButton: {
151
+ label: 'Отменить все',
152
+ onClick: () => console.log('Cancel all'),
153
+ },
154
+ closable: true,
155
+ collapsed: false,
156
+ draggable: true,
157
+ });
158
+
159
+ // Закрытие уведомления
160
+ toaster.upload.dismiss(toastId);
161
+ ```
162
+
9
163
  ## Usage
10
164
 
11
165
  ```typescript
@@ -50,8 +204,9 @@ toaster.upload.dismiss(uploadToastId);
50
204
  | name | type | default value | description |
51
205
  |------|------|---------------|-------------|
52
206
  | title* | `string` | - | |
53
- | closeToast | `() => void` | - | |
207
+ | closeToast | `CloseToastFunc` | - | |
54
208
  | toastProps | `ToastProps` | - | |
209
+ | isPaused | `boolean` | - | |
55
210
  | data | `unknown` | - | |
56
211
  | description | `string` | - | |
57
212
  | appearance | enum ToastSystemEventAppearance: `"neutral"`, `"error"`, `"errorCritical"`, `"warning"`, `"success"` | neutral | |
@@ -67,8 +222,9 @@ toaster.upload.dismiss(uploadToastId);
67
222
  | name | type | default value | description |
68
223
  |------|------|---------------|-------------|
69
224
  | label* | `string` | - | |
70
- | closeToast | `() => void` | - | |
225
+ | closeToast | `CloseToastFunc` | - | |
71
226
  | toastProps | `ToastProps` | - | |
227
+ | isPaused | `boolean` | - | |
72
228
  | data | `unknown` | - | |
73
229
  | appearance | enum ToastUserActionAppearance: `"neutral"`, `"error"`, `"warning"`, `"success"` | neutral | |
74
230
  | link | `ToastUserActionLink` | - | |
@@ -83,6 +239,7 @@ toaster.upload.dismiss(uploadToastId);
83
239
  | containerId | `Id` | - | |
84
240
  | displayCloseAllButton | `boolean` | - | |
85
241
  | type | enum ToasterType: `"system-event"`, `"user-action"`, `"upload"` | system-event | |
242
+ | draggable | `boolean` | - | |
86
243
  ## ToastUpload
87
244
  ### Props
88
245
  | name | type | default value | description |
@@ -92,8 +249,9 @@ toaster.upload.dismiss(uploadToastId);
92
249
  | progress* | `{ current: number; total: number; }` | - | Общий прогресс загрузки |
93
250
  | description* | `string` | - | Описание статуса загрузки |
94
251
  | status* | enum ToastUploadStatus: `"error"`, `"loading"`, `"pause"`, `"uploaded"`, `"errorUploaded"` | - | Общий статус загрузки |
95
- | closeToast | `() => void` | - | |
252
+ | closeToast | `CloseToastFunc` | - | |
96
253
  | toastProps | `ToastProps` | - | |
254
+ | isPaused | `boolean` | - | |
97
255
  | data | `unknown` | - | |
98
256
  | title | `string` | - | Заголовок тостера |
99
257
  | onCloseClick | `(e: MouseEvent<HTMLButtonElement, MouseEvent>, close?: () => void) => void` | - | Закрыть тостер |
@@ -7,5 +7,6 @@ export type ToasterContainerProps = {
7
7
  containerId?: RtToastContainerProps['containerId'];
8
8
  displayCloseAllButton?: boolean;
9
9
  type?: ToasterType;
10
+ draggable?: boolean;
10
11
  };
11
- export declare function ToasterContainer({ position, limit, containerId, displayCloseAllButton, type, }: ToasterContainerProps): import("react/jsx-runtime").JSX.Element;
12
+ export declare function ToasterContainer({ position, limit, containerId, displayCloseAllButton, type, draggable, }: ToasterContainerProps): import("react/jsx-runtime").JSX.Element;
@@ -14,6 +14,7 @@ require("./style.css");
14
14
  const classnames_1 = __importDefault(require("classnames"));
15
15
  const react_1 = require("react");
16
16
  const react_toastify_1 = require("react-toastify");
17
+ const utils_1 = require("@snack-uikit/utils");
17
18
  const constants_1 = require("../../constants");
18
19
  const testIds_1 = require("../../testIds");
19
20
  const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
@@ -23,7 +24,8 @@ function ToasterContainer(_ref) {
23
24
  limit = 5,
24
25
  containerId,
25
26
  displayCloseAllButton,
26
- type = constants_1.TOASTER_TYPE.SystemEvent
27
+ type = constants_1.TOASTER_TYPE.SystemEvent,
28
+ draggable = false
27
29
  } = _ref;
28
30
  const [notificationCounter, setNotificationCounter] = (0, react_1.useState)(0);
29
31
  const [isCloseAllButtonHidden, setIsCloseAllButtonHidden] = (0, react_1.useState)(false);
@@ -31,7 +33,7 @@ function ToasterContainer(_ref) {
31
33
  react_toastify_1.toast.dismiss();
32
34
  setIsCloseAllButtonHidden(true);
33
35
  };
34
- (0, react_1.useEffect)(() => {
36
+ (0, utils_1.useLayoutEffect)(() => {
35
37
  const unsubscribe = react_toastify_1.toast.onChange(_ref2 => {
36
38
  let {
37
39
  status,
@@ -56,7 +58,7 @@ function ToasterContainer(_ref) {
56
58
  closeOnClick: false,
57
59
  autoClose: false,
58
60
  closeButton: false,
59
- draggable: false,
61
+ draggable: draggable,
60
62
  className: (0, classnames_1.default)('osThemeSnack', styles_module_scss_1.default[position], {
61
63
  [styles_module_scss_1.default.containerWithCloseAllButton]: hasCloseAllButton,
62
64
  'osThemeSnack__toast-container__system-event': type === constants_1.TOASTER_TYPE.SystemEvent,
@@ -64,7 +66,6 @@ function ToasterContainer(_ref) {
64
66
  'osThemeSnack__toast-container__upload': type === constants_1.TOASTER_TYPE.Upload
65
67
  }),
66
68
  toastClassName: styles_module_scss_1.default.toaster,
67
- bodyClassName: styles_module_scss_1.default.toaster,
68
69
  position: position,
69
70
  limit: limit,
70
71
  containerId: containerId
@@ -66,6 +66,7 @@
66
66
  }
67
67
  :global .osThemeSnack.Toastify__toast-container{
68
68
  position:fixed;
69
+ left:auto;
69
70
  box-sizing:border-box;
70
71
  padding:0;
71
72
  }
@@ -79,6 +80,7 @@
79
80
  display:flex;
80
81
  justify-content:space-between;
81
82
  box-sizing:border-box;
83
+ width:100%;
82
84
  min-height:unset;
83
85
  margin:0;
84
86
  padding:0;
@@ -7,5 +7,5 @@ export declare const updateToast: UpdateToast;
7
7
  * @function
8
8
  */
9
9
  export declare const dismissToast: (params?: Id) => void;
10
- export declare const isToastActive: typeof import("react-toastify/dist/core/store").isToastActive;
10
+ export declare const isToastActive: (id: Id, containerId?: Id) => boolean;
11
11
  export declare const toaster: Toaster;
@@ -50,12 +50,12 @@ function getToastOptions(_ref2) {
50
50
  } = _ref2;
51
51
  return {
52
52
  toastId: toastOptions === null || toastOptions === void 0 ? void 0 : toastOptions.id,
53
- onClose: data => {
54
- var _a;
55
- (_a = toastOptions === null || toastOptions === void 0 ? void 0 : toastOptions.onClose) === null || _a === void 0 ? void 0 : _a.call(toastOptions, data === null || data === void 0 ? void 0 : data.id);
56
- },
53
+ onClose: toastOptions === null || toastOptions === void 0 ? void 0 : toastOptions.onClose,
57
54
  autoClose: (toasterProps === null || toasterProps === void 0 ? void 0 : toasterProps.loading) ? false : constants_1.AUTO_CLOSE_TIME[type],
58
- containerId: containerId || `${constants_1.TOASTER_CONTAINER_PREFIX}${type}`
55
+ containerId: containerId || `${constants_1.TOASTER_CONTAINER_PREFIX}${type}`,
56
+ draggable: toastOptions === null || toastOptions === void 0 ? void 0 : toastOptions.draggable,
57
+ draggableDirection: type === constants_1.TOASTER_TYPE.UserAction ? 'y' : 'x',
58
+ draggablePercent: 30
59
59
  };
60
60
  }
61
61
  function getToastComponent(_ref3) {
@@ -150,7 +150,8 @@ const userAction = {
150
150
  }),
151
151
  toastOptions: {
152
152
  id: options.id,
153
- onClose: options.onClose
153
+ onClose: options.onClose,
154
+ draggable: options.draggable
154
155
  }
155
156
  });
156
157
  },
@@ -162,7 +163,8 @@ const userAction = {
162
163
  }),
163
164
  toastOptions: {
164
165
  id: options.id,
165
- onClose: options.onClose
166
+ onClose: options.onClose,
167
+ draggable: options.draggable
166
168
  }
167
169
  });
168
170
  },
@@ -174,7 +176,8 @@ const userAction = {
174
176
  }),
175
177
  toastOptions: {
176
178
  id: options.id,
177
- onClose: options.onClose
179
+ onClose: options.onClose,
180
+ draggable: options.draggable
178
181
  }
179
182
  });
180
183
  },
@@ -186,7 +189,8 @@ const userAction = {
186
189
  }),
187
190
  toastOptions: {
188
191
  id: options.id,
189
- onClose: options.onClose
192
+ onClose: options.onClose,
193
+ draggable: options.draggable
190
194
  }
191
195
  });
192
196
  },
@@ -196,7 +200,10 @@ const userAction = {
196
200
  type: constants_1.TOASTER_TYPE.UserAction,
197
201
  toasterProps: Object.assign(Object.assign({}, options), {
198
202
  appearance: 'success'
199
- })
203
+ }),
204
+ toastOptions: {
205
+ draggable: options.draggable
206
+ }
200
207
  });
201
208
  },
202
209
  neutral(id, options) {
@@ -204,7 +211,10 @@ const userAction = {
204
211
  type: constants_1.TOASTER_TYPE.UserAction,
205
212
  toasterProps: Object.assign(Object.assign({}, options), {
206
213
  appearance: 'neutral'
207
- })
214
+ }),
215
+ toastOptions: {
216
+ draggable: options.draggable
217
+ }
208
218
  });
209
219
  },
210
220
  warning(id, options) {
@@ -212,7 +222,10 @@ const userAction = {
212
222
  type: constants_1.TOASTER_TYPE.UserAction,
213
223
  toasterProps: Object.assign(Object.assign({}, options), {
214
224
  appearance: 'warning'
215
- })
225
+ }),
226
+ toastOptions: {
227
+ draggable: options.draggable
228
+ }
216
229
  });
217
230
  },
218
231
  error(id, options) {
@@ -220,7 +233,10 @@ const userAction = {
220
233
  type: constants_1.TOASTER_TYPE.UserAction,
221
234
  toasterProps: Object.assign(Object.assign({}, options), {
222
235
  appearance: 'error'
223
- })
236
+ }),
237
+ toastOptions: {
238
+ draggable: options.draggable
239
+ }
224
240
  });
225
241
  }
226
242
  },
@@ -237,7 +253,8 @@ const systemEvent = {
237
253
  }),
238
254
  toastOptions: {
239
255
  id: options.id,
240
- onClose: options.onClose
256
+ onClose: options.onClose,
257
+ draggable: options.draggable
241
258
  }
242
259
  });
243
260
  },
@@ -249,7 +266,8 @@ const systemEvent = {
249
266
  }),
250
267
  toastOptions: {
251
268
  id: options.id,
252
- onClose: options.onClose
269
+ onClose: options.onClose,
270
+ draggable: options.draggable
253
271
  }
254
272
  });
255
273
  },
@@ -261,7 +279,8 @@ const systemEvent = {
261
279
  }),
262
280
  toastOptions: {
263
281
  id: options.id,
264
- onClose: options.onClose
282
+ onClose: options.onClose,
283
+ draggable: options.draggable
265
284
  }
266
285
  });
267
286
  },
@@ -273,7 +292,8 @@ const systemEvent = {
273
292
  }),
274
293
  toastOptions: {
275
294
  id: options.id,
276
- onClose: options.onClose
295
+ onClose: options.onClose,
296
+ draggable: options.draggable
277
297
  }
278
298
  });
279
299
  },
@@ -285,7 +305,8 @@ const systemEvent = {
285
305
  }),
286
306
  toastOptions: {
287
307
  id: options.id,
288
- onClose: options.onClose
308
+ onClose: options.onClose,
309
+ draggable: options.draggable
289
310
  }
290
311
  });
291
312
  },
@@ -295,7 +316,10 @@ const systemEvent = {
295
316
  type: constants_1.TOASTER_TYPE.SystemEvent,
296
317
  toasterProps: Object.assign(Object.assign({}, options), {
297
318
  appearance: 'success'
298
- })
319
+ }),
320
+ toastOptions: {
321
+ draggable: options.draggable
322
+ }
299
323
  });
300
324
  },
301
325
  neutral(id, options) {
@@ -7,7 +7,8 @@ export type PromisedId = Promise<ToasterId>;
7
7
  export type ToastOptions = {
8
8
  id?: ToasterId;
9
9
  autoClose?: RtToastOptions['autoClose'];
10
- onClose?(id?: ToasterId): void;
10
+ onClose?(reason?: boolean | string): void;
11
+ draggable?: boolean;
11
12
  };
12
13
  export type ToasterType = ValueOf<typeof TOASTER_TYPE>;
13
14
  export type ToasterPropsMap = {
@@ -34,8 +35,8 @@ export type UpdateToast = <T extends keyof ToasterPropsMap>(id: string | number,
34
35
  toastOptions?: ToastOptions;
35
36
  containerId?: ToasterContainerProps['containerId'];
36
37
  }) => void;
37
- export type UserActionOptions = Omit<ToastUserActionProps, 'appearance'> & Pick<ToastOptions, 'id' | 'onClose'>;
38
- export type SystemEventOptions = Omit<ToastSystemEventProps, 'appearance'> & Pick<ToastOptions, 'id' | 'onClose'>;
38
+ export type UserActionOptions = Omit<ToastUserActionProps, 'appearance'> & Pick<ToastOptions, 'id' | 'onClose' | 'draggable'>;
39
+ export type SystemEventOptions = Omit<ToastSystemEventProps, 'appearance'> & Pick<ToastOptions, 'id' | 'onClose' | 'draggable'>;
39
40
  export type UploadOptions = ToastUploadProps & Pick<ToastOptions, 'id' | 'onClose'>;
40
41
  export type Toaster = {
41
42
  userAction: {
@@ -7,5 +7,6 @@ export type ToasterContainerProps = {
7
7
  containerId?: RtToastContainerProps['containerId'];
8
8
  displayCloseAllButton?: boolean;
9
9
  type?: ToasterType;
10
+ draggable?: boolean;
10
11
  };
11
- export declare function ToasterContainer({ position, limit, containerId, displayCloseAllButton, type, }: ToasterContainerProps): import("react/jsx-runtime").JSX.Element;
12
+ export declare function ToasterContainer({ position, limit, containerId, displayCloseAllButton, type, draggable, }: ToasterContainerProps): import("react/jsx-runtime").JSX.Element;
@@ -1,19 +1,20 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import './style.css';
3
3
  import cn from 'classnames';
4
- import { useEffect, useState } from 'react';
4
+ import { useState } from 'react';
5
5
  import { toast, ToastContainer as RtToastContainer, } from 'react-toastify';
6
+ import { useLayoutEffect } from '@snack-uikit/utils';
6
7
  import { TOASTER_CONTAINER_PREFIX, TOASTER_TYPE } from '../../constants';
7
8
  import { TOAST_SYSTEM_EVENT_TEST_IDS } from '../../testIds';
8
9
  import styles from './styles.module.css';
9
- export function ToasterContainer({ position = 'bottom-right', limit = 5, containerId, displayCloseAllButton, type = TOASTER_TYPE.SystemEvent, }) {
10
+ export function ToasterContainer({ position = 'bottom-right', limit = 5, containerId, displayCloseAllButton, type = TOASTER_TYPE.SystemEvent, draggable = false, }) {
10
11
  const [notificationCounter, setNotificationCounter] = useState(0);
11
12
  const [isCloseAllButtonHidden, setIsCloseAllButtonHidden] = useState(false);
12
13
  const closeAll = () => {
13
14
  toast.dismiss();
14
15
  setIsCloseAllButtonHidden(true);
15
16
  };
16
- useEffect(() => {
17
+ useLayoutEffect(() => {
17
18
  const unsubscribe = toast.onChange(({ status, containerId }) => {
18
19
  if (containerId === `${TOASTER_CONTAINER_PREFIX}${TOASTER_TYPE.SystemEvent}`) {
19
20
  if (status === 'added') {
@@ -28,10 +29,10 @@ export function ToasterContainer({ position = 'bottom-right', limit = 5, contain
28
29
  return unsubscribe;
29
30
  }, []);
30
31
  const hasCloseAllButton = displayCloseAllButton && notificationCounter > 2 && !isCloseAllButtonHidden;
31
- return (_jsxs(_Fragment, { children: [_jsx(RtToastContainer, { hideProgressBar: true, closeOnClick: false, autoClose: false, closeButton: false, draggable: false, className: cn('osThemeSnack', styles[position], {
32
+ return (_jsxs(_Fragment, { children: [_jsx(RtToastContainer, { hideProgressBar: true, closeOnClick: false, autoClose: false, closeButton: false, draggable: draggable, className: cn('osThemeSnack', styles[position], {
32
33
  [styles.containerWithCloseAllButton]: hasCloseAllButton,
33
34
  'osThemeSnack__toast-container__system-event': type === TOASTER_TYPE.SystemEvent,
34
35
  'osThemeSnack__toast-container__user-action': type === TOASTER_TYPE.UserAction,
35
36
  'osThemeSnack__toast-container__upload': type === TOASTER_TYPE.Upload,
36
- }), toastClassName: styles.toaster, bodyClassName: styles.toaster, position: position, limit: limit, containerId: containerId }), hasCloseAllButton && (_jsx("div", { className: cn(styles.buttonCloseColumnWrapper, styles[position]), children: _jsx("button", { type: 'button', className: styles.buttonCloseColumn, onClick: closeAll, "data-test-id": TOAST_SYSTEM_EVENT_TEST_IDS.buttonCloseColumn, children: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C \u0432\u0441\u0435" }) }))] }));
37
+ }), toastClassName: styles.toaster, position: position, limit: limit, containerId: containerId }), hasCloseAllButton && (_jsx("div", { className: cn(styles.buttonCloseColumnWrapper, styles[position]), children: _jsx("button", { type: 'button', className: styles.buttonCloseColumn, onClick: closeAll, "data-test-id": TOAST_SYSTEM_EVENT_TEST_IDS.buttonCloseColumn, children: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C \u0432\u0441\u0435" }) }))] }));
37
38
  }
@@ -66,6 +66,7 @@
66
66
  }
67
67
  :global .osThemeSnack.Toastify__toast-container{
68
68
  position:fixed;
69
+ left:auto;
69
70
  box-sizing:border-box;
70
71
  padding:0;
71
72
  }
@@ -79,6 +80,7 @@
79
80
  display:flex;
80
81
  justify-content:space-between;
81
82
  box-sizing:border-box;
83
+ width:100%;
82
84
  min-height:unset;
83
85
  margin:0;
84
86
  padding:0;
@@ -7,5 +7,5 @@ export declare const updateToast: UpdateToast;
7
7
  * @function
8
8
  */
9
9
  export declare const dismissToast: (params?: Id) => void;
10
- export declare const isToastActive: typeof import("react-toastify/dist/core/store").isToastActive;
10
+ export declare const isToastActive: (id: Id, containerId?: Id) => boolean;
11
11
  export declare const toaster: Toaster;
@@ -34,12 +34,12 @@ function getToasterContainer({ type, toasterParent, containerProps, }) {
34
34
  function getToastOptions({ type, toastOptions, containerId, toasterProps, }) {
35
35
  return {
36
36
  toastId: toastOptions === null || toastOptions === void 0 ? void 0 : toastOptions.id,
37
- onClose: ((data) => {
38
- var _a;
39
- (_a = toastOptions === null || toastOptions === void 0 ? void 0 : toastOptions.onClose) === null || _a === void 0 ? void 0 : _a.call(toastOptions, data === null || data === void 0 ? void 0 : data.id);
40
- }),
37
+ onClose: toastOptions === null || toastOptions === void 0 ? void 0 : toastOptions.onClose,
41
38
  autoClose: (toasterProps === null || toasterProps === void 0 ? void 0 : toasterProps.loading) ? false : AUTO_CLOSE_TIME[type],
42
39
  containerId: containerId || `${TOASTER_CONTAINER_PREFIX}${type}`,
40
+ draggable: toastOptions === null || toastOptions === void 0 ? void 0 : toastOptions.draggable,
41
+ draggableDirection: type === TOASTER_TYPE.UserAction ? 'y' : 'x',
42
+ draggablePercent: 30,
43
43
  };
44
44
  }
45
45
  function getToastComponent({ type, toasterProps, }) {
@@ -100,6 +100,7 @@ const userAction = {
100
100
  toastOptions: {
101
101
  id: options.id,
102
102
  onClose: options.onClose,
103
+ draggable: options.draggable,
103
104
  },
104
105
  });
105
106
  },
@@ -110,6 +111,7 @@ const userAction = {
110
111
  toastOptions: {
111
112
  id: options.id,
112
113
  onClose: options.onClose,
114
+ draggable: options.draggable,
113
115
  },
114
116
  });
115
117
  },
@@ -120,6 +122,7 @@ const userAction = {
120
122
  toastOptions: {
121
123
  id: options.id,
122
124
  onClose: options.onClose,
125
+ draggable: options.draggable,
123
126
  },
124
127
  });
125
128
  },
@@ -130,6 +133,7 @@ const userAction = {
130
133
  toastOptions: {
131
134
  id: options.id,
132
135
  onClose: options.onClose,
136
+ draggable: options.draggable,
133
137
  },
134
138
  });
135
139
  },
@@ -138,24 +142,36 @@ const userAction = {
138
142
  updateToast(id, {
139
143
  type: TOASTER_TYPE.UserAction,
140
144
  toasterProps: Object.assign(Object.assign({}, options), { appearance: 'success' }),
145
+ toastOptions: {
146
+ draggable: options.draggable,
147
+ },
141
148
  });
142
149
  },
143
150
  neutral(id, options) {
144
151
  updateToast(id, {
145
152
  type: TOASTER_TYPE.UserAction,
146
153
  toasterProps: Object.assign(Object.assign({}, options), { appearance: 'neutral' }),
154
+ toastOptions: {
155
+ draggable: options.draggable,
156
+ },
147
157
  });
148
158
  },
149
159
  warning(id, options) {
150
160
  updateToast(id, {
151
161
  type: TOASTER_TYPE.UserAction,
152
162
  toasterProps: Object.assign(Object.assign({}, options), { appearance: 'warning' }),
163
+ toastOptions: {
164
+ draggable: options.draggable,
165
+ },
153
166
  });
154
167
  },
155
168
  error(id, options) {
156
169
  updateToast(id, {
157
170
  type: TOASTER_TYPE.UserAction,
158
171
  toasterProps: Object.assign(Object.assign({}, options), { appearance: 'error' }),
172
+ toastOptions: {
173
+ draggable: options.draggable,
174
+ },
159
175
  });
160
176
  },
161
177
  },
@@ -171,6 +187,7 @@ const systemEvent = {
171
187
  toastOptions: {
172
188
  id: options.id,
173
189
  onClose: options.onClose,
190
+ draggable: options.draggable,
174
191
  },
175
192
  });
176
193
  },
@@ -181,6 +198,7 @@ const systemEvent = {
181
198
  toastOptions: {
182
199
  id: options.id,
183
200
  onClose: options.onClose,
201
+ draggable: options.draggable,
184
202
  },
185
203
  });
186
204
  },
@@ -191,6 +209,7 @@ const systemEvent = {
191
209
  toastOptions: {
192
210
  id: options.id,
193
211
  onClose: options.onClose,
212
+ draggable: options.draggable,
194
213
  },
195
214
  });
196
215
  },
@@ -201,6 +220,7 @@ const systemEvent = {
201
220
  toastOptions: {
202
221
  id: options.id,
203
222
  onClose: options.onClose,
223
+ draggable: options.draggable,
204
224
  },
205
225
  });
206
226
  },
@@ -211,6 +231,7 @@ const systemEvent = {
211
231
  toastOptions: {
212
232
  id: options.id,
213
233
  onClose: options.onClose,
234
+ draggable: options.draggable,
214
235
  },
215
236
  });
216
237
  },
@@ -219,6 +240,9 @@ const systemEvent = {
219
240
  return updateToast(id, {
220
241
  type: TOASTER_TYPE.SystemEvent,
221
242
  toasterProps: Object.assign(Object.assign({}, options), { appearance: 'success' }),
243
+ toastOptions: {
244
+ draggable: options.draggable,
245
+ },
222
246
  });
223
247
  },
224
248
  neutral(id, options) {
@@ -7,7 +7,8 @@ export type PromisedId = Promise<ToasterId>;
7
7
  export type ToastOptions = {
8
8
  id?: ToasterId;
9
9
  autoClose?: RtToastOptions['autoClose'];
10
- onClose?(id?: ToasterId): void;
10
+ onClose?(reason?: boolean | string): void;
11
+ draggable?: boolean;
11
12
  };
12
13
  export type ToasterType = ValueOf<typeof TOASTER_TYPE>;
13
14
  export type ToasterPropsMap = {
@@ -34,8 +35,8 @@ export type UpdateToast = <T extends keyof ToasterPropsMap>(id: string | number,
34
35
  toastOptions?: ToastOptions;
35
36
  containerId?: ToasterContainerProps['containerId'];
36
37
  }) => void;
37
- export type UserActionOptions = Omit<ToastUserActionProps, 'appearance'> & Pick<ToastOptions, 'id' | 'onClose'>;
38
- export type SystemEventOptions = Omit<ToastSystemEventProps, 'appearance'> & Pick<ToastOptions, 'id' | 'onClose'>;
38
+ export type UserActionOptions = Omit<ToastUserActionProps, 'appearance'> & Pick<ToastOptions, 'id' | 'onClose' | 'draggable'>;
39
+ export type SystemEventOptions = Omit<ToastSystemEventProps, 'appearance'> & Pick<ToastOptions, 'id' | 'onClose' | 'draggable'>;
39
40
  export type UploadOptions = ToastUploadProps & Pick<ToastOptions, 'id' | 'onClose'>;
40
41
  export type Toaster = {
41
42
  userAction: {
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Toaster",
7
- "version": "0.11.20",
7
+ "version": "0.11.21-preview-83f569e2.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -44,12 +44,12 @@
44
44
  "@snack-uikit/truncate-string": "0.7.6",
45
45
  "@snack-uikit/utils": "4.0.0",
46
46
  "classnames": "2.5.1",
47
- "react-draggable": "4.4.6",
48
- "react-toastify": "10.0.5",
47
+ "react-draggable": "4.5.0",
48
+ "react-toastify": "11.0.5",
49
49
  "uncontrollable": "9.0.0"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "@snack-uikit/locale": "*"
53
53
  },
54
- "gitHead": "6b39e180766635f8190da903bf560d1fbcbfaf52"
54
+ "gitHead": "7e7545cd231d23db02cc090a3199a142383ecfc0"
55
55
  }
@@ -1,7 +1,7 @@
1
1
  import './style.css';
2
2
 
3
3
  import cn from 'classnames';
4
- import { useEffect, useState } from 'react';
4
+ import { useState } from 'react';
5
5
  import {
6
6
  toast,
7
7
  ToastContainer as RtToastContainer,
@@ -10,6 +10,8 @@ import {
10
10
  ToastPosition,
11
11
  } from 'react-toastify';
12
12
 
13
+ import { useLayoutEffect } from '@snack-uikit/utils';
14
+
13
15
  import { TOASTER_CONTAINER_PREFIX, TOASTER_TYPE } from '../../constants';
14
16
  import { TOAST_SYSTEM_EVENT_TEST_IDS } from '../../testIds';
15
17
  import { ToasterType } from '../../types';
@@ -21,6 +23,7 @@ export type ToasterContainerProps = {
21
23
  containerId?: RtToastContainerProps['containerId'];
22
24
  displayCloseAllButton?: boolean;
23
25
  type?: ToasterType;
26
+ draggable?: boolean;
24
27
  };
25
28
 
26
29
  export function ToasterContainer({
@@ -29,6 +32,7 @@ export function ToasterContainer({
29
32
  containerId,
30
33
  displayCloseAllButton,
31
34
  type = TOASTER_TYPE.SystemEvent,
35
+ draggable = false,
32
36
  }: ToasterContainerProps) {
33
37
  const [notificationCounter, setNotificationCounter] = useState(0);
34
38
  const [isCloseAllButtonHidden, setIsCloseAllButtonHidden] = useState(false);
@@ -37,7 +41,7 @@ export function ToasterContainer({
37
41
  setIsCloseAllButtonHidden(true);
38
42
  };
39
43
 
40
- useEffect(() => {
44
+ useLayoutEffect(() => {
41
45
  const unsubscribe = toast.onChange(({ status, containerId }: ToastItem) => {
42
46
  if (containerId === `${TOASTER_CONTAINER_PREFIX}${TOASTER_TYPE.SystemEvent}`) {
43
47
  if (status === 'added') {
@@ -62,7 +66,7 @@ export function ToasterContainer({
62
66
  closeOnClick={false}
63
67
  autoClose={false}
64
68
  closeButton={false}
65
- draggable={false}
69
+ draggable={draggable}
66
70
  className={cn('osThemeSnack', styles[position], {
67
71
  [styles.containerWithCloseAllButton]: hasCloseAllButton,
68
72
  'osThemeSnack__toast-container__system-event': type === TOASTER_TYPE.SystemEvent,
@@ -70,7 +74,6 @@ export function ToasterContainer({
70
74
  'osThemeSnack__toast-container__upload': type === TOASTER_TYPE.Upload,
71
75
  })}
72
76
  toastClassName={styles.toaster}
73
- bodyClassName={styles.toaster}
74
77
  position={position}
75
78
  limit={limit}
76
79
  containerId={containerId}
@@ -76,6 +76,7 @@ $theme-name: osThemeSnack;
76
76
  :global {
77
77
  .#{$theme-name}.Toastify__toast-container {
78
78
  position: fixed;
79
+ left: auto;
79
80
  box-sizing: border-box;
80
81
  padding: 0;
81
82
 
@@ -94,6 +95,7 @@ $theme-name: osThemeSnack;
94
95
  justify-content: space-between;
95
96
 
96
97
  box-sizing: border-box;
98
+ width: 100%;
97
99
  min-height: unset;
98
100
  margin: 0;
99
101
  padding: 0;
package/src/helpers.tsx CHANGED
@@ -80,11 +80,12 @@ function getToastOptions<T extends keyof ToasterPropsMap>({
80
80
  }): RtToastOptions {
81
81
  return {
82
82
  toastId: toastOptions?.id,
83
- onClose: ((data: { id: ToasterId }) => {
84
- toastOptions?.onClose?.(data?.id);
85
- }) as RtToastOptions['onClose'],
83
+ onClose: toastOptions?.onClose,
86
84
  autoClose: toasterProps?.loading ? false : AUTO_CLOSE_TIME[type],
87
85
  containerId: containerId || `${TOASTER_CONTAINER_PREFIX}${type}`,
86
+ draggable: toastOptions?.draggable,
87
+ draggableDirection: type === TOASTER_TYPE.UserAction ? 'y' : 'x',
88
+ draggablePercent: 30,
88
89
  };
89
90
  }
90
91
 
@@ -172,6 +173,7 @@ const userAction = {
172
173
  toastOptions: {
173
174
  id: options.id,
174
175
  onClose: options.onClose,
176
+ draggable: options.draggable,
175
177
  },
176
178
  });
177
179
  },
@@ -183,6 +185,7 @@ const userAction = {
183
185
  toastOptions: {
184
186
  id: options.id,
185
187
  onClose: options.onClose,
188
+ draggable: options.draggable,
186
189
  },
187
190
  });
188
191
  },
@@ -194,6 +197,7 @@ const userAction = {
194
197
  toastOptions: {
195
198
  id: options.id,
196
199
  onClose: options.onClose,
200
+ draggable: options.draggable,
197
201
  },
198
202
  });
199
203
  },
@@ -205,6 +209,7 @@ const userAction = {
205
209
  toastOptions: {
206
210
  id: options.id,
207
211
  onClose: options.onClose,
212
+ draggable: options.draggable,
208
213
  },
209
214
  });
210
215
  },
@@ -214,6 +219,9 @@ const userAction = {
214
219
  updateToast(id, {
215
220
  type: TOASTER_TYPE.UserAction,
216
221
  toasterProps: { ...options, appearance: 'success' },
222
+ toastOptions: {
223
+ draggable: options.draggable,
224
+ },
217
225
  });
218
226
  },
219
227
 
@@ -221,6 +229,9 @@ const userAction = {
221
229
  updateToast(id, {
222
230
  type: TOASTER_TYPE.UserAction,
223
231
  toasterProps: { ...options, appearance: 'neutral' },
232
+ toastOptions: {
233
+ draggable: options.draggable,
234
+ },
224
235
  });
225
236
  },
226
237
 
@@ -228,6 +239,9 @@ const userAction = {
228
239
  updateToast(id, {
229
240
  type: TOASTER_TYPE.UserAction,
230
241
  toasterProps: { ...options, appearance: 'warning' },
242
+ toastOptions: {
243
+ draggable: options.draggable,
244
+ },
231
245
  });
232
246
  },
233
247
 
@@ -235,6 +249,9 @@ const userAction = {
235
249
  updateToast(id, {
236
250
  type: TOASTER_TYPE.UserAction,
237
251
  toasterProps: { ...options, appearance: 'error' },
252
+ toastOptions: {
253
+ draggable: options.draggable,
254
+ },
238
255
  });
239
256
  },
240
257
  },
@@ -252,6 +269,7 @@ const systemEvent = {
252
269
  toastOptions: {
253
270
  id: options.id,
254
271
  onClose: options.onClose,
272
+ draggable: options.draggable,
255
273
  },
256
274
  });
257
275
  },
@@ -263,6 +281,7 @@ const systemEvent = {
263
281
  toastOptions: {
264
282
  id: options.id,
265
283
  onClose: options.onClose,
284
+ draggable: options.draggable,
266
285
  },
267
286
  });
268
287
  },
@@ -274,6 +293,7 @@ const systemEvent = {
274
293
  toastOptions: {
275
294
  id: options.id,
276
295
  onClose: options.onClose,
296
+ draggable: options.draggable,
277
297
  },
278
298
  });
279
299
  },
@@ -285,6 +305,7 @@ const systemEvent = {
285
305
  toastOptions: {
286
306
  id: options.id,
287
307
  onClose: options.onClose,
308
+ draggable: options.draggable,
288
309
  },
289
310
  });
290
311
  },
@@ -296,6 +317,7 @@ const systemEvent = {
296
317
  toastOptions: {
297
318
  id: options.id,
298
319
  onClose: options.onClose,
320
+ draggable: options.draggable,
299
321
  },
300
322
  });
301
323
  },
@@ -305,6 +327,9 @@ const systemEvent = {
305
327
  return updateToast(id, {
306
328
  type: TOASTER_TYPE.SystemEvent,
307
329
  toasterProps: { ...options, appearance: 'success' },
330
+ toastOptions: {
331
+ draggable: options.draggable,
332
+ },
308
333
  });
309
334
  },
310
335
 
package/src/types.ts CHANGED
@@ -11,7 +11,8 @@ export type PromisedId = Promise<ToasterId>;
11
11
  export type ToastOptions = {
12
12
  id?: ToasterId;
13
13
  autoClose?: RtToastOptions['autoClose'];
14
- onClose?(id?: ToasterId): void;
14
+ onClose?(reason?: boolean | string): void;
15
+ draggable?: boolean;
15
16
  };
16
17
 
17
18
  export type ToasterType = ValueOf<typeof TOASTER_TYPE>;
@@ -48,8 +49,10 @@ export type UpdateToast = <T extends keyof ToasterPropsMap>(
48
49
  },
49
50
  ) => void;
50
51
 
51
- export type UserActionOptions = Omit<ToastUserActionProps, 'appearance'> & Pick<ToastOptions, 'id' | 'onClose'>;
52
- export type SystemEventOptions = Omit<ToastSystemEventProps, 'appearance'> & Pick<ToastOptions, 'id' | 'onClose'>;
52
+ export type UserActionOptions = Omit<ToastUserActionProps, 'appearance'> &
53
+ Pick<ToastOptions, 'id' | 'onClose' | 'draggable'>;
54
+ export type SystemEventOptions = Omit<ToastSystemEventProps, 'appearance'> &
55
+ Pick<ToastOptions, 'id' | 'onClose' | 'draggable'>;
53
56
  export type UploadOptions = ToastUploadProps & Pick<ToastOptions, 'id' | 'onClose'>;
54
57
 
55
58
  export type Toaster = {