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

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 (215) hide show
  1. package/dist/atoms/icon/Icon.js.map +1 -1
  2. package/dist/chunks/index.js +33 -30
  3. package/dist/chunks/index.js.map +1 -1
  4. package/dist/chunks/index.module.js +16 -16
  5. package/dist/chunks/index.module.js.map +1 -1
  6. package/dist/chunks/react-select-animated.esm.js +1204 -1101
  7. package/dist/chunks/react-select-animated.esm.js.map +1 -1
  8. package/dist/hooks/keyboard.constants.d.ts +38 -0
  9. package/dist/hooks/keyboard.constants.js +7 -0
  10. package/dist/hooks/keyboard.constants.js.map +1 -0
  11. package/dist/hooks/useKeyboardControls.d.ts +12 -0
  12. package/dist/hooks/useKeyboardControls.js +35 -0
  13. package/dist/hooks/useKeyboardControls.js.map +1 -0
  14. package/dist/hooks/useTooltip.js.map +1 -1
  15. package/dist/interfaces/Operation.d.ts +12 -2
  16. package/dist/molecules/alert/Alert.js.map +1 -1
  17. package/dist/molecules/button/Button.d.ts +18 -5
  18. package/dist/molecules/button/Button.js +22 -26
  19. package/dist/molecules/button/Button.js.map +1 -1
  20. package/dist/molecules/card/Card.js +7 -5
  21. package/dist/molecules/card/Card.js.map +1 -1
  22. package/dist/molecules/forms/form-control/FormControl.js.map +1 -1
  23. package/dist/molecules/forms/input-tags/InputTags.js +14 -14
  24. package/dist/molecules/forms/input-tags/InputTags.js.map +1 -1
  25. package/dist/molecules/forms/input-tags/components/ChoicesTags.js +26 -26
  26. package/dist/molecules/forms/input-tags/components/ChoicesTags.js.map +1 -1
  27. package/dist/molecules/forms/input-tags/components/ReactTags.js +289 -300
  28. package/dist/molecules/forms/input-tags/components/ReactTags.js.map +1 -1
  29. package/dist/molecules/forms/input-text/InputText.js +3 -3
  30. package/dist/molecules/forms/input-text/InputText.js.map +1 -1
  31. package/dist/molecules/forms/select/Select.js.map +1 -1
  32. package/dist/molecules/forms/select/components/ChoicesSelect.js +71 -73
  33. package/dist/molecules/forms/select/components/ChoicesSelect.js.map +1 -1
  34. package/dist/molecules/forms/select/components/HtmlSelect.js.map +1 -1
  35. package/dist/molecules/forms/select/components/ReactSelect.js +13 -14
  36. package/dist/molecules/forms/select/components/ReactSelect.js.map +1 -1
  37. package/dist/molecules/forms/select/components/choices.template.js +2340 -2257
  38. package/dist/molecules/forms/select/components/choices.template.js.map +1 -1
  39. package/dist/molecules/forms/select/hooks/useOptions.js.map +1 -1
  40. package/dist/molecules/loader/Loader.js.map +1 -1
  41. package/dist/molecules/modal/Modal.js +23 -24
  42. package/dist/molecules/modal/Modal.js.map +1 -1
  43. package/dist/molecules/pagination/Pagination.js +19 -19
  44. package/dist/molecules/pagination/Pagination.js.map +1 -1
  45. package/dist/molecules/pagination/PaginationButton.js.map +1 -1
  46. package/dist/molecules/pagination/utils/getPageNumbers.js.map +1 -1
  47. package/dist/molecules/table/Table.d.ts +11 -3
  48. package/dist/molecules/table/Table.js +31 -32
  49. package/dist/molecules/table/Table.js.map +1 -1
  50. package/dist/molecules/table/components/DefaultArrowSort.js.map +1 -1
  51. package/dist/molecules/table/components/DefaultCell.js.map +1 -1
  52. package/dist/molecules/table/components/DefaultCellFooter.js.map +1 -1
  53. package/dist/molecules/table/components/DefaultCellHeader.js.map +1 -1
  54. package/dist/molecules/table/components/DefaultCellOperations.d.ts +12 -4
  55. package/dist/molecules/table/components/DefaultCellOperations.js +13 -7
  56. package/dist/molecules/table/components/DefaultCellOperations.js.map +1 -1
  57. package/dist/molecules/table/components/DefaultFilter.js.map +1 -1
  58. package/dist/molecules/table/components/DefaultOperationButton.d.ts +12 -4
  59. package/dist/molecules/table/components/DefaultOperationButton.js +1 -1
  60. package/dist/molecules/table/components/DefaultOperationButton.js.map +1 -1
  61. package/dist/molecules/table/filters/RangeFilter.js +23 -24
  62. package/dist/molecules/table/filters/RangeFilter.js.map +1 -1
  63. package/dist/molecules/table/filters/SelectFilter.js +11 -13
  64. package/dist/molecules/table/filters/SelectFilter.js.map +1 -1
  65. package/dist/molecules/table/filters/TextFieldFilter.js.map +1 -1
  66. package/dist/molecules/table/hooks/useTable.d.ts +12 -4
  67. package/dist/molecules/table/hooks/useTable.js +7 -7
  68. package/dist/molecules/table/hooks/useTable.js.map +1 -1
  69. package/dist/molecules/table/hooks/useUniqValues.js.map +1 -1
  70. package/dist/molecules/table/utils/mapFormToColumns.js +20 -21
  71. package/dist/molecules/table/utils/mapFormToColumns.js.map +1 -1
  72. package/dist/molecules/tabs/Tab.d.ts +13 -0
  73. package/dist/molecules/tabs/Tab.js +66 -0
  74. package/dist/molecules/tabs/Tab.js.map +1 -0
  75. package/dist/molecules/tabs/TabList.d.ts +2 -0
  76. package/dist/molecules/tabs/TabList.js +23 -0
  77. package/dist/molecules/tabs/TabList.js.map +1 -0
  78. package/dist/molecules/tabs/TabPanel.d.ts +9 -0
  79. package/dist/molecules/tabs/TabPanel.js +27 -0
  80. package/dist/molecules/tabs/TabPanel.js.map +1 -0
  81. package/dist/molecules/tabs/Tabs.d.ts +4 -16
  82. package/dist/molecules/tabs/Tabs.js +7 -67
  83. package/dist/molecules/tabs/Tabs.js.map +1 -1
  84. package/dist/molecules/tabs/TabsBody.d.ts +1 -0
  85. package/dist/molecules/tabs/TabsBody.js +10 -0
  86. package/dist/molecules/tabs/TabsBody.js.map +1 -0
  87. package/dist/molecules/tabs/TabsLegacy.d.ts +17 -0
  88. package/dist/molecules/tabs/TabsLegacy.js +49 -0
  89. package/dist/molecules/tabs/TabsLegacy.js.map +1 -0
  90. package/dist/molecules/tabs/all.d.ts +5 -0
  91. package/dist/molecules/tabs/all.js +13 -0
  92. package/dist/molecules/tabs/all.js.map +1 -0
  93. package/dist/molecules/tabs/context/TabControl.d.ts +52 -0
  94. package/dist/molecules/tabs/context/TabControl.js +85 -0
  95. package/dist/molecules/tabs/context/TabControl.js.map +1 -0
  96. package/dist/molecules/tabs/hooks/tabControl.d.ts +44 -0
  97. package/dist/molecules/tabs/hooks/tabControl.js +34 -0
  98. package/dist/molecules/tabs/hooks/tabControl.js.map +1 -0
  99. package/dist/organisms/form/Form.js.map +1 -1
  100. package/dist/organisms/form/access/FormAccess.js +41 -41
  101. package/dist/organisms/form/access/FormAccess.js.map +1 -1
  102. package/dist/organisms/form/access/FormAccess.schema.js.map +1 -1
  103. package/dist/organisms/form/access/FormAccess.utils.js +2 -2
  104. package/dist/organisms/form/access/FormAccess.utils.js.map +1 -1
  105. package/dist/organisms/form/{action → actions}/FormAction.js +7 -8
  106. package/dist/organisms/form/actions/FormAction.js.map +1 -0
  107. package/dist/organisms/form/builder/FormBuilder.js.map +1 -1
  108. package/dist/organisms/form/builder/FormEdit.d.ts +3 -1
  109. package/dist/organisms/form/builder/FormEdit.js +38 -35
  110. package/dist/organisms/form/builder/FormEdit.js.map +1 -1
  111. package/dist/organisms/form/builder/FormEdit.reducer.js.map +1 -1
  112. package/dist/organisms/form/builder/FormEditCtas.js +34 -34
  113. package/dist/organisms/form/builder/FormEditCtas.js.map +1 -1
  114. package/dist/organisms/form/builder/FormParameters.js.map +1 -1
  115. package/dist/organisms/form/builder/useFormBuilder.js +41 -38
  116. package/dist/organisms/form/builder/useFormBuilder.js.map +1 -1
  117. package/dist/organisms/form/builder/useFormEdit.js +1 -1
  118. package/dist/organisms/form/builder/useFormEdit.js.map +1 -1
  119. package/dist/organisms/form/exports/FormExport.d.ts +5 -0
  120. package/dist/organisms/form/exports/FormExport.js +55 -0
  121. package/dist/organisms/form/exports/FormExport.js.map +1 -0
  122. package/dist/organisms/form/preview/FormPreview.d.ts +6 -0
  123. package/dist/organisms/form/preview/FormPreview.js +11 -0
  124. package/dist/organisms/form/preview/FormPreview.js.map +1 -0
  125. package/dist/organisms/form/settings/FormSettings.js +24 -24
  126. package/dist/organisms/form/settings/FormSettings.js.map +1 -1
  127. package/dist/organisms/form/settings/FormSettings.schema.js.map +1 -1
  128. package/dist/organisms/form/settings/FormSettings.utils.js.map +1 -1
  129. package/dist/organisms/form/useForm.js +664 -661
  130. package/dist/organisms/form/useForm.js.map +1 -1
  131. package/dist/organisms/modal/RemoveModal.js +16 -17
  132. package/dist/organisms/modal/RemoveModal.js.map +1 -1
  133. package/dist/organisms/table/actions/ActionsTable.js.map +1 -1
  134. package/dist/organisms/table/forms/FormsTable.js.map +1 -1
  135. package/dist/organisms/table/forms/components/FormsCell.js.map +1 -1
  136. package/dist/organisms/table/submissions/SubmissionsTable.d.ts +11 -3
  137. package/dist/organisms/table/submissions/SubmissionsTable.js +4 -1
  138. package/dist/organisms/table/submissions/SubmissionsTable.js.map +1 -1
  139. package/dist/organisms/views/FormViews.d.ts +24 -0
  140. package/dist/organisms/views/FormViews.js +96 -0
  141. package/dist/organisms/views/FormViews.js.map +1 -0
  142. package/dist/registries/components.js.map +1 -1
  143. package/dist/utils/getEventValue.js.map +1 -1
  144. package/dist/utils/iconClass.js.map +1 -1
  145. package/dist/utils/mapPagination.js.map +1 -1
  146. package/dist/utils/stopPropagationWrapper.js.map +1 -1
  147. package/package.json +7 -7
  148. package/src/atoms/icon/Icon.stories.tsx +1 -1
  149. package/src/hooks/keyboard.constants.ts +40 -0
  150. package/src/hooks/useKeyboardControls.spec.tsx +208 -0
  151. package/src/hooks/useKeyboardControls.ts +84 -0
  152. package/src/interfaces/Operation.ts +9 -3
  153. package/src/molecules/button/Button.stories.tsx +1 -1
  154. package/src/molecules/button/Button.tsx +43 -24
  155. package/src/molecules/card/Card.tsx +4 -0
  156. package/src/molecules/forms/form-control/FormControl.stories.tsx +1 -1
  157. package/src/molecules/forms/input-tags/InputTags.tsx +1 -1
  158. package/src/molecules/forms/input-tags/components/ChoicesTags.stories.tsx +1 -1
  159. package/src/molecules/forms/input-tags/components/ReactTags.stories.tsx +1 -1
  160. package/src/molecules/forms/input-text/InputText.stories.tsx +2 -2
  161. package/src/molecules/forms/select/components/ChoicesSelect.stories.tsx +2 -2
  162. package/src/molecules/forms/select/components/HtmlSelect.stories.tsx +2 -2
  163. package/src/molecules/forms/select/components/ReactSelect.stories.tsx +2 -2
  164. package/src/molecules/loader/Loader.stories.tsx +1 -1
  165. package/src/molecules/modal/Modal.stories.tsx +1 -1
  166. package/src/molecules/pagination/Pagination.stories.tsx +1 -8
  167. package/src/molecules/pagination/Pagination.tsx +0 -1
  168. package/src/molecules/table/Table.stories.tsx +36 -3
  169. package/src/molecules/table/Table.tsx +12 -6
  170. package/src/molecules/table/components/DefaultCellOperations.tsx +13 -7
  171. package/src/molecules/table/components/DefaultOperationButton.tsx +5 -4
  172. package/src/molecules/table/filters/SelectFilter.tsx +1 -1
  173. package/src/molecules/table/hooks/useTable.tsx +5 -5
  174. package/src/molecules/tabs/Tab.tsx +106 -0
  175. package/src/molecules/tabs/TabList.tsx +37 -0
  176. package/src/molecules/tabs/TabPanel.tsx +37 -0
  177. package/src/molecules/tabs/Tabs.spec.tsx +126 -73
  178. package/src/molecules/tabs/Tabs.stories.tsx +298 -65
  179. package/src/molecules/tabs/Tabs.tsx +10 -81
  180. package/src/molecules/tabs/TabsBody.tsx +11 -0
  181. package/src/molecules/tabs/TabsLegacy.stories.tsx +103 -0
  182. package/src/molecules/tabs/TabsLegacy.tsx +84 -0
  183. package/src/molecules/tabs/all.ts +5 -0
  184. package/src/molecules/tabs/context/TabControl.tsx +166 -0
  185. package/src/molecules/tabs/hooks/tabControl.spec.tsx +388 -0
  186. package/src/molecules/tabs/hooks/tabControl.ts +52 -0
  187. package/src/organisms/__fixtures__/form-firstname.fixture.json +1 -0
  188. package/src/organisms/__fixtures__/form.fixture.json +1 -0
  189. package/src/organisms/form/Form.stories.tsx +94 -118
  190. package/src/organisms/form/access/FormAccess.stories.tsx +2 -2
  191. package/src/organisms/form/actions/FormAction.stories.tsx +422 -0
  192. package/src/organisms/form/builder/FormBuilder.stories.tsx +4 -1
  193. package/src/organisms/form/builder/FormEdit.stories.tsx +1 -1
  194. package/src/organisms/form/builder/FormEdit.tsx +7 -1
  195. package/src/organisms/form/builder/useFormBuilder.ts +5 -1
  196. package/src/organisms/form/builder/useFormEdit.ts +1 -1
  197. package/src/organisms/form/exports/FormExport.stories.tsx +71 -0
  198. package/src/organisms/form/exports/FormExport.tsx +58 -0
  199. package/src/organisms/form/preview/FormPreview.stories.tsx +61 -0
  200. package/src/organisms/form/preview/FormPreview.tsx +21 -0
  201. package/src/organisms/modal/RemoveModal.stories.tsx +1 -1
  202. package/src/organisms/table/actions/ActionsTable.stories.tsx +38 -36
  203. package/src/organisms/table/submissions/SubmissionsTable.stories.tsx +103 -57
  204. package/src/organisms/table/submissions/SubmissionsTable.tsx +10 -4
  205. package/src/organisms/views/FormViews.stories.tsx +224 -0
  206. package/src/organisms/views/FormViews.tsx +146 -0
  207. package/vite.config.mts +2 -2
  208. package/dist/organisms/form/action/FormAction.js.map +0 -1
  209. package/src/organisms/form/action/FormAction.stories.tsx +0 -364
  210. package/tsconfig.app.json +0 -11
  211. package/tsconfig.json +0 -21
  212. package/tsconfig.node.json +0 -13
  213. package/tsconfig.spec.json +0 -14
  214. /package/dist/organisms/form/{action → actions}/FormAction.d.ts +0 -0
  215. /package/src/organisms/form/{action → actions}/FormAction.tsx +0 -0
@@ -0,0 +1,388 @@
1
+ import { act, render, renderHook, screen } from "@testing-library/react";
2
+ import { userEvent } from "@testing-library/user-event";
3
+ import { type PropsWithChildren, useContext, useRef } from "react";
4
+
5
+ import { TabControlContext, TabsProvider } from "../context/TabControl";
6
+ import { Tab } from "../Tab.js";
7
+ import { useActiveTab, useRegisterTabControl, useTabControls, useTabDispatch } from "./tabControl";
8
+
9
+ interface Config {
10
+ selected: number;
11
+ }
12
+
13
+ const createWrapper = ({ selected }: Config = { selected: 3 }) => {
14
+ return ({ children }: PropsWithChildren) => {
15
+ return <TabsProvider selected={selected}>{children}</TabsProvider>;
16
+ };
17
+ };
18
+
19
+ describe("tab control hooks", () => {
20
+ beforeAll(() => {
21
+ vi.spyOn(console, "warn").mockImplementation(() => {});
22
+ });
23
+
24
+ afterAll(() => {
25
+ vi.mocked(console.warn).mockReset();
26
+ });
27
+
28
+ describe("useActiveTab()", () => {
29
+ it("returns the current tab value", () => {
30
+ const { result } = renderHook(useActiveTab, { wrapper: createWrapper() });
31
+
32
+ expect(result.current).toBe(3);
33
+ });
34
+ });
35
+
36
+ describe("useRegisterTabControl()", () => {
37
+ it("returns the dispatch function", () => {
38
+ const { result } = renderHook(() => useRegisterTabControl({ value: 0, ref: useRef(null) }), {
39
+ wrapper: createWrapper()
40
+ });
41
+
42
+ expect(result.current).toEqual(expect.any(Function));
43
+ });
44
+
45
+ it("register and unregister", () => {
46
+ const { result, unmount } = renderHook(() => {
47
+ const div = document.createElement("div");
48
+
49
+ return useRegisterTabControl({ value: 0, ref: useRef<HTMLDivElement>(div) });
50
+ });
51
+
52
+ unmount();
53
+
54
+ expect(result.current).toEqual(expect.any(Function));
55
+ });
56
+
57
+ describe("without provider", () => {
58
+ it("log a warning", async () => {
59
+ const { result, unmount } = renderHook(() => {
60
+ const div = document.createElement("div");
61
+ return useRegisterTabControl({ value: 0, ref: useRef<HTMLDivElement>(div) });
62
+ });
63
+
64
+ await act(() => result.current({ type: "update", payload: 4 }));
65
+
66
+ unmount();
67
+
68
+ expect(console.warn).toHaveBeenCalledWith("Tab Controller Context dispatch used outside of Provider");
69
+ expect(console.warn).toHaveBeenCalledWith("Tab Controller Context register used outside of Provider");
70
+ expect(console.warn).toHaveBeenCalledWith("Tab Controller Context unregister used outside of Provider");
71
+ });
72
+ });
73
+ });
74
+
75
+ describe("useTabDispatch()", () => {
76
+ it("returns the dispatch function", () => {
77
+ const { result } = renderHook(useTabDispatch, {
78
+ wrapper: createWrapper()
79
+ });
80
+
81
+ expect(result.current).toEqual(expect.any(Function));
82
+ });
83
+
84
+ describe("without provider", () => {
85
+ it("log a warning", async () => {
86
+ const { result } = renderHook(useTabDispatch);
87
+
88
+ await act(() => result.current({ type: "update", payload: 4 }));
89
+
90
+ expect(console.warn).toHaveBeenCalledWith("Tab Controller Context dispatch used outside of Provider");
91
+ });
92
+ });
93
+
94
+ describe("dispatch update", () => {
95
+ it("update the state", async () => {
96
+ const Test = () => {
97
+ const dispatch = useTabDispatch();
98
+ const tab = useActiveTab();
99
+
100
+ const update = () => {
101
+ dispatch({ type: "update", payload: 4 });
102
+ };
103
+
104
+ return (
105
+ <>
106
+ <button onClick={update}>update</button>
107
+ <output name='result'>{tab}</output>
108
+ </>
109
+ );
110
+ };
111
+
112
+ render(<Test />, { wrapper: createWrapper() });
113
+
114
+ const button = screen.getByRole("button");
115
+ const output = screen.getByRole("status");
116
+
117
+ expect(output).toHaveValue("3");
118
+
119
+ await userEvent.click(button);
120
+
121
+ expect(output).toHaveValue("4");
122
+ });
123
+ });
124
+
125
+ describe("dispatch end", () => {
126
+ it("update the state", async () => {
127
+ const Test = () => {
128
+ const dispatch = useTabDispatch();
129
+ const tab = useActiveTab();
130
+
131
+ const end = () => {
132
+ dispatch({ type: "end" });
133
+ };
134
+
135
+ return (
136
+ <>
137
+ <Tab value={0}>Label 0</Tab>
138
+ <Tab value={3}>Label 3</Tab>
139
+ <Tab value={5}>Label 5</Tab>
140
+
141
+ <button onClick={end}>end</button>
142
+
143
+ <output name='result'>{tab}</output>
144
+ </>
145
+ );
146
+ };
147
+
148
+ render(<Test />, { wrapper: createWrapper() });
149
+
150
+ const button = screen.getByRole("button");
151
+ const output = screen.getByRole("status");
152
+
153
+ expect(output).toHaveValue("3");
154
+
155
+ await userEvent.click(button);
156
+ expect(output).toHaveValue("5");
157
+ });
158
+ });
159
+
160
+ describe("dispatch start", () => {
161
+ it("update the state", async () => {
162
+ const Test = () => {
163
+ const dispatch = useTabDispatch();
164
+ const tab = useActiveTab();
165
+
166
+ const start = () => {
167
+ dispatch({ type: "start" });
168
+ };
169
+
170
+ return (
171
+ <>
172
+ <Tab value={0}>Label 0</Tab>
173
+ <Tab value={3}>Label 3</Tab>
174
+ <Tab value={5}>Label 5</Tab>
175
+ <button onClick={start}>start</button>
176
+ <output name='result'>{tab}</output>
177
+ </>
178
+ );
179
+ };
180
+
181
+ render(<Test />, { wrapper: createWrapper() });
182
+
183
+ const button = screen.getByRole("button");
184
+ const output = screen.getByRole("status");
185
+
186
+ expect(output).toHaveValue("3");
187
+
188
+ await userEvent.click(button);
189
+
190
+ expect(output).toHaveValue("0");
191
+ });
192
+ });
193
+
194
+ describe("dispatch next", () => {
195
+ it("update the state", async () => {
196
+ const Test = () => {
197
+ const dispatch = useTabDispatch();
198
+ const tab = useActiveTab();
199
+
200
+ const next = () => {
201
+ dispatch({ type: "next" });
202
+ };
203
+
204
+ return (
205
+ <>
206
+ <Tab value={0}>Label 0</Tab>
207
+ <Tab value={3}>Label 3</Tab>
208
+ <Tab value={4}>Label 4</Tab>
209
+ <Tab value={5}>Label 5</Tab>
210
+ <button onClick={next}>next</button>
211
+ <output name='result'>{tab}</output>
212
+ </>
213
+ );
214
+ };
215
+
216
+ render(<Test />, { wrapper: createWrapper() });
217
+
218
+ const button = screen.getByRole("button");
219
+ const output = screen.getByRole("status");
220
+
221
+ expect(output).toHaveValue("3");
222
+
223
+ await userEvent.click(button);
224
+
225
+ expect(output).toHaveValue("4");
226
+ });
227
+
228
+ describe("when current tab is last one", () => {
229
+ it("loop to the first tab", async () => {
230
+ const Test = () => {
231
+ const dispatch = useTabDispatch();
232
+ const tab = useActiveTab();
233
+
234
+ const next = () => {
235
+ dispatch({ type: "next" });
236
+ };
237
+
238
+ return (
239
+ <>
240
+ <Tab value={0}>Label 0</Tab>
241
+ <Tab value={3}>Label 3</Tab>
242
+ <Tab value={4}>Label 4</Tab>
243
+ <Tab value={5}>Label 5</Tab>
244
+ <button onClick={next}>next</button>
245
+ <output name='result'>{tab}</output>
246
+ </>
247
+ );
248
+ };
249
+
250
+ render(<Test />, { wrapper: createWrapper({ selected: 5 }) });
251
+
252
+ const button = screen.getByRole("button");
253
+ const output = screen.getByRole("status");
254
+
255
+ expect(output).toHaveValue("5");
256
+
257
+ await userEvent.click(button);
258
+
259
+ expect(output).toHaveValue("0");
260
+ });
261
+ });
262
+ });
263
+
264
+ describe("dispatch previous", () => {
265
+ it("update the state", async () => {
266
+ const Test = () => {
267
+ const dispatch = useTabDispatch();
268
+ const tab = useActiveTab();
269
+
270
+ const previous = () => {
271
+ dispatch({ type: "previous" });
272
+ };
273
+
274
+ return (
275
+ <>
276
+ <Tab value={0}>Label 0</Tab>
277
+ <Tab value={2}>Label 2</Tab>
278
+ <Tab value={3}>Label 3</Tab>
279
+ <Tab value={4}>Label 4</Tab>
280
+ <Tab value={5}>Label 5</Tab>
281
+ <button onClick={previous}>previous</button>
282
+ <output name='result'>{tab}</output>
283
+ </>
284
+ );
285
+ };
286
+
287
+ render(<Test />, { wrapper: createWrapper() });
288
+
289
+ const button = screen.getByRole("button");
290
+ const output = screen.getByRole("status");
291
+
292
+ expect(output).toHaveValue("3");
293
+
294
+ await userEvent.click(button);
295
+
296
+ expect(output).toHaveValue("2");
297
+ });
298
+
299
+ describe("when current tab is first one", () => {
300
+ it("loop to the last tab", async () => {
301
+ const Test = () => {
302
+ const dispatch = useTabDispatch();
303
+ const tab = useActiveTab();
304
+
305
+ const previous = () => {
306
+ dispatch({ type: "previous" });
307
+ };
308
+
309
+ return (
310
+ <>
311
+ <Tab value={0}>Label 0</Tab>
312
+ <Tab value={2}>Label 2</Tab>
313
+ <Tab value={3}>Label 3</Tab>
314
+ <Tab value={4}>Label 4</Tab>
315
+ <Tab value={5}>Label 5</Tab>
316
+ <button onClick={previous}>previous</button>
317
+ <output name='result'>{tab}</output>
318
+ </>
319
+ );
320
+ };
321
+
322
+ render(<Test />, { wrapper: createWrapper({ selected: 0 }) });
323
+
324
+ const button = screen.getByRole("button");
325
+ const output = screen.getByRole("status");
326
+
327
+ expect(output).toHaveValue("0");
328
+
329
+ await userEvent.click(button);
330
+
331
+ expect(output).toHaveValue("5");
332
+ });
333
+ });
334
+ });
335
+ });
336
+
337
+ describe("useTabControl()", () => {
338
+ it("retuns the elements registered map", () => {
339
+ const Test = () => {
340
+ const div = document.createElement("div");
341
+ const ref = useRef(div);
342
+
343
+ useRegisterTabControl({ value: 0, ref });
344
+
345
+ const controls = useTabControls();
346
+
347
+ return <output name='result'>{controls.size}</output>;
348
+ };
349
+
350
+ render(<Test />, { wrapper: createWrapper() });
351
+
352
+ const output = screen.getByRole("status");
353
+
354
+ expect(output).toHaveValue("1");
355
+ });
356
+
357
+ it("allow unregister", async () => {
358
+ const Test = () => {
359
+ const div = document.createElement("div");
360
+ const ref = useRef(div);
361
+
362
+ const { register, unregister } = useContext(TabControlContext);
363
+ const controls = useTabControls();
364
+
365
+ return (
366
+ <>
367
+ <button onClick={() => register(0, ref)}>REGISTER</button>
368
+ <button onClick={() => unregister(0)}>UNREGISTER</button>
369
+ <output name='result'>{controls.size}</output>
370
+ </>
371
+ );
372
+ };
373
+
374
+ render(<Test />, { wrapper: createWrapper() });
375
+
376
+ const register = screen.getByRole("button", { name: "REGISTER" });
377
+ const unregister = screen.getByRole("button", { name: "UNREGISTER" });
378
+
379
+ await userEvent.click(register);
380
+
381
+ expect(screen.getByRole("status")).toHaveValue("1");
382
+
383
+ await userEvent.click(unregister);
384
+
385
+ expect(screen.getByRole("status")).toHaveValue("0");
386
+ });
387
+ });
388
+ });
@@ -0,0 +1,52 @@
1
+ import { type RefObject, useContext, useEffect } from "react";
2
+
3
+ import { TabControlContext } from "../context/TabControl";
4
+
5
+ export const useActiveTab = () => {
6
+ const { value } = useContext(TabControlContext);
7
+
8
+ return value;
9
+ };
10
+
11
+ export const useTabDispatch = () => {
12
+ const { dispatch } = useContext(TabControlContext);
13
+
14
+ return dispatch;
15
+ };
16
+
17
+ export const useTabsUid = () => {
18
+ const { uid } = useContext(TabControlContext);
19
+
20
+ return uid;
21
+ };
22
+
23
+ interface Props<T extends HTMLElement> {
24
+ value: number;
25
+ ref: RefObject<T>;
26
+ }
27
+
28
+ export function useRegisterTabControl<T extends HTMLElement>({ value, ref }: Props<T>) {
29
+ const { dispatch, register, unregister } = useContext(TabControlContext);
30
+
31
+ useEffect(() => {
32
+ register(value, ref);
33
+
34
+ return () => {
35
+ unregister(value);
36
+ };
37
+ }, [value, ref, register, unregister]);
38
+
39
+ return dispatch;
40
+ }
41
+
42
+ export const useTabControls = () => {
43
+ const { refs } = useContext(TabControlContext);
44
+
45
+ return refs;
46
+ };
47
+
48
+ export const useActiveTabControl = () => {
49
+ const { value, refs } = useContext(TabControlContext);
50
+
51
+ return [value, refs.get(value)] as const;
52
+ };
@@ -1,4 +1,5 @@
1
1
  {
2
+ "title": "Form with First Name",
2
3
  "type": "form",
3
4
  "display": "form",
4
5
  "tags": [],
@@ -1,4 +1,5 @@
1
1
  {
2
+ "title": "Form complex",
2
3
  "type": "form",
3
4
  "tags": [],
4
5
  "components": [