@pie-lib/config-ui 11.30.2 → 11.30.3-next.155

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 (120) hide show
  1. package/CHANGELOG.md +7 -78
  2. package/esm/package.json +3 -0
  3. package/lib/alert-dialog.js +35 -42
  4. package/lib/alert-dialog.js.map +1 -1
  5. package/lib/checkbox.js +56 -71
  6. package/lib/checkbox.js.map +1 -1
  7. package/lib/choice-configuration/feedback-menu.js +29 -64
  8. package/lib/choice-configuration/feedback-menu.js.map +1 -1
  9. package/lib/choice-configuration/index.js +202 -262
  10. package/lib/choice-configuration/index.js.map +1 -1
  11. package/lib/choice-utils.js +6 -18
  12. package/lib/choice-utils.js.map +1 -1
  13. package/lib/feedback-config/feedback-selector.js +79 -115
  14. package/lib/feedback-config/feedback-selector.js.map +1 -1
  15. package/lib/feedback-config/group.js +26 -40
  16. package/lib/feedback-config/group.js.map +1 -1
  17. package/lib/feedback-config/index.js +47 -90
  18. package/lib/feedback-config/index.js.map +1 -1
  19. package/lib/form-section.js +31 -33
  20. package/lib/form-section.js.map +1 -1
  21. package/lib/help.js +39 -80
  22. package/lib/help.js.map +1 -1
  23. package/lib/index.js +1 -31
  24. package/lib/index.js.map +1 -1
  25. package/lib/input.js +21 -54
  26. package/lib/input.js.map +1 -1
  27. package/lib/inputs.js +61 -95
  28. package/lib/inputs.js.map +1 -1
  29. package/lib/langs.js +58 -101
  30. package/lib/langs.js.map +1 -1
  31. package/lib/layout/config-layout.js +40 -70
  32. package/lib/layout/config-layout.js.map +1 -1
  33. package/lib/layout/index.js +0 -3
  34. package/lib/layout/index.js.map +1 -1
  35. package/lib/layout/layout-contents.js +72 -103
  36. package/lib/layout/layout-contents.js.map +1 -1
  37. package/lib/layout/settings-box.js +27 -56
  38. package/lib/layout/settings-box.js.map +1 -1
  39. package/lib/mui-box/index.js +41 -57
  40. package/lib/mui-box/index.js.map +1 -1
  41. package/lib/number-text-field-custom.js +79 -161
  42. package/lib/number-text-field-custom.js.map +1 -1
  43. package/lib/number-text-field.js +80 -114
  44. package/lib/number-text-field.js.map +1 -1
  45. package/lib/radio-with-label.js +30 -31
  46. package/lib/radio-with-label.js.map +1 -1
  47. package/lib/settings/display-size.js +16 -32
  48. package/lib/settings/display-size.js.map +1 -1
  49. package/lib/settings/index.js +14 -47
  50. package/lib/settings/index.js.map +1 -1
  51. package/lib/settings/panel.js +159 -229
  52. package/lib/settings/panel.js.map +1 -1
  53. package/lib/settings/settings-radio-label.js +28 -30
  54. package/lib/settings/settings-radio-label.js.map +1 -1
  55. package/lib/settings/toggle.js +35 -46
  56. package/lib/settings/toggle.js.map +1 -1
  57. package/lib/tabs/index.js +22 -57
  58. package/lib/tabs/index.js.map +1 -1
  59. package/lib/tags-input/index.js +50 -99
  60. package/lib/tags-input/index.js.map +1 -1
  61. package/lib/two-choice.js +46 -90
  62. package/lib/two-choice.js.map +1 -1
  63. package/lib/with-stateful-model.js +8 -31
  64. package/lib/with-stateful-model.js.map +1 -1
  65. package/package.json +20 -12
  66. package/src/__tests__/alert-dialog.test.jsx +283 -0
  67. package/src/__tests__/checkbox.test.jsx +249 -0
  68. package/src/__tests__/form-section.test.jsx +334 -0
  69. package/src/__tests__/help.test.jsx +184 -0
  70. package/src/__tests__/input.test.jsx +192 -0
  71. package/src/__tests__/langs.test.jsx +435 -15
  72. package/src/__tests__/number-text-field-custom.test.jsx +438 -0
  73. package/src/__tests__/number-text-field.test.jsx +295 -102
  74. package/src/__tests__/radio-with-label.test.jsx +259 -0
  75. package/src/__tests__/settings-panel.test.js +66 -83
  76. package/src/__tests__/settings.test.jsx +515 -0
  77. package/src/__tests__/tabs.test.jsx +193 -0
  78. package/src/__tests__/two-choice.test.js +104 -18
  79. package/src/__tests__/with-stateful-model.test.jsx +145 -0
  80. package/src/alert-dialog.jsx +21 -19
  81. package/src/checkbox.jsx +42 -46
  82. package/src/choice-configuration/__tests__/feedback-menu.test.jsx +157 -4
  83. package/src/choice-configuration/__tests__/index.test.jsx +198 -56
  84. package/src/choice-configuration/feedback-menu.jsx +6 -6
  85. package/src/choice-configuration/index.jsx +201 -196
  86. package/src/feedback-config/__tests__/feedback-config.test.jsx +130 -60
  87. package/src/feedback-config/__tests__/feedback-selector.test.jsx +87 -40
  88. package/src/feedback-config/feedback-selector.jsx +52 -53
  89. package/src/feedback-config/group.jsx +21 -22
  90. package/src/feedback-config/index.jsx +27 -29
  91. package/src/form-section.jsx +26 -18
  92. package/src/help.jsx +20 -28
  93. package/src/input.jsx +1 -1
  94. package/src/inputs.jsx +34 -50
  95. package/src/langs.jsx +41 -46
  96. package/src/layout/__tests__/config.layout.test.jsx +55 -38
  97. package/src/layout/config-layout.jsx +38 -32
  98. package/src/layout/layout-contents.jsx +38 -39
  99. package/src/layout/settings-box.jsx +16 -19
  100. package/src/mui-box/index.jsx +35 -43
  101. package/src/number-text-field-custom.jsx +30 -36
  102. package/src/number-text-field.jsx +45 -29
  103. package/src/radio-with-label.jsx +25 -13
  104. package/src/settings/display-size.jsx +12 -11
  105. package/src/settings/panel.jsx +97 -91
  106. package/src/settings/settings-radio-label.jsx +25 -13
  107. package/src/settings/toggle.jsx +30 -29
  108. package/src/tabs/index.jsx +8 -8
  109. package/src/tags-input/__tests__/index.test.jsx +88 -37
  110. package/src/tags-input/index.jsx +35 -38
  111. package/src/two-choice.jsx +15 -19
  112. package/src/__tests__/__snapshots__/langs.test.jsx.snap +0 -32
  113. package/src/__tests__/__snapshots__/settings-panel.test.js.snap +0 -115
  114. package/src/__tests__/__snapshots__/two-choice.test.js.snap +0 -171
  115. package/src/choice-configuration/__tests__/__snapshots__/feedback-menu.test.jsx.snap +0 -51
  116. package/src/choice-configuration/__tests__/__snapshots__/index.test.jsx.snap +0 -519
  117. package/src/feedback-config/__tests__/__snapshots__/feedback-config.test.jsx.snap +0 -27
  118. package/src/feedback-config/__tests__/__snapshots__/feedback-selector.test.jsx.snap +0 -38
  119. package/src/layout/__tests__/__snapshots__/config.layout.test.jsx.snap +0 -59
  120. package/src/tags-input/__tests__/__snapshots__/index.test.jsx.snap +0 -170
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { withStyles } from '@material-ui/core/styles';
4
3
  import get from 'lodash/get';
5
4
  import set from 'lodash/set';
6
- import Select from '@material-ui/core/Select';
7
- import Input from '@material-ui/core/Input';
8
- import MenuItem from '@material-ui/core/MenuItem';
5
+ import { styled } from '@mui/material/styles';
6
+ import Select from '@mui/material/Select';
7
+ import Input from '@mui/material/Input';
8
+ import MenuItem from '@mui/material/MenuItem';
9
+ import Typography from '@mui/material/Typography';
9
10
  import debug from 'debug';
10
11
 
11
12
  import Toggle from './toggle';
@@ -13,7 +14,6 @@ import { NChoice } from '../two-choice';
13
14
  import SettingsRadioLabel from './settings-radio-label';
14
15
  import NumberTextField from '../number-text-field';
15
16
  import Checkbox from '../checkbox';
16
- import Typography from '@material-ui/core/Typography';
17
17
 
18
18
  const log = debug('pie-lib:config-ui:settings:panel');
19
19
 
@@ -46,10 +46,24 @@ CheckboxChoice.propTypes = {
46
46
  onChange: PropTypes.func,
47
47
  };
48
48
 
49
- const Radio = ({ classes, label, value, onChange, choices }) => {
49
+ const StyledNChoice = styled(NChoice)(({ theme }) => ({
50
+ marginTop: theme.spacing(0.5),
51
+ paddingBottom: theme.spacing(0.5),
52
+ width: '100%',
53
+ '& > label': {
54
+ color: 'rgba(0, 0, 0, 0.89)',
55
+ transform: 'translate(0, 10px) scale(1)',
56
+ fontSize: '18px',
57
+ marginTop: theme.spacing(2.5),
58
+ },
59
+ '& > div': {
60
+ marginTop: theme.spacing(2.5),
61
+ },
62
+ }));
63
+
64
+ const Radio = ({ label, value, onChange, choices }) => {
50
65
  return (
51
- <NChoice
52
- className={classes.radioSettings}
66
+ <StyledNChoice
53
67
  direction="horizontal"
54
68
  customLabel={SettingsRadioLabel}
55
69
  value={value}
@@ -62,103 +76,85 @@ const Radio = ({ classes, label, value, onChange, choices }) => {
62
76
 
63
77
  Radio.propTypes = { ...baseTypes, choices: PropTypes.arrayOf(PropTypes.shape(labelValue)) };
64
78
 
65
- const StyledRadio = withStyles((theme) => ({
66
- radioSettings: {
67
- marginTop: theme.spacing.unit / 2,
68
- paddingBottom: theme.spacing.unit / 2,
69
- width: '100%',
70
- '& > label': {
71
- color: 'rgba(0, 0, 0, 0.89)',
72
- transform: 'translate(0, 10px) scale(1)',
73
- fontSize: '14px',
74
- },
75
- '& > div': {
76
- marginTop: theme.spacing.unit * 2.5,
77
- },
78
- },
79
- label: {
80
- display: 'none',
81
- },
82
- }))(Radio);
79
+ const StyledRadio = Radio;
83
80
 
84
- const Dropdown = withStyles((theme) => ({
85
- label: {
86
- margin: 0,
87
- fontSize: theme.typography.fontSize,
88
- },
89
- wrapper: {
90
- marginTop: theme.spacing.unit / 2,
91
- border: '2px solid lightgrey',
92
- borderRadius: '4px',
93
- padding: `0 ${theme.spacing.unit}px`,
94
- },
95
- }))(({ classes, label, value, onChange, choices = [] }) => {
81
+ const StyledLabel = styled('p')(({ theme }) => ({
82
+ margin: 0,
83
+ fontSize: theme.typography.fontSize,
84
+ }));
85
+
86
+ const StyledSelect = styled(Select)(({ theme }) => ({
87
+ marginTop: theme.spacing(0.5),
88
+ border: '2px solid lightgrey',
89
+ padding: `0 ${theme.spacing(1)}`,
90
+ borderRadius: '4px',
91
+ }));
92
+
93
+ const Dropdown = ({ label, value, onChange, choices = [] }) => {
96
94
  const getItemLabel = (l) => (typeof l === 'string' ? l : l.label);
97
95
  const getItemValue = (l) => (typeof l === 'string' ? l : l.value);
98
96
  return (
99
97
  <div>
100
- {label && <p className={classes.label}>{label}</p>}
101
- <Select
102
- className={classes.wrapper}
98
+ {label && <StyledLabel>{label}</StyledLabel>}
99
+ <StyledSelect
103
100
  value={value || (choices && choices[0])}
104
101
  onChange={({ target }) => onChange(target.value)}
105
102
  input={<Input id={`dropdown-${label}`} />}
106
103
  disableUnderline
104
+ MenuProps={{ transitionDuration: { enter: 225, exit: 195 } }}
107
105
  >
108
106
  {choices.map((l, index) => (
109
107
  <MenuItem key={index} value={getItemValue(l)}>
110
108
  {getItemLabel(l)}
111
109
  </MenuItem>
112
110
  ))}
113
- </Select>
111
+ </StyledSelect>
114
112
  </div>
115
113
  );
116
- });
114
+ };
117
115
 
118
116
  Dropdown.propTypes = { ...baseTypes, choices: PropTypes.arrayOf(PropTypes.string) };
119
117
 
120
- const TextField = withStyles((theme) => ({
121
- field: {
122
- marginRight: theme.spacing.unit * 3,
123
- marginTop: theme.spacing.unit,
124
- },
125
- }))(({ classes, label }) => {
126
- return <Typography className={classes.field}>{label}</Typography>;
127
- });
128
-
129
- const NumberField = withStyles((theme) => ({
130
- field: {
131
- width: '35%',
132
- marginRight: theme.spacing.unit * 3,
133
- marginTop: theme.spacing.unit,
134
- },
135
- wrapper: {
136
- marginTop: theme.spacing.unit / 2,
118
+ const StyledTypography = styled(Typography)(({ theme }) => ({
119
+ marginRight: theme.spacing(3),
120
+ marginTop: theme.spacing(1),
121
+ }));
122
+
123
+ const TextField = ({ label }) => {
124
+ return <StyledTypography>{label}</StyledTypography>;
125
+ };
126
+
127
+ const StyledNumberTextField = styled(NumberTextField)(({ theme }) => ({
128
+ width: '35%',
129
+ marginRight: theme.spacing(3),
130
+ marginTop: theme.spacing(1),
131
+ '& .MuiInputBase-root': {
132
+ marginTop: theme.spacing(0.5),
137
133
  border: '2px solid lightgrey',
138
134
  borderRadius: '4px',
139
- padding: `0 ${theme.spacing.unit}px`,
135
+ padding: `0 ${theme.spacing(1)}`,
136
+ backgroundColor: 'transparent',
140
137
  },
141
- }))(({ classes, label, value, onChange = () => {}, suffix, min, max }) => {
138
+ }));
139
+
140
+ const NumberField = ({ label, value, onChange = () => { }, suffix, min, max }) => {
142
141
  return (
143
- <NumberTextField
142
+ <StyledNumberTextField
143
+ variant={'standard'}
144
144
  label={label || 'Label'}
145
145
  value={value}
146
146
  max={max}
147
147
  min={min}
148
148
  onChange={(ev, value) => onChange(value)}
149
149
  suffix={suffix}
150
- className={classes.field}
151
150
  showErrorWhenOutsideRange
152
- inputClassName={classes.wrapper}
153
151
  disableUnderline
154
- classes={classes}
155
152
  />
156
153
  );
157
- });
154
+ };
158
155
 
159
156
  NumberField.propTypes = {
160
157
  ...baseTypes,
161
- classes: PropTypes.object,
162
158
  suffix: PropTypes.string,
163
159
  min: PropTypes.number,
164
160
  max: PropTypes.number,
@@ -184,22 +180,24 @@ const tagMap = {
184
180
  textField: TextField,
185
181
  };
186
182
 
187
- const Group = withStyles((theme) => ({
188
- group: {
189
- margin: `0 0 ${theme.spacing.unit * 2}px 0`,
190
- },
191
- groupHeader: {
192
- color: '#495B8F',
193
- fontSize: theme.typography.fontSize + 2,
194
- fontWeight: 600,
195
- marginBottom: theme.spacing.unit,
196
- },
197
- numberFields: {
198
- fontSize: theme.typography.fontSize,
199
- marginBottom: 0,
200
- },
201
- }))((props) => {
202
- const { classes, model, label, group, configuration, onChange } = props;
183
+ const StyledGroup = styled('div')(({ theme }) => ({
184
+ margin: `0 0 ${theme.spacing(2)} 0`,
185
+ }));
186
+
187
+ const StyledGroupHeader = styled('div')(({ theme }) => ({
188
+ color: '#495B8F',
189
+ fontSize: theme.typography.fontSize + 2,
190
+ fontWeight: 600,
191
+ marginBottom: theme.spacing(1),
192
+ }));
193
+
194
+ const StyledNumberFields = styled('p')(({ theme }) => ({
195
+ fontSize: theme.typography.fontSize,
196
+ marginBottom: 0,
197
+ }));
198
+
199
+ const Group = (props) => {
200
+ const { model, label, group, configuration, onChange } = props;
203
201
 
204
202
  /**
205
203
  * @param group - the group of settings
@@ -227,7 +225,7 @@ const Group = withStyles((theme) => ({
227
225
  if (type === 'numberFields') {
228
226
  return (
229
227
  <div key={`numberField-${label}`}>
230
- <p className={classes.numberFields}>{label}</p>
228
+ <StyledNumberFields>{label}</StyledNumberFields>
231
229
  {Object.keys(fields).map((fieldKey) => {
232
230
  return getTag(group, `${key}.${fieldKey}`, `${key}.fields.${fieldKey}`);
233
231
  })}
@@ -251,15 +249,23 @@ const Group = withStyles((theme) => ({
251
249
  };
252
250
 
253
251
  return (
254
- <div className={classes.group}>
255
- <div className={classes.groupHeader}>{label}</div>
252
+ <StyledGroup>
253
+ <StyledGroupHeader>{label}</StyledGroupHeader>
256
254
 
257
255
  {Object.keys(group).map((key) => {
258
256
  return content(group, key);
259
257
  })}
260
- </div>
258
+ </StyledGroup>
261
259
  );
262
- });
260
+ };
261
+
262
+ Group.propTypes = {
263
+ model: PropTypes.object,
264
+ label: PropTypes.string,
265
+ group: PropTypes.object,
266
+ configuration: PropTypes.object,
267
+ onChange: PropTypes.func,
268
+ };
263
269
 
264
270
  export class Panel extends React.Component {
265
271
  static propTypes = {
@@ -272,8 +278,8 @@ export class Panel extends React.Component {
272
278
  };
273
279
 
274
280
  static defaultProps = {
275
- onChangeModel: () => {},
276
- onChangeConfiguration: () => {},
281
+ onChangeModel: () => { },
282
+ onChangeConfiguration: () => { },
277
283
  };
278
284
 
279
285
  change = (key, value, isConfigProperty = false) => {
@@ -1,24 +1,36 @@
1
- import FormControlLabel from '@material-ui/core/FormControlLabel';
2
- import Radio from '@material-ui/core/Radio';
1
+ import FormControlLabel from '@mui/material/FormControlLabel';
2
+ import Radio from '@mui/material/Radio';
3
3
  import React from 'react';
4
- import { withStyles } from '@material-ui/core/styles';
4
+ import PropTypes from 'prop-types';
5
+ import { styled } from '@mui/material/styles';
5
6
  import { color } from '@pie-lib/render-ui';
6
7
 
7
- export default withStyles((theme) => ({
8
- label: {
8
+ const StyledFormControlLabel = styled(FormControlLabel)(({ theme }) => ({
9
+ '& .MuiFormControlLabel-label': {
9
10
  color: 'rgba(0, 0, 0, 0.89)',
10
11
  fontSize: theme.typography.fontSize - 2,
11
12
  left: '-5px',
12
13
  position: 'relative',
13
14
  },
14
- customColor: {
15
- color: `${color.tertiary()} !important`,
16
- },
17
- }))(({ label, value, checked, onChange, classes }) => (
18
- <FormControlLabel
15
+ }));
16
+
17
+ const StyledRadio = styled(Radio)(() => ({
18
+ color: `${color.tertiary()} !important`,
19
+ }));
20
+
21
+ const SettingsRadioLabel = ({ label, value, checked, onChange }) => (
22
+ <StyledFormControlLabel
19
23
  value={value}
20
- classes={{ label: classes.label }}
21
- control={<Radio className={classes.customColor} checked={checked} onChange={onChange} />}
24
+ control={<StyledRadio checked={checked} onChange={onChange} />}
22
25
  label={label}
23
26
  />
24
- ));
27
+ );
28
+
29
+ SettingsRadioLabel.propTypes = {
30
+ label: PropTypes.string,
31
+ value: PropTypes.string,
32
+ checked: PropTypes.bool,
33
+ onChange: PropTypes.func,
34
+ };
35
+
36
+ export default SettingsRadioLabel;
@@ -1,47 +1,48 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import InputLabel from '@material-ui/core/InputLabel';
4
- import { withStyles } from '@material-ui/core/styles';
5
- import Switch from '@material-ui/core/Switch';
6
- import classNames from 'classnames';
3
+ import InputLabel from '@mui/material/InputLabel';
4
+ import { styled } from '@mui/material/styles';
5
+ import Switch from '@mui/material/Switch';
7
6
  import { color } from '@pie-lib/render-ui';
8
7
 
9
- const Toggle = withStyles((theme) => ({
10
- toggle: {
11
- display: 'flex',
12
- width: '100%',
13
- justifyContent: 'space-between',
14
- },
15
- label: {
16
- color: 'rgba(0, 0, 0, 0.89)',
17
- fontSize: theme.typography.fontSize,
18
- paddingTop: theme.spacing.unit * 2,
19
- },
20
- checkedThumb: {
8
+ const StyledToggle = styled('div')(() => ({
9
+ display: 'flex',
10
+ width: '100%',
11
+ justifyContent: 'space-between',
12
+ }));
13
+
14
+ const StyledInputLabel = styled(InputLabel)(({ theme }) => ({
15
+ color: 'rgba(0, 0, 0, 0.89)',
16
+ fontSize: theme.typography.fontSize,
17
+ paddingTop: theme.spacing(2),
18
+ }));
19
+
20
+ const StyledSwitch = styled(Switch)(({ checked }) => ({
21
+ '&.Mui-checked .MuiSwitch-thumb': {
21
22
  color: `${color.tertiary()} !important`,
22
23
  },
23
- checkedBar: {
24
+ '&.Mui-checked .MuiSwitch-track': {
24
25
  backgroundColor: `${color.tertiaryLight()} !important`,
25
26
  },
26
- }))(({ checked, disabled, label, toggle, classes }) => (
27
- <div className={classes.toggle}>
28
- <InputLabel className={classes.label}>{label}</InputLabel>
29
- <Switch
30
- classes={{
31
- checked: classNames(classes.checkedThumb),
32
- bar: classNames({
33
- [classes.checkedBar]: checked,
34
- }),
35
- }}
27
+ '& .MuiSwitch-track': {
28
+ backgroundColor: checked ? `${color.tertiaryLight()} !important` : undefined,
29
+ },
30
+ }));
31
+
32
+ const Toggle = ({ checked, disabled, label, toggle }) => (
33
+ <StyledToggle>
34
+ <StyledInputLabel>{label}</StyledInputLabel>
35
+ <StyledSwitch
36
36
  checked={checked}
37
37
  disabled={disabled}
38
38
  onChange={(e) => toggle(e.target.checked)}
39
39
  />
40
- </div>
41
- ));
40
+ </StyledToggle>
41
+ );
42
42
 
43
43
  Toggle.propTypes = {
44
44
  checked: PropTypes.bool,
45
+ disabled: PropTypes.bool,
45
46
  label: PropTypes.string.isRequired,
46
47
  toggle: PropTypes.func.isRequired,
47
48
  };
@@ -1,13 +1,14 @@
1
1
  import React from 'react';
2
2
 
3
- import MuiTabs from '@material-ui/core/Tabs';
4
- import MuiTab from '@material-ui/core/Tab';
3
+ import MuiTabs from '@mui/material/Tabs';
4
+ import MuiTab from '@mui/material/Tab';
5
5
  import PropTypes from 'prop-types';
6
- import { withStyles } from '@material-ui/core';
6
+ import { styled } from '@mui/material/styles';
7
+
8
+ const StyledMuiTab = styled(MuiTab)(() => ({}));
7
9
 
8
10
  export class Tabs extends React.Component {
9
11
  static propTypes = {
10
- classes: PropTypes.object,
11
12
  className: PropTypes.string,
12
13
  contentClassName: PropTypes.string,
13
14
  contentStyle: PropTypes.object,
@@ -25,14 +26,13 @@ export class Tabs extends React.Component {
25
26
 
26
27
  render() {
27
28
  const { value } = this.state;
28
- const { children, className, contentClassName, contentStyle = {}, classes } = this.props;
29
- const tabClasses = { root: classes.tabRoot };
29
+ const { children, className, contentClassName, contentStyle = {} } = this.props;
30
30
 
31
31
  return (
32
32
  <div className={className}>
33
33
  <MuiTabs indicatorColor="primary" value={value} onChange={this.handleChange}>
34
34
  {React.Children.map(children, (c, index) =>
35
- c && c.props.title ? <MuiTab classes={tabClasses} key={index} label={c.props.title} /> : null,
35
+ c && c.props.title ? <StyledMuiTab key={index} label={c.props.title} /> : null,
36
36
  )}
37
37
  </MuiTabs>
38
38
 
@@ -44,4 +44,4 @@ export class Tabs extends React.Component {
44
44
  }
45
45
  }
46
46
 
47
- export default withStyles(() => ({ tabRoot: {} }))(Tabs);
47
+ export default Tabs;
@@ -1,61 +1,112 @@
1
1
  import { TagsInput } from '../index';
2
- import toJson from 'enzyme-to-json';
3
- import { shallow, mount } from 'enzyme';
2
+ import { render, screen, userEvent, pressKey, Keys } from '@pie-lib/test-utils';
4
3
  import React from 'react';
5
4
 
6
5
  describe('TagsInput', () => {
7
- describe('snapshots', () => {
8
- it('renders', () => {
9
- const wrapper = mount(<TagsInput classes={{ tagsInput: 'tagsInput' }} tags={['foo']} onChange={jest.fn()} />);
10
- expect(toJson(wrapper)).toMatchSnapshot();
6
+ describe('rendering', () => {
7
+ it('renders existing tags as chips', () => {
8
+ render(<TagsInput tags={['foo', 'bar']} onChange={jest.fn()} />);
9
+
10
+ expect(screen.getByText('foo')).toBeInTheDocument();
11
+ expect(screen.getByText('bar')).toBeInTheDocument();
12
+ });
13
+
14
+ it('renders input field', () => {
15
+ render(<TagsInput tags={['foo']} onChange={jest.fn()} />);
16
+
17
+ const input = screen.getByRole('textbox');
18
+ expect(input).toBeInTheDocument();
11
19
  });
12
20
  });
13
21
 
14
- describe('logic', () => {
22
+ describe('user interactions', () => {
15
23
  let onChange;
16
- const mkWrapper = () => {
24
+ const renderComponent = (tags = ['foo']) => {
17
25
  onChange = jest.fn();
18
- return shallow(<TagsInput onChange={onChange} classes={{}} tags={['foo']} />);
26
+ return render(<TagsInput onChange={onChange} tags={tags} />);
19
27
  };
20
28
 
21
- describe('onFocus', () => {
22
- it('sets state.focused = true', () => {
23
- const wrapper = mkWrapper();
24
- wrapper.instance().onFocus();
25
- expect(wrapper.state('focused')).toEqual(true);
29
+ describe('focus behavior', () => {
30
+ it('allows user to focus the input', async () => {
31
+ const user = userEvent.setup();
32
+ renderComponent();
33
+
34
+ const input = screen.getByRole('textbox');
35
+ await user.click(input);
36
+
37
+ expect(input).toHaveFocus();
26
38
  });
27
- });
28
39
 
29
- describe('onBlur', () => {
30
- it('sets state.focused = false', () => {
31
- const wrapper = mkWrapper();
32
- wrapper.instance().onFocus();
33
- wrapper.instance().onBlur();
34
- expect(wrapper.state('focused')).toEqual(false);
40
+ it('allows user to blur the input', async () => {
41
+ const user = userEvent.setup();
42
+ renderComponent();
43
+
44
+ const input = screen.getByRole('textbox');
45
+ await user.click(input);
46
+ expect(input).toHaveFocus();
47
+
48
+ await user.tab();
49
+ expect(input).not.toHaveFocus();
35
50
  });
36
51
  });
37
52
 
38
- describe('onChange', () => {
39
- it('sets state.value ', () => {
40
- const wrapper = mkWrapper();
41
- wrapper.instance().onChange({ target: { value: 'boo' } });
42
- expect(wrapper.state('value')).toEqual('boo');
53
+ describe('typing in input', () => {
54
+ it('updates input value when user types', async () => {
55
+ const user = userEvent.setup();
56
+ renderComponent();
57
+
58
+ const input = screen.getByRole('textbox');
59
+ await user.type(input, 'boo');
60
+
61
+ expect(input).toHaveValue('boo');
43
62
  });
44
63
  });
45
64
 
46
- describe('onKeyDown', () => {
47
- it('calls onChange on enter', () => {
48
- const wrapper = mkWrapper();
49
- wrapper.setState({ value: 'banana' });
50
- wrapper.instance().onKeyDown({ keyCode: 13 });
51
- expect(onChange).toBeCalledWith(['foo', 'banana']);
65
+ describe('adding tags', () => {
66
+ it('adds new tag when user presses Enter', async () => {
67
+ const user = userEvent.setup();
68
+ renderComponent();
69
+
70
+ const input = screen.getByRole('textbox');
71
+ await user.type(input, 'banana');
72
+ pressKey(input, Keys.ENTER);
73
+
74
+ expect(onChange).toHaveBeenCalledWith(['foo', 'banana']);
75
+ });
76
+
77
+ it('does not add duplicate tags', async () => {
78
+ const user = userEvent.setup();
79
+ renderComponent();
80
+
81
+ const input = screen.getByRole('textbox');
82
+ await user.type(input, 'foo');
83
+ pressKey(input, Keys.ENTER);
84
+
85
+ expect(onChange).not.toHaveBeenCalled();
86
+ });
87
+
88
+ it('clears input after adding tag', async () => {
89
+ const user = userEvent.setup();
90
+ renderComponent();
91
+
92
+ const input = screen.getByRole('textbox');
93
+ await user.type(input, 'banana');
94
+ pressKey(input, Keys.ENTER);
95
+
96
+ expect(input).toHaveValue('');
52
97
  });
98
+ });
99
+
100
+ describe('deleting tags', () => {
101
+ it('removes tag when user clicks delete button', async () => {
102
+ const user = userEvent.setup();
103
+ renderComponent(['foo', 'bar']);
104
+
105
+ // Find the delete button for 'foo' tag
106
+ const deleteButtons = screen.getAllByTestId('CancelIcon');
107
+ await user.click(deleteButtons[0]);
53
108
 
54
- it('doesnt calls onChange on enter if the value is the same as a value in tags', () => {
55
- const wrapper = mkWrapper();
56
- wrapper.setState({ value: 'foo' });
57
- wrapper.instance().onKeyDown({ keyCode: 13 });
58
- expect(onChange).not.toBeCalled();
109
+ expect(onChange).toHaveBeenCalledWith(['bar']);
59
110
  });
60
111
  });
61
112
  });