@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,465 @@
|
|
|
1
|
+
# Calendar
|
|
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/Calendar/Calendar.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 Calendar, { CalendarCell } from "./Calendar";
|
|
18
|
+
import { fn } from "storybook/test";
|
|
19
|
+
import { useState } from "react";
|
|
20
|
+
import styled from "styled-components";
|
|
21
|
+
import YearMonthPicker from "../YearMonthPicker/YearMonthPicker";
|
|
22
|
+
|
|
23
|
+
const meta: Meta<typeof Calendar> = {
|
|
24
|
+
component: Calendar,
|
|
25
|
+
parameters: {
|
|
26
|
+
layout: "centered",
|
|
27
|
+
},
|
|
28
|
+
argTypes: {
|
|
29
|
+
mode: { control: false },
|
|
30
|
+
value: { control: false },
|
|
31
|
+
visibleDuration: { control: false },
|
|
32
|
+
minValue: { control: false },
|
|
33
|
+
maxValue: { control: false },
|
|
34
|
+
defaultFocusedValue: { control: false },
|
|
35
|
+
onChange: { control: false },
|
|
36
|
+
focusedValue: { control: false },
|
|
37
|
+
},
|
|
38
|
+
args: {
|
|
39
|
+
onChange: fn(),
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
export default meta;
|
|
43
|
+
|
|
44
|
+
type Story = StoryObj<typeof Calendar>;
|
|
45
|
+
|
|
46
|
+
export const Playground: Story = {
|
|
47
|
+
args: {},
|
|
48
|
+
render: (args) => {
|
|
49
|
+
const ParentComponent = () => {
|
|
50
|
+
const [value, setValue] = useState<string | null>("2021-01-04");
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<Calendar
|
|
54
|
+
{...args}
|
|
55
|
+
value={value}
|
|
56
|
+
onChange={setValue}
|
|
57
|
+
mode="single"
|
|
58
|
+
defaultFocusedValue="2021-01-04"
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
return <ParentComponent />;
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const SingleMode: Story = {
|
|
67
|
+
render: () => {
|
|
68
|
+
const ParentComponent = () => {
|
|
69
|
+
const [value, setValue] = useState<string | null>("2021-01-04");
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<>
|
|
73
|
+
<Calendar
|
|
74
|
+
mode="single"
|
|
75
|
+
value={value}
|
|
76
|
+
onChange={setValue}
|
|
77
|
+
defaultFocusedValue="2021-01-01"
|
|
78
|
+
/>
|
|
79
|
+
<p>Debug value: {value}</p>
|
|
80
|
+
</>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return <ParentComponent />;
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const RangeMode: Story = {
|
|
89
|
+
render: () => {
|
|
90
|
+
const ParentComponent = () => {
|
|
91
|
+
const [value, setValue] = useState<null | { start: string; end: string }>(
|
|
92
|
+
{
|
|
93
|
+
start: "2021-01-01",
|
|
94
|
+
end: "2021-01-21",
|
|
95
|
+
},
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<>
|
|
100
|
+
<Calendar
|
|
101
|
+
mode="range"
|
|
102
|
+
value={value}
|
|
103
|
+
onChange={setValue}
|
|
104
|
+
defaultFocusedValue="2021-01-01"
|
|
105
|
+
/>
|
|
106
|
+
<p>Start: {value?.start}</p>
|
|
107
|
+
<p>End: {value?.end}</p>
|
|
108
|
+
</>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return <ParentComponent />;
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export const MultipleMode: Story = {
|
|
117
|
+
render: () => {
|
|
118
|
+
const ParentComponent = () => {
|
|
119
|
+
const [value, setValue] = useState<string[]>([
|
|
120
|
+
"2021-01-01",
|
|
121
|
+
"2021-01-04",
|
|
122
|
+
"2021-01-10",
|
|
123
|
+
"2021-01-21",
|
|
124
|
+
]);
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<>
|
|
128
|
+
<Calendar
|
|
129
|
+
mode="multiple"
|
|
130
|
+
value={value}
|
|
131
|
+
onChange={setValue}
|
|
132
|
+
defaultFocusedValue="2021-01-01"
|
|
133
|
+
/>
|
|
134
|
+
<p>Debug: value:</p>
|
|
135
|
+
<ul>
|
|
136
|
+
{value.map((v) => (
|
|
137
|
+
<li key={v}>{v}</li>
|
|
138
|
+
))}
|
|
139
|
+
</ul>
|
|
140
|
+
</>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
return <ParentComponent />;
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const Compact: Story = {
|
|
149
|
+
render: () => {
|
|
150
|
+
const ParentComponent = () => {
|
|
151
|
+
const [value, setValue] = useState<string | null>("2021-01-04");
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<Calendar
|
|
155
|
+
mode="single"
|
|
156
|
+
value={value}
|
|
157
|
+
onChange={setValue}
|
|
158
|
+
defaultFocusedValue="2021-01-01"
|
|
159
|
+
size="compact"
|
|
160
|
+
/>
|
|
161
|
+
);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return <ParentComponent />;
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export const NoContainer: Story = {
|
|
169
|
+
render: () => {
|
|
170
|
+
const ParentComponent = () => {
|
|
171
|
+
const [value, setValue] = useState<string | null>("2021-01-04");
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<Calendar
|
|
175
|
+
mode="single"
|
|
176
|
+
value={value}
|
|
177
|
+
onChange={setValue}
|
|
178
|
+
defaultFocusedValue="2021-01-01"
|
|
179
|
+
noContainer
|
|
180
|
+
/>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
return <ParentComponent />;
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export const ControlledHeading: Story = {
|
|
189
|
+
render: () => {
|
|
190
|
+
const ParentComponent = () => {
|
|
191
|
+
const [focusedValue, setFocusedValue] = useState<string>("2021-01-01");
|
|
192
|
+
const [value, setValue] = useState<string | null>("2021-01-04");
|
|
193
|
+
|
|
194
|
+
const year = focusedValue.split("-")[0];
|
|
195
|
+
const month = focusedValue.split("-")[1];
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<>
|
|
199
|
+
<YearMonthPicker
|
|
200
|
+
mode="month-year"
|
|
201
|
+
value={{ year, month }}
|
|
202
|
+
onChange={(yearMonth) => {
|
|
203
|
+
setFocusedValue(yearMonth.year + "-" + yearMonth.month + "-01");
|
|
204
|
+
}}
|
|
205
|
+
fullWidth
|
|
206
|
+
/>
|
|
207
|
+
<Calendar
|
|
208
|
+
mode="single"
|
|
209
|
+
value={value}
|
|
210
|
+
onChange={setValue}
|
|
211
|
+
focusedValue={focusedValue}
|
|
212
|
+
onFocusChange={setFocusedValue}
|
|
213
|
+
noHeading
|
|
214
|
+
/>
|
|
215
|
+
</>
|
|
216
|
+
);
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
return <ParentComponent />;
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
export const CustomCellSingleMode: Story = {
|
|
224
|
+
render: () => {
|
|
225
|
+
// In another file, (i.e. CustomCalendar.styled.ts)
|
|
226
|
+
const CustomCalendarCell = styled(CalendarCell)`
|
|
227
|
+
--left-color: transparent;
|
|
228
|
+
--right-color: transparent;
|
|
229
|
+
|
|
230
|
+
&::before,
|
|
231
|
+
&::after {
|
|
232
|
+
content: "";
|
|
233
|
+
position: absolute;
|
|
234
|
+
inset: -1px;
|
|
235
|
+
border-radius: 50%;
|
|
236
|
+
border: 2px solid transparent;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
&::before {
|
|
240
|
+
border-color: var(--left-color);
|
|
241
|
+
clip-path: polygon(0 0, 50% 0, 50% 100%, 0 100%);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
&::after {
|
|
245
|
+
border-color: var(--right-color);
|
|
246
|
+
clip-path: polygon(50% 0, 100% 0, 100% 100%, 50% 100%);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
&[data-is-indisponibility="true"] {
|
|
250
|
+
--left-color: var(--color-content-message-negative);
|
|
251
|
+
--right-color: var(--color-content-message-negative);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
&[data-is-activation="true"] {
|
|
255
|
+
--left-color: var(--color-content-message-positive);
|
|
256
|
+
--right-color: var(--color-content-message-positive);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
&[data-is-indisponibility="true"][data-is-activation="true"] {
|
|
260
|
+
--left-color: var(--color-content-message-negative);
|
|
261
|
+
--right-color: var(--color-content-message-positive);
|
|
262
|
+
}
|
|
263
|
+
`;
|
|
264
|
+
|
|
265
|
+
const ParentComponent = () => {
|
|
266
|
+
const [selected, setSelected] = useState<string | null>(null);
|
|
267
|
+
|
|
268
|
+
const indisponibilityDates = ["2021-01-05", "2021-01-06", "2021-01-07"];
|
|
269
|
+
const activationDates = [
|
|
270
|
+
"2021-01-01",
|
|
271
|
+
"2021-01-02",
|
|
272
|
+
"2021-01-07",
|
|
273
|
+
"2021-01-08",
|
|
274
|
+
];
|
|
275
|
+
|
|
276
|
+
return (
|
|
277
|
+
<Calendar
|
|
278
|
+
mode="single"
|
|
279
|
+
value={selected}
|
|
280
|
+
onChange={setSelected}
|
|
281
|
+
defaultFocusedValue="2021-01-01"
|
|
282
|
+
renderCalendarCell={(date) => (
|
|
283
|
+
<CustomCalendarCell
|
|
284
|
+
date={date}
|
|
285
|
+
mode="single"
|
|
286
|
+
data-is-indisponibility={indisponibilityDates.includes(date)}
|
|
287
|
+
data-is-activation={activationDates.includes(date)}
|
|
288
|
+
/>
|
|
289
|
+
)}
|
|
290
|
+
/>
|
|
291
|
+
);
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
return <ParentComponent />;
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## How to test this component
|
|
300
|
+
|
|
301
|
+
Here are some more advanced stories with more testing coverage and examples that you can read to understand how to test this component.
|
|
302
|
+
|
|
303
|
+
```tsx
|
|
304
|
+
import { Meta, StoryObj } from "@storybook/react-vite";
|
|
305
|
+
import Calendar from "../Calendar";
|
|
306
|
+
import * as CalendarStories from "../Calendar.stories";
|
|
307
|
+
import { expect, fireEvent, within } from "storybook/test";
|
|
308
|
+
import { I18nProvider } from "react-aria-components";
|
|
309
|
+
|
|
310
|
+
const meta: Meta<typeof Calendar> = {
|
|
311
|
+
component: Calendar,
|
|
312
|
+
...CalendarStories.default,
|
|
313
|
+
parameters: {
|
|
314
|
+
...CalendarStories.default.parameters,
|
|
315
|
+
chromatic: { disableSnapshot: true },
|
|
316
|
+
},
|
|
317
|
+
decorators: [
|
|
318
|
+
(Story) => (
|
|
319
|
+
<I18nProvider locale="en-EN">
|
|
320
|
+
<Story />
|
|
321
|
+
</I18nProvider>
|
|
322
|
+
),
|
|
323
|
+
],
|
|
324
|
+
};
|
|
325
|
+
export default meta;
|
|
326
|
+
|
|
327
|
+
type Story = StoryObj<typeof Calendar>;
|
|
328
|
+
|
|
329
|
+
export const TestSingleMode: Story = {
|
|
330
|
+
render: CalendarStories.SingleMode.render,
|
|
331
|
+
play: async ({ canvasElement }) => {
|
|
332
|
+
const canvas = within(canvasElement);
|
|
333
|
+
await fireEvent.click(canvas.getByLabelText("Saturday, January 2, 2021"));
|
|
334
|
+
await canvas.findByLabelText("Saturday, January 2, 2021 selected");
|
|
335
|
+
await canvas.findByText("Debug value: 2021-01-02");
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
export const TestRangeMode: Story = {
|
|
340
|
+
render: CalendarStories.RangeMode.render,
|
|
341
|
+
play: async ({ canvasElement }) => {
|
|
342
|
+
const canvas = within(canvasElement);
|
|
343
|
+
await canvas.findByLabelText(
|
|
344
|
+
"Selected Range: Friday, January 1 to Thursday, January 21, 2021, Friday, January 1, 2021 selected",
|
|
345
|
+
);
|
|
346
|
+
await canvas.findByLabelText("Saturday, January 2, 2021 selected");
|
|
347
|
+
await canvas.findByLabelText(
|
|
348
|
+
"Selected Range: Friday, January 1 to Thursday, January 21, 2021, Thursday, January 21, 2021 selected",
|
|
349
|
+
);
|
|
350
|
+
await canvas.findByText("Start: 2021-01-01");
|
|
351
|
+
await canvas.findByText("End: 2021-01-21");
|
|
352
|
+
await fireEvent.click(canvas.getByLabelText("Sunday, January 24, 2021"));
|
|
353
|
+
await fireEvent.click(canvas.getByLabelText("Saturday, January 30, 2021"));
|
|
354
|
+
await canvas.findByLabelText(
|
|
355
|
+
"Selected Range: Sunday, January 24 to Saturday, January 30, 2021, Sunday, January 24, 2021 selected",
|
|
356
|
+
);
|
|
357
|
+
await canvas.findByLabelText(
|
|
358
|
+
"Selected Range: Sunday, January 24 to Saturday, January 30, 2021, Saturday, January 30, 2021 selected",
|
|
359
|
+
);
|
|
360
|
+
await canvas.findByText("Start: 2021-01-24");
|
|
361
|
+
await canvas.findByText("End: 2021-01-30");
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
export const TestMultipleMode: Story = {
|
|
366
|
+
render: CalendarStories.MultipleMode.render,
|
|
367
|
+
play: async ({ canvasElement }) => {
|
|
368
|
+
const canvas = within(canvasElement);
|
|
369
|
+
// Check that an initial value is selected on the Calendar
|
|
370
|
+
await expect(
|
|
371
|
+
canvas.getByLabelText("Friday, January 1, 2021"),
|
|
372
|
+
).toHaveAttribute("data-multiple-selected", "true");
|
|
373
|
+
|
|
374
|
+
// Check that the initial values are present in the debug state
|
|
375
|
+
await canvas.findByText("2021-01-01");
|
|
376
|
+
|
|
377
|
+
// Check that an element is unselected, then click on it, and check that it is selected
|
|
378
|
+
await expect(
|
|
379
|
+
canvas.getByLabelText("Saturday, January 2, 2021"),
|
|
380
|
+
).toHaveAttribute("data-multiple-selected", "false");
|
|
381
|
+
await fireEvent.click(canvas.getByLabelText("Saturday, January 2, 2021"));
|
|
382
|
+
await expect(
|
|
383
|
+
canvas.getByLabelText("Saturday, January 2, 2021"),
|
|
384
|
+
).toHaveAttribute("data-multiple-selected", "true");
|
|
385
|
+
},
|
|
386
|
+
};
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Developer notes
|
|
390
|
+
|
|
391
|
+
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.
|
|
392
|
+
|
|
393
|
+
```mdx
|
|
394
|
+
import { Meta, Controls, Source, Canvas } from "@storybook/addon-docs/blocks";
|
|
395
|
+
|
|
396
|
+
import * as Calendar from "./Calendar.stories";
|
|
397
|
+
import * as CalendarTests from "./tests/Calendar.stories";
|
|
398
|
+
|
|
399
|
+
<Meta of={Calendar} />
|
|
400
|
+
|
|
401
|
+
# Calendar
|
|
402
|
+
|
|
403
|
+
A calendar displays one or more date grids and allows users to select a single date.
|
|
404
|
+
|
|
405
|
+
This is the exact same component as the one used in the DatePicker and DateRangePicker components.
|
|
406
|
+
|
|
407
|
+
<Canvas of={Calendar.Playground} />
|
|
408
|
+
<Controls of={Calendar.Playground} />
|
|
409
|
+
|
|
410
|
+
## Example usage : "single" mode
|
|
411
|
+
|
|
412
|
+
<Canvas of={Calendar.SingleMode} sourceState="shown" />
|
|
413
|
+
|
|
414
|
+
## Example usage : "range" mode
|
|
415
|
+
|
|
416
|
+
<Canvas of={Calendar.RangeMode} sourceState="shown" />
|
|
417
|
+
|
|
418
|
+
## Example usage : "multiple" mode
|
|
419
|
+
|
|
420
|
+
<Canvas of={Calendar.MultipleMode} sourceState="shown" />
|
|
421
|
+
|
|
422
|
+
## Customizing the Calendar Cells
|
|
423
|
+
|
|
424
|
+
The Calendar provides you with a `CalendarCell` component that you can use to customize the cells of the calendar.
|
|
425
|
+
|
|
426
|
+
this way, you have complete control over the calendar's appearance and can create totally unique behaviors specific to your application.
|
|
427
|
+
|
|
428
|
+
Below are a few use cases and how to achieve them.
|
|
429
|
+
|
|
430
|
+
### Cells with multiple states : activation and indisponibility
|
|
431
|
+
|
|
432
|
+
Here is the feature needed :
|
|
433
|
+
|
|
434
|
+
- Have a calendar that display dates that can have multiple states : activation and indisponibility
|
|
435
|
+
- When a date is activated, the cell is green
|
|
436
|
+
- When a date is indisponible, the cell is red
|
|
437
|
+
- When a date is both activated and indisponible, the cell is half green and half red
|
|
438
|
+
|
|
439
|
+
To achieve this, we can use the `CalendarCell` component and override the default styles with CSS variables.
|
|
440
|
+
Also, we use the "single" mode on the Calendar to allow the user to select a single date (to see more details above for example)
|
|
441
|
+
|
|
442
|
+
<Canvas of={Calendar.CustomCellSingleMode} sourceState="shown" />
|
|
443
|
+
|
|
444
|
+
## How to test the Calendar component
|
|
445
|
+
|
|
446
|
+
Here are some code examples based on react-testing-library about how to test each mode of the Calendar component.
|
|
447
|
+
|
|
448
|
+
As you can see, **we must use `fireEvent` instead of `userEvent`** due to some limitations.
|
|
449
|
+
|
|
450
|
+
To know the text you need to target for a specific date, use your browser's dev tools and inspect the aria-label attribute of the element.
|
|
451
|
+
|
|
452
|
+
The language of those aria-labels depends on the user's locale or the `I18nProvider` provided in your app (or test file).
|
|
453
|
+
|
|
454
|
+
### Testing the "single" mode
|
|
455
|
+
|
|
456
|
+
<Source of={CalendarTests.TestSingleMode} />
|
|
457
|
+
|
|
458
|
+
### Testing the "range" mode
|
|
459
|
+
|
|
460
|
+
<Source of={CalendarTests.TestRangeMode} />
|
|
461
|
+
|
|
462
|
+
### Testing the "multiple" mode
|
|
463
|
+
|
|
464
|
+
<Source of={CalendarTests.TestMultipleMode} />
|
|
465
|
+
```
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# ChartLegend
|
|
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/ChartLegend/ChartLegend.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 { userEvent, within, waitFor, expect, fn } from "storybook/test";
|
|
18
|
+
|
|
19
|
+
import ChartLegend from "./ChartLegend";
|
|
20
|
+
import { chartIcons } from "@packages/internal-components/ChartIcon/ChartIcon";
|
|
21
|
+
|
|
22
|
+
const meta: Meta<typeof ChartLegend> = {
|
|
23
|
+
component: ChartLegend,
|
|
24
|
+
tags: ["autodocs"],
|
|
25
|
+
argTypes: {
|
|
26
|
+
text: { type: "string" },
|
|
27
|
+
},
|
|
28
|
+
parameters: {
|
|
29
|
+
layout: "centered",
|
|
30
|
+
},
|
|
31
|
+
globals: {
|
|
32
|
+
backgrounds: { value: "light" },
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
export default meta;
|
|
36
|
+
|
|
37
|
+
export const Playground: StoryObj<typeof ChartLegend> = {
|
|
38
|
+
args: {
|
|
39
|
+
text: "Legend",
|
|
40
|
+
onClick: fn(),
|
|
41
|
+
chartColor: "var(--color-content-brand-brand-2)",
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const Clicked: StoryObj<typeof ChartLegend> = {
|
|
46
|
+
args: {
|
|
47
|
+
...Playground.args,
|
|
48
|
+
},
|
|
49
|
+
play: async ({ canvasElement, args }) => {
|
|
50
|
+
const canvas = within(canvasElement);
|
|
51
|
+
const user = userEvent.setup({ delay: 50 });
|
|
52
|
+
await user.click(canvas.getByText("Legend"));
|
|
53
|
+
await waitFor(() => expect(args.onClick).toHaveBeenCalledTimes(1));
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const Hover: StoryObj<typeof ChartLegend> = {
|
|
58
|
+
args: {
|
|
59
|
+
...Playground.args,
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
"data-force-hovered": true,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const Selected: StoryObj<typeof ChartLegend> = {
|
|
66
|
+
args: {
|
|
67
|
+
...Playground.args,
|
|
68
|
+
isSelected: true,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const SelectedHover: StoryObj<typeof ChartLegend> = {
|
|
73
|
+
args: {
|
|
74
|
+
...Selected.args,
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
"data-force-hovered": true,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const DefaultFocus: StoryObj<typeof ChartLegend> = {
|
|
81
|
+
args: {
|
|
82
|
+
...Playground.args,
|
|
83
|
+
// @ts-ignore
|
|
84
|
+
"data-force-focus-visible": true,
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const SelectedFocus: StoryObj<typeof ChartLegend> = {
|
|
89
|
+
args: {
|
|
90
|
+
...Selected.args,
|
|
91
|
+
// @ts-ignore
|
|
92
|
+
"data-force-focus-visible": true,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const Pressed: StoryObj<typeof ChartLegend> = {
|
|
97
|
+
args: {
|
|
98
|
+
...Playground.args,
|
|
99
|
+
// @ts-ignore
|
|
100
|
+
"data-force-pressed": true,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const WithoutInteraction: StoryObj<typeof ChartLegend> = {
|
|
105
|
+
args: {
|
|
106
|
+
...Playground.args,
|
|
107
|
+
onClick: undefined,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const AllIcons: StoryObj<typeof ChartLegend> = {
|
|
112
|
+
args: {
|
|
113
|
+
...Playground.args,
|
|
114
|
+
onClick: undefined,
|
|
115
|
+
},
|
|
116
|
+
render: (args) => (
|
|
117
|
+
<div style={{ display: "flex", gap: "var(--spacing-xs)" }}>
|
|
118
|
+
{chartIcons.map((icon) => (
|
|
119
|
+
<ChartLegend key={icon} {...args} icon={icon} text={icon} />
|
|
120
|
+
))}
|
|
121
|
+
</div>
|
|
122
|
+
),
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const WithCustomIcon: StoryObj<typeof ChartLegend> = {
|
|
126
|
+
args: {
|
|
127
|
+
...Playground.args,
|
|
128
|
+
onClick: undefined,
|
|
129
|
+
customIcon: (
|
|
130
|
+
<svg width="12" height="12" viewBox="0 0 32 32">
|
|
131
|
+
<path
|
|
132
|
+
cx="16"
|
|
133
|
+
cy="16"
|
|
134
|
+
transform="translate(16, 16)"
|
|
135
|
+
d="M0,-16L9.237604307034012,0L0,16L-9.237604307034012,0Z"
|
|
136
|
+
fill="var(--chart-color)" // use this CSS variable to get the proper color for each item
|
|
137
|
+
/>
|
|
138
|
+
</svg>
|
|
139
|
+
),
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export const WithLightColor: StoryObj<typeof ChartLegend> = {
|
|
144
|
+
args: {
|
|
145
|
+
...Playground.args,
|
|
146
|
+
onClick: undefined,
|
|
147
|
+
chartColor: "var(--color-content-dataviz-azure-2)",
|
|
148
|
+
circleOutlineColor: "var(--color-content-dataviz-azure-3)",
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
```
|