@jasperoosthoek/react-toolbox 0.8.0 → 0.9.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 (63) hide show
  1. package/change-log.md +330 -309
  2. package/dist/components/buttons/ConfirmButton.d.ts +2 -2
  3. package/dist/components/buttons/DeleteConfirmButton.d.ts +2 -2
  4. package/dist/components/buttons/IconButtons.d.ts +40 -41
  5. package/dist/components/errors/Errors.d.ts +1 -2
  6. package/dist/components/forms/FormField.d.ts +22 -0
  7. package/dist/components/forms/FormFields.d.ts +1 -56
  8. package/dist/components/forms/FormModal.d.ts +7 -34
  9. package/dist/components/forms/FormModalProvider.d.ts +19 -26
  10. package/dist/components/forms/FormProvider.d.ts +66 -0
  11. package/dist/components/forms/fields/FormBadgesSelection.d.ts +26 -0
  12. package/dist/components/forms/fields/FormCheckbox.d.ts +7 -0
  13. package/dist/components/forms/fields/FormDropdown.d.ts +19 -0
  14. package/dist/components/forms/fields/FormInput.d.ts +17 -0
  15. package/dist/components/forms/fields/FormSelect.d.ts +12 -0
  16. package/dist/components/forms/fields/index.d.ts +5 -0
  17. package/dist/components/indicators/CheckIndicator.d.ts +1 -2
  18. package/dist/components/indicators/LoadingIndicator.d.ts +4 -4
  19. package/dist/components/login/LoginPage.d.ts +1 -1
  20. package/dist/components/tables/DataTable.d.ts +2 -2
  21. package/dist/components/tables/DragAndDropList.d.ts +2 -2
  22. package/dist/components/tables/SearchBox.d.ts +2 -2
  23. package/dist/index.d.ts +4 -1
  24. package/dist/index.js +2 -2
  25. package/dist/index.js.LICENSE.txt +0 -4
  26. package/dist/localization/LocalizationContext.d.ts +1 -1
  27. package/dist/utils/hooks.d.ts +1 -1
  28. package/dist/utils/timeAndDate.d.ts +5 -2
  29. package/dist/utils/utils.d.ts +3 -3
  30. package/package.json +10 -11
  31. package/src/__tests__/buttons.test.tsx +545 -0
  32. package/src/__tests__/errors.test.tsx +339 -0
  33. package/src/__tests__/forms.test.tsx +3021 -0
  34. package/src/__tests__/hooks.test.tsx +413 -0
  35. package/src/__tests__/indicators.test.tsx +284 -0
  36. package/src/__tests__/localization.test.tsx +462 -0
  37. package/src/__tests__/login.test.tsx +417 -0
  38. package/src/__tests__/setupTests.ts +328 -0
  39. package/src/__tests__/tables.test.tsx +609 -0
  40. package/src/__tests__/timeAndDate.test.tsx +308 -0
  41. package/src/__tests__/utils.test.tsx +422 -0
  42. package/src/components/forms/FormField.tsx +92 -0
  43. package/src/components/forms/FormFields.tsx +3 -423
  44. package/src/components/forms/FormModal.tsx +168 -243
  45. package/src/components/forms/FormModalProvider.tsx +141 -95
  46. package/src/components/forms/FormProvider.tsx +218 -0
  47. package/src/components/forms/fields/FormBadgesSelection.tsx +108 -0
  48. package/src/components/forms/fields/FormCheckbox.tsx +76 -0
  49. package/src/components/forms/fields/FormDropdown.tsx +123 -0
  50. package/src/components/forms/fields/FormInput.tsx +114 -0
  51. package/src/components/forms/fields/FormSelect.tsx +47 -0
  52. package/src/components/forms/fields/index.ts +6 -0
  53. package/src/index.ts +32 -28
  54. package/src/localization/LocalizationContext.tsx +156 -131
  55. package/src/localization/localization.ts +131 -131
  56. package/src/utils/hooks.ts +108 -94
  57. package/src/utils/timeAndDate.ts +33 -4
  58. package/src/utils/utils.ts +74 -66
  59. package/dist/components/forms/CreateEditModal.d.ts +0 -41
  60. package/dist/components/forms/CreateEditModalProvider.d.ts +0 -41
  61. package/dist/components/forms/FormFields.test.d.ts +0 -4
  62. package/dist/login/Login.d.ts +0 -70
  63. package/src/components/forms/FormFields.test.tsx +0 -107
@@ -0,0 +1,328 @@
1
+ // Test setup with React Testing Library and jsdom
2
+
3
+ import '@testing-library/react';
4
+ import '@testing-library/jest-dom';
5
+
6
+ // Mock console to reduce noise during tests
7
+ global.console = {
8
+ ...console,
9
+ error: jest.fn(),
10
+ warn: jest.fn(),
11
+ };
12
+
13
+ // Mock react-localization
14
+ jest.mock('react-localization', () => {
15
+ return jest.fn().mockImplementation((translations) => {
16
+ const instance = {
17
+ translations,
18
+ currentLanguage: 'en',
19
+ setLanguage: jest.fn(function(lang) {
20
+ this.currentLanguage = lang;
21
+ }),
22
+ getString: jest.fn(function(key, lang) {
23
+ const targetLang = lang || this.currentLanguage;
24
+ if (this.translations && this.translations[targetLang] && this.translations[targetLang][key]) {
25
+ return this.translations[targetLang][key];
26
+ }
27
+ return key;
28
+ }),
29
+ getLanguage: jest.fn(function() {
30
+ return this.currentLanguage;
31
+ }),
32
+ getAvailableLanguages: jest.fn(() => ['en']),
33
+ };
34
+ return instance;
35
+ });
36
+ });
37
+
38
+ // Mock react-dnd
39
+ jest.mock('react-dnd', () => ({
40
+ useDrag: jest.fn(() => [{}, jest.fn(), jest.fn()]),
41
+ useDrop: jest.fn(() => [{}, jest.fn()]),
42
+ DndProvider: ({ children }) => children,
43
+ useDragLayer: jest.fn(() => ({})),
44
+ }));
45
+
46
+ // Mock react-dnd-html5-backend
47
+ jest.mock('react-dnd-html5-backend', () => ({
48
+ HTML5Backend: 'HTML5Backend',
49
+ }));
50
+
51
+ // Mock react-bootstrap with proper React elements
52
+ jest.mock('react-bootstrap', () => {
53
+ const mockReact = require('react');
54
+ return {
55
+ Button: mockReact.forwardRef((props, ref) => {
56
+ const { variant, size, className = '', ...restProps } = props;
57
+ let classes = 'btn';
58
+ if (variant) classes += ` btn-${variant}`;
59
+ if (size) classes += ` btn-${size}`;
60
+ if (className) classes += ` ${className}`;
61
+
62
+ return mockReact.createElement('button', {
63
+ ...restProps,
64
+ ref,
65
+ className: classes.trim()
66
+ }, props.children);
67
+ }),
68
+ Container: (props) => mockReact.createElement('div', { ...props, className: `container ${props.className || ''}` }, props.children),
69
+ Row: (props) => mockReact.createElement('div', { ...props, className: `row ${props.className || ''}` }, props.children),
70
+ Col: (props) => mockReact.createElement('div', { ...props, className: `col ${props.className || ''}` }, props.children),
71
+ Spinner: (props) => mockReact.createElement('div', { ...props, 'data-testid': 'spinner' }, props.children),
72
+ Badge: (props) => {
73
+ const { bg, className = '', ...restProps } = props;
74
+ let classes = 'badge';
75
+ if (bg) classes += ` badge-${bg}`;
76
+ if (className) classes += ` ${className}`;
77
+ return mockReact.createElement('span', {
78
+ ...restProps,
79
+ className: classes.trim()
80
+ }, props.children);
81
+ },
82
+ Modal: Object.assign(
83
+ (props) => {
84
+ if (!props.show) return null;
85
+
86
+ const modalElement = mockReact.createElement('div', {
87
+ ...props,
88
+ className: 'modal',
89
+ role: props.role || 'dialog'
90
+ },
91
+ // Clone children and pass onHide to Modal.Header
92
+ mockReact.Children.map(props.children, (child) => {
93
+ if (child && child.type && child.type.displayName === 'Modal.Header') {
94
+ return mockReact.cloneElement(child, { onHide: props.onHide });
95
+ }
96
+ return child;
97
+ })
98
+ );
99
+
100
+ return modalElement;
101
+ },
102
+ {
103
+ Header: Object.assign(
104
+ (props) => {
105
+ const headerContent = mockReact.createElement('div', {
106
+ key: 'header-content',
107
+ className: 'modal-header'
108
+ }, [
109
+ props.children,
110
+ // Add close button if closeButton prop is true
111
+ props.closeButton && mockReact.createElement('button', {
112
+ key: 'close-button',
113
+ type: 'button',
114
+ className: 'btn-close',
115
+ 'aria-label': 'Close',
116
+ onClick: props.onHide, // Wire up the close button to onHide
117
+ children: 'Close' // Accessible text for testing
118
+ })
119
+ ].filter(Boolean));
120
+
121
+ return headerContent;
122
+ },
123
+ { displayName: 'Modal.Header' }
124
+ ),
125
+ Title: (props) => mockReact.createElement('h4', { ...props, className: 'modal-title' }, props.children),
126
+ Body: (props) => mockReact.createElement('div', { ...props, className: 'modal-body' }, props.children),
127
+ Footer: (props) => mockReact.createElement('div', { ...props, className: 'modal-footer' }, props.children)
128
+ }
129
+ ),
130
+ Form: Object.assign(
131
+ (props) => mockReact.createElement('form', props, props.children),
132
+ {
133
+ Group: (props) => {
134
+ const { controlId, ...restProps } = props;
135
+ return mockReact.createElement('div', {
136
+ ...restProps,
137
+ className: 'form-group'
138
+ }, props.children);
139
+ },
140
+ Label: (props) => mockReact.createElement('label', {
141
+ ...props,
142
+ htmlFor: props.htmlFor || undefined
143
+ }, props.children),
144
+ Control: mockReact.forwardRef((props, ref) => {
145
+ const element = props.as || (props.type === 'textarea' ? 'textarea' : 'input');
146
+ const { isInvalid, className = '', ...restProps } = props;
147
+ let classes = className;
148
+ if (isInvalid) {
149
+ classes += (classes ? ' ' : '') + 'is-invalid';
150
+ }
151
+ const controlProps = {
152
+ ...restProps,
153
+ ref,
154
+ id: props.id || undefined,
155
+ className: classes.trim() || undefined
156
+ };
157
+ // Add default type="text" for input elements if not specified
158
+ if (element === 'input' && !controlProps.type) {
159
+ controlProps.type = 'text';
160
+ }
161
+ return mockReact.createElement(element, controlProps);
162
+ }),
163
+ Select: mockReact.forwardRef((props, ref) => {
164
+ const { isInvalid, className = '', ...restProps } = props;
165
+ let classes = className;
166
+ if (isInvalid) {
167
+ classes += (classes ? ' ' : '') + 'is-invalid';
168
+ }
169
+ return mockReact.createElement('select', {
170
+ ...restProps,
171
+ ref,
172
+ className: classes.trim() || undefined
173
+ }, props.children);
174
+ }),
175
+ Check: mockReact.forwardRef((props, ref) => {
176
+ const { label, type, checked, isInvalid, className = '', id, ...restProps } = props;
177
+ let classes = 'form-check-input';
178
+ if (isInvalid) {
179
+ classes += ' is-invalid';
180
+ }
181
+ if (className) {
182
+ classes += ` ${className}`;
183
+ }
184
+
185
+ const checkboxId = id || 'checkbox';
186
+
187
+ return mockReact.createElement('div', { className: 'form-check' }, [
188
+ mockReact.createElement('input', {
189
+ key: 'input',
190
+ ...restProps,
191
+ ref,
192
+ type: type === 'switch' ? 'checkbox' : (type || 'checkbox'),
193
+ className: classes.trim(),
194
+ checked: !!checked,
195
+ id: checkboxId
196
+ }),
197
+ label && mockReact.createElement('label', {
198
+ key: 'label',
199
+ className: 'form-check-label',
200
+ htmlFor: checkboxId
201
+ }, label)
202
+ ]);
203
+ }),
204
+ Text: (props) => mockReact.createElement('div', { ...props, className: 'form-text' }, props.children),
205
+ }
206
+ ),
207
+ Table: (props) => mockReact.createElement('table', props, props.children),
208
+ InputGroup: (props) => mockReact.createElement('div', { ...props, className: 'input-group' }, props.children),
209
+ Alert: (props) => mockReact.createElement('div', { ...props, className: 'alert' }, props.children),
210
+ Card: (props) => mockReact.createElement('div', { ...props, className: 'card' }, props.children),
211
+ ButtonGroup: (props) => mockReact.createElement('div', { ...props, className: 'btn-group' }, props.children),
212
+ Dropdown: Object.assign(
213
+ (props) => mockReact.createElement('div', { ...props, className: 'dropdown' }, props.children),
214
+ {
215
+ Toggle: mockReact.forwardRef((props, ref) => {
216
+ const Component = props.as || 'button';
217
+ return mockReact.createElement(Component, { ...props, ref }, props.children);
218
+ }),
219
+ Menu: (props) => mockReact.createElement('div', { ...props, className: 'dropdown-menu' }, props.children),
220
+ Item: (props) => mockReact.createElement('a', { ...props, className: 'dropdown-item' }, props.children),
221
+ }
222
+ ),
223
+ Nav: (props) => mockReact.createElement('nav', props, props.children),
224
+ Navbar: (props) => mockReact.createElement('nav', { ...props, className: 'navbar' }, props.children),
225
+ };
226
+ });
227
+
228
+ // Mock react-icons
229
+ jest.mock('react-icons/ai', () => {
230
+ const mockReact = require('react');
231
+ return {
232
+ AiOutlineCheck: () => mockReact.createElement('span', { 'data-testid': 'check-icon' }, '✓'),
233
+ AiOutlineClose: () => mockReact.createElement('span', { 'data-testid': 'close-icon' }, '✗'),
234
+ AiFillCaretDown: () => mockReact.createElement('span', { 'data-testid': 'caret-down' }, '▼'),
235
+ AiFillCaretUp: () => mockReact.createElement('span', { 'data-testid': 'caret-up' }, '▲'),
236
+ AiFillEdit: () => mockReact.createElement('span', { 'data-testid': 'edit-icon' }, '✎'),
237
+ AiOutlinePlus: () => mockReact.createElement('span', { 'data-testid': 'plus-icon' }, '+'),
238
+ AiOutlineUpload: () => mockReact.createElement('span', { 'data-testid': 'upload-icon' }, '↑'),
239
+ AiOutlineDownload: () => mockReact.createElement('span', { 'data-testid': 'download-icon' }, '↓'),
240
+ AiOutlineFileAdd: () => mockReact.createElement('span', { 'data-testid': 'file-add-icon' }, '📄+'),
241
+ AiOutlineFolderAdd: () => mockReact.createElement('span', { 'data-testid': 'folder-add-icon' }, '📁+'),
242
+ AiOutlineArrowRight: () => mockReact.createElement('span', { 'data-testid': 'arrow-right-icon' }, '→'),
243
+ AiOutlineUnlock: () => mockReact.createElement('span', { 'data-testid': 'unlock-icon' }, '🔓'),
244
+ AiOutlineSearch: () => mockReact.createElement('span', { 'data-testid': 'search-icon' }, '🔍'),
245
+ AiOutlineSave: () => mockReact.createElement('span', { 'data-testid': 'save-icon' }, '💾'),
246
+ AiOutlineHome: () => mockReact.createElement('span', { 'data-testid': 'home-icon' }, '🏠'),
247
+ };
248
+ });
249
+
250
+ // Mock other react-icons
251
+ jest.mock('react-icons/fi', () => {
252
+ const mockReact = require('react');
253
+ return {
254
+ FiCopy: () => mockReact.createElement('span', { 'data-testid': 'copy-icon' }, '📋'),
255
+ };
256
+ });
257
+
258
+ jest.mock('react-icons/fa', () => {
259
+ const mockReact = require('react');
260
+ return {
261
+ FaTimes: () => mockReact.createElement('span', { 'data-testid': 'times-icon' }, '✕'),
262
+ FaSort: () => mockReact.createElement('span', { 'data-testid': 'sort-icon' }, '↕'),
263
+ FaSortUp: () => mockReact.createElement('span', { 'data-testid': 'sort-up-icon' }, '↑'),
264
+ FaSortDown: () => mockReact.createElement('span', { 'data-testid': 'sort-down-icon' }, '↓'),
265
+ FaRegFlag: () => mockReact.createElement('span', { 'data-testid': 'flag-icon' }, '🚩'),
266
+ FaSyncAlt: () => mockReact.createElement('span', { 'data-testid': 'sync-icon' }, '🔄'),
267
+ };
268
+ });
269
+
270
+ jest.mock('react-icons/cg', () => {
271
+ const mockReact = require('react');
272
+ return {
273
+ CgTrash: () => mockReact.createElement('span', { 'data-testid': 'trash-icon' }, '🗑'),
274
+ CgNotes: () => mockReact.createElement('span', { 'data-testid': 'notes-icon' }, '📝'),
275
+ CgSpinner: () => mockReact.createElement('span', { 'data-testid': 'spinner-icon' }, '⟳'),
276
+ };
277
+ });
278
+
279
+ jest.mock('react-icons/bs', () => {
280
+ const mockReact = require('react');
281
+ return {
282
+ BsArrowsMove: () => mockReact.createElement('span', { 'data-testid': 'arrows-move-icon' }, '⇄'),
283
+ BsCardList: () => mockReact.createElement('span', { 'data-testid': 'card-list-icon' }, '📋'),
284
+ BsPencil: () => mockReact.createElement('span', { 'data-testid': 'pencil-icon' }, '✏'),
285
+ };
286
+ });
287
+
288
+ jest.mock('react-icons/bi', () => {
289
+ const mockReact = require('react');
290
+ return {
291
+ BiRightArrow: () => mockReact.createElement('span', { 'data-testid': 'right-arrow-icon' }, '▶'),
292
+ BiSquare: () => mockReact.createElement('span', { 'data-testid': 'square-icon' }, '⬜'),
293
+ BiHide: () => mockReact.createElement('span', { 'data-testid': 'hide-icon' }, '👁‍🗨'),
294
+ BiShow: () => mockReact.createElement('span', { 'data-testid': 'show-icon' }, '👁'),
295
+ };
296
+ });
297
+
298
+ jest.mock('react-icons/hi', () => {
299
+ const mockReact = require('react');
300
+ return {
301
+ HiOutlineCog: () => mockReact.createElement('span', { 'data-testid': 'cog-icon' }, '⚙'),
302
+ HiOutlineLink: () => mockReact.createElement('span', { 'data-testid': 'link-icon' }, '🔗'),
303
+ };
304
+ });
305
+
306
+ jest.mock('react-icons/vsc', () => {
307
+ const mockReact = require('react');
308
+ return {
309
+ VscMenu: () => mockReact.createElement('span', { 'data-testid': 'menu-icon' }, '☰'),
310
+ };
311
+ });
312
+
313
+ jest.mock('react-icons/ri', () => {
314
+ const mockReact = require('react');
315
+ return {
316
+ RiQuestionnaireLine: () => mockReact.createElement('span', { 'data-testid': 'questionnaire-icon' }, '❓'),
317
+ RiDropdownList: () => mockReact.createElement('span', { 'data-testid': 'dropdown-list-icon' }, '📃'),
318
+ RiResetLeftLine: () => mockReact.createElement('span', { 'data-testid': 'reset-left-icon' }, '↺'),
319
+ };
320
+ });
321
+
322
+ jest.mock('react-icons/lu', () => {
323
+ const mockReact = require('react');
324
+ return {
325
+ LuClipboardPaste: () => mockReact.createElement('span', { 'data-testid': 'clipboard-paste-icon' }, '📋'),
326
+ };
327
+ });
328
+