@agregio-solutions/design-system 1.102.5 → 2.0.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 (51) hide show
  1. package/dist/design-system.cjs +544 -629
  2. package/dist/design-system.js +7772 -27711
  3. package/dist/packages/components/Button/doc.md +33 -2
  4. package/dist/packages/components/Combobox/Combobox.d.ts +2 -2
  5. package/dist/packages/components/Combobox/doc.md +0 -4
  6. package/dist/packages/components/DataTable/DataTable.d.ts +15 -6
  7. package/dist/packages/components/DataTable/DataTableRow/DataTableRow.d.ts +1 -6
  8. package/dist/packages/components/DataTable/doc.md +495 -389
  9. package/dist/packages/components/DatePicker/DatePicker.d.ts +2 -2
  10. package/dist/packages/components/DatePicker/doc.md +0 -1
  11. package/dist/packages/components/DateRangePicker/DateRangePicker.d.ts +2 -2
  12. package/dist/packages/components/DateRangePicker/doc.md +0 -1
  13. package/dist/packages/components/Drawer/Drawer.d.ts +7 -24
  14. package/dist/packages/components/Drawer/doc.md +136 -106
  15. package/dist/packages/components/Dropdown/Dropdown.d.ts +1 -7
  16. package/dist/packages/components/Dropdown/doc.md +2 -29
  17. package/dist/packages/components/FileUpload/doc.md +0 -2
  18. package/dist/packages/components/Filter/Filter.d.ts +24 -10
  19. package/dist/packages/components/Filter/doc.md +31 -1
  20. package/dist/packages/components/Modal/doc.md +1 -2
  21. package/dist/packages/components/Navigation/Navigation.d.ts +2 -1
  22. package/dist/packages/components/Navigation/doc.md +14 -9
  23. package/dist/packages/components/NavigationItem/NavigationItem.d.ts +4 -0
  24. package/dist/packages/components/NavigationItem/doc.md +15 -3
  25. package/dist/packages/components/PageLayout/doc.md +190 -149
  26. package/dist/packages/components/Select/Select.d.ts +1 -1
  27. package/dist/packages/components/Select/doc.md +0 -9
  28. package/dist/packages/components/Slider/Slider.d.ts +3 -9
  29. package/dist/packages/components/Slider/doc.md +1 -4
  30. package/dist/packages/components/Tabs/Tab/Tab.d.ts +0 -5
  31. package/dist/packages/components/TextInput/TextInput.d.ts +2 -2
  32. package/dist/packages/components/TextInput/doc.md +0 -22
  33. package/dist/packages/components/TimeField/TimeField.d.ts +2 -2
  34. package/dist/packages/components/TimeField/doc.md +0 -1
  35. package/dist/packages/components/TimePicker/TimePicker.d.ts +2 -2
  36. package/dist/packages/components/Timeline/Timeline.styled.d.ts +15 -20
  37. package/dist/packages/components/Timeline/components/BlockLineContainer/BlockLineContainer.styled.d.ts +23 -27
  38. package/dist/packages/components/Timeline/components/GroupLineContainer/GroupLineContainer.styled.d.ts +3 -4
  39. package/dist/packages/components/Timeline/components/TimelineRange/TimelineRange.styled.d.ts +12 -16
  40. package/dist/packages/components/Timeline/doc.md +38 -1
  41. package/dist/packages/components/YearMonthPicker/YearMonthPicker.d.ts +2 -2
  42. package/dist/packages/components/YearMonthPicker/doc.md +0 -1
  43. package/dist/packages/ds-design-tokens/index.d.ts +1 -2
  44. package/dist/packages/ds-design-tokens/src/tokens.style.d.ts +138 -135
  45. package/dist/packages/index.d.ts +3 -4
  46. package/dist/packages/internal-components/FormGroupWrapper/FormGroupWrapper.d.ts +0 -12
  47. package/dist/public_docs/index.md +4 -1
  48. package/dist/public_docs/migration-guide-v2.md +444 -0
  49. package/package.json +6 -8
  50. package/dist/packages/ds-design-tokens/src/fontSize.style.d.ts +0 -60
  51. package/dist/packages/mui/mui-theme.d.ts +0 -3
@@ -1,7 +1,7 @@
1
1
  import { Props as FormGroupWrapperProps } from '../../internal-components/FormGroupWrapper/FormGroupWrapper';
2
2
  import { default as React } from 'react';
3
3
  import { Props as LabelProps } from '../Label/Label';
4
- export type Props = Pick<LabelProps, "label" | "labelIconRight" | "labelIconRightTooltip" | "required"> & Pick<FormGroupWrapperProps, "description" | "helperText" | "helperTextIcon" | "errorHelperText" | "errorHelperTextIcon" | "successHelperText" | "successHelperTextIcon" | "warningHelperText" | "warningHelperTextIcon" | "orientation"> & {
4
+ export type Props = Pick<LabelProps, "label" | "labelIconRight" | "labelIconRightTooltip" | "required"> & Pick<FormGroupWrapperProps, "helperText" | "helperTextIcon" | "errorHelperText" | "errorHelperTextIcon" | "successHelperText" | "successHelperTextIcon" | "warningHelperText" | "warningHelperTextIcon" | "orientation"> & {
5
5
  /**
6
6
  * Required id, used mainly to link the label to the field
7
7
  */
@@ -114,7 +114,7 @@ export type Props = Pick<LabelProps, "label" | "labelIconRight" | "labelIconRigh
114
114
  */
115
115
  fullWidth?: boolean;
116
116
  };
117
- declare const DatePicker: React.ForwardRefExoticComponent<Pick<LabelProps, "label" | "required" | "labelIconRight" | "labelIconRightTooltip"> & Pick<FormGroupWrapperProps, "orientation" | "description" | "helperText" | "helperTextIcon" | "errorHelperText" | "errorHelperTextIcon" | "successHelperText" | "successHelperTextIcon" | "warningHelperText" | "warningHelperTextIcon"> & {
117
+ declare const DatePicker: React.ForwardRefExoticComponent<Pick<LabelProps, "label" | "required" | "labelIconRight" | "labelIconRightTooltip"> & Pick<FormGroupWrapperProps, "orientation" | "helperText" | "helperTextIcon" | "errorHelperText" | "errorHelperTextIcon" | "successHelperText" | "successHelperTextIcon" | "warningHelperText" | "warningHelperTextIcon"> & {
118
118
  /**
119
119
  * Required id, used mainly to link the label to the field
120
120
  */
@@ -28,7 +28,6 @@ const meta: Meta<typeof DatePicker> = {
28
28
  options: ["America/New_York", "Europe/Paris"],
29
29
  },
30
30
  shouldCloseOnSelect: { control: "boolean" },
31
- description: { control: "text" },
32
31
  helperText: { control: "text" },
33
32
  errorHelperText: { control: "text" },
34
33
  successHelperText: { control: "text" },
@@ -5,7 +5,7 @@ export type DatePickerValue = null | {
5
5
  start: string;
6
6
  end: string;
7
7
  };
8
- export type Props = Pick<LabelProps, "label" | "labelIconRight" | "labelIconRightTooltip" | "required"> & Pick<FormGroupWrapperProps, "description" | "helperText" | "helperTextIcon" | "errorHelperText" | "errorHelperTextIcon" | "successHelperText" | "successHelperTextIcon" | "warningHelperText" | "warningHelperTextIcon" | "orientation"> & {
8
+ export type Props = Pick<LabelProps, "label" | "labelIconRight" | "labelIconRightTooltip" | "required"> & Pick<FormGroupWrapperProps, "helperText" | "helperTextIcon" | "errorHelperText" | "errorHelperTextIcon" | "successHelperText" | "successHelperTextIcon" | "warningHelperText" | "warningHelperTextIcon" | "orientation"> & {
9
9
  /**
10
10
  * Required id, used mainly to link the label to the field
11
11
  */
@@ -114,7 +114,7 @@ export type Props = Pick<LabelProps, "label" | "labelIconRight" | "labelIconRigh
114
114
  */
115
115
  fullWidth?: boolean;
116
116
  };
117
- declare const DateRangePicker: React.ForwardRefExoticComponent<Pick<LabelProps, "label" | "required" | "labelIconRight" | "labelIconRightTooltip"> & Pick<FormGroupWrapperProps, "orientation" | "description" | "helperText" | "helperTextIcon" | "errorHelperText" | "errorHelperTextIcon" | "successHelperText" | "successHelperTextIcon" | "warningHelperText" | "warningHelperTextIcon"> & {
117
+ declare const DateRangePicker: React.ForwardRefExoticComponent<Pick<LabelProps, "label" | "required" | "labelIconRight" | "labelIconRightTooltip"> & Pick<FormGroupWrapperProps, "orientation" | "helperText" | "helperTextIcon" | "errorHelperText" | "errorHelperTextIcon" | "successHelperText" | "successHelperTextIcon" | "warningHelperText" | "warningHelperTextIcon"> & {
118
118
  /**
119
119
  * Required id, used mainly to link the label to the field
120
120
  */
@@ -28,7 +28,6 @@ const meta: Meta<typeof DateRangePicker> = {
28
28
  options: ["America/New_York", "Europe/Paris"],
29
29
  },
30
30
  shouldCloseOnSelect: { control: "boolean" },
31
- description: { control: "text" },
32
31
  helperText: { control: "text" },
33
32
  errorHelperText: { control: "text" },
34
33
  successHelperText: { control: "text" },
@@ -1,4 +1,5 @@
1
1
  import { default as React } from 'react';
2
+ import { DrawerActions, DrawerContent, DrawerForm } from './Drawer.styled';
2
3
  export interface Props {
3
4
  /**
4
5
  * Determines if the drawer is open or closed
@@ -13,34 +14,16 @@ export interface Props {
13
14
  */
14
15
  title: string;
15
16
  /**
16
- * Content to be rendered inside the drawer
17
+ * Content to be rendered inside the drawer, below the title.
18
+ * Compose it with `DrawerContent` (scrollable padded body) and `DrawerActions` (bottom action bar),
19
+ * wrapped in `DrawerForm` when the drawer holds a form.
17
20
  */
18
21
  children: React.ReactNode;
19
22
  /**
20
- * Handler call on click on the primary action button
21
- */
22
- onPrimaryClick?: () => void;
23
- /**
24
- * Label for the primary action button
25
- */
26
- primaryLabel?: string;
27
- /**
28
- * Handler call on click on the secondary action button
29
- */
30
- onSecondaryClick?: () => void;
31
- /**
32
- * Label for the secondary action button
33
- */
34
- secondaryLabel?: string;
35
- /**
36
- * Whether the user can close the modal by clicking outside of it or pressing the escape key
23
+ * Whether the user can close the drawer by clicking outside of it or pressing the escape key
37
24
  * @default true
38
25
  */
39
26
  isDismissable?: boolean;
40
- /**
41
- * Custom implementation of the bottom action bar (with primary and secondary buttons)
42
- * Please ensure there is at least a close button.
43
- */
44
- customActionsBar?: React.ReactNode;
45
27
  }
46
- export default function Drawer({ children, onPrimaryClick, primaryLabel, onSecondaryClick, secondaryLabel, isOpen, onOpenChange, title, isDismissable, customActionsBar, }: Props): React.JSX.Element;
28
+ export default function Drawer({ children, isOpen, onOpenChange, title, isDismissable, }: Props): React.JSX.Element;
29
+ export { DrawerContent, DrawerActions, DrawerForm };
@@ -14,8 +14,8 @@ Base stories:
14
14
 
15
15
  ```tsx
16
16
  import { Meta, StoryObj } from "@storybook/react-vite";
17
- import Drawer, { Props } from "./Drawer";
18
- import { screen, fn } from "storybook/test";
17
+ import Drawer, { DrawerActions, DrawerContent, Props } from "./Drawer";
18
+ import { screen, fn, expect } from "storybook/test";
19
19
  import { useState } from "react";
20
20
  import Button from "@components/Button/Button";
21
21
  import {
@@ -35,17 +35,6 @@ const meta: Meta<typeof Drawer> = {
35
35
  function ParentComponent(props: Props) {
36
36
  const [isOpen, setIsOpen] = useState(props.isOpen);
37
37
 
38
- // Trick to make the drawer close on button with text "Close" (to avoid generating a lot of render stories)
39
- const onPrimaryClick =
40
- props.primaryLabel === "Close"
41
- ? () => setIsOpen(false)
42
- : props.onPrimaryClick;
43
-
44
- const onSecondaryClick =
45
- props.secondaryLabel === "Close"
46
- ? () => setIsOpen(false)
47
- : props.onSecondaryClick;
48
-
49
38
  return (
50
39
  <div
51
40
  style={{
@@ -55,14 +44,17 @@ const meta: Meta<typeof Drawer> = {
55
44
  height: "100vh",
56
45
  }}
57
46
  >
58
- <Drawer
59
- {...props}
60
- onPrimaryClick={onPrimaryClick}
61
- onSecondaryClick={onSecondaryClick}
62
- isOpen={isOpen}
63
- onOpenChange={setIsOpen}
64
- >
65
- {props.children}
47
+ <Drawer {...props} isOpen={isOpen} onOpenChange={setIsOpen}>
48
+ <DrawerContent>{props.children}</DrawerContent>
49
+
50
+ <DrawerActions>
51
+ <Button
52
+ onClick={() => setIsOpen(false)}
53
+ text="Close"
54
+ mode="secondary"
55
+ />
56
+ <Button onClick={() => setIsOpen(false)} text="Apply" />
57
+ </DrawerActions>
66
58
  </Drawer>
67
59
 
68
60
  <div style={{ textAlign: "center" }}>
@@ -85,29 +77,31 @@ export const Playground: StoryObj<typeof Drawer> = {
85
77
  title: "[Insert drawer title]",
86
78
  children: <div>The content</div>,
87
79
  isOpen: true,
88
- primaryLabel: "Close",
89
- onPrimaryClick: fn(),
90
- onSecondaryClick: fn(),
91
80
  onOpenChange: fn(),
92
81
  },
93
82
  play: async ({ args }) => {
94
83
  await screen.findByText(args.title);
95
84
  await screen.findByText("The content");
96
85
  await screen.findByText("Close");
86
+ await screen.findByText("Apply");
97
87
  await screen.findByLabelText("Close");
98
- await expectNotPresent(() => screen.queryByText("Submit"));
99
88
  },
100
89
  };
101
90
 
102
- export const WithSecondaryAction: StoryObj<typeof Drawer> = {
91
+ export const WithoutActions: StoryObj<typeof Drawer> = {
103
92
  args: {
104
93
  ...Playground.args,
105
- primaryLabel: "Send",
106
- secondaryLabel: "Close",
107
94
  },
108
- play: async () => {
109
- await screen.findByText("Send");
110
- await screen.findByText("Close");
95
+ render: (args) => (
96
+ <Drawer {...args}>
97
+ <DrawerContent>{args.children}</DrawerContent>
98
+ </Drawer>
99
+ ),
100
+ play: async ({ args }) => {
101
+ const drawer = await screen.findByRole("dialog", { name: args.title });
102
+ await screen.findByText("The content");
103
+ await expectNotPresent(() => screen.queryByText("Apply"));
104
+ await expect(drawer.querySelector("footer")).toBeNull();
111
105
  },
112
106
  };
113
107
 
@@ -116,6 +110,10 @@ export const OverflowingContent: StoryObj<typeof Drawer> = {
116
110
  ...Playground.args,
117
111
  children: "The content. ".repeat(300),
118
112
  },
113
+ play: async ({ args }) => {
114
+ await screen.findByText(args.title);
115
+ await screen.findByText("Apply");
116
+ },
119
117
  };
120
118
 
121
119
  export const Mobile: StoryObj<typeof Drawer> = {
@@ -130,17 +128,9 @@ export const Mobile: StoryObj<typeof Drawer> = {
130
128
  ...Playground.args,
131
129
  children: "The content. ".repeat(300),
132
130
  },
133
- };
134
-
135
- export const WithCustomActionsBar: StoryObj<typeof Drawer> = {
136
- args: {
137
- ...Playground.args,
138
- customActionsBar: (
139
- <>
140
- <Button text="Close" mode="secondary" />
141
- <Button text="Validate" isLoading />
142
- </>
143
- ),
131
+ play: async ({ args }) => {
132
+ await screen.findByText(args.title);
133
+ await screen.findByText("Apply");
144
134
  },
145
135
  };
146
136
  ```
@@ -151,12 +141,12 @@ Here are some more advanced stories with more testing coverage and examples that
151
141
 
152
142
  ```tsx
153
143
  import { Meta, StoryObj } from "@storybook/react-vite";
154
- import Drawer from "../Drawer";
155
- import { userEvent, within, screen, expect } from "storybook/test";
144
+ import Drawer, { DrawerActions, DrawerContent, DrawerForm } from "../Drawer";
145
+ import { userEvent, within, screen, expect, fn } from "storybook/test";
156
146
  import { useState } from "react";
157
147
  import Button from "@components/Button/Button";
158
148
  import { expectNotPresent } from "@internal/test-utils-storybook/test-utils-storybook";
159
- import { Playground, WithSecondaryAction } from "../Drawer.stories";
149
+ import { Playground } from "../Drawer.stories";
160
150
  import baseMeta from "../Drawer.stories";
161
151
  import { useForm } from "react-hook-form";
162
152
  import TextInput from "@packages/components/TextInput/TextInput";
@@ -203,21 +193,6 @@ export const TestFooterCloseButtonShouldCloseDrawer: StoryObj<typeof Drawer> = {
203
193
  },
204
194
  };
205
195
 
206
- export const TestShouldShowASecondaryButtonIfGiven: StoryObj<typeof Drawer> = {
207
- args: {
208
- ...WithSecondaryAction.args,
209
- secondaryLabel: "Dismiss",
210
- },
211
- play: async ({ args }) => {
212
- const user = userEvent.setup({ delay: 50 });
213
- await screen.findByText(args.title);
214
- await user.click(screen.getByText("Send"));
215
- await expect(args.onPrimaryClick).toHaveBeenCalledTimes(1);
216
- await user.click(screen.getByText("Dismiss"));
217
- await expect(args.onSecondaryClick).toHaveBeenCalledTimes(1);
218
- },
219
- };
220
-
221
196
  export const ExampleUsage: StoryObj<typeof Drawer> = {
222
197
  render: () => {
223
198
  function ParentComponent() {
@@ -228,14 +203,16 @@ export const ExampleUsage: StoryObj<typeof Drawer> = {
228
203
  <div>
229
204
  <Button onClick={() => setIsOpen(true)} text="Open drawer" />
230
205
  </div>
231
- <Drawer
232
- isOpen={isOpen}
233
- onOpenChange={setIsOpen}
234
- title="Drawer title"
235
- primaryLabel="Close"
236
- onPrimaryClick={() => setIsOpen(false)}
237
- >
238
- <div>Drawer content</div>
206
+ <Drawer isOpen={isOpen} onOpenChange={setIsOpen} title="Drawer title">
207
+ <DrawerContent>Drawer content</DrawerContent>
208
+ <DrawerActions>
209
+ <Button
210
+ onClick={() => setIsOpen(false)}
211
+ text="Close"
212
+ mode="secondary"
213
+ />
214
+ <Button onClick={() => setIsOpen(false)} text="Apply" />
215
+ </DrawerActions>
239
216
  </Drawer>
240
217
  </div>
241
218
  );
@@ -245,24 +222,46 @@ export const ExampleUsage: StoryObj<typeof Drawer> = {
245
222
  },
246
223
  };
247
224
 
225
+ type UserForm = {
226
+ name: string;
227
+ email: string;
228
+ };
229
+
230
+ type UserFormProps = {
231
+ onClose: () => void;
232
+ onSubmit: (values: UserForm) => Promise<void> | void;
233
+ };
234
+
235
+ function CreateUserForm({ onClose, onSubmit }: UserFormProps) {
236
+ const form = useForm<UserForm>();
237
+
238
+ return (
239
+ <DrawerForm onSubmit={form.handleSubmit(onSubmit)} noValidate>
240
+ <DrawerContent>
241
+ <TextInput
242
+ {...form.register("name", { required: "Name is required" })}
243
+ id="name"
244
+ label="Name"
245
+ errorHelperText={form.formState.errors.name?.message}
246
+ />
247
+ <TextInput {...form.register("email")} id="email" label="Email" />
248
+ </DrawerContent>
249
+ <DrawerActions>
250
+ <Button onClick={onClose} text="Close" mode="secondary" />
251
+ <Button
252
+ type="submit"
253
+ text="Create user"
254
+ isLoading={form.formState.isSubmitting}
255
+ />
256
+ </DrawerActions>
257
+ </DrawerForm>
258
+ );
259
+ }
260
+
248
261
  export const ExampleWithReactHookForm: StoryObj<typeof Drawer> = {
249
262
  render: () => {
250
- type Form = {
251
- name: string;
252
- email: string;
253
- };
254
-
255
263
  function ParentComponent() {
256
264
  const [isOpen, setIsOpen] = useState(false);
257
- const form = useForm<Form>();
258
-
259
- const onSubmit = form.handleSubmit(async (data: Form) => {
260
- // API call for example
261
- console.log(data); // eslint-disable-line no-console
262
- await new Promise((resolve) => setTimeout(resolve, 250));
263
- form.reset();
264
- setIsOpen(false);
265
- });
266
265
 
267
266
  return (
268
267
  <>
@@ -275,31 +274,16 @@ export const ExampleWithReactHookForm: StoryObj<typeof Drawer> = {
275
274
  isOpen={isOpen}
276
275
  onOpenChange={setIsOpen}
277
276
  title="Creating a new user"
278
- customActionsBar={
279
- <>
280
- <Button
281
- onClick={() => setIsOpen(false)}
282
- text="Close"
283
- mode="secondary"
284
- />
285
- <Button
286
- type="submit"
287
- form="create-user-form" // <- link the form to the button (by the form id)
288
- text="Create user"
289
- isLoading={form.formState.isSubmitting}
290
- />
291
- </>
292
- }
293
277
  >
294
- <form id="create-user-form" onSubmit={onSubmit} noValidate>
295
- <TextInput
296
- {...form.register("name", { required: "Name is required" })}
297
- id="name"
298
- label="Name"
299
- errorHelperText={form.formState.errors.name?.message}
300
- />
301
- <TextInput {...form.register("email")} id="email" label="Email" />
302
- </form>
278
+ <CreateUserForm
279
+ onClose={() => setIsOpen(false)}
280
+ onSubmit={async (values) => {
281
+ // API call for example
282
+ console.log(values); // eslint-disable-line no-console
283
+ await new Promise((resolve) => setTimeout(resolve, 250));
284
+ setIsOpen(false);
285
+ }}
286
+ />
303
287
  </Drawer>
304
288
  </>
305
289
  );
@@ -308,6 +292,52 @@ export const ExampleWithReactHookForm: StoryObj<typeof Drawer> = {
308
292
  return <ParentComponent />;
309
293
  },
310
294
  };
295
+
296
+ const onSubmitUser = fn();
297
+
298
+ export const TestFormShouldSubmitOnEnterFromAField: StoryObj<typeof Drawer> = {
299
+ args: {
300
+ ...Playground.args,
301
+ },
302
+ render: (args) => (
303
+ <Drawer {...args}>
304
+ <CreateUserForm onClose={() => {}} onSubmit={onSubmitUser} />
305
+ </Drawer>
306
+ ),
307
+ beforeEach: () => {
308
+ onSubmitUser.mockClear();
309
+ },
310
+ play: async () => {
311
+ const user = userEvent.setup({ delay: 50 });
312
+ await user.type(await screen.findByLabelText("Name"), "Jane{Enter}");
313
+ await expect(onSubmitUser).toHaveBeenCalledTimes(1);
314
+ await expect(onSubmitUser.mock.calls[0][0]).toMatchObject({
315
+ name: "Jane",
316
+ });
317
+ },
318
+ };
319
+
320
+ export const TestFormShouldShowErrorsWhenSubmittedInvalid: StoryObj<
321
+ typeof Drawer
322
+ > = {
323
+ args: {
324
+ ...Playground.args,
325
+ },
326
+ render: (args) => (
327
+ <Drawer {...args}>
328
+ <CreateUserForm onClose={() => {}} onSubmit={onSubmitUser} />
329
+ </Drawer>
330
+ ),
331
+ beforeEach: () => {
332
+ onSubmitUser.mockClear();
333
+ },
334
+ play: async () => {
335
+ const user = userEvent.setup({ delay: 50 });
336
+ await user.click(await screen.findByText("Create user"));
337
+ await screen.findByText("Name is required");
338
+ await expect(onSubmitUser).not.toHaveBeenCalled();
339
+ },
340
+ };
311
341
  ```
312
342
 
313
343
  ## Developer notes
@@ -1,13 +1,7 @@
1
1
  import { default as React } from 'react';
2
- import { Props as DropdownListItemProps } from './components/DropdownListItem/DropdownListItem';
3
2
  export type Props = {
4
3
  /**
5
- * The items to display in the dropdown. Same props as `DropdownListItem`.
6
- * @deprecated use `children` instead
7
- */
8
- items?: Array<DropdownListItemProps>;
9
- /**
10
- * Render you items manually if you prefer to use composition instead of props.
4
+ * The `DropdownListItem` components to display in the dropdown.
11
5
  */
12
6
  children?: React.ReactNode;
13
7
  /**
@@ -31,7 +31,6 @@ const meta: Meta<typeof Dropdown> = {
31
31
  },
32
32
  argTypes: {
33
33
  children: { control: false },
34
- items: { control: false },
35
34
  },
36
35
  };
37
36
  export default meta;
@@ -143,29 +142,6 @@ export const WithControlledSelectedItem: StoryObj<typeof Dropdown> = {
143
142
  );
144
143
  },
145
144
  };
146
-
147
- export const WithDeprecatedItemsProp: StoryObj<typeof Dropdown> = {
148
- args: {
149
- items: generateItems(5),
150
- style: {
151
- width: 315,
152
- },
153
- },
154
- play: async ({ canvasElement }) => {
155
- const canvas = within(canvasElement);
156
- await canvas.findByText("Item 1");
157
- await canvas.findByText("Item 2");
158
- await canvas.findByText("Item 3");
159
- await expect(canvas.queryByText("Item 4")?.parentElement).toHaveAttribute(
160
- "data-selected",
161
- "true",
162
- );
163
- await expect(canvas.queryByText("Item 5")?.parentElement).toHaveAttribute(
164
- "data-disabled",
165
- "true",
166
- );
167
- },
168
- };
169
145
  ```
170
146
 
171
147
  ## Developer notes
@@ -186,10 +162,7 @@ The dropdown is a simple component that allows you to create a dropdown menu.
186
162
 
187
163
  This component **does not handle it's absolute positioning**, you need to do it yourself with whatever method or lib you prefer.
188
164
 
189
- There is two ways of using this component:
190
-
191
- - ✅ **Recommended:** pass a list of `DropdownListItem` components as `children`
192
- - ⚠️ **Deprecated:** pass an array of `items` which values are the same as [DropdownListItem](?path=/docs/components-dropdown-components-dropdownlistitem--docs) props. (this prop may be removed in a future version)
165
+ Pass a list of [DropdownListItem](?path=/docs/components-dropdown-components-dropdownlistitem--docs) components as `children`.
193
166
 
194
167
  <Canvas of={Dropdown.Default} />
195
168
 
@@ -197,7 +170,7 @@ There is two ways of using this component:
197
170
 
198
171
  <Controls of={Dropdown.Default} />
199
172
 
200
- ### Dropdown `items` keys (for reference)
173
+ ### DropdownListItem props
201
174
 
202
175
  <Controls of={DropdownListItem.Default} />
203
176
 
@@ -42,7 +42,6 @@ export const Playground: Story = {
42
42
  formGroupWrapperProps: {
43
43
  htmlForId: "file-upload",
44
44
  label: "[Insert label]",
45
- description: "[Insert description]",
46
45
  errorHelperText: "[Insert helper]",
47
46
  errorHelperTextIcon: "error_outline",
48
47
  required: true,
@@ -77,7 +76,6 @@ export const Playground: Story = {
77
76
  play: async ({ canvasElement }) => {
78
77
  const canvas = within(canvasElement);
79
78
  await canvas.findByText("[Insert label]");
80
- await canvas.findByText("[Insert description]");
81
79
  await canvas.findByText("[Insert helper]");
82
80
  await canvas.findByText("[Filename.exe]");
83
81
  await canvas.findByText("test 2.txt");
@@ -1,10 +1,24 @@
1
1
  import { default as React } from 'react';
2
- import { Column, Table } from '@tanstack/react-table';
3
- type Props<TData> = {
2
+ import { Column, ReactTable, RowData, Table_ColumnFiltering, Table_GlobalFiltering, TableFeatures, TableState_All } from '@tanstack/react-table';
3
+ /**
4
+ * Since `react-table` v9, an API only exists on the instance when its feature is
5
+ * registered through `tableFeatures()`. `Filter` reads the filtering APIs
6
+ * optionally so a table without them still renders.
7
+ */
8
+ type OptionalFilteringApi<TFeatures extends TableFeatures, TData extends RowData> =
9
+ /** Requires `columnFilteringFeature`. */
10
+ Partial<Pick<Table_ColumnFiltering, "resetColumnFilters">> &
11
+ /** Requires `globalFilteringFeature`. */
12
+ Partial<Pick<Table_GlobalFiltering<TFeatures, TData>, "setGlobalFilter">>;
13
+ type Props<TFeatures extends TableFeatures, TData extends RowData> = {
4
14
  /**
5
- * Table instance from react-table
15
+ * Table instance from react-table.
16
+ * Call `useTable` without a state selector: `table.state` only holds the
17
+ * slices the selector keeps, and this component reads `globalFilter`.
6
18
  */
7
- table: Table<TData>;
19
+ table: ReactTable<TFeatures, TData> & OptionalFilteringApi<TFeatures, TData> & {
20
+ state: TableState_All;
21
+ };
8
22
  /**
9
23
  * Aria label for the filter input
10
24
  */
@@ -36,12 +50,12 @@ type Props<TData> = {
36
50
  */
37
51
  divProps?: React.HTMLProps<HTMLDivElement>;
38
52
  };
39
- export type TypeTableColumnWithFilter<TData> = {
53
+ export type TypeTableColumnWithFilter<TFeatures extends TableFeatures, TData extends RowData> = {
40
54
  /**
41
55
  * Filter form component that will be rendered in the drawer
42
56
  */
43
- FilterInDrawer?: ({ column }: {
44
- column: Column<TData>;
57
+ FilterInDrawer?: ({ column, }: {
58
+ column: Column<TFeatures, TData, unknown>;
45
59
  }) => React.ReactNode;
46
60
  /**
47
61
  * If true, the automatic filter chips will not be displayed (even if there is active filters for this column)
@@ -52,12 +66,12 @@ export type TypeTableColumnWithFilter<TData> = {
52
66
  * use it if you really need to manipulate the display of the chips
53
67
  * or if you have complexe data objects that cannont be automatically transformed into Chips by the Filter component
54
68
  */
55
- filterChips?: ({ column }: {
56
- column: Column<TData>;
69
+ filterChips?: ({ column, }: {
70
+ column: Column<TFeatures, TData, unknown>;
57
71
  }) => Array<{
58
72
  value: string;
59
73
  onClose: () => void;
60
74
  }>;
61
75
  };
62
- export default function Filter<TData>({ extraLeftContent, extraRightContent, divProps, onDownloadClick: onDownload, onSettingsClick: onSettings, table, searchAriaLabel, searchPlaceholder, }: Props<TData>): React.JSX.Element;
76
+ export default function Filter<TFeatures extends TableFeatures, TData extends RowData>({ extraLeftContent, extraRightContent, divProps, onDownloadClick: onDownload, onSettingsClick: onSettings, table, searchAriaLabel, searchPlaceholder, }: Props<TFeatures, TData>): React.JSX.Element;
63
77
  export {};
@@ -163,10 +163,21 @@ To enable the search bar, when creating your `table` instance with `react-table`
163
163
 
164
164
  To remove it, simply do not set it (or set it to `undefined`).
165
165
 
166
+ Since `react-table` v9, the `globalFilteringFeature` also has to be registered in
167
+ `tableFeatures()`, otherwise the `globalFilter` state does not exist.
168
+
166
169
  Code example to **enable** the search bar:
167
170
 
168
171
  ```
169
- const table = useReactTable({
172
+ const features = tableFeatures({
173
+ globalFilteringFeature, // <- Without it, there is no globalFilter state
174
+ columnFilteringFeature,
175
+ filterFns: { includesString: filterFn_includesString }, // Only the built-ins you use
176
+ filteredRowModel: createFilteredRowModel(),
177
+ });
178
+
179
+ const table = useTable({
180
+ features,
170
181
  data,
171
182
  columns,
172
183
  initialState: {
@@ -181,6 +192,25 @@ As you can see in the source code for the example story, adding a filter into th
181
192
 
182
193
  Please use the exported type `TypeTableColumnWithFilter` to benefit from the type-safety and autocompletion features of your IDE.
183
194
 
195
+ Since `react-table` v9, declare it through module augmentation so that every column
196
+ definition gets it, and so that `column` is correctly typed inside `FilterInDrawer`
197
+ and `filterChips`:
198
+
199
+ ```
200
+ declare module "@tanstack/react-table" {
201
+ interface ColumnMeta<
202
+ TFeatures extends TableFeatures,
203
+ TData extends RowData,
204
+ TValue,
205
+ > extends TypeTableColumnWithFilter<TFeatures, TData> {}
206
+ }
207
+ ```
208
+
209
+ v9 also offers a per-table `columnMeta` slot (`metaHelper<MyMeta>()` inside
210
+ `tableFeatures()`), but it cannot carry `TypeTableColumnWithFilter`: the type needs
211
+ `typeof features`, which would reference the features object inside its own
212
+ initializer.
213
+
184
214
  Here are the available keys for the `meta` object with filter abilities:
185
215
 
186
216
  - `FilterInDrawer`: function that must return a React node, typically the form to filter the column entry (like a Select, Radios, etc.)
@@ -105,7 +105,7 @@ Here are some more advanced stories with more testing coverage and examples that
105
105
 
106
106
  ```tsx
107
107
  import { Meta, StoryObj } from "@storybook/react-vite";
108
- import Modal, { ModalActions, ModalContent } from "../Modal";
108
+ import Modal, { ModalActions, ModalContent, ModalForm } from "../Modal";
109
109
  import { userEvent, within, screen } from "storybook/test";
110
110
  import { useState } from "react";
111
111
  import Button from "@components/Button/Button";
@@ -114,7 +114,6 @@ import { Playground } from "../Modal.stories";
114
114
  import baseMeta from "../Modal.stories";
115
115
  import { useForm } from "react-hook-form";
116
116
  import TextInput from "@components/TextInput/TextInput";
117
- import { ModalForm } from "../Modal.styled";
118
117
 
119
118
  const meta: Meta<typeof Modal> = {
120
119
  component: Modal,