@ttoss/react-notifications 1.22.24 → 1.22.26

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
@@ -77,3 +77,42 @@ const Component = () => {
77
77
  );
78
78
  };
79
79
  ```
80
+
81
+ ### Resolving notifications
82
+
83
+ Additionally, the API accepts a third property in `setNotifications`: `notificationKey`.
84
+ In this property, you can insert a placeholder for a particular notification, and, the library gonna resolve any repetated key for this notification to be only one notification.
85
+
86
+ In that way, you have more control if you gonna render a repeated notification or not:
87
+
88
+ ```tsx
89
+ import { useNotifications } from '@ttoss/react-notifications';
90
+
91
+ const Component = () => {
92
+ const { setNotifications } = useNotifications();
93
+
94
+ return (
95
+ <div>
96
+ <button
97
+ onClick={() =>
98
+ setNotifications([
99
+ {
100
+ message: "I'm a notification",
101
+ type: 'info',
102
+ key: 'information',
103
+ },
104
+ {
105
+ message: "I'm considered to be the same notification",
106
+ type: 'info',
107
+ key: 'information',
108
+ },
109
+ ])
110
+ }
111
+ >
112
+ Click Me!
113
+ </button>
114
+ <NotificationsModal />
115
+ </div>
116
+ );
117
+ };
118
+ ```
package/dist/esm/index.js CHANGED
@@ -67,7 +67,7 @@ var NotificationBoxWrapper = ({
67
67
  gap: "md",
68
68
  marginTop: !notifications || Array.isArray(notifications) && !notifications.length ? 0 : "2xl"
69
69
  };
70
- return direction === "flex" ? /* @__PURE__ */jsx2(Flex2, {
70
+ return direction === "row" ? /* @__PURE__ */jsx2(Flex2, {
71
71
  sx,
72
72
  children
73
73
  }) : /* @__PURE__ */jsx2(Stack, {
@@ -75,8 +75,25 @@ var NotificationBoxWrapper = ({
75
75
  children
76
76
  });
77
77
  };
78
+ var resolveNotifications = notifications => {
79
+ if (!Array.isArray(notifications)) return notifications;
80
+ const keyedNotifications = new Map(notifications.filter(notification => {
81
+ return notification.key;
82
+ }).map(notification => {
83
+ return [notification?.key, notification];
84
+ })).values();
85
+ const nonKeyedNotifications = notifications.filter(notification => {
86
+ return !notification.key;
87
+ }).map((notification, index) => {
88
+ return {
89
+ ...notification,
90
+ key: index.toString()
91
+ };
92
+ });
93
+ return Array.from(keyedNotifications).concat(nonKeyedNotifications);
94
+ };
78
95
  var NotificationsBox = ({
79
- direction = "flex"
96
+ direction = "row"
80
97
  }) => {
81
98
  const {
82
99
  setNotifications,
@@ -85,18 +102,22 @@ var NotificationsBox = ({
85
102
  if (!notifications) {
86
103
  return null;
87
104
  }
105
+ const renderNotifications = resolveNotifications(notifications);
88
106
  const ButtonMemoized = /*#__PURE__*/React2.memo(({
89
- message,
90
- type
107
+ notification: {
108
+ key,
109
+ type,
110
+ message
111
+ }
91
112
  }) => {
92
113
  return /* @__PURE__ */jsx2(Button, {
93
114
  sx: {
94
115
  backgroundColor: type === "error" ? "danger" : "positive"
95
116
  },
96
117
  onClick: () => {
97
- if (Array.isArray(notifications) && notifications.length > 1) {
98
- return setNotifications(notifications.filter(notification => {
99
- return notification.message !== message;
118
+ if (Array.isArray(renderNotifications) && renderNotifications.length > 1) {
119
+ return setNotifications(renderNotifications.filter(notification => {
120
+ return notification.key !== key;
100
121
  }));
101
122
  }
102
123
  return setNotifications(void 0);
@@ -112,12 +133,12 @@ var NotificationsBox = ({
112
133
  notifications,
113
134
  direction
114
135
  },
115
- children: Array.isArray(notifications) ? notifications.map(notification => {
136
+ children: Array.isArray(renderNotifications) ? renderNotifications.map(notification => {
116
137
  return /* @__PURE__ */jsx2(ButtonMemoized, {
117
- ...notification
118
- }, JSON.stringify(notification));
138
+ notification
139
+ }, notification.key);
119
140
  }) : /* @__PURE__ */jsx2(ButtonMemoized, {
120
- ...notifications
141
+ notification: renderNotifications
121
142
  })
122
143
  });
123
144
  };
@@ -137,7 +158,7 @@ var NotificationsModal = () => {
137
158
  }
138
159
  },
139
160
  children: /* @__PURE__ */jsx3(NotificationsBox, {
140
- direction: "stack"
161
+ direction: "row"
141
162
  })
142
163
  });
143
164
  };
package/dist/index.d.mts CHANGED
@@ -2,6 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
 
4
4
  type NotifyParams = {
5
+ key?: string;
5
6
  message: 'string' | React.ReactNode;
6
7
  type: 'success' | 'error' | 'warning' | 'info';
7
8
  };
@@ -18,7 +19,7 @@ declare const useNotifications: () => {
18
19
  };
19
20
 
20
21
  declare const NotificationsBox: ({ direction, }: {
21
- direction?: "flex" | "stack" | undefined;
22
+ direction?: "row" | "column" | undefined;
22
23
  }) => react_jsx_runtime.JSX.Element | null;
23
24
 
24
25
  declare const NotificationsModal: () => react_jsx_runtime.JSX.Element;
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
 
4
4
  type NotifyParams = {
5
+ key?: string;
5
6
  message: 'string' | React.ReactNode;
6
7
  type: 'success' | 'error' | 'warning' | 'info';
7
8
  };
@@ -18,7 +19,7 @@ declare const useNotifications: () => {
18
19
  };
19
20
 
20
21
  declare const NotificationsBox: ({ direction, }: {
21
- direction?: "flex" | "stack" | undefined;
22
+ direction?: "row" | "column" | undefined;
22
23
  }) => react_jsx_runtime.JSX.Element | null;
23
24
 
24
25
  declare const NotificationsModal: () => react_jsx_runtime.JSX.Element;
package/dist/index.js CHANGED
@@ -112,7 +112,7 @@ var NotificationBoxWrapper = ({
112
112
  gap: "md",
113
113
  marginTop: !notifications || Array.isArray(notifications) && !notifications.length ? 0 : "2xl"
114
114
  };
115
- return direction === "flex" ? /* @__PURE__ */(0, import_jsx_runtime2.jsx)(import_ui2.Flex, {
115
+ return direction === "row" ? /* @__PURE__ */(0, import_jsx_runtime2.jsx)(import_ui2.Flex, {
116
116
  sx,
117
117
  children
118
118
  }) : /* @__PURE__ */(0, import_jsx_runtime2.jsx)(import_ui2.Stack, {
@@ -120,8 +120,25 @@ var NotificationBoxWrapper = ({
120
120
  children
121
121
  });
122
122
  };
123
+ var resolveNotifications = notifications => {
124
+ if (!Array.isArray(notifications)) return notifications;
125
+ const keyedNotifications = new Map(notifications.filter(notification => {
126
+ return notification.key;
127
+ }).map(notification => {
128
+ return [notification?.key, notification];
129
+ })).values();
130
+ const nonKeyedNotifications = notifications.filter(notification => {
131
+ return !notification.key;
132
+ }).map((notification, index) => {
133
+ return {
134
+ ...notification,
135
+ key: index.toString()
136
+ };
137
+ });
138
+ return Array.from(keyedNotifications).concat(nonKeyedNotifications);
139
+ };
123
140
  var NotificationsBox = ({
124
- direction = "flex"
141
+ direction = "row"
125
142
  }) => {
126
143
  const {
127
144
  setNotifications,
@@ -130,18 +147,22 @@ var NotificationsBox = ({
130
147
  if (!notifications) {
131
148
  return null;
132
149
  }
150
+ const renderNotifications = resolveNotifications(notifications);
133
151
  const ButtonMemoized = React2.memo(({
134
- message,
135
- type
152
+ notification: {
153
+ key,
154
+ type,
155
+ message
156
+ }
136
157
  }) => {
137
158
  return /* @__PURE__ */(0, import_jsx_runtime2.jsx)(import_ui2.Button, {
138
159
  sx: {
139
160
  backgroundColor: type === "error" ? "danger" : "positive"
140
161
  },
141
162
  onClick: () => {
142
- if (Array.isArray(notifications) && notifications.length > 1) {
143
- return setNotifications(notifications.filter(notification => {
144
- return notification.message !== message;
163
+ if (Array.isArray(renderNotifications) && renderNotifications.length > 1) {
164
+ return setNotifications(renderNotifications.filter(notification => {
165
+ return notification.key !== key;
145
166
  }));
146
167
  }
147
168
  return setNotifications(void 0);
@@ -157,12 +178,12 @@ var NotificationsBox = ({
157
178
  notifications,
158
179
  direction
159
180
  },
160
- children: Array.isArray(notifications) ? notifications.map(notification => {
181
+ children: Array.isArray(renderNotifications) ? renderNotifications.map(notification => {
161
182
  return /* @__PURE__ */(0, import_jsx_runtime2.jsx)(ButtonMemoized, {
162
- ...notification
163
- }, JSON.stringify(notification));
183
+ notification
184
+ }, notification.key);
164
185
  }) : /* @__PURE__ */(0, import_jsx_runtime2.jsx)(ButtonMemoized, {
165
- ...notifications
186
+ notification: renderNotifications
166
187
  })
167
188
  });
168
189
  };
@@ -182,7 +203,7 @@ var NotificationsModal = () => {
182
203
  }
183
204
  },
184
205
  children: /* @__PURE__ */(0, import_jsx_runtime3.jsx)(NotificationsBox, {
185
- direction: "stack"
206
+ direction: "row"
186
207
  })
187
208
  });
188
209
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/react-notifications",
3
- "version": "1.22.24",
3
+ "version": "1.22.26",
4
4
  "description": "ttoss notifications module for React apps.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "ttoss",
@@ -22,15 +22,15 @@
22
22
  "typings": "dist/index.d.ts",
23
23
  "peerDependencies": {
24
24
  "react": ">=16.8.0",
25
- "@ttoss/components": "^1.29.7",
26
- "@ttoss/ui": "^2.0.3"
25
+ "@ttoss/components": "^1.29.8",
26
+ "@ttoss/ui": "^2.0.4"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/react": "^18.2.12",
30
30
  "jest": "^29.6.1",
31
31
  "react": "^18.2.0",
32
32
  "tsup": "^7.1.0",
33
- "@ttoss/components": "^1.29.7",
33
+ "@ttoss/components": "^1.29.8",
34
34
  "@ttoss/config": "^1.30.5",
35
35
  "@ttoss/test-utils": "^1.23.6"
36
36
  },
@@ -7,7 +7,7 @@ const NotificationBoxWrapper = ({
7
7
  notifications,
8
8
  children,
9
9
  }: React.PropsWithChildren<{
10
- direction: 'flex' | 'stack';
10
+ direction: 'row' | 'column';
11
11
  notifications: NotifyParams | NotifyParams[] | undefined;
12
12
  }>) => {
13
13
  const sx = {
@@ -20,17 +20,45 @@ const NotificationBoxWrapper = ({
20
20
  : '2xl',
21
21
  };
22
22
 
23
- return direction === 'flex' ? (
23
+ return direction === 'row' ? (
24
24
  <Flex sx={sx}>{children}</Flex>
25
25
  ) : (
26
26
  <Stack sx={sx}>{children}</Stack>
27
27
  );
28
28
  };
29
29
 
30
+ const resolveNotifications = (notifications: NotifyParams | NotifyParams[]) => {
31
+ if (!Array.isArray(notifications)) return notifications;
32
+
33
+ // keyed notifications should be unique
34
+ const keyedNotifications = new Map<string | undefined, NotifyParams>(
35
+ notifications
36
+ .filter((notification) => {
37
+ return notification.key;
38
+ })
39
+ .map((notification) => {
40
+ return [notification?.key, notification];
41
+ })
42
+ ).values();
43
+
44
+ const nonKeyedNotifications = notifications
45
+ .filter((notification) => {
46
+ return !notification.key;
47
+ })
48
+ .map((notification, index) => {
49
+ return {
50
+ ...notification,
51
+ key: index.toString() as string,
52
+ };
53
+ });
54
+
55
+ return Array.from(keyedNotifications).concat(nonKeyedNotifications);
56
+ };
57
+
30
58
  export const NotificationsBox = ({
31
- direction = 'flex',
59
+ direction = 'row',
32
60
  }: {
33
- direction?: 'flex' | 'stack';
61
+ direction?: 'row' | 'column';
34
62
  }) => {
35
63
  const { setNotifications, notifications } = useNotifications();
36
64
 
@@ -38,45 +66,56 @@ export const NotificationsBox = ({
38
66
  return null;
39
67
  }
40
68
 
41
- const ButtonMemoized = React.memo(({ message, type }: NotifyParams) => {
42
- return (
43
- <Button
44
- sx={{
45
- backgroundColor: type === 'error' ? 'danger' : 'positive',
46
- }}
47
- onClick={() => {
48
- if (Array.isArray(notifications) && notifications.length > 1) {
49
- return setNotifications(
50
- notifications.filter((notification) => {
51
- return notification.message !== message;
52
- })
53
- );
54
- }
55
- return setNotifications(undefined);
56
- }}
57
- rightIcon="close"
58
- leftIcon={type === 'error' ? 'warning' : undefined}
59
- >
60
- {message}
61
- </Button>
62
- );
63
- });
69
+ const renderNotifications = resolveNotifications(notifications);
70
+
71
+ const ButtonMemoized = React.memo(
72
+ ({
73
+ notification: { key, type, message },
74
+ }: {
75
+ notification: NotifyParams;
76
+ }) => {
77
+ return (
78
+ <Button
79
+ sx={{
80
+ backgroundColor: type === 'error' ? 'danger' : 'positive',
81
+ }}
82
+ onClick={() => {
83
+ if (
84
+ Array.isArray(renderNotifications) &&
85
+ renderNotifications.length > 1
86
+ ) {
87
+ return setNotifications(
88
+ renderNotifications.filter((notification) => {
89
+ return notification.key !== key;
90
+ })
91
+ );
92
+ }
93
+ return setNotifications(undefined);
94
+ }}
95
+ rightIcon="close"
96
+ leftIcon={type === 'error' ? 'warning' : undefined}
97
+ >
98
+ {message}
99
+ </Button>
100
+ );
101
+ }
102
+ );
64
103
 
65
104
  ButtonMemoized.displayName = 'ButtonMemoized';
66
105
 
67
106
  return (
68
107
  <NotificationBoxWrapper {...{ notifications, direction }}>
69
- {Array.isArray(notifications) ? (
70
- notifications.map((notification) => {
108
+ {Array.isArray(renderNotifications) ? (
109
+ renderNotifications.map((notification) => {
71
110
  return (
72
111
  <ButtonMemoized
73
- key={JSON.stringify(notification)}
74
- {...notification}
112
+ key={notification.key}
113
+ notification={notification}
75
114
  />
76
115
  );
77
116
  })
78
117
  ) : (
79
- <ButtonMemoized {...notifications} />
118
+ <ButtonMemoized notification={renderNotifications} />
80
119
  )}
81
120
  </NotificationBoxWrapper>
82
121
  );
@@ -7,7 +7,7 @@ export const NotificationsModal = () => {
7
7
 
8
8
  return (
9
9
  <Modal isOpen={!!notifications} style={{ content: { minWidth: '30%' } }}>
10
- <NotificationsBox direction="stack" />
10
+ <NotificationsBox direction="row" />
11
11
  </Modal>
12
12
  );
13
13
  };
package/src/Provider.tsx CHANGED
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import { Flex, InfiniteLinearProgress } from '@ttoss/ui';
3
3
 
4
4
  export type NotifyParams = {
5
+ key?: string;
5
6
  message: 'string' | React.ReactNode;
6
7
  type: 'success' | 'error' | 'warning' | 'info';
7
8
  };