@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:
|
|
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:
|
|
11
|
+
FROM node:22-alpine
|
|
12
12
|
|
|
13
13
|
COPY --from=builder ./docs/ ./docs
|
|
14
14
|
|
package/package.json
CHANGED
|
@@ -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
|
-
};
|