@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.
Files changed (68) hide show
  1. package/dist/design-system.cjs +9 -5
  2. package/dist/design-system.js +14 -6
  3. package/dist/packages/components/Accordion/doc.md +342 -0
  4. package/dist/packages/components/Badge/doc.md +192 -0
  5. package/dist/packages/components/Breadcrumbs/doc.md +332 -0
  6. package/dist/packages/components/Button/doc.md +425 -0
  7. package/dist/packages/components/Calendar/doc.md +465 -0
  8. package/dist/packages/components/ChartLegend/doc.md +151 -0
  9. package/dist/packages/components/ChartTooltip/doc.md +124 -0
  10. package/dist/packages/components/Checkbox/doc.md +329 -0
  11. package/dist/packages/components/CheckboxGroup/doc.md +242 -0
  12. package/dist/packages/components/Chip/doc.md +99 -0
  13. package/dist/packages/components/Combobox/Combobox.d.ts +8 -0
  14. package/dist/packages/components/Combobox/doc.md +680 -0
  15. package/dist/packages/components/DataTable/doc.md +1124 -0
  16. package/dist/packages/components/DatePicker/doc.md +579 -0
  17. package/dist/packages/components/DateRangePicker/doc.md +638 -0
  18. package/dist/packages/components/Drawer/doc.md +338 -0
  19. package/dist/packages/components/Dropdown/Dropdown.d.ts +4 -0
  20. package/dist/packages/components/Dropdown/doc.md +205 -0
  21. package/dist/packages/components/EmptyState/doc.md +101 -0
  22. package/dist/packages/components/FileUpload/doc.md +449 -0
  23. package/dist/packages/components/Filter/doc.md +196 -0
  24. package/dist/packages/components/Header/doc.md +373 -0
  25. package/dist/packages/components/I18nProvider/doc.md +187 -0
  26. package/dist/packages/components/Icon/doc.md +63 -0
  27. package/dist/packages/components/Label/doc.md +60 -0
  28. package/dist/packages/components/LinearProgressBar/doc.md +148 -0
  29. package/dist/packages/components/Link/doc.md +206 -0
  30. package/dist/packages/components/List/doc.md +481 -0
  31. package/dist/packages/components/Loader/doc.md +53 -0
  32. package/dist/packages/components/Menu/Menu.d.ts +5 -1
  33. package/dist/packages/components/Menu/doc.md +231 -0
  34. package/dist/packages/components/Message/doc.md +166 -0
  35. package/dist/packages/components/Modal/doc.md +289 -0
  36. package/dist/packages/components/Navigation/doc.md +992 -0
  37. package/dist/packages/components/NavigationItem/doc.md +167 -0
  38. package/dist/packages/components/NotificationCard/doc.md +206 -0
  39. package/dist/packages/components/Notifications/doc.md +240 -0
  40. package/dist/packages/components/NumberField/doc.md +582 -0
  41. package/dist/packages/components/PageLayout/doc.md +651 -0
  42. package/dist/packages/components/Pagination/doc.md +227 -0
  43. package/dist/packages/components/Popover/doc.md +245 -0
  44. package/dist/packages/components/Radio/doc.md +370 -0
  45. package/dist/packages/components/RouterProvider/doc.md +64 -0
  46. package/dist/packages/components/SearchBar/doc.md +504 -0
  47. package/dist/packages/components/SegmentedControl/doc.md +398 -0
  48. package/dist/packages/components/Select/Select.d.ts +4 -0
  49. package/dist/packages/components/Select/doc.md +1133 -0
  50. package/dist/packages/components/Skeleton/doc.md +129 -0
  51. package/dist/packages/components/Slider/doc.md +362 -0
  52. package/dist/packages/components/Stepper/doc.md +104 -0
  53. package/dist/packages/components/Switch/doc.md +296 -0
  54. package/dist/packages/components/Tabs/doc.md +295 -0
  55. package/dist/packages/components/Tag/doc.md +81 -0
  56. package/dist/packages/components/TextInput/doc.md +490 -0
  57. package/dist/packages/components/TimeField/doc.md +353 -0
  58. package/dist/packages/components/Timeline/doc.md +1046 -0
  59. package/dist/packages/components/Toaster/doc.md +263 -0
  60. package/dist/packages/components/ToggleButton/doc.md +108 -0
  61. package/dist/packages/components/ToggleButtonGroup/doc.md +307 -0
  62. package/dist/packages/components/Tooltip/doc.md +206 -0
  63. package/dist/packages/components/YearMonthPicker/YearMonthPicker.d.ts +8 -0
  64. package/dist/packages/components/YearMonthPicker/doc.md +638 -0
  65. package/dist/public_docs/components.md +68 -0
  66. package/dist/public_docs/index.md +30 -0
  67. package/dist/public_docs/tokens.md +121 -0
  68. package/package.json +3 -2
@@ -0,0 +1,449 @@
1
+ # FileUpload
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/FileUpload/FileUpload.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 } from "storybook/test";
18
+ import FileUpload from "./FileUpload";
19
+ import { I18nProvider } from "react-aria-components";
20
+ import { useState } from "react";
21
+ import Button from "../Button/Button";
22
+
23
+ const meta: Meta<typeof FileUpload> = {
24
+ component: FileUpload,
25
+ parameters: {
26
+ layout: "centered",
27
+ },
28
+ decorators: [
29
+ (Story) => (
30
+ <I18nProvider locale="en-US">
31
+ <Story />
32
+ </I18nProvider>
33
+ ),
34
+ ],
35
+ };
36
+ export default meta;
37
+
38
+ type Story = StoryObj<typeof meta>;
39
+
40
+ export const Playground: Story = {
41
+ args: {
42
+ formGroupWrapperProps: {
43
+ htmlForId: "file-upload",
44
+ label: "[Insert label]",
45
+ description: "[Insert description]",
46
+ errorHelperText: "[Insert helper]",
47
+ errorHelperTextIcon: "error_outline",
48
+ required: true,
49
+ labelIconRight: "help_outline",
50
+ labelIconRightTooltip: "Additional information",
51
+ },
52
+ onSelectionChange: fn(),
53
+ allowsMultiple: true,
54
+ files: [
55
+ {
56
+ id: "1",
57
+ fileName: "[Filename.exe]",
58
+ fileSize: "[Size Mo]",
59
+ isUploading: true,
60
+ onDelete: fn(),
61
+ },
62
+ {
63
+ id: "2",
64
+ fileName: "test 2.txt",
65
+ fileSize: "100KB",
66
+ isUploading: false,
67
+ onDelete: fn(),
68
+ },
69
+ {
70
+ id: "3",
71
+ fileName: "test 3.txt",
72
+ isUploading: false,
73
+ onDelete: fn(),
74
+ },
75
+ ],
76
+ },
77
+ play: async ({ canvasElement }) => {
78
+ const canvas = within(canvasElement);
79
+ await canvas.findByText("[Insert label]");
80
+ await canvas.findByText("[Insert description]");
81
+ await canvas.findByText("[Insert helper]");
82
+ await canvas.findByText("[Filename.exe]");
83
+ await canvas.findByText("test 2.txt");
84
+ await canvas.findByText("test 3.txt");
85
+ },
86
+ };
87
+
88
+ export const FunctionnalForm: Story = {
89
+ args: {
90
+ ...Playground.args,
91
+ },
92
+ render: (args) => {
93
+ const ParentComponent = () => {
94
+ const [files, setFiles] = useState<File[]>([]);
95
+
96
+ return (
97
+ <form
98
+ onSubmit={(e) => {
99
+ e.preventDefault();
100
+ // Here put you API call and state changes accordingly
101
+ args.onSelectionChange(files);
102
+ }}
103
+ >
104
+ <FileUpload
105
+ {...args}
106
+ formGroupWrapperProps={args.formGroupWrapperProps}
107
+ onSelectionChange={(files) =>
108
+ setFiles((prev) => [...prev, ...files])
109
+ }
110
+ files={files.map((file) => ({
111
+ id: file.name,
112
+ fileName: file.name,
113
+ fileSize: `${file.size} bytes`, // <- may need a util to format this
114
+ onDelete: () =>
115
+ setFiles((prev) => prev.filter((f) => f !== file)),
116
+ }))}
117
+ />
118
+
119
+ <hr />
120
+ <Button type="submit" text="Submit" />
121
+ </form>
122
+ );
123
+ };
124
+
125
+ return <ParentComponent />;
126
+ },
127
+ };
128
+
129
+ export const OnlyOneFile: Story = {
130
+ args: {
131
+ ...Playground.args,
132
+ allowsMultiple: false,
133
+ },
134
+ render: FunctionnalForm.render,
135
+ };
136
+
137
+ export const Disabled: Story = {
138
+ args: {
139
+ ...Playground.args,
140
+ isDisabled: true,
141
+ },
142
+ render: FunctionnalForm.render,
143
+ };
144
+
145
+ export const TestOverflowingContent: Story = {
146
+ decorators: [
147
+ (Story) => (
148
+ <div style={{ width: "313px", overflow: "hidden" }}>
149
+ <Story />
150
+ </div>
151
+ ),
152
+ ],
153
+ args: {
154
+ ...Playground.args,
155
+ files: [
156
+ {
157
+ id: "1",
158
+ fileName: "verylongfilename-verylongfilename-verylongfilename.txt",
159
+ fileSize: "100000000000000000000000000000000000000000To",
160
+ isUploading: false,
161
+ onDelete: fn(),
162
+ },
163
+ ],
164
+ },
165
+ };
166
+ ```
167
+
168
+ ## How to test this component
169
+
170
+ Here are some more advanced stories with more testing coverage and examples that you can read to understand how to test this component.
171
+
172
+ ```tsx
173
+ import { Meta, StoryObj } from "@storybook/react-vite";
174
+ import { expect, fn, userEvent, within } from "storybook/test";
175
+ import FileUpload from "../FileUpload";
176
+ import * as FileUploadStories from "../FileUpload.stories";
177
+ import { useState } from "react";
178
+ import Button from "@packages/components/Button/Button";
179
+ import {
180
+ expectNotPresent,
181
+ someTime,
182
+ } from "@internal/test-utils-storybook/test-utils-storybook";
183
+
184
+ const meta: Meta<typeof FileUpload> = {
185
+ ...FileUploadStories.default,
186
+ parameters: {
187
+ ...FileUploadStories.default.parameters,
188
+ chromatic: { disableSnapshot: true },
189
+ },
190
+ component: FileUpload,
191
+ };
192
+ export default meta;
193
+
194
+ const csvFile = new File(["test"], "test.csv", { type: "text/csv" });
195
+ const txtFile = new File(["test"], "test.txt", { type: "text/plain" });
196
+
197
+ type Story = StoryObj<typeof meta>;
198
+
199
+ export const TestOnlyCsv: Story = {
200
+ args: {
201
+ ...FileUploadStories.Playground.args,
202
+ acceptedFileTypes: ["text/csv"],
203
+ formGroupWrapperProps: {
204
+ label: "Upload a CSV file",
205
+ htmlForId: "file-upload",
206
+ },
207
+ files: [],
208
+ },
209
+ play: async ({ canvasElement, args }) => {
210
+ const canvas = within(canvasElement);
211
+ const user = userEvent.setup({ delay: 50 });
212
+ await someTime(200); // Needed for use effect to run
213
+ const fileInput = canvas.getByLabelText("Upload a CSV file");
214
+ await user.upload(fileInput, [txtFile]);
215
+ await expect(args.onSelectionChange).not.toHaveBeenCalled();
216
+ await user.upload(fileInput, [csvFile]);
217
+ await expect(args.onSelectionChange).toHaveBeenCalledTimes(1);
218
+ },
219
+ };
220
+
221
+ export const ExampleOnlyCsv: Story = {
222
+ render: () => (
223
+ <FileUpload
224
+ onSelectionChange={fn()}
225
+ acceptedFileTypes={["text/csv"]}
226
+ formGroupWrapperProps={{ label: "Upload a CSV file" }}
227
+ />
228
+ ),
229
+ };
230
+
231
+ export const ExampleMultipleFiles: Story = {
232
+ render: () => (
233
+ <FileUpload
234
+ onSelectionChange={fn()}
235
+ allowsMultiple={true}
236
+ formGroupWrapperProps={{ label: "Upload multiple files" }}
237
+ />
238
+ ),
239
+ };
240
+
241
+ export const SimpleStateAndUploadOnSubmitExample: Story = {
242
+ render: () => {
243
+ const ParentComponent = () => {
244
+ const [files, setFiles] = useState<File[]>([]);
245
+
246
+ return (
247
+ <form
248
+ onSubmit={(e) => {
249
+ e.preventDefault();
250
+ // Here put you API call and state changes accordingly
251
+ console.log({ files }); // eslint-disable-line no-console
252
+ }}
253
+ >
254
+ <FileUpload
255
+ onSelectionChange={(files) =>
256
+ setFiles((prev) => [...prev, ...files])
257
+ }
258
+ allowsMultiple
259
+ formGroupWrapperProps={{
260
+ label: "Upload a file",
261
+ htmlForId: "file-upload", // <- required for a11y and testing
262
+ }}
263
+ files={files.map((file) => ({
264
+ id: file.name,
265
+ fileName: file.name,
266
+ fileSize: `${file.size} bytes`, // <- may need a util to format this
267
+ onDelete: () =>
268
+ setFiles((prev) => prev.filter((f) => f !== file)),
269
+ }))}
270
+ />
271
+
272
+ <hr />
273
+ <Button type="submit" text="Submit" />
274
+ </form>
275
+ );
276
+ };
277
+
278
+ return <ParentComponent />;
279
+ },
280
+ };
281
+
282
+ export const TestSimpleStateAndUploadOnSubmitExample: Story = {
283
+ // ⬇️ same code as example above
284
+ render: SimpleStateAndUploadOnSubmitExample.render,
285
+ play: async ({ canvasElement }) => {
286
+ const canvas = within(canvasElement);
287
+ const user = userEvent.setup();
288
+ await someTime(100); // This delay is needed due to a hack we had to make in the component to make it work with testing-library
289
+ const fileInput = canvas.getByLabelText("Upload a file");
290
+
291
+ await user.upload(fileInput, [
292
+ new File(["test"], "test.txt", { type: "text/plain" }),
293
+ ]);
294
+ await canvas.findByText("test.txt");
295
+ },
296
+ };
297
+
298
+ export const SimpleStateAndUploadDirectlyExample: Story = {
299
+ render: () => {
300
+ const fakeApiCall = async () => {
301
+ await new Promise((resolve) => setTimeout(resolve, 1000));
302
+ };
303
+
304
+ const ParentComponent = () => {
305
+ const [files, setFiles] = useState<File[]>([]);
306
+ const [uploadingFiles, setUploadingFiles] = useState<File[]>([]);
307
+
308
+ return (
309
+ <form
310
+ onSubmit={(e) => {
311
+ e.preventDefault();
312
+ // Here put you API call and state changes accordingly
313
+ console.log({ files }); // eslint-disable-line no-console
314
+ }}
315
+ >
316
+ <FileUpload
317
+ onSelectionChange={async (files) => {
318
+ // Here is just a naive example implementation, feel free to adjust it based on your own needs and stack (react-query mutation for example).
319
+ // The important thing is to show the user the uploading state.
320
+ setUploadingFiles((prev) => [...prev, ...files]);
321
+ setFiles((prev) => [...prev, ...files]);
322
+ await fakeApiCall();
323
+ setUploadingFiles([]);
324
+ }}
325
+ allowsMultiple
326
+ formGroupWrapperProps={{
327
+ label: "Upload a file",
328
+ htmlForId: "file-upload", // <- required for a11y and testing
329
+ }}
330
+ files={files.map((file) => ({
331
+ id: file.name,
332
+ fileName: file.name,
333
+ fileSize: `${file.size} bytes`, // <- may need a util to format this.
334
+ onDelete: () =>
335
+ setFiles((prev) => prev.filter((f) => f !== file)),
336
+ isUploading: uploadingFiles.includes(file), // <- here you have to show the user the uploading state.
337
+ }))}
338
+ />
339
+
340
+ <hr />
341
+ <Button type="submit" text="Submit" />
342
+ </form>
343
+ );
344
+ };
345
+
346
+ return <ParentComponent />;
347
+ },
348
+ };
349
+
350
+ export const TestOnlyOneFile: Story = {
351
+ ...FileUploadStories.OnlyOneFile,
352
+ play: async ({ canvasElement }) => {
353
+ const canvas = within(canvasElement);
354
+ const user = userEvent.setup();
355
+ await someTime(100);
356
+ const fileInput = canvas.getByLabelText("[Insert label]");
357
+
358
+ await user.upload(fileInput, [
359
+ new File(["test"], "test.txt", { type: "text/plain" }),
360
+ ]);
361
+ await canvas.findByText("test.txt");
362
+ await user.upload(fileInput, [
363
+ new File(["test"], "test-2.txt", { type: "text/plain" }),
364
+ ]);
365
+ await expectNotPresent(() => canvas.queryByText("test-2.txt"));
366
+ await canvas.findByText("test.txt");
367
+ },
368
+ };
369
+ ```
370
+
371
+ ## Developer notes
372
+
373
+ 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.
374
+
375
+ ```mdx
376
+ import {
377
+ Canvas,
378
+ Meta,
379
+ Stories,
380
+ Controls,
381
+ Source,
382
+ } from "@storybook/addon-docs/blocks";
383
+
384
+ import * as FileUpload from "./FileUpload.stories";
385
+ import * as FileUploadTests from "./tests/FileUpload.stories";
386
+
387
+ <Meta of={FileUpload} />
388
+
389
+ # FileUpload
390
+
391
+ The FileUpload component allows users to upload files from their **file system** by searching or using **drag-and-drop**.
392
+
393
+ ## Accepted file types
394
+
395
+ By default, the file trigger will accept any file type.
396
+ To support only certain file types, pass an array of the mime type of files via the acceptedFileTypes prop.
397
+
398
+ <Source of={FileUploadTests.ExampleOnlyCsv} type="code" dark />
399
+
400
+ ## Multiple files
401
+
402
+ A file trigger can accept multiple files by passsing the `allowsMultiple` property.
403
+
404
+ <Source of={FileUploadTests.ExampleMultipleFiles} type="code" dark />
405
+
406
+ ## Usage with simple state, upload on submit
407
+
408
+ <Source
409
+ of={FileUploadTests.SimpleStateAndUploadOnSubmitExample}
410
+ type="code"
411
+ dark
412
+ />
413
+
414
+ ## Usage with simple state, upload directly
415
+
416
+ <Source
417
+ of={FileUploadTests.SimpleStateAndUploadDirectlyExample}
418
+ type="code"
419
+ dark
420
+ />
421
+
422
+ ## Usage with react-hook-form
423
+
424
+ The usage is the same, you just need to use a `Controller` component (or `useController`) to control the file upload because it does not work on uncontrolled mode.
425
+
426
+ ## How to test this component
427
+
428
+ The most important thing is to ensure there is an `htmlForId` prop passed to the `formGroupWrapperProps` component prop.
429
+
430
+ This is needed to link the label to the input.
431
+
432
+ After that here is an example of how to test the component using testing-library and userEvent.
433
+ You will notice that **we need to add a delay** before starting to run assertions.
434
+ This is because of a hack we had to make in the component to make it work with testing-library.
435
+
436
+ <Source
437
+ of={FileUploadTests.TestSimpleStateAndUploadOnSubmitExample}
438
+ type="code"
439
+ dark
440
+ />
441
+
442
+ ## Playground & Props
443
+
444
+ <Canvas of={FileUpload.Playground} />
445
+
446
+ <Controls of={FileUpload.Playground} />
447
+
448
+ <Stories />
449
+ ```
@@ -0,0 +1,196 @@
1
+ # Filter
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/Filter/Filter.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 Filter from "./Filter";
18
+ import { WithReactTableFrontEndManaged } from "../DataTable/DataTable.stories";
19
+
20
+ const meta: Meta<typeof Filter> = {
21
+ component: Filter,
22
+ parameters: {
23
+ layout: "padded",
24
+ chromatic: { disableSnapshot: true },
25
+ },
26
+ };
27
+ export default meta;
28
+
29
+ // We just forward the DataTable Story to keep all things grouped and avoid duplications
30
+ export const FullFeatured: StoryObj<typeof Filter> = {
31
+ decorators: WithReactTableFrontEndManaged.decorators as any,
32
+ render: WithReactTableFrontEndManaged.render as any,
33
+ };
34
+ ```
35
+
36
+ ## How to test this component
37
+
38
+ Here are some more advanced stories with more testing coverage and examples that you can read to understand how to test this component.
39
+
40
+ ```tsx
41
+ import { Meta, StoryObj } from "@storybook/react-vite";
42
+ import Filter from "../Filter";
43
+ import { fireEvent, screen, userEvent, within } from "storybook/test";
44
+ import { FullFeatured } from "../Filter.stories";
45
+ import { expectNotPresent } from "@internal/test-utils-storybook/test-utils-storybook";
46
+
47
+ const meta: Meta<typeof Filter> = {
48
+ component: Filter,
49
+ parameters: {
50
+ layout: "padded",
51
+ chromatic: { disableSnapshot: true },
52
+ },
53
+ };
54
+ export default meta;
55
+
56
+ export const ShouldFilterTheRadio: StoryObj<typeof Filter> = {
57
+ ...FullFeatured,
58
+ play: async ({ canvasElement }) => {
59
+ const canvas = within(canvasElement);
60
+ const user = userEvent.setup({ delay: 50 });
61
+
62
+ // Assert initial state (no filter)
63
+ await canvas.findAllByText("Monday");
64
+ await canvas.findAllByText("Tuesday");
65
+
66
+ // Open the filter and select
67
+ await user.click(canvas.getByText("Filter"));
68
+ await fireEvent.click(screen.getByLabelText("Monday")); // fireEvent is used to avoid issue on Firefox
69
+ await user.click(screen.getByText("Apply"));
70
+ await canvas.findAllByText("Monday");
71
+ await canvas.findByText("Day: Monday");
72
+ await expectNotPresent(() => canvas.queryByText("Tuesday"));
73
+
74
+ // Remove the filter with the Chip
75
+ await user.click(canvas.getByLabelText("Close Day: Monday"));
76
+ await expectNotPresent(() => canvas.queryByText("Day: Monday"));
77
+ await canvas.findAllByText("Monday");
78
+ await canvas.findAllByText("Tuesday");
79
+ },
80
+ };
81
+
82
+ export const ShouldFilterTheCheckboxes: StoryObj<typeof Filter> = {
83
+ ...FullFeatured,
84
+ play: async ({ canvasElement }) => {
85
+ const canvas = within(canvasElement);
86
+ const user = userEvent.setup({ delay: 50 });
87
+
88
+ // Assert initial state (no filter)
89
+ await canvas.findAllByText("Pizza, Hamburger");
90
+ await canvas.findAllByText("Hamburger, Ramen");
91
+
92
+ // Open the filter and select
93
+ await user.click(canvas.getByText("Filter"));
94
+ await fireEvent.click(screen.getByLabelText("Pizza")); // fireEvent is used to avoid issue on Firefox
95
+ await user.click(screen.getByText("Apply"));
96
+ await canvas.findAllByText("Pizza, Hamburger");
97
+ await canvas.findByText("Foods: Pizza");
98
+ await expectNotPresent(() => canvas.queryByText("Hamburger, Ramen"));
99
+
100
+ // Remove the filter with the Chip
101
+ await user.click(canvas.getByLabelText("Close Foods: Pizza"));
102
+ await expectNotPresent(() => canvas.queryByText("Foods: Pizza"));
103
+ await canvas.findAllByText("Pizza, Hamburger");
104
+ await canvas.findAllByText("Hamburger, Ramen");
105
+ },
106
+ };
107
+
108
+ export const ShouldFilterTheOrganization: StoryObj<typeof Filter> = {
109
+ ...FullFeatured,
110
+ play: async ({ canvasElement }) => {
111
+ const canvas = within(canvasElement);
112
+ const user = userEvent.setup({ delay: 50 });
113
+
114
+ // Assert initial state (no filter)
115
+ await canvas.findAllByText("EDF Store and Forecast");
116
+ await canvas.findAllByText("Agregio Solutions");
117
+
118
+ // Open the filter and select
119
+ await user.click(canvas.getByText("Filter"));
120
+ await fireEvent.click(screen.getByLabelText("Filter by organization:")); // fireEvent is used to avoid issue on Firefox
121
+ await fireEvent.click(
122
+ screen.getByLabelText("DropdownItem EDF Store and Forecast"),
123
+ ); // fireEvent is used to avoid issue on Firefox
124
+ await user.click(screen.getByText("Apply"));
125
+ await canvas.findAllByText("EDF Store and Forecast");
126
+ await canvas.findByText("Organization: EDF Store and Forecast");
127
+ await expectNotPresent(() => canvas.queryByText("Agregio Solutions"));
128
+
129
+ // Remove the filter with the Chip
130
+ await user.click(
131
+ canvas.getByLabelText("Close Organization: EDF Store and Forecast"),
132
+ );
133
+ await expectNotPresent(() =>
134
+ canvas.queryByText("Organization: EDF Store and Forecast"),
135
+ );
136
+ await canvas.findAllByText("EDF Store and Forecast");
137
+ await canvas.findAllByText("Agregio Solutions");
138
+ },
139
+ };
140
+ ```
141
+
142
+ ## Developer notes
143
+
144
+ 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.
145
+
146
+ ````mdx
147
+ import { Meta, Controls, Stories, Source } from "@storybook/addon-docs/blocks";
148
+
149
+ import * as Filter from "./Filter.stories";
150
+ import { WithReactTableFrontEndManaged } from "../DataTable/DataTable.stories";
151
+
152
+ <Meta of={Filter} />
153
+
154
+ # Filter
155
+
156
+ ## Filter props
157
+
158
+ <Controls of={Filter.FullFeatured} />
159
+
160
+ ## How to enable/disable the search bar?
161
+
162
+ To enable the search bar, when creating your `table` instance with `react-table`, simply set an empty string as the `globalFilter` in the `state` or `initialState` of the table (depending on your use-case).
163
+
164
+ To remove it, simply do not set it (or set it to `undefined`).
165
+
166
+ Code example to **enable** the search bar:
167
+
168
+ ```
169
+ const table = useReactTable({
170
+ data,
171
+ columns,
172
+ initialState: {
173
+ globalFilter: "", // <- Enable the search bar
174
+ },
175
+ });
176
+ ```
177
+
178
+ ## How to use custom meta on react-table to create a filter?
179
+
180
+ As you can see in the source code for the example story, adding a filter into the drawer is as simple as using the `meta` key on the column definition.
181
+
182
+ Please use the exported type `TypeTableColumnWithFilter` to benefit from the type-safety and autocompletion features of your IDE.
183
+
184
+ Here are the available keys for the `meta` object with filter abilities:
185
+
186
+ - `FilterInDrawer`: function that must return a React node, typically the form to filter the column entry (like a Select, Radios, etc.)
187
+ - `skipFilterChips`: by default, we automatically add little Chips for the user to be able to remove the filter. If you want to hide them, set this to `true`.
188
+ - `filterChips`: when using complex data, we cannot automatically generate the chips for you. So you have to use this function that must return an array of chip data (value and onClose precisely)
189
+
190
+ Here is a complete example on how to use the `meta` key in a lot of different ways.
191
+ It also show you how to connect an external form element (here, a Switch) outside the drawer while still being able to filter the table.
192
+
193
+ Please read it carefully (maybe copy-paste it in your code editor to have better syntax highlighting), with this example you may be able to handle almost all use-cases.
194
+
195
+ <Source of={WithReactTableFrontEndManaged} type="code" dark />
196
+ ````