@cerebruminc/cerebellum 17.3.10 → 17.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # react-component-lib-boilerplate
2
2
 
3
+ ## [17.4.0](https://github.com/cerebruminc/cerebellum/compare/v17.3.10...v17.4.0) (2026-07-13)
4
+
5
+
6
+ ### Features
7
+
8
+ * **node:** update node version to be 22 ([906ccf1](https://github.com/cerebruminc/cerebellum/commit/906ccf105b79cfe286de71f09402e61ea83beefd))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **dialog:** increase the default notificationMaxHeight on notifications ([886779a](https://github.com/cerebruminc/cerebellum/commit/886779a18ae8c812b36be339ecd55986528ab5f5))
14
+
3
15
  ## [17.3.10](https://github.com/cerebruminc/cerebellum/compare/v17.3.9...v17.3.10) (2026-06-26)
4
16
 
5
17
 
package/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM node:20 as builder
1
+ FROM node:22 as builder
2
2
 
3
3
  ARG NPM_TOKEN
4
4
 
@@ -8,7 +8,7 @@ COPY . .
8
8
 
9
9
  RUN npm ci --include=dev && NODE_OPTIONS=--max_old_space_size=8192 npm run build-storybook
10
10
 
11
- FROM node:20-alpine
11
+ FROM node:22-alpine
12
12
 
13
13
  COPY --from=builder ./docs/ ./docs
14
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cerebruminc/cerebellum",
3
- "version": "17.3.10",
3
+ "version": "17.4.0",
4
4
  "description": "Cerebrum's React Component Library",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -698,6 +698,11 @@ export const createCustomMantineTheme = (optionsOrBrandColor?: CreateCustomManti
698
698
  label: getLabelStyles(theme),
699
699
  }),
700
700
  },
701
+ Notifications: {
702
+ defaultProps: {
703
+ notificationMaxHeight: 800,
704
+ },
705
+ },
701
706
  Notification: {
702
707
  defaultProps: {
703
708
  classNames: {
@@ -0,0 +1,290 @@
1
+ import { Button, Group, Stack } from "@mantine/core";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+ import React from "react";
4
+ import { showBar, showDialog, showToast } from "../services/notifications";
5
+
6
+ /**
7
+ * Mantine notification wrappers: `showToast`, `showBar`, and `showDialog`.
8
+ *
9
+ * Switch between Cerebellum and High Contrast themes in the Storybook toolbar
10
+ * to verify visual parity with the styled-components equivalents.
11
+ */
12
+ const meta: Meta = {
13
+ title: "Mantine/Notifications",
14
+ };
15
+
16
+ export default meta;
17
+
18
+ // ---------- Toast ----------
19
+
20
+ export const Toast: StoryObj = {
21
+ name: "Toast",
22
+ render: () => (
23
+ <Stack gap="md">
24
+ <Group>
25
+ <Button onClick={() => showToast({ message: "Neutral toast notification" })}>Neutral</Button>
26
+ <Button color="aqua" onClick={() => showToast({ message: "Positive toast", tone: "positive" })}>
27
+ Positive
28
+ </Button>
29
+ <Button color="red" onClick={() => showToast({ message: "Negative toast", tone: "negative" })}>
30
+ Negative
31
+ </Button>
32
+ </Group>
33
+ </Stack>
34
+ ),
35
+ };
36
+
37
+ // ---------- Bar ----------
38
+
39
+ export const Bar: StoryObj = {
40
+ name: "Bar",
41
+ render: () => (
42
+ <Stack gap="md">
43
+ <Group>
44
+ <Button
45
+ color="aqua"
46
+ onClick={() =>
47
+ showBar({
48
+ message: "Changes saved",
49
+ tone: "positive",
50
+ })
51
+ }
52
+ >
53
+ Positive
54
+ </Button>
55
+ <Button
56
+ color="red"
57
+ onClick={() =>
58
+ showBar({
59
+ message: "Connection lost",
60
+ tone: "negative",
61
+ })
62
+ }
63
+ >
64
+ Negative
65
+ </Button>
66
+ <Button
67
+ onClick={() =>
68
+ showBar({
69
+ message: "Something happened",
70
+ tone: "neutral",
71
+ })
72
+ }
73
+ >
74
+ Neutral
75
+ </Button>
76
+ <Button
77
+ color="red"
78
+ variant="light"
79
+ onClick={() =>
80
+ showBar({
81
+ message: "Connection lost",
82
+ tone: "negative",
83
+ buttonText: "Retry",
84
+ buttonClick: () => console.log("Retry clicked"),
85
+ })
86
+ }
87
+ >
88
+ Negative with action
89
+ </Button>
90
+ <Button
91
+ color="aqua"
92
+ variant="light"
93
+ onClick={() =>
94
+ showBar({
95
+ message: "File uploaded successfully",
96
+ tone: "positive",
97
+ buttonText: "View",
98
+ buttonClick: () => console.log("View clicked"),
99
+ })
100
+ }
101
+ >
102
+ Positive with action
103
+ </Button>
104
+ </Group>
105
+ </Stack>
106
+ ),
107
+ };
108
+
109
+ // ---------- Dialog ----------
110
+
111
+ export const Dialog: StoryObj = {
112
+ name: "Dialog",
113
+ render: () => (
114
+ <Stack gap="md">
115
+ <Group>
116
+ <Button
117
+ onClick={() =>
118
+ showDialog({
119
+ title: "Update available",
120
+ message: "A new version is ready to install.",
121
+ tone: "neutral",
122
+ })
123
+ }
124
+ >
125
+ Neutral
126
+ </Button>
127
+ <Button
128
+ color="aqua"
129
+ onClick={() =>
130
+ showDialog({
131
+ title: "Success",
132
+ message: "Your changes have been saved successfully.",
133
+ tone: "positive",
134
+ })
135
+ }
136
+ >
137
+ Positive
138
+ </Button>
139
+ <Button
140
+ color="red"
141
+ onClick={() =>
142
+ showDialog({
143
+ title: "Error",
144
+ message: "Something went wrong. Please try again.",
145
+ tone: "negative",
146
+ })
147
+ }
148
+ >
149
+ Negative
150
+ </Button>
151
+ <Button
152
+ variant="light"
153
+ onClick={() =>
154
+ showDialog({
155
+ title: "So that happened",
156
+ message: "Decide how you feel about it.",
157
+ tone: "neutral",
158
+ buttonText: "Do something",
159
+ buttonClick: () => console.log("Neutral button action"),
160
+ })
161
+ }
162
+ >
163
+ Neutral with button
164
+ </Button>
165
+ <Button
166
+ color="aqua"
167
+ variant="light"
168
+ onClick={() =>
169
+ showDialog({
170
+ title: "Nice job!",
171
+ message: "You deserve a reward. Click the button.",
172
+ tone: "positive",
173
+ buttonText: "Claim reward",
174
+ buttonClick: () => console.log("Reward claimed"),
175
+ })
176
+ }
177
+ >
178
+ Positive with button
179
+ </Button>
180
+ <Button
181
+ color="red"
182
+ variant="light"
183
+ onClick={() =>
184
+ showDialog({
185
+ title: "This is unfortunate",
186
+ message: "That didn't work, and there's only one thing left to do.",
187
+ tone: "negative",
188
+ buttonText: "Self Destruct",
189
+ buttonClick: () => console.log("Self destruct activated"),
190
+ })
191
+ }
192
+ >
193
+ Negative with button
194
+ </Button>
195
+ </Group>
196
+ </Stack>
197
+ ),
198
+ };
199
+
200
+ // ---------- Dialog — Long Text ----------
201
+
202
+ const LONG_PARAGRAPH =
203
+ "This is a much longer notification message that simulates real-world usage where the system needs to communicate detailed information to the user. It might include technical details, instructions for next steps, or a thorough explanation of what went wrong and why. The user should be able to read all of this text without it being clipped or overflowing the notification container.";
204
+
205
+ const MULTI_PARAGRAPH = `Your session is about to expire due to inactivity. Any unsaved changes in the current form will be lost if you do not take action.
206
+
207
+ To continue working, click the button below. If you do not respond within the next 2 minutes, you will be automatically logged out and redirected to the sign-in page.`;
208
+
209
+ const VERY_LONG_TEXT =
210
+ "We encountered an unexpected error while processing your recent batch upload of 847 records. The first 612 records were imported successfully, but the remaining 235 records failed validation. Common issues include: missing required fields (company name, email), invalid date formats (expected YYYY-MM-DD), and duplicate entries that conflict with existing records. A detailed error report has been generated and is available for download. You can fix the flagged records in the original file and re-upload only the failed entries using the partial import feature. If you believe this error is incorrect, please contact support with reference ID ERR-2024-8847.";
211
+
212
+ export const DialogLongText: StoryObj = {
213
+ name: "Dialog — Long Text",
214
+ render: () => (
215
+ <Stack gap="md">
216
+ <Group>
217
+ <Button
218
+ onClick={() =>
219
+ showDialog({
220
+ title: "Important Information",
221
+ message: LONG_PARAGRAPH,
222
+ tone: "neutral",
223
+ })
224
+ }
225
+ >
226
+ Long text (no button)
227
+ </Button>
228
+ <Button
229
+ variant="light"
230
+ onClick={() =>
231
+ showDialog({
232
+ title: "Important Information",
233
+ message: LONG_PARAGRAPH,
234
+ tone: "neutral",
235
+ buttonText: "Acknowledge",
236
+ buttonClick: () => console.log("Acknowledged"),
237
+ })
238
+ }
239
+ >
240
+ Long text with button
241
+ </Button>
242
+ <Button
243
+ color="red"
244
+ variant="light"
245
+ onClick={() =>
246
+ showDialog({
247
+ title: "Session Expiring Soon",
248
+ message: MULTI_PARAGRAPH,
249
+ tone: "negative",
250
+ buttonText: "Stay logged in",
251
+ buttonClick: () => console.log("Session extended"),
252
+ })
253
+ }
254
+ >
255
+ Multi-paragraph with button
256
+ </Button>
257
+ <Button
258
+ color="red"
259
+ onClick={() =>
260
+ showDialog({
261
+ title: "Batch Import Partially Failed",
262
+ message: VERY_LONG_TEXT,
263
+ tone: "negative",
264
+ buttonText: "Download Report",
265
+ buttonClick: () => console.log("Report downloaded"),
266
+ })
267
+ }
268
+ >
269
+ Very long text with button
270
+ </Button>
271
+ <Button
272
+ color="aqua"
273
+ variant="light"
274
+ onClick={() =>
275
+ showDialog({
276
+ title:
277
+ "Your organization's subscription renewal has been processed and the new billing cycle begins immediately",
278
+ message: LONG_PARAGRAPH,
279
+ tone: "positive",
280
+ buttonText: "View details",
281
+ buttonClick: () => console.log("Details viewed"),
282
+ })
283
+ }
284
+ >
285
+ Long title + long text
286
+ </Button>
287
+ </Group>
288
+ </Stack>
289
+ ),
290
+ };
@@ -0,0 +1,34 @@
1
+ import { Group, Stack, Switch } from "@mantine/core";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+ import React from "react";
4
+
5
+ /**
6
+ * Mantine Switch component styled via `createCustomMantineTheme`.
7
+ *
8
+ * Switch between Cerebellum and High Contrast themes in the Storybook toolbar
9
+ * to verify visual parity with the styled-components equivalents.
10
+ */
11
+ const meta: Meta = {
12
+ title: "Mantine/Switch",
13
+ };
14
+
15
+ export default meta;
16
+
17
+ export const SwitchStory: StoryObj = {
18
+ name: "Switch",
19
+ render: () => (
20
+ <Stack gap="lg">
21
+ <Group>
22
+ <Switch label="Default off" />
23
+ <Switch label="Default on" defaultChecked />
24
+ </Group>
25
+ <Group>
26
+ <Switch size="xs" label="Extra small" />
27
+ <Switch size="sm" label="Small" />
28
+ <Switch size="md" label="Medium" />
29
+ <Switch size="lg" label="Large" />
30
+ </Group>
31
+ <Switch label="Disabled" disabled />
32
+ </Stack>
33
+ ),
34
+ };
@@ -1,138 +0,0 @@
1
- import { Button, Group, Stack, Switch } from "@mantine/core";
2
- import { Meta, StoryObj } from "@storybook/react";
3
- import React from "react";
4
- import { showBar, showDialog, showToast } from "../services/notifications";
5
-
6
- /**
7
- * Mantine Switch and Notification components styled via `createCustomMantineTheme`.
8
- *
9
- * Switch between Cerebellum and High Contrast themes in the Storybook toolbar
10
- * to verify visual parity with the styled-components equivalents.
11
- */
12
- const meta: Meta = {
13
- title: "Mantine/Feedback",
14
- };
15
-
16
- export default meta;
17
-
18
- // ---------- Switch ----------
19
-
20
- export const SwitchStory: StoryObj = {
21
- name: "Switch",
22
- render: () => (
23
- <Stack gap="lg">
24
- <Group>
25
- <Switch label="Default off" />
26
- <Switch label="Default on" defaultChecked />
27
- </Group>
28
- <Group>
29
- <Switch size="xs" label="Extra small" />
30
- <Switch size="sm" label="Small" />
31
- <Switch size="md" label="Medium" />
32
- <Switch size="lg" label="Large" />
33
- </Group>
34
- <Switch label="Disabled" disabled />
35
- </Stack>
36
- ),
37
- };
38
-
39
- // ---------- Notifications ----------
40
-
41
- export const ToastNotifications: StoryObj = {
42
- name: "Notifications — Toast",
43
- render: () => (
44
- <Stack gap="md">
45
- <Group>
46
- <Button onClick={() => showToast({ message: "Neutral toast notification" })}>Neutral Toast</Button>
47
- <Button color="aqua" onClick={() => showToast({ message: "Positive toast", tone: "positive" })}>
48
- Positive Toast
49
- </Button>
50
- <Button color="red" onClick={() => showToast({ message: "Negative toast", tone: "negative" })}>
51
- Negative Toast
52
- </Button>
53
- </Group>
54
- </Stack>
55
- ),
56
- };
57
-
58
- export const BarNotifications: StoryObj = {
59
- name: "Notifications — Bar",
60
- render: () => (
61
- <Stack gap="md">
62
- <Group>
63
- <Button
64
- onClick={() =>
65
- showBar({
66
- message: "Changes saved",
67
- tone: "positive",
68
- })
69
- }
70
- >
71
- Bar (positive)
72
- </Button>
73
- <Button
74
- color="red"
75
- onClick={() =>
76
- showBar({
77
- message: "Connection lost",
78
- tone: "negative",
79
- buttonText: "Retry",
80
- buttonClick: () => console.log("Retry clicked"),
81
- })
82
- }
83
- >
84
- Bar with action (negative)
85
- </Button>
86
- </Group>
87
- </Stack>
88
- ),
89
- };
90
-
91
- export const DialogNotifications: StoryObj = {
92
- name: "Notifications — Dialog",
93
- render: () => (
94
- <Stack gap="md">
95
- <Group>
96
- <Button
97
- onClick={() =>
98
- showDialog({
99
- title: "Update available",
100
- message: "A new version is ready to install.",
101
- tone: "neutral",
102
- buttonText: "Install",
103
- buttonClick: () => console.log("Install clicked"),
104
- })
105
- }
106
- >
107
- Dialog (neutral)
108
- </Button>
109
- <Button
110
- color="aqua"
111
- onClick={() =>
112
- showDialog({
113
- title: "Success",
114
- message: "Your changes have been saved successfully.",
115
- tone: "positive",
116
- })
117
- }
118
- >
119
- Dialog (positive)
120
- </Button>
121
- <Button
122
- color="red"
123
- onClick={() =>
124
- showDialog({
125
- title: "Error",
126
- message: "Something went wrong. Please try again.",
127
- tone: "negative",
128
- buttonText: "Retry",
129
- buttonClick: () => console.log("Retry clicked"),
130
- })
131
- }
132
- >
133
- Dialog (negative)
134
- </Button>
135
- </Group>
136
- </Stack>
137
- ),
138
- };