@tsed/react-formio 3.0.0-alpha.10 → 3.0.0-alpha.11

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 (115) hide show
  1. package/dist/hooks/keyboard.constants.d.ts +38 -0
  2. package/dist/hooks/keyboard.constants.js +7 -0
  3. package/dist/hooks/keyboard.constants.js.map +1 -0
  4. package/dist/hooks/useKeyboardControls.d.ts +12 -0
  5. package/dist/hooks/useKeyboardControls.js +35 -0
  6. package/dist/hooks/useKeyboardControls.js.map +1 -0
  7. package/dist/interfaces/Operation.d.ts +12 -2
  8. package/dist/molecules/button/Button.d.ts +18 -5
  9. package/dist/molecules/button/Button.js +29 -30
  10. package/dist/molecules/button/Button.js.map +1 -1
  11. package/dist/molecules/card/Card.js +7 -5
  12. package/dist/molecules/card/Card.js.map +1 -1
  13. package/dist/molecules/forms/input-tags/InputTags.js +14 -14
  14. package/dist/molecules/forms/input-tags/InputTags.js.map +1 -1
  15. package/dist/molecules/table/Table.d.ts +11 -3
  16. package/dist/molecules/table/Table.js +8 -3
  17. package/dist/molecules/table/Table.js.map +1 -1
  18. package/dist/molecules/table/components/DefaultCellOperations.d.ts +12 -4
  19. package/dist/molecules/table/components/DefaultCellOperations.js +12 -6
  20. package/dist/molecules/table/components/DefaultCellOperations.js.map +1 -1
  21. package/dist/molecules/table/components/DefaultOperationButton.d.ts +12 -4
  22. package/dist/molecules/table/components/DefaultOperationButton.js.map +1 -1
  23. package/dist/molecules/table/hooks/useTable.d.ts +12 -4
  24. package/dist/molecules/table/hooks/useTable.js.map +1 -1
  25. package/dist/molecules/tabs/Tab.d.ts +13 -0
  26. package/dist/molecules/tabs/Tab.js +67 -0
  27. package/dist/molecules/tabs/Tab.js.map +1 -0
  28. package/dist/molecules/tabs/TabList.d.ts +2 -0
  29. package/dist/molecules/tabs/TabList.js +24 -0
  30. package/dist/molecules/tabs/TabList.js.map +1 -0
  31. package/dist/molecules/tabs/TabPanel.d.ts +9 -0
  32. package/dist/molecules/tabs/TabPanel.js +27 -0
  33. package/dist/molecules/tabs/TabPanel.js.map +1 -0
  34. package/dist/molecules/tabs/Tabs.d.ts +4 -16
  35. package/dist/molecules/tabs/Tabs.js +7 -67
  36. package/dist/molecules/tabs/Tabs.js.map +1 -1
  37. package/dist/molecules/tabs/TabsBody.d.ts +1 -0
  38. package/dist/molecules/tabs/TabsBody.js +10 -0
  39. package/dist/molecules/tabs/TabsBody.js.map +1 -0
  40. package/dist/molecules/tabs/TabsLegacy.d.ts +17 -0
  41. package/dist/molecules/tabs/TabsLegacy.js +49 -0
  42. package/dist/molecules/tabs/TabsLegacy.js.map +1 -0
  43. package/dist/molecules/tabs/all.d.ts +5 -0
  44. package/dist/molecules/tabs/all.js +13 -0
  45. package/dist/molecules/tabs/all.js.map +1 -0
  46. package/dist/molecules/tabs/context/TabControl.d.ts +52 -0
  47. package/dist/molecules/tabs/context/TabControl.js +85 -0
  48. package/dist/molecules/tabs/context/TabControl.js.map +1 -0
  49. package/dist/molecules/tabs/hooks/tabControl.d.ts +44 -0
  50. package/dist/molecules/tabs/hooks/tabControl.js +34 -0
  51. package/dist/molecules/tabs/hooks/tabControl.js.map +1 -0
  52. package/dist/organisms/form/actions/FormAction.js.map +1 -0
  53. package/dist/organisms/form/builder/FormEdit.d.ts +3 -1
  54. package/dist/organisms/form/builder/FormEdit.js +38 -35
  55. package/dist/organisms/form/builder/FormEdit.js.map +1 -1
  56. package/dist/organisms/form/builder/useFormEdit.js +17 -17
  57. package/dist/organisms/form/builder/useFormEdit.js.map +1 -1
  58. package/dist/organisms/form/exports/FormExport.d.ts +5 -0
  59. package/dist/organisms/form/exports/FormExport.js +55 -0
  60. package/dist/organisms/form/exports/FormExport.js.map +1 -0
  61. package/dist/organisms/form/preview/FormPreview.d.ts +6 -0
  62. package/dist/organisms/form/preview/FormPreview.js +11 -0
  63. package/dist/organisms/form/preview/FormPreview.js.map +1 -0
  64. package/dist/organisms/table/submissions/SubmissionsTable.d.ts +11 -3
  65. package/dist/organisms/table/submissions/SubmissionsTable.js +4 -1
  66. package/dist/organisms/table/submissions/SubmissionsTable.js.map +1 -1
  67. package/dist/organisms/views/FormViews.d.ts +24 -0
  68. package/dist/organisms/views/FormViews.js +96 -0
  69. package/dist/organisms/views/FormViews.js.map +1 -0
  70. package/package.json +3 -3
  71. package/src/hooks/keyboard.constants.ts +40 -0
  72. package/src/hooks/useKeyboardControls.spec.tsx +208 -0
  73. package/src/hooks/useKeyboardControls.ts +84 -0
  74. package/src/interfaces/Operation.ts +9 -3
  75. package/src/molecules/button/Button.tsx +43 -24
  76. package/src/molecules/card/Card.tsx +4 -0
  77. package/src/molecules/forms/input-tags/InputTags.tsx +1 -1
  78. package/src/molecules/pagination/Pagination.stories.tsx +0 -7
  79. package/src/molecules/table/Table.stories.tsx +34 -1
  80. package/src/molecules/table/Table.tsx +12 -6
  81. package/src/molecules/table/components/DefaultCellOperations.tsx +13 -7
  82. package/src/molecules/table/components/DefaultOperationButton.tsx +5 -4
  83. package/src/molecules/table/hooks/useTable.tsx +5 -5
  84. package/src/molecules/tabs/Tab.tsx +106 -0
  85. package/src/molecules/tabs/TabList.tsx +37 -0
  86. package/src/molecules/tabs/TabPanel.tsx +37 -0
  87. package/src/molecules/tabs/Tabs.spec.tsx +126 -73
  88. package/src/molecules/tabs/Tabs.stories.tsx +298 -65
  89. package/src/molecules/tabs/Tabs.tsx +10 -81
  90. package/src/molecules/tabs/TabsBody.tsx +11 -0
  91. package/src/molecules/tabs/TabsLegacy.stories.tsx +103 -0
  92. package/src/molecules/tabs/TabsLegacy.tsx +84 -0
  93. package/src/molecules/tabs/all.ts +5 -0
  94. package/src/molecules/tabs/context/TabControl.tsx +166 -0
  95. package/src/molecules/tabs/hooks/tabControl.spec.tsx +388 -0
  96. package/src/molecules/tabs/hooks/tabControl.ts +52 -0
  97. package/src/organisms/__fixtures__/form-firstname.fixture.json +1 -0
  98. package/src/organisms/__fixtures__/form.fixture.json +1 -0
  99. package/src/organisms/form/actions/FormAction.stories.tsx +422 -0
  100. package/src/organisms/form/builder/FormEdit.tsx +7 -1
  101. package/src/organisms/form/builder/useFormEdit.ts +1 -1
  102. package/src/organisms/form/exports/FormExport.stories.tsx +71 -0
  103. package/src/organisms/form/exports/FormExport.tsx +58 -0
  104. package/src/organisms/form/preview/FormPreview.stories.tsx +61 -0
  105. package/src/organisms/form/preview/FormPreview.tsx +21 -0
  106. package/src/organisms/table/actions/ActionsTable.stories.tsx +36 -34
  107. package/src/organisms/table/submissions/SubmissionsTable.stories.tsx +103 -57
  108. package/src/organisms/table/submissions/SubmissionsTable.tsx +10 -4
  109. package/src/organisms/views/FormViews.stories.tsx +224 -0
  110. package/src/organisms/views/FormViews.tsx +146 -0
  111. package/dist/organisms/form/action/FormAction.js.map +0 -1
  112. package/src/organisms/form/action/FormAction.stories.tsx +0 -364
  113. /package/dist/organisms/form/{action → actions}/FormAction.d.ts +0 -0
  114. /package/dist/organisms/form/{action → actions}/FormAction.js +0 -0
  115. /package/src/organisms/form/{action → actions}/FormAction.tsx +0 -0
@@ -1,141 +1,374 @@
1
- import { Meta, StoryObj } from "@storybook/react";
2
- import { useState } from "react";
3
-
4
- import { Tabs } from "./Tabs";
1
+ import "./all.js";
5
2
 
6
- const useTabs = (args: any) => {
7
- const [current, onClick] = useState(args.value);
3
+ import { Meta, StoryObj } from "@storybook/react";
4
+ import { expect, fn, userEvent, waitFor, within } from "@storybook/test";
8
5
 
9
- return {
10
- ...args,
11
- current,
12
- onClick
13
- };
14
- };
6
+ import { Icon } from "../../atoms/icon/Icon.js";
7
+ import { Button } from "../button/Button.js";
8
+ import { Tab } from "./Tab.js";
9
+ import { TabList } from "./TabList.js";
10
+ import { TabPanel } from "./TabPanel.js";
11
+ import { Tabs } from "./Tabs.js";
12
+ import { TabsBody } from "./TabsBody.js";
15
13
 
16
14
  /**
17
- * Tabs component
15
+ * Tabs component.
16
+ *
17
+ * You can import this component and use it like:
18
+ *
19
+ * ```tsx
20
+ * import {Tabs} from "@tsed/react-formio/molecules/tabs/all"
21
+ *
22
+ * or
23
+ *
24
+ * import {Tabs} from "@tsed/react-formio/molecules/tabs/Tabs";
25
+ * ```
26
+ *
27
+ * Tabs component support DI container and can be used with custom component. Here is the list of components that you can override:
28
+ *
29
+ * - Tab
30
+ * - TabList
31
+ * - TabPanel
32
+ * - Tabs
33
+ * - TabsBody
18
34
  *
19
35
  * ```tsx
20
- * import {Modal} from "@tsed/react-formio/molecules/tabs/Tabs";
36
+ * function CustomTab() {
37
+ *
38
+ * }
39
+ *
40
+ * registerComponent("Tab", CustomTab);
21
41
  * ```
22
42
  */
23
43
  export default {
24
44
  title: "Tabs",
25
45
  component: Tabs,
26
- argTypes: {},
46
+ argTypes: {
47
+ reverse: {
48
+ control: "boolean",
49
+ description: "Reverse the order of the tabs"
50
+ },
51
+ selected: {
52
+ control: { type: "number", min: 0, max: 10 },
53
+ description: "Selected tab index"
54
+ },
55
+ items: {
56
+ control: "object",
57
+ description: "Array of tab items with label, icon, and content"
58
+ }
59
+ },
27
60
  parameters: {},
28
- render: (args: any) => {
29
- // eslint-disable-next-line react-hooks/rules-of-hooks
30
- const tabs = useTabs(args);
61
+ args: {}
62
+ } satisfies Meta<typeof Tabs>;
63
+
64
+ type Story = StoryObj<typeof Tabs>;
65
+
66
+ export const Usage: Story = {
67
+ args: {
68
+ reverse: false,
69
+ items: [
70
+ {
71
+ action: "edit",
72
+ exact: true,
73
+ icon: "edit",
74
+ label: "Edit",
75
+ children: <div className='bg-red-100 p-5'>Edit</div>
76
+ },
77
+ {
78
+ action: "submissions",
79
+ exact: false,
80
+ icon: "data",
81
+ label: "Data",
82
+ children: <div className='bg-orange-100 p-5'>Data</div>
83
+ },
84
+ {
85
+ action: "preview",
86
+ exact: true,
87
+ icon: "test-tube",
88
+ label: "Preview",
89
+ children: <div className='bg-yellow-100 p-5'>Preview</div>
90
+ },
91
+ {
92
+ action: "actions",
93
+ exact: false,
94
+ icon: "paper-plane",
95
+ label: "Actions",
96
+ children: <div className='bg-green-100 p-5'>Actions</div>
97
+ },
98
+ {
99
+ action: "access",
100
+ exact: true,
101
+ icon: "lock",
102
+ label: "Access",
103
+ children: <div className='bg-blue-100 p-5'>Access</div>
104
+ },
105
+ {
106
+ action: "export",
107
+ exact: true,
108
+ icon: "download",
109
+ label: "Export",
110
+ children: <div className='bg-purple-100 p-5'>Export</div>
111
+ },
112
+ {
113
+ action: "delete",
114
+ exact: true,
115
+ icon: "trash",
116
+ label: "Delete",
117
+ roles: ["administrator", "owner"],
118
+ children: <div className='bg-gray-100 p-5'>Trash</div>
119
+ }
120
+ ],
121
+ onClick: fn()
122
+ },
123
+
124
+ play: async ({ canvasElement, args }) => {
125
+ const canvas = within(canvasElement);
126
+
127
+ // Vérifie que tous les onglets sont présents
128
+ await expect(canvas.getByRole("tab", { name: "Edit" })).toBeInTheDocument();
129
+ await expect(canvas.getByRole("tab", { name: "Data" })).toBeInTheDocument();
130
+ await expect(canvas.getByRole("tab", { name: "Preview" })).toBeInTheDocument();
131
+ await expect(canvas.getByRole("tab", { name: "Actions" })).toBeInTheDocument();
132
+ await expect(canvas.getByRole("tab", { name: "Access" })).toBeInTheDocument();
133
+ await expect(canvas.getByRole("tab", { name: "Export" })).toBeInTheDocument();
134
+ await expect(canvas.getByRole("tab", { name: "Delete" })).toBeInTheDocument();
135
+
136
+ await waitFor(() => expect(canvas.getByRole("tabpanel")).toHaveTextContent("Edit"));
137
+
138
+ // Clique sur l'onglet "Preview" et vérifie le contenu
139
+ await userEvent.click(canvas.getByRole("tab", { name: "Preview" }));
140
+
141
+ await expect(args.onClick).toHaveBeenCalledWith(
142
+ expect.objectContaining({
143
+ action: "preview"
144
+ })
145
+ );
146
+
147
+ await waitFor(() => expect(canvas.getByRole("tabpanel")).toHaveTextContent("Preview"));
148
+
149
+ // Clique sur l'onglet "Delete" et vérifie le contenu
150
+ await userEvent.click(canvas.getByRole("tab", { name: "Delete" }));
151
+ await expect(args.onClick).toHaveBeenCalledWith(
152
+ expect.objectContaining({
153
+ action: "delete"
154
+ })
155
+ );
156
+
157
+ await waitFor(() => expect(canvas.getByRole("tabpanel")).toHaveTextContent("Trash"));
158
+ },
159
+
160
+ render: (args) => {
161
+ const items: any[] = args.items.filter((item: any) => item.label || item.icon);
31
162
 
32
163
  return (
33
164
  <div className={"border-gray-300 border-1 shadow"}>
34
- <Tabs {...tabs} i18n={(f) => f}>
35
- <div className={"p-5"}>{tabs?.current?.action}</div>
165
+ <Tabs selected={args.selected}>
166
+ <TabList>
167
+ {items.map((item, index) => {
168
+ return (
169
+ <Tab
170
+ onClick={() => args.onClick(item)}
171
+ key={index}
172
+ icon={item.icon}
173
+ value={index}
174
+ className={args.reverse ? "-reverse" : ""}
175
+ >
176
+ {item.label}
177
+ </Tab>
178
+ );
179
+ })}
180
+ </TabList>
181
+ <TabsBody>
182
+ {items.map((item, index) => {
183
+ return (
184
+ <TabPanel key={index} value={index}>
185
+ {item.children}
186
+ </TabPanel>
187
+ );
188
+ })}
189
+ </TabsBody>
36
190
  </Tabs>
37
191
  </div>
38
192
  );
39
193
  }
40
- } satisfies Meta<typeof Tabs>;
41
-
42
- type Story = StoryObj<typeof Tabs>;
194
+ };
43
195
 
44
- export const Sandbox: Story = {
196
+ export const WithSelectedTab: Story = {
45
197
  args: {
198
+ selected: 2,
199
+ reverse: false,
46
200
  items: [
47
- {
48
- action: "back",
49
- exact: true,
50
- icon: "chevron-left",
51
- back: true
52
- },
53
201
  {
54
202
  action: "edit",
55
203
  exact: true,
56
204
  icon: "edit",
57
- label: "Edit"
205
+ label: "Edit",
206
+ children: <div className='bg-red-100 p-5'>Edit</div>
58
207
  },
59
208
  {
60
209
  action: "submissions",
61
210
  exact: false,
62
211
  icon: "data",
63
- label: "Data"
212
+ label: "Data",
213
+ children: <div className='bg-orange-100 p-5'>Data</div>
64
214
  },
65
215
  {
66
216
  action: "preview",
67
217
  exact: true,
68
218
  icon: "test-tube",
69
- label: "Preview"
219
+ label: "Preview",
220
+ children: <div className='bg-yellow-100 p-5'>Preview</div>
70
221
  },
71
222
  {
72
223
  action: "actions",
73
224
  exact: false,
74
225
  icon: "paper-plane",
75
- label: "Actions"
226
+ label: "Actions",
227
+ children: <div className='bg-green-100 p-5'>Actions</div>
76
228
  },
77
229
  {
78
230
  action: "access",
79
231
  exact: true,
80
232
  icon: "lock",
81
- label: "Access"
233
+ label: "Access",
234
+ children: <div className='bg-blue-100 p-5'>Access</div>
82
235
  },
83
236
  {
84
237
  action: "export",
85
238
  exact: true,
86
239
  icon: "download",
87
- label: "Export"
240
+ label: "Export",
241
+ children: <div className='bg-purple-100 p-5'>Export</div>
88
242
  },
89
243
  {
90
244
  action: "delete",
91
245
  exact: true,
92
246
  icon: "trash",
93
247
  label: "Delete",
94
- roles: ["administrator", "owner"]
248
+ roles: ["administrator", "owner"],
249
+ children: <div className='bg-gray-100 p-5'>Trash</div>
95
250
  }
96
251
  ]
97
- }
98
- };
99
-
100
- function AddButton({ onCreate }: any) {
101
- return (
102
- <div>
103
- <button onClick={onCreate}>+</button>
104
- </div>
105
- );
106
- }
107
-
108
- function HeaderChildren() {
109
- return <div className={"px-3 bg-gray-100 border-b-1 border-gray-light"}>test</div>;
110
- }
111
-
112
- export const WithCloseable = {
113
- render: (args: any) => {
114
- args.value = args.value === undefined ? 0 : args.value;
115
- // eslint-disable-next-line react-hooks/rules-of-hooks
116
- const tabs = useTabs(args);
252
+ },
253
+ render: (args) => {
254
+ const items: any[] = args.items.filter((item: any) => item.label || item.icon);
117
255
 
118
256
  return (
119
257
  <div className={"border-gray-300 border-1 shadow"}>
120
- <Tabs {...tabs} i18n={(f) => f} AddButton={AddButton} HeaderChildren={HeaderChildren}>
121
- <div className={"p-5"}>{tabs?.current?.action}</div>
258
+ <Tabs selected={args.selected}>
259
+ <TabList>
260
+ {items.map((item, index) => {
261
+ return (
262
+ <Tab key={index} icon={item.icon} value={index}>
263
+ {item.label}
264
+ </Tab>
265
+ );
266
+ })}
267
+ </TabList>
268
+ <TabsBody>
269
+ {items.map((item, index) => {
270
+ return (
271
+ <TabPanel key={index} value={index}>
272
+ {item.children}
273
+ </TabPanel>
274
+ );
275
+ })}
276
+ </TabsBody>
122
277
  </Tabs>
123
278
  </div>
124
279
  );
125
- },
280
+ }
281
+ };
282
+
283
+ export const WithExtraControls: Story = {
126
284
  args: {
127
- reverse: true,
285
+ reverse: false,
128
286
  items: [
129
287
  {
288
+ action: "edit",
289
+ exact: true,
290
+ icon: "edit",
291
+ label: "Edit",
292
+ children: <div className='bg-red-100 p-5'>Edit</div>
293
+ },
294
+ {
295
+ action: "submissions",
296
+ exact: false,
297
+ icon: "data",
298
+ label: "Data",
299
+ children: <div className='bg-orange-100 p-5'>Data</div>
300
+ },
301
+ {
302
+ action: "preview",
303
+ exact: true,
304
+ icon: "test-tube",
305
+ label: "Preview",
306
+ children: <div className='bg-yellow-100 p-5'>Preview</div>
307
+ },
308
+ {
309
+ action: "actions",
310
+ exact: false,
311
+ icon: "paper-plane",
312
+ label: "Actions",
313
+ children: <div className='bg-green-100 p-5'>Actions</div>
314
+ },
315
+ {
316
+ action: "access",
130
317
  exact: true,
131
- action: 0,
132
- label: "Test (0)"
318
+ icon: "lock",
319
+ label: "Access",
320
+ children: <div className='bg-blue-100 p-5'>Access</div>
133
321
  },
134
322
  {
323
+ action: "export",
135
324
  exact: true,
136
- action: 1,
137
- label: "Test (1)"
325
+ icon: "download",
326
+ label: "Export",
327
+ children: <div className='bg-purple-100 p-5'>Export</div>
328
+ },
329
+ {
330
+ action: "delete",
331
+ exact: true,
332
+ icon: "trash",
333
+ label: "Delete",
334
+ roles: ["administrator", "owner"],
335
+ children: <div className='bg-gray-100 p-5'>Trash</div>
138
336
  }
139
337
  ]
338
+ },
339
+ render: (args) => {
340
+ const items: any[] = args.items.filter((item: any) => item.label || item.icon);
341
+
342
+ return (
343
+ <div className={"border-gray-300 border-1 shadow"}>
344
+ <Tabs selected={args.selected}>
345
+ <TabList>
346
+ <Button variant='link' aria-label='Previous tab'>
347
+ <Icon name='chevron-left' />
348
+ </Button>
349
+
350
+ {items.map((item, index) => {
351
+ return (
352
+ <Tab key={index} icon={item.icon} value={index} className={args.reverse ? "-reverse" : ""}>
353
+ {item.label}
354
+ </Tab>
355
+ );
356
+ })}
357
+ <Button variant='link' aria-label='Add tab'>
358
+ <Icon name='plus' />
359
+ </Button>
360
+ </TabList>
361
+ <TabsBody>
362
+ {items.map((item, index) => {
363
+ return (
364
+ <TabPanel key={index} value={index}>
365
+ {item.children}
366
+ </TabPanel>
367
+ );
368
+ })}
369
+ </TabsBody>
370
+ </Tabs>
371
+ </div>
372
+ );
140
373
  }
141
374
  };
@@ -1,92 +1,21 @@
1
1
  import classnames from "classnames";
2
- import { PropsWithChildren } from "react";
2
+ import type { CSSProperties, PropsWithChildren } from "react";
3
3
 
4
- import { iconClass } from "../../utils/iconClass";
5
-
6
- export function ButtonTab({ icon, back, onClick, isActive, reverse, children, className, after }: PropsWithChildren<any>) {
7
- return (
8
- <div
9
- title={"button-wrapper"}
10
- className={classnames("tw-tabs__button-wrapper", isActive ? "-active" : "", back ? "-back" : "", className)}
11
- >
12
- <button
13
- title={"button-tab"}
14
- className={classnames("tw-tabs__button", reverse ? "-reverse" : "", isActive ? "-active" : "", back ? "-back" : "")}
15
- onClick={onClick}
16
- >
17
- {icon && <i className={classnames(iconClass(undefined, icon), "tw-tabs__button-icon")} />}
18
- <span className={"tw-tabs__button-label"}>{children}</span>
19
- {after}
20
- </button>
21
- <div className={classnames("tw-tabs__button-border", isActive ? "-active" : "")} />
22
- </div>
23
- );
24
- }
25
-
26
- export interface TabsItemProps extends Record<string, any> {
27
- label?: string;
28
- icon?: string;
29
- }
4
+ import { registerComponent } from "../../registries/components.js";
5
+ import { TabsProvider } from "./context/TabControl.js";
30
6
 
31
7
  export interface TabsProps extends Record<string, any> {
32
- headerChildren?: any;
33
- AddButton?: any;
34
- current?: TabsItemProps;
35
- items?: TabsItemProps[];
36
- style?: any;
8
+ style?: CSSProperties;
37
9
  className?: string;
38
- reverse?: boolean;
39
- Button?: any;
40
- onClick?: (item: TabsItemProps) => void;
41
- i18n?: (f: string) => string;
10
+ selected?: number;
42
11
  }
43
12
 
44
- export function Tabs({
45
- style,
46
- current,
47
- items = [],
48
- children,
49
- HeaderChildren,
50
- AddButton,
51
- Button = ButtonTab,
52
- className,
53
- onClick,
54
- i18n = (f) => f,
55
- ...additionalProps
56
- }: PropsWithChildren<TabsProps>) {
13
+ export function Tabs({ style, selected, children, className }: PropsWithChildren<TabsProps>) {
57
14
  return (
58
- <div data-testid={"tabs-comp"} className={`tw-tabs ${className}`} style={style}>
59
- <div>
60
- <nav className='tw-tabs__header'>
61
- <div className='tw-tabs__header-wrapper'>
62
- <div className='tw-tabs__header-border' />
63
- {items
64
- .filter((item) => item.label || item.icon)
65
- .map((item, index) => {
66
- return (
67
- <Button
68
- key={index}
69
- back={item.back}
70
- isActive={current?.action === item.action}
71
- exact={item.exact}
72
- onClick={() => {
73
- onClick && onClick(item);
74
- }}
75
- {...additionalProps}
76
- {...item}
77
- >
78
- {i18n(item.label || "")}
79
- </Button>
80
- );
81
- })}
82
- {AddButton && <AddButton {...additionalProps} current={current} />}
83
- </div>
84
- </nav>
85
- {HeaderChildren && <HeaderChildren {...additionalProps} current={current} />}
86
- </div>
87
- <div title={"tab-body"} className={"tw-tabs__body"}>
88
- {children}
89
- </div>
15
+ <div data-testid={"Tabs"} className={classnames("tw-tabs", className)} style={style}>
16
+ <TabsProvider selected={selected}>{children}</TabsProvider>
90
17
  </div>
91
18
  );
92
19
  }
20
+
21
+ registerComponent("Tabs", Tabs);
@@ -0,0 +1,11 @@
1
+ import { registerComponent } from "../../registries/components.js";
2
+
3
+ export function TabsBody(props: React.PropsWithChildren<{}>) {
4
+ return (
5
+ <div title={"tabs-body"} data-testid={"TabsBody"} className={"tw-tabs__body"}>
6
+ {props.children}
7
+ </div>
8
+ );
9
+ }
10
+
11
+ registerComponent("TabsBody", TabsBody);
@@ -0,0 +1,103 @@
1
+ import "./all.js";
2
+
3
+ import { Meta, StoryObj } from "@storybook/react";
4
+
5
+ import { TabsLegacy } from "./TabsLegacy.js";
6
+
7
+ /**
8
+ * TabsLegacy component.
9
+ *
10
+ * You can import this component and use it like:
11
+ *
12
+ * ```tsx
13
+ * import {Tabs} from "@tsed/react-formio/molecules/tabs/TabsLegacy";
14
+ * ```
15
+ *
16
+ * TabsLegacy component support DI container and can be used with custom component. Here is the list of components that you can override:
17
+ *
18
+ * - Tab
19
+ * - TabList
20
+ * - TabPanel
21
+ * - Tabs
22
+ * - TabsBody
23
+ *
24
+ * ```tsx
25
+ * function CustomTab() {
26
+ *
27
+ * }
28
+ *
29
+ * registerComponent("Tab", CustomTab);
30
+ * ```
31
+ */
32
+ export default {
33
+ title: "TabsLegacy",
34
+ component: TabsLegacy,
35
+ argTypes: {},
36
+ parameters: {},
37
+ render: (args: any) => {
38
+ return (
39
+ <div className={"border-gray-300 border-1 shadow"}>
40
+ <TabsLegacy {...args} i18n={(f) => f} />
41
+ </div>
42
+ );
43
+ }
44
+ } satisfies Meta<typeof TabsLegacy>;
45
+
46
+ type Story = StoryObj<typeof TabsLegacy>;
47
+
48
+ export const Sandbox: Story = {
49
+ args: {
50
+ items: [
51
+ {
52
+ action: "edit",
53
+ exact: true,
54
+ icon: "edit",
55
+ label: "Edit",
56
+ children: <div className='bg-red-100 p-5'>Edit</div>
57
+ },
58
+ {
59
+ action: "submissions",
60
+ exact: false,
61
+ icon: "data",
62
+ label: "Data",
63
+ children: <div className='bg-orange-100 p-5'>Data</div>
64
+ },
65
+ {
66
+ action: "preview",
67
+ exact: true,
68
+ icon: "test-tube",
69
+ label: "Preview",
70
+ children: <div className='bg-yellow-100 p-5'>Preview</div>
71
+ },
72
+ {
73
+ action: "actions",
74
+ exact: false,
75
+ icon: "paper-plane",
76
+ label: "Actions",
77
+ children: <div className='bg-green-100 p-5'>Actions</div>
78
+ },
79
+ {
80
+ action: "access",
81
+ exact: true,
82
+ icon: "lock",
83
+ label: "Access",
84
+ children: <div className='bg-blue-100 p-5'>Access</div>
85
+ },
86
+ {
87
+ action: "export",
88
+ exact: true,
89
+ icon: "download",
90
+ label: "Export",
91
+ children: <div className='bg-purple-100 p-5'>Export</div>
92
+ },
93
+ {
94
+ action: "delete",
95
+ exact: true,
96
+ icon: "trash",
97
+ label: "Delete",
98
+ roles: ["administrator", "owner"],
99
+ children: <div className='bg-gray-100 p-5'>Trash</div>
100
+ }
101
+ ]
102
+ }
103
+ };