@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.
- package/CHANGELOG.json +8 -1653
- package/CHANGELOG.md +345 -4
- package/LICENSE.md +5 -0
- package/NEXT.CHANGELOG.json +1 -0
- package/lib/__tests__/alert-dialog.test.js +262 -0
- package/lib/__tests__/checkbox.test.js +227 -0
- package/lib/__tests__/choice-utils.test.js +14 -0
- package/lib/__tests__/form-section.test.js +252 -0
- package/lib/__tests__/help.test.js +270 -0
- package/lib/__tests__/input.test.js +268 -0
- package/lib/__tests__/langs.test.js +541 -0
- package/lib/__tests__/number-text-field-custom.test.js +362 -0
- package/lib/__tests__/number-text-field.test.js +421 -0
- package/lib/__tests__/radio-with-label.test.js +233 -0
- package/lib/__tests__/settings-panel.test.js +184 -0
- package/lib/__tests__/settings.test.js +653 -0
- package/lib/__tests__/tabs.test.js +211 -0
- package/lib/__tests__/two-choice.test.js +124 -0
- package/lib/__tests__/with-stateful-model.test.js +221 -0
- package/lib/alert-dialog.js +41 -11
- package/lib/alert-dialog.js.map +1 -1
- package/lib/checkbox.js +59 -49
- package/lib/checkbox.js.map +1 -1
- package/lib/choice-configuration/__tests__/feedback-menu.test.js +287 -0
- package/lib/choice-configuration/__tests__/index.test.js +253 -0
- package/lib/choice-configuration/feedback-menu.js +25 -27
- package/lib/choice-configuration/feedback-menu.js.map +1 -1
- package/lib/choice-configuration/index.js +183 -186
- package/lib/choice-configuration/index.js.map +1 -1
- package/lib/choice-utils.js +6 -8
- package/lib/choice-utils.js.map +1 -1
- package/lib/feedback-config/__tests__/feedback-config.test.js +201 -0
- package/lib/feedback-config/__tests__/feedback-selector.test.js +177 -0
- package/lib/feedback-config/feedback-selector.js +70 -74
- package/lib/feedback-config/feedback-selector.js.map +1 -1
- package/lib/feedback-config/group.js +23 -26
- package/lib/feedback-config/group.js.map +1 -1
- package/lib/feedback-config/index.js +42 -45
- package/lib/feedback-config/index.js.map +1 -1
- package/lib/form-section.js +32 -26
- package/lib/form-section.js.map +1 -1
- package/lib/help.js +38 -48
- package/lib/help.js.map +1 -1
- package/lib/index.js +2 -3
- package/lib/index.js.map +1 -1
- package/lib/input.js +13 -18
- package/lib/input.js.map +1 -1
- package/lib/inputs.js +59 -68
- package/lib/inputs.js.map +1 -1
- package/lib/langs.js +57 -71
- package/lib/langs.js.map +1 -1
- package/lib/layout/__tests__/config.layout.test.js +70 -0
- package/lib/layout/__tests__/layout-content.test.js +6 -0
- package/lib/layout/config-layout.js +79 -48
- package/lib/layout/config-layout.js.map +1 -1
- package/lib/layout/index.js +1 -1
- package/lib/layout/index.js.map +1 -1
- package/lib/layout/layout-contents.js +59 -61
- package/lib/layout/layout-contents.js.map +1 -1
- package/lib/layout/settings-box.js +26 -34
- package/lib/layout/settings-box.js.map +1 -1
- package/lib/mui-box/index.js +42 -51
- package/lib/mui-box/index.js.map +1 -1
- package/lib/number-text-field-custom.js +152 -90
- package/lib/number-text-field-custom.js.map +1 -1
- package/lib/number-text-field.js +75 -64
- package/lib/number-text-field.js.map +1 -1
- package/lib/radio-with-label.js +31 -17
- package/lib/radio-with-label.js.map +1 -1
- package/lib/settings/display-size.js +17 -21
- package/lib/settings/display-size.js.map +1 -1
- package/lib/settings/index.js +14 -20
- package/lib/settings/index.js.map +1 -1
- package/lib/settings/panel.js +141 -142
- package/lib/settings/panel.js.map +1 -1
- package/lib/settings/settings-radio-label.js +30 -17
- package/lib/settings/settings-radio-label.js.map +1 -1
- package/lib/settings/toggle.js +40 -26
- package/lib/settings/toggle.js.map +1 -1
- package/lib/tabs/index.js +19 -31
- package/lib/tabs/index.js.map +1 -1
- package/lib/tags-input/__tests__/index.test.js +183 -0
- package/lib/tags-input/index.js +50 -62
- package/lib/tags-input/index.js.map +1 -1
- package/lib/two-choice.js +34 -44
- package/lib/two-choice.js.map +1 -1
- package/lib/with-stateful-model.js +9 -13
- package/lib/with-stateful-model.js.map +1 -1
- package/package.json +14 -11
- package/src/__tests__/alert-dialog.test.jsx +283 -0
- package/src/__tests__/checkbox.test.jsx +249 -0
- package/src/__tests__/choice-utils.test.js +12 -0
- package/src/__tests__/form-section.test.jsx +334 -0
- package/src/__tests__/help.test.jsx +184 -0
- package/src/__tests__/input.test.jsx +192 -0
- package/src/__tests__/langs.test.jsx +457 -0
- package/src/__tests__/number-text-field-custom.test.jsx +438 -0
- package/src/__tests__/number-text-field.test.jsx +341 -0
- package/src/__tests__/radio-with-label.test.jsx +259 -0
- package/src/__tests__/settings-panel.test.js +187 -0
- package/src/__tests__/settings.test.jsx +515 -0
- package/src/__tests__/tabs.test.jsx +193 -0
- package/src/__tests__/two-choice.test.js +110 -0
- package/src/__tests__/with-stateful-model.test.jsx +145 -0
- package/src/alert-dialog.jsx +30 -8
- package/src/checkbox.jsx +43 -37
- package/src/choice-configuration/__tests__/feedback-menu.test.jsx +163 -0
- package/src/choice-configuration/__tests__/index.test.jsx +234 -0
- package/src/choice-configuration/feedback-menu.jsx +6 -6
- package/src/choice-configuration/index.jsx +208 -199
- package/src/feedback-config/__tests__/feedback-config.test.jsx +141 -0
- package/src/feedback-config/__tests__/feedback-selector.test.jsx +97 -0
- package/src/feedback-config/feedback-selector.jsx +50 -55
- package/src/feedback-config/group.jsx +21 -22
- package/src/feedback-config/index.jsx +27 -29
- package/src/form-section.jsx +26 -18
- package/src/help.jsx +20 -28
- package/src/input.jsx +1 -1
- package/src/inputs.jsx +35 -44
- package/src/langs.jsx +41 -46
- package/src/layout/__tests__/config.layout.test.jsx +59 -0
- package/src/layout/__tests__/layout-content.test.jsx +3 -0
- package/src/layout/config-layout.jsx +53 -23
- package/src/layout/layout-contents.jsx +38 -40
- package/src/layout/settings-box.jsx +16 -19
- package/src/mui-box/index.jsx +35 -43
- package/src/number-text-field-custom.jsx +117 -65
- package/src/number-text-field.jsx +51 -34
- package/src/radio-with-label.jsx +26 -10
- package/src/settings/display-size.jsx +12 -11
- package/src/settings/index.js +2 -1
- package/src/settings/panel.jsx +101 -92
- package/src/settings/settings-radio-label.jsx +26 -10
- package/src/settings/toggle.jsx +37 -18
- package/src/tabs/index.jsx +8 -8
- package/src/tags-input/__tests__/index.test.jsx +113 -0
- package/src/tags-input/index.jsx +35 -38
- package/src/two-choice.jsx +15 -19
- package/README.md +0 -12
package/src/settings/panel.jsx
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
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
|
|
7
|
-
import
|
|
8
|
-
import
|
|
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';
|
|
12
13
|
import { NChoice } from '../two-choice';
|
|
13
14
|
import SettingsRadioLabel from './settings-radio-label';
|
|
14
|
-
import
|
|
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
|
|
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
|
-
<
|
|
52
|
-
className={classes.radioSettings}
|
|
66
|
+
<StyledNChoice
|
|
53
67
|
direction="horizontal"
|
|
54
68
|
customLabel={SettingsRadioLabel}
|
|
55
69
|
value={value}
|
|
@@ -62,102 +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 =
|
|
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
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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 && <
|
|
101
|
-
<
|
|
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
|
-
</
|
|
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
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return <
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
|
135
|
+
padding: `0 ${theme.spacing(1)}`,
|
|
136
|
+
backgroundColor: 'transparent',
|
|
140
137
|
},
|
|
141
|
-
}))
|
|
138
|
+
}));
|
|
139
|
+
|
|
140
|
+
const NumberField = ({ label, value, onChange = () => { }, suffix, min, max }) => {
|
|
142
141
|
return (
|
|
143
|
-
<
|
|
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
152
|
/>
|
|
155
153
|
);
|
|
156
|
-
}
|
|
154
|
+
};
|
|
157
155
|
|
|
158
156
|
NumberField.propTypes = {
|
|
159
157
|
...baseTypes,
|
|
160
|
-
classes: PropTypes.object,
|
|
161
158
|
suffix: PropTypes.string,
|
|
162
159
|
min: PropTypes.number,
|
|
163
160
|
max: PropTypes.number,
|
|
@@ -168,7 +165,9 @@ TextField.propTypes = {
|
|
|
168
165
|
...baseTypes,
|
|
169
166
|
};
|
|
170
167
|
|
|
171
|
-
const ToggleWrapper = ({ label, value, onChange }) =>
|
|
168
|
+
const ToggleWrapper = ({ disabled, label, value, onChange }) => (
|
|
169
|
+
<Toggle label={label} checked={!!value} disabled={!!disabled} toggle={onChange} />
|
|
170
|
+
);
|
|
172
171
|
|
|
173
172
|
ToggleWrapper.propTypes = { ...baseTypes, value: PropTypes.bool };
|
|
174
173
|
|
|
@@ -181,22 +180,24 @@ const tagMap = {
|
|
|
181
180
|
textField: TextField,
|
|
182
181
|
};
|
|
183
182
|
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}))
|
|
199
|
-
|
|
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;
|
|
200
201
|
|
|
201
202
|
/**
|
|
202
203
|
* @param group - the group of settings
|
|
@@ -224,7 +225,7 @@ const Group = withStyles((theme) => ({
|
|
|
224
225
|
if (type === 'numberFields') {
|
|
225
226
|
return (
|
|
226
227
|
<div key={`numberField-${label}`}>
|
|
227
|
-
<
|
|
228
|
+
<StyledNumberFields>{label}</StyledNumberFields>
|
|
228
229
|
{Object.keys(fields).map((fieldKey) => {
|
|
229
230
|
return getTag(group, `${key}.${fieldKey}`, `${key}.fields.${fieldKey}`);
|
|
230
231
|
})}
|
|
@@ -248,15 +249,23 @@ const Group = withStyles((theme) => ({
|
|
|
248
249
|
};
|
|
249
250
|
|
|
250
251
|
return (
|
|
251
|
-
<
|
|
252
|
-
<
|
|
252
|
+
<StyledGroup>
|
|
253
|
+
<StyledGroupHeader>{label}</StyledGroupHeader>
|
|
253
254
|
|
|
254
255
|
{Object.keys(group).map((key) => {
|
|
255
256
|
return content(group, key);
|
|
256
257
|
})}
|
|
257
|
-
</
|
|
258
|
+
</StyledGroup>
|
|
258
259
|
);
|
|
259
|
-
}
|
|
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
|
+
};
|
|
260
269
|
|
|
261
270
|
export class Panel extends React.Component {
|
|
262
271
|
static propTypes = {
|
|
@@ -269,8 +278,8 @@ export class Panel extends React.Component {
|
|
|
269
278
|
};
|
|
270
279
|
|
|
271
280
|
static defaultProps = {
|
|
272
|
-
onChangeModel: () => {},
|
|
273
|
-
onChangeConfiguration: () => {},
|
|
281
|
+
onChangeModel: () => { },
|
|
282
|
+
onChangeConfiguration: () => { },
|
|
274
283
|
};
|
|
275
284
|
|
|
276
285
|
change = (key, value, isConfigProperty = false) => {
|
|
@@ -1,20 +1,36 @@
|
|
|
1
|
-
import FormControlLabel from '@material
|
|
2
|
-
import Radio from '@material
|
|
1
|
+
import FormControlLabel from '@mui/material/FormControlLabel';
|
|
2
|
+
import Radio from '@mui/material/Radio';
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
5
|
+
import { styled } from '@mui/material/styles';
|
|
6
|
+
import { color } from '@pie-lib/render-ui';
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
label: {
|
|
8
|
+
const StyledFormControlLabel = styled(FormControlLabel)(({ theme }) => ({
|
|
9
|
+
'& .MuiFormControlLabel-label': {
|
|
8
10
|
color: 'rgba(0, 0, 0, 0.89)',
|
|
9
11
|
fontSize: theme.typography.fontSize - 2,
|
|
10
12
|
left: '-5px',
|
|
11
13
|
position: 'relative',
|
|
12
14
|
},
|
|
13
|
-
}))
|
|
14
|
-
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
const StyledRadio = styled(Radio)(() => ({
|
|
18
|
+
color: `${color.tertiary()} !important`,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
const SettingsRadioLabel = ({ label, value, checked, onChange }) => (
|
|
22
|
+
<StyledFormControlLabel
|
|
15
23
|
value={value}
|
|
16
|
-
|
|
17
|
-
control={<Radio checked={checked} onChange={onChange} />}
|
|
24
|
+
control={<StyledRadio checked={checked} onChange={onChange} />}
|
|
18
25
|
label={label}
|
|
19
26
|
/>
|
|
20
|
-
)
|
|
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;
|
package/src/settings/toggle.jsx
CHANGED
|
@@ -1,29 +1,48 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import InputLabel from '@material
|
|
4
|
-
import {
|
|
5
|
-
import Switch from '@material
|
|
3
|
+
import InputLabel from '@mui/material/InputLabel';
|
|
4
|
+
import { styled } from '@mui/material/styles';
|
|
5
|
+
import Switch from '@mui/material/Switch';
|
|
6
|
+
import { color } from '@pie-lib/render-ui';
|
|
6
7
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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': {
|
|
22
|
+
color: `${color.tertiary()} !important`,
|
|
12
23
|
},
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
fontSize: theme.typography.fontSize,
|
|
16
|
-
paddingTop: theme.spacing.unit * 2,
|
|
24
|
+
'&.Mui-checked .MuiSwitch-track': {
|
|
25
|
+
backgroundColor: `${color.tertiaryLight()} !important`,
|
|
17
26
|
},
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
)
|
|
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
|
+
checked={checked}
|
|
37
|
+
disabled={disabled}
|
|
38
|
+
onChange={(e) => toggle(e.target.checked)}
|
|
39
|
+
/>
|
|
40
|
+
</StyledToggle>
|
|
41
|
+
);
|
|
24
42
|
|
|
25
43
|
Toggle.propTypes = {
|
|
26
44
|
checked: PropTypes.bool,
|
|
45
|
+
disabled: PropTypes.bool,
|
|
27
46
|
label: PropTypes.string.isRequired,
|
|
28
47
|
toggle: PropTypes.func.isRequired,
|
|
29
48
|
};
|
package/src/tabs/index.jsx
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import MuiTabs from '@material
|
|
4
|
-
import MuiTab from '@material
|
|
3
|
+
import MuiTabs from '@mui/material/Tabs';
|
|
4
|
+
import MuiTab from '@mui/material/Tab';
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
|
-
import {
|
|
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 = {}
|
|
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 ? <
|
|
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
|
|
47
|
+
export default Tabs;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { TagsInput } from '../index';
|
|
2
|
+
import { render, screen, userEvent, pressKey, Keys } from '@pie-lib/test-utils';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
|
|
5
|
+
describe('TagsInput', () => {
|
|
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();
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('user interactions', () => {
|
|
23
|
+
let onChange;
|
|
24
|
+
const renderComponent = (tags = ['foo']) => {
|
|
25
|
+
onChange = jest.fn();
|
|
26
|
+
return render(<TagsInput onChange={onChange} tags={tags} />);
|
|
27
|
+
};
|
|
28
|
+
|
|
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();
|
|
38
|
+
});
|
|
39
|
+
|
|
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();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
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');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
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('');
|
|
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]);
|
|
108
|
+
|
|
109
|
+
expect(onChange).toHaveBeenCalledWith(['bar']);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
package/src/tags-input/index.jsx
CHANGED
|
@@ -1,27 +1,48 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import {
|
|
3
|
+
import { styled } from '@mui/material/styles';
|
|
4
4
|
import uniq from 'lodash/uniq';
|
|
5
|
-
import Chip from '@material
|
|
5
|
+
import Chip from '@mui/material/Chip';
|
|
6
6
|
import MuiBox from '../mui-box';
|
|
7
7
|
|
|
8
8
|
const ENTER = 13;
|
|
9
9
|
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
const StyledChip = styled(Chip)(() => ({
|
|
11
|
+
padding: '0px',
|
|
12
|
+
margin: '1px',
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
const Tag = ({ label, onDelete }) => <StyledChip label={label} onDelete={onDelete} />;
|
|
16
16
|
|
|
17
17
|
Tag.propTypes = {
|
|
18
18
|
label: PropTypes.string.isRequired,
|
|
19
19
|
onDelete: PropTypes.func.isRequired,
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
const StyledTagsInput = styled('div')(({ theme }) => ({
|
|
23
|
+
border: `0px solid ${theme.palette.background.paper}`,
|
|
24
|
+
display: 'flex',
|
|
25
|
+
flexWrap: 'wrap',
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
const StyledInput = styled('input')(({ theme }) => ({
|
|
29
|
+
padding: '2px',
|
|
30
|
+
margin: '1px',
|
|
31
|
+
minWidth: '30px',
|
|
32
|
+
width: '100%',
|
|
33
|
+
flex: '1',
|
|
34
|
+
border: `0px solid ${theme.palette.background.paper}`,
|
|
35
|
+
height: '28px',
|
|
36
|
+
fontSize: theme.typography.fontSize,
|
|
37
|
+
fontFamily: theme.typography.fontFamily,
|
|
38
|
+
outline: 'none',
|
|
39
|
+
'&:focus': {
|
|
40
|
+
outline: 'none',
|
|
41
|
+
},
|
|
42
|
+
}));
|
|
43
|
+
|
|
22
44
|
export class TagsInput extends React.Component {
|
|
23
45
|
static propTypes = {
|
|
24
|
-
classes: PropTypes.object.isRequired,
|
|
25
46
|
tags: PropTypes.arrayOf(PropTypes.string).isRequired,
|
|
26
47
|
onChange: PropTypes.func.isRequired,
|
|
27
48
|
};
|
|
@@ -70,50 +91,26 @@ export class TagsInput extends React.Component {
|
|
|
70
91
|
};
|
|
71
92
|
|
|
72
93
|
render() {
|
|
73
|
-
const {
|
|
94
|
+
const { tags } = this.props;
|
|
74
95
|
return (
|
|
75
96
|
<MuiBox focused={this.state.focused}>
|
|
76
|
-
<
|
|
97
|
+
<StyledTagsInput>
|
|
77
98
|
{(tags || []).map((t, index) => (
|
|
78
99
|
<Tag key={index} label={t} onDelete={() => this.deleteTag(t)} />
|
|
79
100
|
))}
|
|
80
|
-
<
|
|
101
|
+
<StyledInput
|
|
81
102
|
ref={(r) => (this.input = r)}
|
|
82
103
|
onKeyDown={this.onKeyDown}
|
|
83
104
|
onChange={this.onChange}
|
|
84
|
-
className={classes.input}
|
|
85
105
|
value={this.state.value}
|
|
86
106
|
onFocus={this.onFocus}
|
|
87
107
|
onBlur={this.onBlur}
|
|
88
108
|
type="text"
|
|
89
109
|
/>
|
|
90
|
-
</
|
|
110
|
+
</StyledTagsInput>
|
|
91
111
|
</MuiBox>
|
|
92
112
|
);
|
|
93
113
|
}
|
|
94
114
|
}
|
|
95
115
|
|
|
96
|
-
|
|
97
|
-
tagsInput: {
|
|
98
|
-
border: `0px solid ${theme.palette.background.paper}`,
|
|
99
|
-
display: 'flex',
|
|
100
|
-
flexWrap: 'wrap',
|
|
101
|
-
},
|
|
102
|
-
input: {
|
|
103
|
-
padding: '2px',
|
|
104
|
-
margin: '1px',
|
|
105
|
-
minWidth: '30px',
|
|
106
|
-
width: '100%',
|
|
107
|
-
flex: '1',
|
|
108
|
-
border: `0px solid ${theme.palette.background.paper}`,
|
|
109
|
-
height: '28px',
|
|
110
|
-
fontSize: theme.typography.fontSize,
|
|
111
|
-
fontFamily: theme.typography.fontFamily,
|
|
112
|
-
outline: 'none',
|
|
113
|
-
'&:focus': {
|
|
114
|
-
outline: 'none',
|
|
115
|
-
},
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
export default withStyles(styles)(TagsInput);
|
|
116
|
+
export default TagsInput;
|