@pie-lib/config-ui 12.0.0-beta.5 → 12.1.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 (139) 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/__tests__/alert-dialog.test.js +262 -0
  6. package/lib/__tests__/checkbox.test.js +227 -0
  7. package/lib/__tests__/choice-utils.test.js +14 -0
  8. package/lib/__tests__/form-section.test.js +252 -0
  9. package/lib/__tests__/help.test.js +270 -0
  10. package/lib/__tests__/input.test.js +268 -0
  11. package/lib/__tests__/langs.test.js +541 -0
  12. package/lib/__tests__/number-text-field-custom.test.js +362 -0
  13. package/lib/__tests__/number-text-field.test.js +421 -0
  14. package/lib/__tests__/radio-with-label.test.js +233 -0
  15. package/lib/__tests__/settings-panel.test.js +184 -0
  16. package/lib/__tests__/settings.test.js +653 -0
  17. package/lib/__tests__/tabs.test.js +211 -0
  18. package/lib/__tests__/two-choice.test.js +124 -0
  19. package/lib/__tests__/with-stateful-model.test.js +221 -0
  20. package/lib/alert-dialog.js +41 -11
  21. package/lib/alert-dialog.js.map +1 -1
  22. package/lib/checkbox.js +59 -49
  23. package/lib/checkbox.js.map +1 -1
  24. package/lib/choice-configuration/__tests__/feedback-menu.test.js +287 -0
  25. package/lib/choice-configuration/__tests__/index.test.js +253 -0
  26. package/lib/choice-configuration/feedback-menu.js +25 -27
  27. package/lib/choice-configuration/feedback-menu.js.map +1 -1
  28. package/lib/choice-configuration/index.js +183 -186
  29. package/lib/choice-configuration/index.js.map +1 -1
  30. package/lib/choice-utils.js +6 -8
  31. package/lib/choice-utils.js.map +1 -1
  32. package/lib/feedback-config/__tests__/feedback-config.test.js +201 -0
  33. package/lib/feedback-config/__tests__/feedback-selector.test.js +177 -0
  34. package/lib/feedback-config/feedback-selector.js +70 -74
  35. package/lib/feedback-config/feedback-selector.js.map +1 -1
  36. package/lib/feedback-config/group.js +23 -26
  37. package/lib/feedback-config/group.js.map +1 -1
  38. package/lib/feedback-config/index.js +42 -45
  39. package/lib/feedback-config/index.js.map +1 -1
  40. package/lib/form-section.js +32 -26
  41. package/lib/form-section.js.map +1 -1
  42. package/lib/help.js +38 -48
  43. package/lib/help.js.map +1 -1
  44. package/lib/index.js +2 -3
  45. package/lib/index.js.map +1 -1
  46. package/lib/input.js +13 -18
  47. package/lib/input.js.map +1 -1
  48. package/lib/inputs.js +59 -68
  49. package/lib/inputs.js.map +1 -1
  50. package/lib/langs.js +57 -71
  51. package/lib/langs.js.map +1 -1
  52. package/lib/layout/__tests__/config.layout.test.js +70 -0
  53. package/lib/layout/__tests__/layout-content.test.js +6 -0
  54. package/lib/layout/config-layout.js +79 -48
  55. package/lib/layout/config-layout.js.map +1 -1
  56. package/lib/layout/index.js +1 -1
  57. package/lib/layout/index.js.map +1 -1
  58. package/lib/layout/layout-contents.js +59 -61
  59. package/lib/layout/layout-contents.js.map +1 -1
  60. package/lib/layout/settings-box.js +26 -34
  61. package/lib/layout/settings-box.js.map +1 -1
  62. package/lib/mui-box/index.js +42 -51
  63. package/lib/mui-box/index.js.map +1 -1
  64. package/lib/number-text-field-custom.js +152 -90
  65. package/lib/number-text-field-custom.js.map +1 -1
  66. package/lib/number-text-field.js +75 -64
  67. package/lib/number-text-field.js.map +1 -1
  68. package/lib/radio-with-label.js +31 -17
  69. package/lib/radio-with-label.js.map +1 -1
  70. package/lib/settings/display-size.js +17 -21
  71. package/lib/settings/display-size.js.map +1 -1
  72. package/lib/settings/index.js +14 -20
  73. package/lib/settings/index.js.map +1 -1
  74. package/lib/settings/panel.js +141 -142
  75. package/lib/settings/panel.js.map +1 -1
  76. package/lib/settings/settings-radio-label.js +30 -17
  77. package/lib/settings/settings-radio-label.js.map +1 -1
  78. package/lib/settings/toggle.js +40 -26
  79. package/lib/settings/toggle.js.map +1 -1
  80. package/lib/tabs/index.js +19 -31
  81. package/lib/tabs/index.js.map +1 -1
  82. package/lib/tags-input/__tests__/index.test.js +183 -0
  83. package/lib/tags-input/index.js +50 -62
  84. package/lib/tags-input/index.js.map +1 -1
  85. package/lib/two-choice.js +34 -44
  86. package/lib/two-choice.js.map +1 -1
  87. package/lib/with-stateful-model.js +9 -13
  88. package/lib/with-stateful-model.js.map +1 -1
  89. package/package.json +14 -11
  90. package/src/__tests__/alert-dialog.test.jsx +283 -0
  91. package/src/__tests__/checkbox.test.jsx +249 -0
  92. package/src/__tests__/choice-utils.test.js +12 -0
  93. package/src/__tests__/form-section.test.jsx +334 -0
  94. package/src/__tests__/help.test.jsx +184 -0
  95. package/src/__tests__/input.test.jsx +192 -0
  96. package/src/__tests__/langs.test.jsx +457 -0
  97. package/src/__tests__/number-text-field-custom.test.jsx +438 -0
  98. package/src/__tests__/number-text-field.test.jsx +341 -0
  99. package/src/__tests__/radio-with-label.test.jsx +259 -0
  100. package/src/__tests__/settings-panel.test.js +187 -0
  101. package/src/__tests__/settings.test.jsx +515 -0
  102. package/src/__tests__/tabs.test.jsx +193 -0
  103. package/src/__tests__/two-choice.test.js +110 -0
  104. package/src/__tests__/with-stateful-model.test.jsx +145 -0
  105. package/src/alert-dialog.jsx +30 -8
  106. package/src/checkbox.jsx +43 -37
  107. package/src/choice-configuration/__tests__/feedback-menu.test.jsx +163 -0
  108. package/src/choice-configuration/__tests__/index.test.jsx +234 -0
  109. package/src/choice-configuration/feedback-menu.jsx +6 -6
  110. package/src/choice-configuration/index.jsx +208 -199
  111. package/src/feedback-config/__tests__/feedback-config.test.jsx +141 -0
  112. package/src/feedback-config/__tests__/feedback-selector.test.jsx +97 -0
  113. package/src/feedback-config/feedback-selector.jsx +50 -55
  114. package/src/feedback-config/group.jsx +21 -22
  115. package/src/feedback-config/index.jsx +27 -29
  116. package/src/form-section.jsx +26 -18
  117. package/src/help.jsx +20 -28
  118. package/src/input.jsx +1 -1
  119. package/src/inputs.jsx +35 -44
  120. package/src/langs.jsx +41 -46
  121. package/src/layout/__tests__/config.layout.test.jsx +59 -0
  122. package/src/layout/__tests__/layout-content.test.jsx +3 -0
  123. package/src/layout/config-layout.jsx +53 -23
  124. package/src/layout/layout-contents.jsx +38 -40
  125. package/src/layout/settings-box.jsx +16 -19
  126. package/src/mui-box/index.jsx +35 -43
  127. package/src/number-text-field-custom.jsx +117 -65
  128. package/src/number-text-field.jsx +51 -34
  129. package/src/radio-with-label.jsx +26 -10
  130. package/src/settings/display-size.jsx +12 -11
  131. package/src/settings/index.js +2 -1
  132. package/src/settings/panel.jsx +101 -92
  133. package/src/settings/settings-radio-label.jsx +26 -10
  134. package/src/settings/toggle.jsx +37 -18
  135. package/src/tabs/index.jsx +8 -8
  136. package/src/tags-input/__tests__/index.test.jsx +113 -0
  137. package/src/tags-input/index.jsx +35 -38
  138. package/src/two-choice.jsx +15 -19
  139. package/README.md +0 -12
@@ -0,0 +1,193 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { Tabs } from '../tabs';
5
+
6
+ describe('Tabs Component', () => {
7
+ it('renders tabs with correct titles', () => {
8
+ render(
9
+ <Tabs>
10
+ <div title="Tab 1">Content 1</div>
11
+ <div title="Tab 2">Content 2</div>
12
+ <div title="Tab 3">Content 3</div>
13
+ </Tabs>,
14
+ );
15
+
16
+ expect(screen.getByText('Tab 1')).toBeInTheDocument();
17
+ expect(screen.getByText('Tab 2')).toBeInTheDocument();
18
+ expect(screen.getByText('Tab 3')).toBeInTheDocument();
19
+ });
20
+
21
+ it('renders first tab content by default', () => {
22
+ render(
23
+ <Tabs>
24
+ <div title="Tab 1">Content 1</div>
25
+ <div title="Tab 2">Content 2</div>
26
+ <div title="Tab 3">Content 3</div>
27
+ </Tabs>,
28
+ );
29
+
30
+ expect(screen.getByText('Content 1')).toBeInTheDocument();
31
+ expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
32
+ expect(screen.queryByText('Content 3')).not.toBeInTheDocument();
33
+ });
34
+
35
+ it('switches to selected tab when clicked', async () => {
36
+ const user = userEvent.setup();
37
+ render(
38
+ <Tabs>
39
+ <div title="Tab 1">Content 1</div>
40
+ <div title="Tab 2">Content 2</div>
41
+ <div title="Tab 3">Content 3</div>
42
+ </Tabs>,
43
+ );
44
+
45
+ const tab2 = screen.getByRole('tab', { name: 'Tab 2' });
46
+ await user.click(tab2);
47
+
48
+ expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
49
+ expect(screen.getByText('Content 2')).toBeInTheDocument();
50
+ expect(screen.queryByText('Content 3')).not.toBeInTheDocument();
51
+ });
52
+
53
+ it('displays correct content when multiple tabs are clicked', async () => {
54
+ const user = userEvent.setup();
55
+ render(
56
+ <Tabs>
57
+ <div title="Tab 1">Content 1</div>
58
+ <div title="Tab 2">Content 2</div>
59
+ <div title="Tab 3">Content 3</div>
60
+ </Tabs>,
61
+ );
62
+
63
+ await user.click(screen.getByRole('tab', { name: 'Tab 2' }));
64
+ expect(screen.getByText('Content 2')).toBeInTheDocument();
65
+
66
+ await user.click(screen.getByRole('tab', { name: 'Tab 3' }));
67
+ expect(screen.getByText('Content 3')).toBeInTheDocument();
68
+
69
+ await user.click(screen.getByRole('tab', { name: 'Tab 1' }));
70
+ expect(screen.getByText('Content 1')).toBeInTheDocument();
71
+ });
72
+
73
+ it('applies custom className to root element', () => {
74
+ const { container } = render(
75
+ <Tabs className="custom-tabs-class">
76
+ <div title="Tab 1">Content 1</div>
77
+ </Tabs>,
78
+ );
79
+
80
+ const rootDiv = container.querySelector('.custom-tabs-class');
81
+ expect(rootDiv).toBeInTheDocument();
82
+ });
83
+
84
+
85
+ it('handles tabs without title prop gracefully', () => {
86
+ render(
87
+ <Tabs>
88
+ <div title="Tab 1">Content 1</div>
89
+ <div>No Title Child</div>
90
+ <div title="Tab 2">Content 2</div>
91
+ </Tabs>,
92
+ );
93
+
94
+ const tabs = screen.getAllByRole('tab');
95
+ // Should only have 2 tabs since one doesn't have a title
96
+ expect(tabs).toHaveLength(2);
97
+ expect(screen.getByText('Tab 1')).toBeInTheDocument();
98
+ expect(screen.getByText('Tab 2')).toBeInTheDocument();
99
+ });
100
+
101
+ it('handles null children gracefully', () => {
102
+ render(
103
+ <Tabs>
104
+ <div title="Tab 1">Content 1</div>
105
+ {null}
106
+ <div title="Tab 2">Content 2</div>
107
+ </Tabs>,
108
+ );
109
+
110
+ const tabs = screen.getAllByRole('tab');
111
+ expect(tabs).toHaveLength(2);
112
+ });
113
+
114
+ it('handles complex content in tabs', () => {
115
+ render(
116
+ <Tabs>
117
+ <div title="Tab 1">
118
+ <div>
119
+ <h2>Tab 1 Header</h2>
120
+ <p>Tab 1 description</p>
121
+ <button>Button in Tab 1</button>
122
+ </div>
123
+ </div>
124
+ <div title="Tab 2">
125
+ <div>
126
+ <h2>Tab 2 Header</h2>
127
+ <input type="text" placeholder="Input in Tab 2" />
128
+ </div>
129
+ </div>
130
+ </Tabs>,
131
+ );
132
+
133
+ expect(screen.getByText('Tab 1 Header')).toBeInTheDocument();
134
+ expect(screen.getByRole('button', { name: 'Button in Tab 1' })).toBeInTheDocument();
135
+
136
+ const tab2 = screen.getByRole('tab', { name: 'Tab 2' });
137
+ expect(tab2).toBeInTheDocument();
138
+ });
139
+
140
+ it('renders all tabs in MuiTabs component', () => {
141
+ const { container } = render(
142
+ <Tabs>
143
+ <div title="Tab A">Content A</div>
144
+ <div title="Tab B">Content B</div>
145
+ <div title="Tab C">Content C</div>
146
+ </Tabs>,
147
+ );
148
+
149
+ const tabsComponent = container.querySelector('[role="tablist"]');
150
+ expect(tabsComponent).toBeInTheDocument();
151
+ });
152
+
153
+ it('applies correct value prop to MuiTabs', async () => {
154
+ const user = userEvent.setup();
155
+ render(
156
+ <Tabs>
157
+ <div title="Tab 1">Content 1</div>
158
+ <div title="Tab 2">Content 2</div>
159
+ </Tabs>,
160
+ );
161
+
162
+ // Initially first tab should be selected (value 0)
163
+ const tab1 = screen.getByRole('tab', { name: 'Tab 1' });
164
+ expect(tab1).toHaveAttribute('aria-selected', 'true');
165
+
166
+ // Click second tab
167
+ await user.click(screen.getByRole('tab', { name: 'Tab 2' }));
168
+ const tab2 = screen.getByRole('tab', { name: 'Tab 2' });
169
+ expect(tab2).toHaveAttribute('aria-selected', 'true');
170
+ expect(tab1).toHaveAttribute('aria-selected', 'false');
171
+ });
172
+
173
+ it('renders with empty children array', () => {
174
+ const { container } = render(<Tabs>{[]}</Tabs>);
175
+ expect(container).toBeInTheDocument();
176
+ });
177
+
178
+ it('handles long tab titles', () => {
179
+ render(
180
+ <Tabs>
181
+ <div title="This is a very long tab title that should still render correctly">
182
+ Content 1
183
+ </div>
184
+ <div title="Short">Content 2</div>
185
+ </Tabs>,
186
+ );
187
+
188
+ expect(
189
+ screen.getByText('This is a very long tab title that should still render correctly'),
190
+ ).toBeInTheDocument();
191
+ expect(screen.getByText('Short')).toBeInTheDocument();
192
+ });
193
+ });
@@ -0,0 +1,110 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { NChoice } from '../two-choice';
5
+
6
+ describe('NChoice', () => {
7
+ const onChange = jest.fn();
8
+
9
+ beforeEach(() => {
10
+ onChange.mockClear();
11
+ });
12
+
13
+ it('renders radio buttons with vertical direction', () => {
14
+ render(
15
+ <NChoice
16
+ direction="vertical"
17
+ header="n-choice-vertical"
18
+ value={'left'}
19
+ onChange={onChange}
20
+ opts={[
21
+ { label: 'left', value: 'left' },
22
+ { label: 'center', value: 'center' },
23
+ { label: 'right', value: 'right' },
24
+ ]}
25
+ />,
26
+ );
27
+
28
+ expect(screen.getByText('n-choice-vertical')).toBeInTheDocument();
29
+ expect(screen.getByLabelText('left')).toBeInTheDocument();
30
+ expect(screen.getByLabelText('center')).toBeInTheDocument();
31
+ expect(screen.getByLabelText('right')).toBeInTheDocument();
32
+ });
33
+
34
+ it('shows selected value as checked', () => {
35
+ render(
36
+ <NChoice
37
+ direction="vertical"
38
+ header="Options"
39
+ value={'center'}
40
+ onChange={onChange}
41
+ opts={[
42
+ { label: 'left', value: 'left' },
43
+ { label: 'center', value: 'center' },
44
+ { label: 'right', value: 'right' },
45
+ ]}
46
+ />,
47
+ );
48
+
49
+ const centerRadio = screen.getByLabelText('center');
50
+ expect(centerRadio).toBeChecked();
51
+ expect(screen.getByLabelText('left')).not.toBeChecked();
52
+ expect(screen.getByLabelText('right')).not.toBeChecked();
53
+ });
54
+
55
+ it('calls onChange when user selects a different option', async () => {
56
+ const user = userEvent.setup();
57
+ render(
58
+ <NChoice
59
+ direction="vertical"
60
+ header="Options"
61
+ value={'left'}
62
+ onChange={onChange}
63
+ opts={[
64
+ { label: 'left', value: 'left' },
65
+ { label: 'center', value: 'center' },
66
+ { label: 'right', value: 'right' },
67
+ ]}
68
+ />,
69
+ );
70
+
71
+ await user.click(screen.getByLabelText('center'));
72
+
73
+ expect(onChange).toHaveBeenCalledWith('center');
74
+ });
75
+
76
+ it('renders with horizontal direction', () => {
77
+ const { container } = render(
78
+ <NChoice
79
+ direction="horizontal"
80
+ header="Options"
81
+ value={'left'}
82
+ onChange={onChange}
83
+ opts={[
84
+ { label: 'left', value: 'left' },
85
+ { label: 'right', value: 'right' },
86
+ ]}
87
+ />,
88
+ );
89
+
90
+ // Check that all options are rendered
91
+ expect(screen.getByLabelText('left')).toBeInTheDocument();
92
+ expect(screen.getByLabelText('right')).toBeInTheDocument();
93
+ });
94
+
95
+ it('handles string options by converting them', () => {
96
+ render(
97
+ <NChoice
98
+ direction="vertical"
99
+ header="Options"
100
+ value={'option1'}
101
+ onChange={onChange}
102
+ opts={['option1', 'option2', 'option3']}
103
+ />,
104
+ );
105
+
106
+ expect(screen.getByLabelText('option1')).toBeInTheDocument();
107
+ expect(screen.getByLabelText('option2')).toBeInTheDocument();
108
+ expect(screen.getByLabelText('option3')).toBeInTheDocument();
109
+ });
110
+ });
@@ -0,0 +1,145 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import withStatefulModel from '../with-stateful-model';
5
+
6
+ const MockComponent = ({ model, onChange }) => (
7
+ <div>
8
+ <div data-testid="model-value">{JSON.stringify(model)}</div>
9
+ <button onClick={() => onChange({ ...model, updated: true })}>Update Model</button>
10
+ </div>
11
+ );
12
+
13
+ describe('withStatefulModel', () => {
14
+ it('wraps component and passes model and onChange', () => {
15
+ const WrappedComponent = withStatefulModel(MockComponent);
16
+ const model = { name: 'test' };
17
+ const onChange = jest.fn();
18
+
19
+ render(<WrappedComponent model={model} onChange={onChange} />);
20
+
21
+ expect(screen.getByTestId('model-value')).toBeInTheDocument();
22
+ expect(screen.getByText(JSON.stringify(model))).toBeInTheDocument();
23
+ });
24
+
25
+ it('manages local state with initial model prop', () => {
26
+ const WrappedComponent = withStatefulModel(MockComponent);
27
+ const model = { id: 1, name: 'test' };
28
+
29
+ render(<WrappedComponent model={model} onChange={jest.fn()} />);
30
+
31
+ expect(screen.getByText(JSON.stringify(model))).toBeInTheDocument();
32
+ });
33
+
34
+ it('calls onChange with updated model when component calls onChange', async () => {
35
+ const user = userEvent.setup();
36
+ const WrappedComponent = withStatefulModel(MockComponent);
37
+ const model = { name: 'test' };
38
+ const onChange = jest.fn();
39
+
40
+ render(<WrappedComponent model={model} onChange={onChange} />);
41
+
42
+ const updateButton = screen.getByRole('button', { name: /Update Model/i });
43
+ await user.click(updateButton);
44
+
45
+ expect(onChange).toHaveBeenCalled();
46
+ expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ updated: true }));
47
+ });
48
+
49
+ it('updates internal state when model prop changes', () => {
50
+ const WrappedComponent = withStatefulModel(MockComponent);
51
+ const initialModel = { name: 'initial' };
52
+ const updatedModel = { name: 'updated' };
53
+ const onChange = jest.fn();
54
+
55
+ const { rerender } = render(
56
+ <WrappedComponent model={initialModel} onChange={onChange} />
57
+ );
58
+
59
+ expect(screen.getByText(JSON.stringify(initialModel))).toBeInTheDocument();
60
+
61
+ rerender(<WrappedComponent model={updatedModel} onChange={onChange} />);
62
+
63
+ expect(screen.getByText(JSON.stringify(updatedModel))).toBeInTheDocument();
64
+ });
65
+
66
+ it('maintains state across multiple onChange calls', async () => {
67
+ const user = userEvent.setup();
68
+ const WrappedComponent = withStatefulModel(MockComponent);
69
+ const model = { count: 0 };
70
+ const onChange = jest.fn();
71
+
72
+ render(<WrappedComponent model={model} onChange={onChange} />);
73
+
74
+ const updateButton = screen.getByRole('button', { name: /Update Model/i });
75
+
76
+ await user.click(updateButton);
77
+ expect(onChange).toHaveBeenCalledTimes(1);
78
+
79
+ await user.click(updateButton);
80
+ expect(onChange).toHaveBeenCalledTimes(2);
81
+ });
82
+
83
+ it('passes updated model state to onChange callback', async () => {
84
+ const user = userEvent.setup();
85
+ const WrappedComponent = withStatefulModel(MockComponent);
86
+ const model = { value: 'original' };
87
+ const onChange = jest.fn();
88
+
89
+ render(<WrappedComponent model={model} onChange={onChange} />);
90
+
91
+ const updateButton = screen.getByRole('button', { name: /Update Model/i });
92
+ await user.click(updateButton);
93
+
94
+ const lastCall = onChange.mock.calls[onChange.mock.calls.length - 1];
95
+ expect(lastCall[0]).toHaveProperty('updated', true);
96
+ expect(lastCall[0]).toHaveProperty('value', 'original');
97
+ });
98
+
99
+ it('handles empty model object', () => {
100
+ const WrappedComponent = withStatefulModel(MockComponent);
101
+ const model = {};
102
+ const onChange = jest.fn();
103
+
104
+ render(<WrappedComponent model={model} onChange={onChange} />);
105
+
106
+ expect(screen.getByText(JSON.stringify(model))).toBeInTheDocument();
107
+ });
108
+
109
+ it('handles model with nested properties', () => {
110
+ const WrappedComponent = withStatefulModel(MockComponent);
111
+ const model = { user: { name: 'John', age: 30 }, settings: { theme: 'dark' } };
112
+ const onChange = jest.fn();
113
+
114
+ render(<WrappedComponent model={model} onChange={onChange} />);
115
+
116
+ expect(screen.getByText(JSON.stringify(model))).toBeInTheDocument();
117
+ });
118
+
119
+ it('requires model and onChange props', () => {
120
+ const WrappedComponent = withStatefulModel(MockComponent);
121
+
122
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
123
+
124
+ render(
125
+ <WrappedComponent model={{ test: 'data' }} onChange={jest.fn()} />
126
+ );
127
+
128
+ expect(screen.getByTestId('model-value')).toBeInTheDocument();
129
+
130
+ consoleSpy.mockRestore();
131
+ });
132
+
133
+ it('renders wrapped component with correct props structure', () => {
134
+ const WrappedComponent = withStatefulModel(MockComponent);
135
+ const model = { id: 1 };
136
+ const onChange = jest.fn();
137
+
138
+ const { container } = render(
139
+ <WrappedComponent model={model} onChange={onChange} />
140
+ );
141
+
142
+ expect(container.querySelector('[data-testid="model-value"]')).toBeInTheDocument();
143
+ expect(container.querySelector('button')).toBeInTheDocument();
144
+ });
145
+ });
@@ -1,36 +1,58 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from '@material-ui/core';
3
+ import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from '@mui/material';
4
+ import { styled } from '@mui/material/styles';
4
5
 
5
- const AlertDialog = ({ text, title, onClose, onConfirm, open }) => (
6
- <Dialog open={open} onClose={onClose}>
7
- {title && <DialogTitle>{title}</DialogTitle>}
6
+ const StyledDialogTitle = styled(DialogTitle)(() => ({
7
+ fontSize: 'max(1.25rem, 18px)',
8
+ }));
9
+
10
+ const StyledDialogContentText = styled(DialogContentText)(() => ({
11
+ fontSize: 'max(1rem, 14px)',
12
+ }));
13
+
14
+ const AlertDialog = ({ text, title, onClose, onConfirm, open, onCloseText, onConfirmText, disableAutoFocus, disableEnforceFocus, disableRestoreFocus }) => (
15
+ <Dialog open={open} disableAutoFocus={disableAutoFocus} disableEnforceFocus={disableEnforceFocus} disableRestoreFocus={disableRestoreFocus} onClose={onClose}>
16
+ {title && <StyledDialogTitle>{title}</StyledDialogTitle>}
8
17
  {text && (
9
18
  <DialogContent>
10
- <DialogContentText>{text}</DialogContentText>
19
+ <StyledDialogContentText>{text}</StyledDialogContentText>
11
20
  </DialogContent>
12
21
  )}
13
22
  <DialogActions>
14
23
  {onClose && (
15
24
  <Button onClick={onClose} color="primary">
16
- CANCEL
25
+ {onCloseText}
17
26
  </Button>
18
27
  )}
19
28
  {onConfirm && (
20
29
  <Button autoFocus onClick={onConfirm} color="primary">
21
- OK
30
+ {onConfirmText}
22
31
  </Button>
23
32
  )}
24
33
  </DialogActions>
25
34
  </Dialog>
26
35
  );
27
36
 
37
+ AlertDialog.defaultProps = {
38
+ onCloseText: 'CANCEL',
39
+ onConfirmText: 'OK',
40
+ disableAutoFocus: false,
41
+ disableEnforceFocus: false,
42
+ disableRestoreFocus: false,
43
+ };
44
+
28
45
  AlertDialog.propTypes = {
29
- text: PropTypes.string,
46
+ text: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
30
47
  title: PropTypes.string,
31
48
  onClose: PropTypes.func,
32
49
  onConfirm: PropTypes.func,
33
50
  open: PropTypes.bool,
51
+ onConfirmText: PropTypes.string,
52
+ onCloseText: PropTypes.string,
53
+ disableAutoFocus: PropTypes.bool,
54
+ disableEnforceFocus: PropTypes.bool,
55
+ disableRestoreFocus: PropTypes.bool,
34
56
  };
35
57
 
36
58
  export default AlertDialog;
package/src/checkbox.jsx CHANGED
@@ -1,23 +1,50 @@
1
- import FormControlLabel from '@material-ui/core/FormControlLabel';
2
- import MuiCheckbox from '@material-ui/core/Checkbox';
1
+ import FormControlLabel from '@mui/material/FormControlLabel';
2
+ import MuiCheckbox from '@mui/material/Checkbox';
3
3
  import PropTypes from 'prop-types';
4
4
  import React from 'react';
5
- import { withStyles } from '@material-ui/core/styles';
6
- import classNames from 'classnames';
7
- import grey from '@material-ui/core/colors/grey';
5
+ import { styled } from '@mui/material/styles';
6
+ import { color } from '@pie-lib/render-ui';
7
+ import { grey } from '@mui/material/colors';
8
8
 
9
- const Checkbox = ({ mini, checked, onChange, value, label, classes }) => (
10
- <FormControlLabel
11
- className={classNames(classes.mini)}
12
- classes={{
13
- label: classNames(classes.label, mini && classes.miniLabel),
14
- }}
9
+ const StyledFormControlLabel = styled(FormControlLabel)(({ theme, mini }) => ({
10
+ margin: 0,
11
+ marginLeft: 0,
12
+ padding: 0,
13
+ '& .MuiFormControlLabel-label': {
14
+ fontSize: theme.typography.fontSize - 1,
15
+ transform: 'translate(-4%, 2%)',
16
+ color: 'rgba(0,0,0,1.0)',
17
+ ...(mini && {
18
+ marginLeft: theme.spacing(1),
19
+ color: grey[700],
20
+ fontSize: theme.typography.fontSize - 3,
21
+ }),
22
+ },
23
+ }));
24
+
25
+ const StyledCheckbox = styled(MuiCheckbox)(({ theme, mini, error }) => ({
26
+ color: `${color.tertiary()} !important`,
27
+ ...(mini && {
28
+ margin: 0,
29
+ padding: 0,
30
+ width: theme.spacing(3),
31
+ height: theme.spacing(3),
32
+ }),
33
+ ...(error && {
34
+ color: `${theme.palette.error.main} !important`,
35
+ }),
36
+ }));
37
+
38
+ const Checkbox = ({ mini, checked, onChange, value, label, error }) => (
39
+ <StyledFormControlLabel
40
+ mini={mini}
15
41
  control={
16
- <MuiCheckbox
42
+ <StyledCheckbox
17
43
  checked={checked}
18
44
  onChange={onChange}
19
45
  value={value}
20
- className={classNames(mini && classes.miniCheckbox)}
46
+ mini={mini}
47
+ error={error}
21
48
  />
22
49
  }
23
50
  label={label}
@@ -26,38 +53,17 @@ const Checkbox = ({ mini, checked, onChange, value, label, classes }) => (
26
53
 
27
54
  Checkbox.propTypes = {
28
55
  mini: PropTypes.bool,
29
- classes: PropTypes.object.isRequired,
30
56
  checked: PropTypes.bool.isRequired,
31
57
  onChange: PropTypes.func.isRequired,
32
58
  value: PropTypes.string,
33
59
  label: PropTypes.string.isRequired,
60
+ error: PropTypes.bool,
34
61
  };
35
62
 
36
63
  Checkbox.defaultProps = {
37
64
  value: '',
38
65
  mini: false,
66
+ error: false,
39
67
  };
40
68
 
41
- export default withStyles((theme) => ({
42
- label: {
43
- fontSize: theme.typography.fontSize - 1,
44
- transform: 'translate(-4%, 2%)',
45
- color: 'rgba(0,0,0,1.0)',
46
- },
47
- miniCheckbox: {
48
- margin: 0,
49
- padding: 0,
50
- width: theme.spacing.unit * 3,
51
- height: theme.spacing.unit * 3,
52
- },
53
- miniLabel: {
54
- marginLeft: theme.spacing.unit,
55
- color: grey[700],
56
- fontSize: theme.typography.fontSize - 3,
57
- },
58
- mini: {
59
- margin: 0,
60
- marginLeft: 0,
61
- padding: 0,
62
- },
63
- }))(Checkbox);
69
+ export default Checkbox;