@pie-lib/config-ui 12.0.0-beta.5 → 12.0.0-next.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 (116) hide show
  1. package/CHANGELOG.json +8 -1653
  2. package/CHANGELOG.md +345 -4
  3. package/LICENSE.md +5 -0
  4. package/NEXT.CHANGELOG.json +1 -0
  5. package/lib/alert-dialog.js +40 -10
  6. package/lib/alert-dialog.js.map +1 -1
  7. package/lib/checkbox.js +58 -48
  8. package/lib/checkbox.js.map +1 -1
  9. package/lib/choice-configuration/feedback-menu.js +24 -26
  10. package/lib/choice-configuration/feedback-menu.js.map +1 -1
  11. package/lib/choice-configuration/index.js +182 -185
  12. package/lib/choice-configuration/index.js.map +1 -1
  13. package/lib/choice-utils.js +5 -7
  14. package/lib/choice-utils.js.map +1 -1
  15. package/lib/feedback-config/feedback-selector.js +69 -73
  16. package/lib/feedback-config/feedback-selector.js.map +1 -1
  17. package/lib/feedback-config/group.js +22 -25
  18. package/lib/feedback-config/group.js.map +1 -1
  19. package/lib/feedback-config/index.js +41 -44
  20. package/lib/feedback-config/index.js.map +1 -1
  21. package/lib/form-section.js +31 -25
  22. package/lib/form-section.js.map +1 -1
  23. package/lib/help.js +37 -47
  24. package/lib/help.js.map +1 -1
  25. package/lib/index.js +1 -2
  26. package/lib/index.js.map +1 -1
  27. package/lib/input.js +12 -17
  28. package/lib/input.js.map +1 -1
  29. package/lib/inputs.js +58 -67
  30. package/lib/inputs.js.map +1 -1
  31. package/lib/langs.js +56 -70
  32. package/lib/langs.js.map +1 -1
  33. package/lib/layout/config-layout.js +78 -47
  34. package/lib/layout/config-layout.js.map +1 -1
  35. package/lib/layout/index.js.map +1 -1
  36. package/lib/layout/layout-contents.js +58 -60
  37. package/lib/layout/layout-contents.js.map +1 -1
  38. package/lib/layout/settings-box.js +25 -33
  39. package/lib/layout/settings-box.js.map +1 -1
  40. package/lib/mui-box/index.js +41 -50
  41. package/lib/mui-box/index.js.map +1 -1
  42. package/lib/number-text-field-custom.js +151 -89
  43. package/lib/number-text-field-custom.js.map +1 -1
  44. package/lib/number-text-field.js +74 -63
  45. package/lib/number-text-field.js.map +1 -1
  46. package/lib/radio-with-label.js +30 -16
  47. package/lib/radio-with-label.js.map +1 -1
  48. package/lib/settings/display-size.js +16 -20
  49. package/lib/settings/display-size.js.map +1 -1
  50. package/lib/settings/index.js +13 -19
  51. package/lib/settings/index.js.map +1 -1
  52. package/lib/settings/panel.js +140 -141
  53. package/lib/settings/panel.js.map +1 -1
  54. package/lib/settings/settings-radio-label.js +29 -16
  55. package/lib/settings/settings-radio-label.js.map +1 -1
  56. package/lib/settings/toggle.js +39 -25
  57. package/lib/settings/toggle.js.map +1 -1
  58. package/lib/tabs/index.js +18 -30
  59. package/lib/tabs/index.js.map +1 -1
  60. package/lib/tags-input/index.js +49 -61
  61. package/lib/tags-input/index.js.map +1 -1
  62. package/lib/two-choice.js +33 -43
  63. package/lib/two-choice.js.map +1 -1
  64. package/lib/with-stateful-model.js +8 -12
  65. package/lib/with-stateful-model.js.map +1 -1
  66. package/package.json +22 -11
  67. package/src/__tests__/alert-dialog.test.jsx +283 -0
  68. package/src/__tests__/checkbox.test.jsx +249 -0
  69. package/src/__tests__/choice-utils.test.js +12 -0
  70. package/src/__tests__/form-section.test.jsx +334 -0
  71. package/src/__tests__/help.test.jsx +184 -0
  72. package/src/__tests__/input.test.jsx +192 -0
  73. package/src/__tests__/langs.test.jsx +457 -0
  74. package/src/__tests__/number-text-field-custom.test.jsx +438 -0
  75. package/src/__tests__/number-text-field.test.jsx +341 -0
  76. package/src/__tests__/radio-with-label.test.jsx +259 -0
  77. package/src/__tests__/settings-panel.test.js +187 -0
  78. package/src/__tests__/settings.test.jsx +515 -0
  79. package/src/__tests__/tabs.test.jsx +193 -0
  80. package/src/__tests__/two-choice.test.js +110 -0
  81. package/src/__tests__/with-stateful-model.test.jsx +145 -0
  82. package/src/alert-dialog.jsx +30 -8
  83. package/src/checkbox.jsx +43 -37
  84. package/src/choice-configuration/__tests__/feedback-menu.test.jsx +163 -0
  85. package/src/choice-configuration/__tests__/index.test.jsx +234 -0
  86. package/src/choice-configuration/feedback-menu.jsx +6 -6
  87. package/src/choice-configuration/index.jsx +208 -192
  88. package/src/feedback-config/__tests__/feedback-config.test.jsx +141 -0
  89. package/src/feedback-config/__tests__/feedback-selector.test.jsx +107 -0
  90. package/src/feedback-config/feedback-selector.jsx +52 -53
  91. package/src/feedback-config/group.jsx +21 -22
  92. package/src/feedback-config/index.jsx +27 -29
  93. package/src/form-section.jsx +26 -18
  94. package/src/help.jsx +20 -28
  95. package/src/input.jsx +1 -1
  96. package/src/inputs.jsx +35 -44
  97. package/src/langs.jsx +41 -46
  98. package/src/layout/__tests__/config.layout.test.jsx +59 -0
  99. package/src/layout/__tests__/layout-content.test.jsx +3 -0
  100. package/src/layout/config-layout.jsx +53 -23
  101. package/src/layout/layout-contents.jsx +38 -40
  102. package/src/layout/settings-box.jsx +16 -19
  103. package/src/mui-box/index.jsx +35 -43
  104. package/src/number-text-field-custom.jsx +117 -65
  105. package/src/number-text-field.jsx +51 -34
  106. package/src/radio-with-label.jsx +26 -10
  107. package/src/settings/display-size.jsx +12 -11
  108. package/src/settings/index.js +2 -1
  109. package/src/settings/panel.jsx +101 -92
  110. package/src/settings/settings-radio-label.jsx +26 -10
  111. package/src/settings/toggle.jsx +37 -18
  112. package/src/tabs/index.jsx +8 -8
  113. package/src/tags-input/__tests__/index.test.jsx +113 -0
  114. package/src/tags-input/index.jsx +35 -38
  115. package/src/two-choice.jsx +15 -19
  116. package/README.md +0 -12
@@ -0,0 +1,283 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import AlertDialog from '../alert-dialog';
5
+
6
+ describe('AlertDialog Component', () => {
7
+ const onClose = jest.fn();
8
+ const onConfirm = jest.fn();
9
+
10
+ beforeEach(() => {
11
+ onClose.mockClear();
12
+ onConfirm.mockClear();
13
+ });
14
+
15
+ describe('Rendering when open', () => {
16
+ it('should render dialog when open is true', () => {
17
+ render(
18
+ <AlertDialog
19
+ open={true}
20
+ title="Confirm"
21
+ text="Are you sure?"
22
+ onClose={onClose}
23
+ onConfirm={onConfirm}
24
+ />,
25
+ );
26
+
27
+ expect(screen.getByText('Confirm')).toBeInTheDocument();
28
+ expect(screen.getByText('Are you sure?')).toBeInTheDocument();
29
+ });
30
+
31
+ it('should not render dialog when open is false', () => {
32
+ const { container } = render(
33
+ <AlertDialog
34
+ open={false}
35
+ title="Confirm"
36
+ text="Are you sure?"
37
+ onClose={onClose}
38
+ onConfirm={onConfirm}
39
+ />,
40
+ );
41
+
42
+ const dialogs = container.querySelectorAll('[role="dialog"]');
43
+ expect(dialogs.length).toBe(0);
44
+ });
45
+ });
46
+
47
+ describe('Title and Text', () => {
48
+ it('should handle both title and text', () => {
49
+ render(
50
+ <AlertDialog
51
+ open={true}
52
+ title="Important"
53
+ text="This is an important message"
54
+ onClose={onClose}
55
+ onConfirm={onConfirm}
56
+ />,
57
+ );
58
+
59
+ expect(screen.getByText('Important')).toBeInTheDocument();
60
+ expect(screen.getByText('This is an important message')).toBeInTheDocument();
61
+ });
62
+
63
+ it('should handle text as object', () => {
64
+ const textObj = <div>Rich text content</div>;
65
+ render(
66
+ <AlertDialog
67
+ open={true}
68
+ title="Rich Content"
69
+ text={textObj}
70
+ onClose={onClose}
71
+ onConfirm={onConfirm}
72
+ />,
73
+ );
74
+
75
+ expect(screen.getByText('Rich text content')).toBeInTheDocument();
76
+ });
77
+ });
78
+
79
+ describe('Buttons', () => {
80
+ it('should render close button when onClose is provided', () => {
81
+ render(
82
+ <AlertDialog
83
+ open={true}
84
+ title="Dialog"
85
+ text="Content"
86
+ onClose={onClose}
87
+ onConfirm={onConfirm}
88
+ />,
89
+ );
90
+
91
+ expect(screen.getByRole('button', { name: 'CANCEL' })).toBeInTheDocument();
92
+ });
93
+
94
+ it('should render confirm button when onConfirm is provided', () => {
95
+ render(
96
+ <AlertDialog
97
+ open={true}
98
+ title="Dialog"
99
+ text="Content"
100
+ onClose={onClose}
101
+ onConfirm={onConfirm}
102
+ />,
103
+ );
104
+
105
+ expect(screen.getByRole('button', { name: 'OK' })).toBeInTheDocument();
106
+ });
107
+
108
+ it('should have default button text', () => {
109
+ render(
110
+ <AlertDialog
111
+ open={true}
112
+ title="Dialog"
113
+ text="Content"
114
+ onClose={onClose}
115
+ onConfirm={onConfirm}
116
+ />,
117
+ );
118
+
119
+ expect(screen.getByRole('button', { name: 'CANCEL' })).toBeInTheDocument();
120
+ expect(screen.getByRole('button', { name: 'OK' })).toBeInTheDocument();
121
+ });
122
+ });
123
+
124
+ describe('User interactions', () => {
125
+ it('should call onClose when close button is clicked', async () => {
126
+ const user = userEvent.setup();
127
+ render(
128
+ <AlertDialog
129
+ open={true}
130
+ title="Dialog"
131
+ text="Content"
132
+ onClose={onClose}
133
+ onConfirm={onConfirm}
134
+ />,
135
+ );
136
+
137
+ const closeButton = screen.getByRole('button', { name: 'CANCEL' });
138
+ await user.click(closeButton);
139
+
140
+ expect(onClose).toHaveBeenCalled();
141
+ });
142
+
143
+ it('should call onConfirm when confirm button is clicked', async () => {
144
+ const user = userEvent.setup();
145
+ render(
146
+ <AlertDialog
147
+ open={true}
148
+ title="Dialog"
149
+ text="Content"
150
+ onClose={onClose}
151
+ onConfirm={onConfirm}
152
+ />,
153
+ );
154
+
155
+ const confirmButton = screen.getByRole('button', { name: 'OK' });
156
+ await user.click(confirmButton);
157
+
158
+ expect(onConfirm).toHaveBeenCalled();
159
+ });
160
+ });
161
+
162
+ describe('Focus management', () => {
163
+ it('should have autoFocus on confirm button by default', () => {
164
+ render(
165
+ <AlertDialog
166
+ open={true}
167
+ title="Dialog"
168
+ text="Content"
169
+ onClose={onClose}
170
+ onConfirm={onConfirm}
171
+ />,
172
+ );
173
+
174
+ const confirmButton = screen.getByRole('button', { name: 'OK' });
175
+ expect(confirmButton).toBeInTheDocument();
176
+ });
177
+
178
+ it('should disable auto focus when disableAutoFocus is true', () => {
179
+ render(
180
+ <AlertDialog
181
+ open={true}
182
+ title="Dialog"
183
+ text="Content"
184
+ onClose={onClose}
185
+ onConfirm={onConfirm}
186
+ disableAutoFocus={true}
187
+ />,
188
+ );
189
+
190
+ expect(screen.getByText('Dialog')).toBeInTheDocument();
191
+ });
192
+
193
+ it('should disable enforce focus when disableEnforceFocus is true', () => {
194
+ render(
195
+ <AlertDialog
196
+ open={true}
197
+ title="Dialog"
198
+ text="Content"
199
+ onClose={onClose}
200
+ onConfirm={onConfirm}
201
+ disableEnforceFocus={true}
202
+ />,
203
+ );
204
+
205
+ expect(screen.getByText('Dialog')).toBeInTheDocument();
206
+ });
207
+
208
+ it('should disable restore focus when disableRestoreFocus is true', () => {
209
+ render(
210
+ <AlertDialog
211
+ open={true}
212
+ title="Dialog"
213
+ text="Content"
214
+ onClose={onClose}
215
+ onConfirm={onConfirm}
216
+ disableRestoreFocus={true}
217
+ />,
218
+ );
219
+
220
+ expect(screen.getByText('Dialog')).toBeInTheDocument();
221
+ });
222
+ });
223
+
224
+ describe('Edge cases', () => {
225
+ it('should handle very long title', () => {
226
+ const longTitle = 'This is a very long title that should wrap properly in the dialog';
227
+ render(
228
+ <AlertDialog
229
+ open={true}
230
+ title={longTitle}
231
+ text="Content"
232
+ onClose={onClose}
233
+ onConfirm={onConfirm}
234
+ />,
235
+ );
236
+
237
+ expect(screen.getByText(longTitle)).toBeInTheDocument();
238
+ });
239
+
240
+ it('should handle very long text', () => {
241
+ const longText = 'This is a very long text that should wrap properly in the dialog. '.repeat(10);
242
+ render(
243
+ <AlertDialog
244
+ open={true}
245
+ title="Dialog"
246
+ text={longText}
247
+ onClose={onClose}
248
+ onConfirm={onConfirm}
249
+ />,
250
+ );
251
+
252
+ expect(screen.getByText(new RegExp(longText.slice(0, 50)))).toBeInTheDocument();
253
+ });
254
+
255
+ it('should handle only close callback', () => {
256
+ render(
257
+ <AlertDialog
258
+ open={true}
259
+ title="Close Only"
260
+ text="Content"
261
+ onClose={onClose}
262
+ />,
263
+ );
264
+
265
+ expect(screen.getByRole('button', { name: 'CANCEL' })).toBeInTheDocument();
266
+ expect(screen.queryByRole('button', { name: 'OK' })).not.toBeInTheDocument();
267
+ });
268
+
269
+ it('should handle only confirm callback', () => {
270
+ render(
271
+ <AlertDialog
272
+ open={true}
273
+ title="Confirm Only"
274
+ text="Content"
275
+ onConfirm={onConfirm}
276
+ />,
277
+ );
278
+
279
+ expect(screen.getByRole('button', { name: 'OK' })).toBeInTheDocument();
280
+ expect(screen.queryByRole('button', { name: 'CANCEL' })).not.toBeInTheDocument();
281
+ });
282
+ });
283
+ });
@@ -0,0 +1,249 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import Checkbox from '../checkbox';
5
+
6
+ describe('Checkbox Component', () => {
7
+ const onChange = jest.fn();
8
+
9
+ beforeEach(() => {
10
+ onChange.mockClear();
11
+ });
12
+
13
+ describe('Rendering', () => {
14
+ it('should render checkbox with label', () => {
15
+ render(
16
+ <Checkbox
17
+ checked={false}
18
+ onChange={onChange}
19
+ label="Accept terms"
20
+ />,
21
+ );
22
+
23
+ expect(screen.getByText('Accept terms')).toBeInTheDocument();
24
+ expect(screen.getByRole('checkbox')).toBeInTheDocument();
25
+ });
26
+
27
+ it('should render checkbox in checked state', () => {
28
+ render(
29
+ <Checkbox
30
+ checked={true}
31
+ onChange={onChange}
32
+ label="Accept terms"
33
+ />,
34
+ );
35
+
36
+ expect(screen.getByRole('checkbox')).toBeChecked();
37
+ });
38
+
39
+ it('should render checkbox in unchecked state', () => {
40
+ render(
41
+ <Checkbox
42
+ checked={false}
43
+ onChange={onChange}
44
+ label="Accept terms"
45
+ />,
46
+ );
47
+
48
+ expect(screen.getByRole('checkbox')).not.toBeChecked();
49
+ });
50
+
51
+ it('should render mini checkbox with reduced styling', () => {
52
+ render(
53
+ <Checkbox
54
+ checked={false}
55
+ onChange={onChange}
56
+ label="Mini"
57
+ mini={true}
58
+ />,
59
+ );
60
+
61
+ expect(screen.getByRole('checkbox')).toBeInTheDocument();
62
+ expect(screen.getByText('Mini')).toBeInTheDocument();
63
+ });
64
+ });
65
+
66
+ describe('User interaction', () => {
67
+ it('should call onChange when checkbox is clicked', async () => {
68
+ const user = userEvent.setup();
69
+ render(
70
+ <Checkbox
71
+ checked={false}
72
+ onChange={onChange}
73
+ label="Accept"
74
+ />,
75
+ );
76
+
77
+ const checkbox = screen.getByRole('checkbox');
78
+ await user.click(checkbox);
79
+
80
+ expect(onChange).toHaveBeenCalled();
81
+ });
82
+
83
+ it('should call onChange when label is clicked', async () => {
84
+ const user = userEvent.setup();
85
+ render(
86
+ <Checkbox
87
+ checked={false}
88
+ onChange={onChange}
89
+ label="Click label"
90
+ />,
91
+ );
92
+
93
+ const label = screen.getByText('Click label');
94
+ await user.click(label);
95
+
96
+ expect(onChange).toHaveBeenCalled();
97
+ });
98
+ });
99
+
100
+ describe('Props', () => {
101
+ it('should handle value prop', () => {
102
+ render(
103
+ <Checkbox
104
+ checked={true}
105
+ onChange={onChange}
106
+ label="With value"
107
+ value="option1"
108
+ />,
109
+ );
110
+
111
+ expect(screen.getByRole('checkbox')).toBeInTheDocument();
112
+ });
113
+
114
+ it('should display error styling when error is true', () => {
115
+ render(
116
+ <Checkbox
117
+ checked={false}
118
+ onChange={onChange}
119
+ label="Error state"
120
+ error={true}
121
+ />,
122
+ );
123
+
124
+ expect(screen.getByRole('checkbox')).toBeInTheDocument();
125
+ expect(screen.getByText('Error state')).toBeInTheDocument();
126
+ });
127
+ });
128
+
129
+ describe('Default props', () => {
130
+ it('should have mini default to false', () => {
131
+ const { container } = render(
132
+ <Checkbox
133
+ checked={true}
134
+ onChange={onChange}
135
+ label="Test"
136
+ />,
137
+ );
138
+
139
+ expect(screen.getByRole('checkbox')).toBeInTheDocument();
140
+ });
141
+
142
+ it('should have error default to false', () => {
143
+ const { container } = render(
144
+ <Checkbox
145
+ checked={true}
146
+ onChange={onChange}
147
+ label="Test"
148
+ />,
149
+ );
150
+
151
+ expect(screen.getByRole('checkbox')).toBeInTheDocument();
152
+ });
153
+
154
+ it('should have value default to empty string', () => {
155
+ render(
156
+ <Checkbox
157
+ checked={true}
158
+ onChange={onChange}
159
+ label="Test"
160
+ />,
161
+ );
162
+
163
+ expect(screen.getByRole('checkbox')).toBeInTheDocument();
164
+ });
165
+ });
166
+
167
+ describe('Accessibility', () => {
168
+ it('should have proper label association', () => {
169
+ render(
170
+ <Checkbox
171
+ checked={false}
172
+ onChange={onChange}
173
+ label="Accessible label"
174
+ />,
175
+ );
176
+
177
+ expect(screen.getByLabelText('Accessible label')).toBeInTheDocument();
178
+ });
179
+
180
+ it('should be keyboard accessible', async () => {
181
+ const user = userEvent.setup();
182
+ render(
183
+ <Checkbox
184
+ checked={false}
185
+ onChange={onChange}
186
+ label="Keyboard test"
187
+ />,
188
+ );
189
+
190
+ const checkbox = screen.getByRole('checkbox');
191
+ checkbox.focus();
192
+ expect(checkbox).toHaveFocus();
193
+
194
+ await user.keyboard(' ');
195
+ expect(onChange).toHaveBeenCalled();
196
+ });
197
+ });
198
+
199
+ describe('Multiple checkboxes', () => {
200
+ it('should render multiple independent checkboxes', () => {
201
+ const onChange1 = jest.fn();
202
+ const onChange2 = jest.fn();
203
+
204
+ render(
205
+ <>
206
+ <Checkbox
207
+ checked={true}
208
+ onChange={onChange1}
209
+ label="Option 1"
210
+ />
211
+ <Checkbox
212
+ checked={false}
213
+ onChange={onChange2}
214
+ label="Option 2"
215
+ />
216
+ </>,
217
+ );
218
+
219
+ expect(screen.getByLabelText('Option 1')).toBeChecked();
220
+ expect(screen.getByLabelText('Option 2')).not.toBeChecked();
221
+ });
222
+
223
+ it('should handle independent onChange callbacks', async () => {
224
+ const user = userEvent.setup();
225
+ const onChange1 = jest.fn();
226
+ const onChange2 = jest.fn();
227
+
228
+ render(
229
+ <>
230
+ <Checkbox
231
+ checked={true}
232
+ onChange={onChange1}
233
+ label="Option 1"
234
+ />
235
+ <Checkbox
236
+ checked={false}
237
+ onChange={onChange2}
238
+ label="Option 2"
239
+ />
240
+ </>,
241
+ );
242
+
243
+ await user.click(screen.getByLabelText('Option 2'));
244
+
245
+ expect(onChange2).toHaveBeenCalled();
246
+ expect(onChange1).not.toHaveBeenCalled();
247
+ });
248
+ });
249
+ });
@@ -0,0 +1,12 @@
1
+ import { firstAvailableIndex } from '../choice-utils';
2
+
3
+ describe('firstAvailableIndex', () => {
4
+ const assert = (values, index, expected) => {
5
+ it(`[${values.join(',')}], ${index} ==> ${expected}`, () => {
6
+ expect(firstAvailableIndex(['0'], 0)).toEqual('1');
7
+ });
8
+ };
9
+ assert(['0'], 0, '1');
10
+ assert(['0', '1', '2'], 0, '3');
11
+ assert(['0', '1', '2'], 100, '100');
12
+ });