@agregio-solutions/design-system 1.90.1 → 1.92.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/dist/design-system.cjs +9 -5
- package/dist/design-system.js +14 -6
- package/dist/packages/components/Accordion/doc.md +342 -0
- package/dist/packages/components/Badge/doc.md +192 -0
- package/dist/packages/components/Breadcrumbs/doc.md +332 -0
- package/dist/packages/components/Button/doc.md +425 -0
- package/dist/packages/components/Calendar/doc.md +465 -0
- package/dist/packages/components/ChartLegend/doc.md +151 -0
- package/dist/packages/components/ChartTooltip/doc.md +124 -0
- package/dist/packages/components/Checkbox/doc.md +329 -0
- package/dist/packages/components/CheckboxGroup/doc.md +242 -0
- package/dist/packages/components/Chip/doc.md +99 -0
- package/dist/packages/components/Combobox/Combobox.d.ts +8 -0
- package/dist/packages/components/Combobox/doc.md +680 -0
- package/dist/packages/components/DataTable/doc.md +1124 -0
- package/dist/packages/components/DatePicker/doc.md +579 -0
- package/dist/packages/components/DateRangePicker/doc.md +638 -0
- package/dist/packages/components/Drawer/doc.md +338 -0
- package/dist/packages/components/Dropdown/Dropdown.d.ts +4 -0
- package/dist/packages/components/Dropdown/doc.md +205 -0
- package/dist/packages/components/EmptyState/doc.md +101 -0
- package/dist/packages/components/FileUpload/doc.md +449 -0
- package/dist/packages/components/Filter/doc.md +196 -0
- package/dist/packages/components/Header/doc.md +373 -0
- package/dist/packages/components/I18nProvider/doc.md +187 -0
- package/dist/packages/components/Icon/doc.md +63 -0
- package/dist/packages/components/Label/doc.md +60 -0
- package/dist/packages/components/LinearProgressBar/doc.md +148 -0
- package/dist/packages/components/Link/doc.md +206 -0
- package/dist/packages/components/List/doc.md +481 -0
- package/dist/packages/components/Loader/doc.md +53 -0
- package/dist/packages/components/Menu/Menu.d.ts +5 -1
- package/dist/packages/components/Menu/doc.md +231 -0
- package/dist/packages/components/Message/doc.md +166 -0
- package/dist/packages/components/Modal/doc.md +289 -0
- package/dist/packages/components/Navigation/doc.md +992 -0
- package/dist/packages/components/NavigationItem/doc.md +167 -0
- package/dist/packages/components/NotificationCard/doc.md +206 -0
- package/dist/packages/components/Notifications/doc.md +240 -0
- package/dist/packages/components/NumberField/doc.md +582 -0
- package/dist/packages/components/PageLayout/doc.md +651 -0
- package/dist/packages/components/Pagination/doc.md +227 -0
- package/dist/packages/components/Popover/doc.md +245 -0
- package/dist/packages/components/Radio/doc.md +370 -0
- package/dist/packages/components/RouterProvider/doc.md +64 -0
- package/dist/packages/components/SearchBar/doc.md +504 -0
- package/dist/packages/components/SegmentedControl/doc.md +398 -0
- package/dist/packages/components/Select/Select.d.ts +4 -0
- package/dist/packages/components/Select/doc.md +1133 -0
- package/dist/packages/components/Skeleton/doc.md +129 -0
- package/dist/packages/components/Slider/doc.md +362 -0
- package/dist/packages/components/Stepper/doc.md +104 -0
- package/dist/packages/components/Switch/doc.md +296 -0
- package/dist/packages/components/Tabs/doc.md +295 -0
- package/dist/packages/components/Tag/doc.md +81 -0
- package/dist/packages/components/TextInput/doc.md +490 -0
- package/dist/packages/components/TimeField/doc.md +353 -0
- package/dist/packages/components/Timeline/doc.md +1046 -0
- package/dist/packages/components/Toaster/doc.md +263 -0
- package/dist/packages/components/ToggleButton/doc.md +108 -0
- package/dist/packages/components/ToggleButtonGroup/doc.md +307 -0
- package/dist/packages/components/Tooltip/doc.md +206 -0
- package/dist/packages/components/YearMonthPicker/YearMonthPicker.d.ts +8 -0
- package/dist/packages/components/YearMonthPicker/doc.md +638 -0
- package/dist/public_docs/components.md +68 -0
- package/dist/public_docs/index.md +30 -0
- package/dist/public_docs/tokens.md +121 -0
- package/package.json +3 -2
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# NavigationItem
|
|
2
|
+
|
|
3
|
+
## Props
|
|
4
|
+
|
|
5
|
+
The complete Props documentation with JS doc for this component is available at this path:
|
|
6
|
+
|
|
7
|
+
node_modules/@agregio-solutions/design-system/dist/packages/components/NavigationItem/NavigationItem.d.ts
|
|
8
|
+
|
|
9
|
+
## Example usage
|
|
10
|
+
|
|
11
|
+
Here are the Storybook Stories.
|
|
12
|
+
|
|
13
|
+
Base stories:
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { Meta, StoryObj } from "@storybook/react-vite";
|
|
17
|
+
import { expect, within } from "storybook/test";
|
|
18
|
+
import NavigationItem from "./NavigationItem";
|
|
19
|
+
import { expectNotPresent } from "@internal/test-utils-storybook/test-utils-storybook";
|
|
20
|
+
import { NavigationProvider } from "../Navigation/context";
|
|
21
|
+
|
|
22
|
+
const meta = {
|
|
23
|
+
component: NavigationItem,
|
|
24
|
+
tags: ["autodocs"],
|
|
25
|
+
parameters: {
|
|
26
|
+
layout: "centered",
|
|
27
|
+
},
|
|
28
|
+
globals: {
|
|
29
|
+
backgrounds: { value: "dark" },
|
|
30
|
+
},
|
|
31
|
+
argTypes: {
|
|
32
|
+
href: { control: "text" },
|
|
33
|
+
subLinks: { control: false },
|
|
34
|
+
},
|
|
35
|
+
decorators: [
|
|
36
|
+
(Story) => (
|
|
37
|
+
<NavigationProvider>
|
|
38
|
+
<Story />
|
|
39
|
+
</NavigationProvider>
|
|
40
|
+
),
|
|
41
|
+
],
|
|
42
|
+
} satisfies Meta<typeof NavigationItem>;
|
|
43
|
+
export default meta;
|
|
44
|
+
|
|
45
|
+
type Story = StoryObj<typeof meta>;
|
|
46
|
+
|
|
47
|
+
export const Link: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
label: "Libellé",
|
|
50
|
+
href: "/some-url",
|
|
51
|
+
iconLeft: "home",
|
|
52
|
+
},
|
|
53
|
+
play: async ({ canvasElement, args }) => {
|
|
54
|
+
const canvas = within(canvasElement);
|
|
55
|
+
await canvas.findByText(args.label as string);
|
|
56
|
+
await expect(
|
|
57
|
+
canvas.getByText(args.label as string).parentElement,
|
|
58
|
+
).toHaveAttribute("href", args.href);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const ActiveLink: Story = {
|
|
63
|
+
args: {
|
|
64
|
+
...Link.args,
|
|
65
|
+
isActive: true,
|
|
66
|
+
},
|
|
67
|
+
play: async ({ canvasElement, args }) => {
|
|
68
|
+
const canvas = within(canvasElement);
|
|
69
|
+
await expect(
|
|
70
|
+
canvas.getByText(args.label as string).parentElement,
|
|
71
|
+
).toHaveAttribute("data-active", "true");
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const Dropdown: Story = {
|
|
76
|
+
args: {
|
|
77
|
+
...Link.args,
|
|
78
|
+
href: undefined,
|
|
79
|
+
subLinks: [
|
|
80
|
+
{
|
|
81
|
+
label: "Sous-libellé 1",
|
|
82
|
+
href: "/some-url-1",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
label: "Sous-libellé 2",
|
|
86
|
+
href: "/some-url-2",
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
play: async ({ canvasElement, args }) => {
|
|
91
|
+
const canvas = within(canvasElement);
|
|
92
|
+
await canvas.findByText(args.label as string);
|
|
93
|
+
await expect(
|
|
94
|
+
canvas.getByText(args.label as string).parentElement,
|
|
95
|
+
).not.toHaveAttribute("href");
|
|
96
|
+
await expectNotPresent(() => canvas.queryByText("Sous-libellé 1"));
|
|
97
|
+
await expectNotPresent(() => canvas.queryByText("Sous-libellé 2"));
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const DropdownOpenByDefault: Story = {
|
|
102
|
+
args: {
|
|
103
|
+
...Dropdown.args,
|
|
104
|
+
defaultOpen: true,
|
|
105
|
+
},
|
|
106
|
+
play: async ({ canvasElement, args }) => {
|
|
107
|
+
const canvas = within(canvasElement);
|
|
108
|
+
await canvas.findByText(args.label as string);
|
|
109
|
+
await expect(
|
|
110
|
+
canvas.getByText(args.label as string).parentElement,
|
|
111
|
+
).not.toHaveAttribute("href");
|
|
112
|
+
await expect(
|
|
113
|
+
canvas.getByText("Sous-libellé 1").parentElement,
|
|
114
|
+
).toHaveAttribute("href", "/some-url-1");
|
|
115
|
+
await expect(
|
|
116
|
+
canvas.getByText("Sous-libellé 2").parentElement,
|
|
117
|
+
).toHaveAttribute("href", "/some-url-2");
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const LinkCollapsed: Story = {
|
|
122
|
+
decorators: [
|
|
123
|
+
(Story) => (
|
|
124
|
+
<NavigationProvider initialIsCollapsed={true}>
|
|
125
|
+
<Story />
|
|
126
|
+
</NavigationProvider>
|
|
127
|
+
),
|
|
128
|
+
],
|
|
129
|
+
args: {
|
|
130
|
+
...Link.args,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const LinkCollapsedActive: Story = {
|
|
135
|
+
decorators: [
|
|
136
|
+
(Story) => (
|
|
137
|
+
<NavigationProvider initialIsCollapsed={true}>
|
|
138
|
+
<Story />
|
|
139
|
+
</NavigationProvider>
|
|
140
|
+
),
|
|
141
|
+
],
|
|
142
|
+
args: {
|
|
143
|
+
...Link.args,
|
|
144
|
+
isActive: true,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const WithReactNodeLabel: Story = {
|
|
149
|
+
args: {
|
|
150
|
+
...Link.args,
|
|
151
|
+
"aria-label": "Indisponibilités",
|
|
152
|
+
label: (
|
|
153
|
+
<div>
|
|
154
|
+
<div>Tableau de bord</div>
|
|
155
|
+
<div style={{ fontSize: "10px", lineHeight: "12px" }}>
|
|
156
|
+
Indisponibilités
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
),
|
|
160
|
+
},
|
|
161
|
+
play: async ({ canvasElement }) => {
|
|
162
|
+
const canvas = within(canvasElement);
|
|
163
|
+
await canvas.findByText("Indisponibilités");
|
|
164
|
+
await canvas.findByText("Tableau de bord");
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
```
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# NotificationCard
|
|
2
|
+
|
|
3
|
+
## Props
|
|
4
|
+
|
|
5
|
+
The complete Props documentation with JS doc for this component is available at this path:
|
|
6
|
+
|
|
7
|
+
node_modules/@agregio-solutions/design-system/dist/packages/components/NotificationCard/NotificationCard.d.ts
|
|
8
|
+
|
|
9
|
+
## Example usage
|
|
10
|
+
|
|
11
|
+
Here are the Storybook Stories.
|
|
12
|
+
|
|
13
|
+
Base stories:
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { Meta, StoryObj } from "@storybook/react-vite";
|
|
17
|
+
import { fn, within, expect } from "storybook/test";
|
|
18
|
+
import NotificationCard from "./NotificationCard";
|
|
19
|
+
import Button from "../Button/Button";
|
|
20
|
+
import { expectNotPresent } from "@internal/test-utils-storybook/test-utils-storybook";
|
|
21
|
+
|
|
22
|
+
const meta: Meta<typeof NotificationCard> = {
|
|
23
|
+
component: NotificationCard,
|
|
24
|
+
tags: ["autodocs"],
|
|
25
|
+
parameters: {
|
|
26
|
+
layout: "centered",
|
|
27
|
+
},
|
|
28
|
+
decorators: [
|
|
29
|
+
(Story) => (
|
|
30
|
+
<div style={{ width: "400px" }}>
|
|
31
|
+
<Story />
|
|
32
|
+
</div>
|
|
33
|
+
),
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
export default meta;
|
|
37
|
+
|
|
38
|
+
type Story = StoryObj<typeof meta>;
|
|
39
|
+
|
|
40
|
+
export const Playground: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
title: "[Insert title]",
|
|
43
|
+
description: "[Insert description]",
|
|
44
|
+
dateAndTime: "[Day & Hour] • [Timer]",
|
|
45
|
+
isRead: false,
|
|
46
|
+
type: "default",
|
|
47
|
+
menuActions: [
|
|
48
|
+
{ text: "Action 1", onClick: fn() },
|
|
49
|
+
{ text: "Action 2", onClick: fn() },
|
|
50
|
+
],
|
|
51
|
+
children: (
|
|
52
|
+
<>
|
|
53
|
+
<Button
|
|
54
|
+
text="[Insert name]"
|
|
55
|
+
mode="secondary"
|
|
56
|
+
size="small"
|
|
57
|
+
onClick={fn()}
|
|
58
|
+
/>
|
|
59
|
+
<Button
|
|
60
|
+
text="[Insert name]"
|
|
61
|
+
mode="secondary"
|
|
62
|
+
size="small"
|
|
63
|
+
onClick={fn()}
|
|
64
|
+
/>
|
|
65
|
+
</>
|
|
66
|
+
),
|
|
67
|
+
},
|
|
68
|
+
play: async ({ canvasElement }) => {
|
|
69
|
+
const canvas = within(canvasElement);
|
|
70
|
+
await canvas.findByText("[Insert title]");
|
|
71
|
+
await canvas.findByText("[Insert description]");
|
|
72
|
+
await canvas.findByText("[Day & Hour] • [Timer]");
|
|
73
|
+
await expect(await canvas.findAllByText("[Insert name]")).toHaveLength(2);
|
|
74
|
+
await canvas.findByTestId("unread-badge");
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const ReadNotification: Story = {
|
|
79
|
+
args: {
|
|
80
|
+
...Playground.args,
|
|
81
|
+
isRead: true,
|
|
82
|
+
},
|
|
83
|
+
play: async ({ canvasElement }) => {
|
|
84
|
+
const canvas = within(canvasElement);
|
|
85
|
+
await expectNotPresent(() => canvas.queryByTestId("unread-badge"));
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const WithAvatar: Story = {
|
|
90
|
+
args: {
|
|
91
|
+
...Playground.args,
|
|
92
|
+
avatarUrl: "https://i.pravatar.cc/300?img=5",
|
|
93
|
+
avatarAlt: "John Doe",
|
|
94
|
+
title: "Jesse Pokman",
|
|
95
|
+
description: "You have a new message",
|
|
96
|
+
dateAndTime: "15 min ago",
|
|
97
|
+
children: (
|
|
98
|
+
<Button text="View" mode="secondary" size="small" onClick={fn()} />
|
|
99
|
+
),
|
|
100
|
+
menuActions: [
|
|
101
|
+
{ text: "Mark as read", onClick: fn() },
|
|
102
|
+
{ text: "Delete", onClick: fn() },
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export const Minimal: Story = {
|
|
108
|
+
args: {
|
|
109
|
+
title: "Minimal example",
|
|
110
|
+
isRead: true,
|
|
111
|
+
menuActions: [],
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const InformativeUnread: Story = {
|
|
116
|
+
args: {
|
|
117
|
+
...Playground.args,
|
|
118
|
+
isRead: false,
|
|
119
|
+
type: "informative",
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const InformativeRead: Story = {
|
|
124
|
+
args: {
|
|
125
|
+
...Playground.args,
|
|
126
|
+
isRead: true,
|
|
127
|
+
type: "informative",
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const NegativeUnread: Story = {
|
|
132
|
+
args: {
|
|
133
|
+
...Playground.args,
|
|
134
|
+
isRead: false,
|
|
135
|
+
type: "negative",
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const NegativeRead: Story = {
|
|
140
|
+
args: {
|
|
141
|
+
...Playground.args,
|
|
142
|
+
isRead: true,
|
|
143
|
+
type: "negative",
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const WarningUnread: Story = {
|
|
148
|
+
args: {
|
|
149
|
+
...Playground.args,
|
|
150
|
+
isRead: false,
|
|
151
|
+
type: "warning",
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export const WarningRead: Story = {
|
|
156
|
+
args: {
|
|
157
|
+
...Playground.args,
|
|
158
|
+
isRead: true,
|
|
159
|
+
type: "warning",
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export const PositiveUnread: Story = {
|
|
164
|
+
args: {
|
|
165
|
+
...Playground.args,
|
|
166
|
+
isRead: false,
|
|
167
|
+
type: "positive",
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export const PositiveRead: Story = {
|
|
172
|
+
args: {
|
|
173
|
+
...Playground.args,
|
|
174
|
+
isRead: true,
|
|
175
|
+
type: "positive",
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export const WithCustomIcon: Story = {
|
|
180
|
+
args: {
|
|
181
|
+
...Playground.args,
|
|
182
|
+
customIcon: "bolt",
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export const WithCloseButton: Story = {
|
|
187
|
+
args: {
|
|
188
|
+
...Playground.args,
|
|
189
|
+
menuActions: undefined,
|
|
190
|
+
isRead: true,
|
|
191
|
+
onClose: fn(),
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const WithLongContent: Story = {
|
|
196
|
+
args: {
|
|
197
|
+
...Playground.args,
|
|
198
|
+
title:
|
|
199
|
+
"This is a very long title that should overflow. This is a very long title that should overflow",
|
|
200
|
+
description:
|
|
201
|
+
"This is a very long description that should overflow. This is a very long description that should overflow",
|
|
202
|
+
dateAndTime:
|
|
203
|
+
"This is a very long date and time that should overflow. This is a very long date and time that should overflow",
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
```
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# Notifications
|
|
2
|
+
|
|
3
|
+
## Props
|
|
4
|
+
|
|
5
|
+
The complete Props documentation with JS doc for this component is available at this path:
|
|
6
|
+
|
|
7
|
+
node_modules/@agregio-solutions/design-system/dist/packages/components/Notifications/Notifications.d.ts
|
|
8
|
+
|
|
9
|
+
## Example usage
|
|
10
|
+
|
|
11
|
+
Here are the Storybook Stories.
|
|
12
|
+
|
|
13
|
+
Base stories:
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { Meta, StoryObj } from "@storybook/react-vite";
|
|
17
|
+
import { fn, userEvent, within } from "storybook/test";
|
|
18
|
+
import Notifications from "./Notifications";
|
|
19
|
+
import NotificationCard from "../NotificationCard/NotificationCard";
|
|
20
|
+
import { expectNotPresent } from "@internal/test-utils-storybook/test-utils-storybook";
|
|
21
|
+
import { I18nProvider } from "react-aria-components";
|
|
22
|
+
import Toaster from "../Toaster/Toaster";
|
|
23
|
+
import { toast } from "sonner";
|
|
24
|
+
import { useEffect } from "react";
|
|
25
|
+
|
|
26
|
+
const meta: Meta<typeof Notifications> = {
|
|
27
|
+
component: Notifications,
|
|
28
|
+
argTypes: {
|
|
29
|
+
children: { control: false },
|
|
30
|
+
},
|
|
31
|
+
decorators: [
|
|
32
|
+
(Story) => (
|
|
33
|
+
<I18nProvider locale="en">
|
|
34
|
+
<Toaster />
|
|
35
|
+
<Story />
|
|
36
|
+
</I18nProvider>
|
|
37
|
+
),
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
export default meta;
|
|
41
|
+
|
|
42
|
+
type Story = StoryObj<typeof meta>;
|
|
43
|
+
|
|
44
|
+
export const Playground: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
triggerProps: {
|
|
47
|
+
iconLeft: "notifications_none",
|
|
48
|
+
size: "small",
|
|
49
|
+
mode: "tertiary",
|
|
50
|
+
},
|
|
51
|
+
nbOfReadNotifications: 1,
|
|
52
|
+
nbOfUnreadNotifications: 2,
|
|
53
|
+
onParametersClick: fn(),
|
|
54
|
+
onMarkAllAsReadClick: fn(),
|
|
55
|
+
children: (
|
|
56
|
+
<>
|
|
57
|
+
<NotificationCard
|
|
58
|
+
title="Notification 1"
|
|
59
|
+
isRead={false}
|
|
60
|
+
description="Description 1"
|
|
61
|
+
dateAndTime="16/07/2025 • 10:00"
|
|
62
|
+
/>
|
|
63
|
+
<NotificationCard
|
|
64
|
+
title="Notification 2"
|
|
65
|
+
isRead={true}
|
|
66
|
+
description="Description 2"
|
|
67
|
+
dateAndTime="18/07/2025 • 11:00"
|
|
68
|
+
/>
|
|
69
|
+
<NotificationCard
|
|
70
|
+
title="Notification 3"
|
|
71
|
+
isRead={false}
|
|
72
|
+
description="Description 3"
|
|
73
|
+
dateAndTime="21/07/2025 • 13:00"
|
|
74
|
+
/>
|
|
75
|
+
</>
|
|
76
|
+
),
|
|
77
|
+
},
|
|
78
|
+
play: async ({ canvasElement }) => {
|
|
79
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
|
80
|
+
const user = userEvent.setup({ delay: 25 });
|
|
81
|
+
await user.click(canvas.getByRole("button"));
|
|
82
|
+
await canvas.findByText("Notifications");
|
|
83
|
+
await canvas.findByText("Mark all as read");
|
|
84
|
+
await canvas.findByLabelText("Parameters");
|
|
85
|
+
await canvas.findByLabelText("Close");
|
|
86
|
+
await canvas.findByText("Notification 1");
|
|
87
|
+
await canvas.findByText("Notification 2");
|
|
88
|
+
await canvas.findByText("Notification 3");
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const LotsOfItems: Story = {
|
|
93
|
+
args: {
|
|
94
|
+
...Playground.args,
|
|
95
|
+
nbOfReadNotifications: 20,
|
|
96
|
+
nbOfUnreadNotifications: 20,
|
|
97
|
+
children: (
|
|
98
|
+
<>
|
|
99
|
+
{Array.from({ length: 20 }).map((_, index) => (
|
|
100
|
+
<NotificationCard
|
|
101
|
+
key={index}
|
|
102
|
+
title={`Notification ${index + 1}`}
|
|
103
|
+
isRead={false}
|
|
104
|
+
description={`Description ${index + 1}`}
|
|
105
|
+
dateAndTime={`${index + 1}/07/2025 • ${index + 1}:00`}
|
|
106
|
+
menuActions={[{ text: "Mark as read", onClick: fn() }]}
|
|
107
|
+
/>
|
|
108
|
+
))}
|
|
109
|
+
</>
|
|
110
|
+
),
|
|
111
|
+
},
|
|
112
|
+
play: async ({ canvasElement }) => {
|
|
113
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
|
114
|
+
const user = userEvent.setup({ delay: 25 });
|
|
115
|
+
await user.click(canvas.getByRole("button"));
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const WithoutFooter: Story = {
|
|
120
|
+
args: {
|
|
121
|
+
...Playground.args,
|
|
122
|
+
onParametersClick: undefined,
|
|
123
|
+
onMarkAllAsReadClick: undefined,
|
|
124
|
+
},
|
|
125
|
+
play: async ({ canvasElement }) => {
|
|
126
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
|
127
|
+
const user = userEvent.setup({ delay: 25 });
|
|
128
|
+
await user.click(canvas.getByRole("button"));
|
|
129
|
+
await canvas.findByText("Notifications");
|
|
130
|
+
await canvas.findByText("Notification 1");
|
|
131
|
+
await canvas.findByText("Notification 2");
|
|
132
|
+
await canvas.findByText("Notification 3");
|
|
133
|
+
await canvas.findByLabelText("Close");
|
|
134
|
+
await expectNotPresent(() => canvas.queryByText("Mark all as read"));
|
|
135
|
+
await expectNotPresent(() => canvas.queryByLabelText("Parameters"));
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const Loading: Story = {
|
|
140
|
+
args: {
|
|
141
|
+
...Playground.args,
|
|
142
|
+
children: undefined,
|
|
143
|
+
isLoading: true,
|
|
144
|
+
nbOfReadNotifications: 0,
|
|
145
|
+
nbOfUnreadNotifications: 0,
|
|
146
|
+
},
|
|
147
|
+
play: async ({ canvasElement }) => {
|
|
148
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
|
149
|
+
const user = userEvent.setup({ delay: 25 });
|
|
150
|
+
await user.click(canvas.getByRole("button"));
|
|
151
|
+
await canvas.findByText("Notifications");
|
|
152
|
+
await canvas.findByLabelText("Close");
|
|
153
|
+
await expectNotPresent(() => canvas.queryByText("Mark all as read"));
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export const Empty: Story = {
|
|
158
|
+
args: {
|
|
159
|
+
...Playground.args,
|
|
160
|
+
children: undefined,
|
|
161
|
+
nbOfReadNotifications: 0,
|
|
162
|
+
nbOfUnreadNotifications: 0,
|
|
163
|
+
},
|
|
164
|
+
play: async ({ canvasElement }) => {
|
|
165
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
|
166
|
+
const user = userEvent.setup({ delay: 25 });
|
|
167
|
+
await user.click(canvas.getByRole("button"));
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export const StandaloneNotification: Story = {
|
|
172
|
+
render: () => {
|
|
173
|
+
const ParentComponent = () => {
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
toast.custom(
|
|
176
|
+
(toastId) => (
|
|
177
|
+
<NotificationCard
|
|
178
|
+
title="Success message"
|
|
179
|
+
isRead={false}
|
|
180
|
+
description="Description"
|
|
181
|
+
dateAndTime="16/07/2025 • 10:00"
|
|
182
|
+
onClose={() => toast.dismiss(toastId)}
|
|
183
|
+
style={{ width: 400 }}
|
|
184
|
+
/>
|
|
185
|
+
),
|
|
186
|
+
{
|
|
187
|
+
unstyled: true,
|
|
188
|
+
position: "top-right",
|
|
189
|
+
closeButton: false,
|
|
190
|
+
},
|
|
191
|
+
);
|
|
192
|
+
}, []);
|
|
193
|
+
return <div />;
|
|
194
|
+
};
|
|
195
|
+
return <ParentComponent />;
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Developer notes
|
|
201
|
+
|
|
202
|
+
Here are the notes available for the developer on the built Storybook, you can read them to understand the component and how to use it.
|
|
203
|
+
|
|
204
|
+
```mdx
|
|
205
|
+
import { Meta, Controls, Source, Canvas } from "@storybook/addon-docs/blocks";
|
|
206
|
+
|
|
207
|
+
import * as Notifications from "./Notifications.stories";
|
|
208
|
+
import * as NotificationsTests from "./tests/NotificationsTests.stories";
|
|
209
|
+
|
|
210
|
+
<Meta of={Notifications} />
|
|
211
|
+
|
|
212
|
+
# Notifications
|
|
213
|
+
|
|
214
|
+
<Canvas of={Notifications.Playground} />
|
|
215
|
+
<Controls of={Notifications.Playground} />
|
|
216
|
+
|
|
217
|
+
## Full featured example usage
|
|
218
|
+
|
|
219
|
+
Bellow you can find a full featured example usage of the Notifications component.
|
|
220
|
+
|
|
221
|
+
- integration within a Header component
|
|
222
|
+
- integration with useQuery and useMutation (from Tanstack Query) to handle fetching/updating the notifications
|
|
223
|
+
- generated using composition, to allow you advanced customization (see performance section below)
|
|
224
|
+
|
|
225
|
+
The dataset is abstracted away, please refer to the [NotificationCard component](?path=/docs/components-notificationcard--docs) to see all available props.
|
|
226
|
+
|
|
227
|
+
<Source of={NotificationsTests.FullImplementationExample} type="code" dark />
|
|
228
|
+
|
|
229
|
+
## Performance and customization
|
|
230
|
+
|
|
231
|
+
If you intend to receive a lot of notifications, you might want to consider using advanced features like pagination, infinite scroll, virtualized list, etc.
|
|
232
|
+
|
|
233
|
+
With the actual implementation, you will notice that the component is not optimized for performance.
|
|
234
|
+
This is intended, Notifications and NotificationCard are only responsible for rendering the UI.
|
|
235
|
+
But the composition allows you to easily add these features.
|
|
236
|
+
|
|
237
|
+
For example, you can easily add a wrapper around the NotificationCards to add infinite scroll, pagination, or even virtualized list.
|
|
238
|
+
|
|
239
|
+
Feel free to contact us if you need help with this.
|
|
240
|
+
```
|