@ttoss/react-notifications 1.22.25 → 1.23.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 +39 -0
- package/dist/esm/index.js +55 -18
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +54 -17
- package/package.json +1 -1
- package/src/NotificationsBox.tsx +71 -32
- package/src/NotificationsModal.tsx +23 -3
- package/src/Provider.tsx +1 -0
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 === "
|
|
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 = "
|
|
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
|
-
|
|
90
|
-
|
|
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(
|
|
98
|
-
return setNotifications(
|
|
99
|
-
return notification.
|
|
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,33 +133,49 @@ var NotificationsBox = ({
|
|
|
112
133
|
notifications,
|
|
113
134
|
direction
|
|
114
135
|
},
|
|
115
|
-
children: Array.isArray(
|
|
136
|
+
children: Array.isArray(renderNotifications) ? renderNotifications.map(notification => {
|
|
116
137
|
return /* @__PURE__ */jsx2(ButtonMemoized, {
|
|
117
|
-
|
|
118
|
-
},
|
|
138
|
+
notification
|
|
139
|
+
}, notification.key);
|
|
119
140
|
}) : /* @__PURE__ */jsx2(ButtonMemoized, {
|
|
120
|
-
|
|
141
|
+
notification: renderNotifications
|
|
121
142
|
})
|
|
122
143
|
});
|
|
123
144
|
};
|
|
124
145
|
|
|
125
146
|
// src/NotificationsModal.tsx
|
|
147
|
+
import { Button as Button2, Icon } from "@ttoss/ui";
|
|
126
148
|
import { Modal } from "@ttoss/components";
|
|
127
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
149
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
128
150
|
var NotificationsModal = () => {
|
|
129
151
|
const {
|
|
130
|
-
notifications
|
|
152
|
+
notifications,
|
|
153
|
+
setNotifications
|
|
131
154
|
} = useNotifications();
|
|
132
|
-
return /* @__PURE__ */
|
|
155
|
+
return /* @__PURE__ */jsxs2(Modal, {
|
|
133
156
|
isOpen: !!notifications,
|
|
134
157
|
style: {
|
|
135
158
|
content: {
|
|
136
|
-
minWidth: "30%"
|
|
159
|
+
minWidth: "30%",
|
|
160
|
+
display: "flex",
|
|
161
|
+
flexDirection: "column",
|
|
162
|
+
alignItems: "center"
|
|
137
163
|
}
|
|
138
164
|
},
|
|
139
|
-
children: /* @__PURE__ */jsx3(
|
|
140
|
-
|
|
141
|
-
|
|
165
|
+
children: [/* @__PURE__ */jsx3(Button2, {
|
|
166
|
+
placeholder: "Close",
|
|
167
|
+
style: {
|
|
168
|
+
alignSelf: "flex-end"
|
|
169
|
+
},
|
|
170
|
+
onClick: () => {
|
|
171
|
+
setNotifications(void 0);
|
|
172
|
+
},
|
|
173
|
+
children: /* @__PURE__ */jsx3(Icon, {
|
|
174
|
+
icon: "close"
|
|
175
|
+
})
|
|
176
|
+
}), /* @__PURE__ */jsx3(NotificationsBox, {
|
|
177
|
+
direction: "row"
|
|
178
|
+
})]
|
|
142
179
|
});
|
|
143
180
|
};
|
|
144
181
|
export { NotificationsBox, NotificationsModal, NotificationsProvider, useNotifications };
|
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?: "
|
|
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?: "
|
|
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 === "
|
|
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 = "
|
|
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
|
-
|
|
135
|
-
|
|
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(
|
|
143
|
-
return setNotifications(
|
|
144
|
-
return notification.
|
|
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,33 +178,49 @@ var NotificationsBox = ({
|
|
|
157
178
|
notifications,
|
|
158
179
|
direction
|
|
159
180
|
},
|
|
160
|
-
children: Array.isArray(
|
|
181
|
+
children: Array.isArray(renderNotifications) ? renderNotifications.map(notification => {
|
|
161
182
|
return /* @__PURE__ */(0, import_jsx_runtime2.jsx)(ButtonMemoized, {
|
|
162
|
-
|
|
163
|
-
},
|
|
183
|
+
notification
|
|
184
|
+
}, notification.key);
|
|
164
185
|
}) : /* @__PURE__ */(0, import_jsx_runtime2.jsx)(ButtonMemoized, {
|
|
165
|
-
|
|
186
|
+
notification: renderNotifications
|
|
166
187
|
})
|
|
167
188
|
});
|
|
168
189
|
};
|
|
169
190
|
|
|
170
191
|
// src/NotificationsModal.tsx
|
|
192
|
+
var import_ui3 = require("@ttoss/ui");
|
|
171
193
|
var import_components = require("@ttoss/components");
|
|
172
194
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
173
195
|
var NotificationsModal = () => {
|
|
174
196
|
const {
|
|
175
|
-
notifications
|
|
197
|
+
notifications,
|
|
198
|
+
setNotifications
|
|
176
199
|
} = useNotifications();
|
|
177
|
-
return /* @__PURE__ */(0, import_jsx_runtime3.
|
|
200
|
+
return /* @__PURE__ */(0, import_jsx_runtime3.jsxs)(import_components.Modal, {
|
|
178
201
|
isOpen: !!notifications,
|
|
179
202
|
style: {
|
|
180
203
|
content: {
|
|
181
|
-
minWidth: "30%"
|
|
204
|
+
minWidth: "30%",
|
|
205
|
+
display: "flex",
|
|
206
|
+
flexDirection: "column",
|
|
207
|
+
alignItems: "center"
|
|
182
208
|
}
|
|
183
209
|
},
|
|
184
|
-
children: /* @__PURE__ */(0, import_jsx_runtime3.jsx)(
|
|
185
|
-
|
|
186
|
-
|
|
210
|
+
children: [/* @__PURE__ */(0, import_jsx_runtime3.jsx)(import_ui3.Button, {
|
|
211
|
+
placeholder: "Close",
|
|
212
|
+
style: {
|
|
213
|
+
alignSelf: "flex-end"
|
|
214
|
+
},
|
|
215
|
+
onClick: () => {
|
|
216
|
+
setNotifications(void 0);
|
|
217
|
+
},
|
|
218
|
+
children: /* @__PURE__ */(0, import_jsx_runtime3.jsx)(import_ui3.Icon, {
|
|
219
|
+
icon: "close"
|
|
220
|
+
})
|
|
221
|
+
}), /* @__PURE__ */(0, import_jsx_runtime3.jsx)(NotificationsBox, {
|
|
222
|
+
direction: "row"
|
|
223
|
+
})]
|
|
187
224
|
});
|
|
188
225
|
};
|
|
189
226
|
// Annotate the CommonJS export names for ESM import in node:
|
package/package.json
CHANGED
package/src/NotificationsBox.tsx
CHANGED
|
@@ -7,7 +7,7 @@ const NotificationBoxWrapper = ({
|
|
|
7
7
|
notifications,
|
|
8
8
|
children,
|
|
9
9
|
}: React.PropsWithChildren<{
|
|
10
|
-
direction: '
|
|
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 === '
|
|
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 = '
|
|
59
|
+
direction = 'row',
|
|
32
60
|
}: {
|
|
33
|
-
direction?: '
|
|
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
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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(
|
|
70
|
-
|
|
108
|
+
{Array.isArray(renderNotifications) ? (
|
|
109
|
+
renderNotifications.map((notification) => {
|
|
71
110
|
return (
|
|
72
111
|
<ButtonMemoized
|
|
73
|
-
key={
|
|
74
|
-
{
|
|
112
|
+
key={notification.key}
|
|
113
|
+
notification={notification}
|
|
75
114
|
/>
|
|
76
115
|
);
|
|
77
116
|
})
|
|
78
117
|
) : (
|
|
79
|
-
<ButtonMemoized {
|
|
118
|
+
<ButtonMemoized notification={renderNotifications} />
|
|
80
119
|
)}
|
|
81
120
|
</NotificationBoxWrapper>
|
|
82
121
|
);
|
|
@@ -1,13 +1,33 @@
|
|
|
1
|
+
import { Button, Icon } from '@ttoss/ui';
|
|
1
2
|
import { Modal } from '@ttoss/components';
|
|
2
3
|
import { NotificationsBox } from './NotificationsBox';
|
|
3
4
|
import { useNotifications } from './Provider';
|
|
4
5
|
|
|
5
6
|
export const NotificationsModal = () => {
|
|
6
|
-
const { notifications } = useNotifications();
|
|
7
|
+
const { notifications, setNotifications } = useNotifications();
|
|
7
8
|
|
|
8
9
|
return (
|
|
9
|
-
<Modal
|
|
10
|
-
|
|
10
|
+
<Modal
|
|
11
|
+
isOpen={!!notifications}
|
|
12
|
+
style={{
|
|
13
|
+
content: {
|
|
14
|
+
minWidth: '30%',
|
|
15
|
+
display: 'flex',
|
|
16
|
+
flexDirection: 'column',
|
|
17
|
+
alignItems: 'center',
|
|
18
|
+
},
|
|
19
|
+
}}
|
|
20
|
+
>
|
|
21
|
+
<Button
|
|
22
|
+
placeholder="Close"
|
|
23
|
+
style={{ alignSelf: 'flex-end' }}
|
|
24
|
+
onClick={() => {
|
|
25
|
+
setNotifications(undefined);
|
|
26
|
+
}}
|
|
27
|
+
>
|
|
28
|
+
<Icon icon={'close'}></Icon>
|
|
29
|
+
</Button>
|
|
30
|
+
<NotificationsBox direction="row" />
|
|
11
31
|
</Modal>
|
|
12
32
|
);
|
|
13
33
|
};
|