@pie-lib/config-ui 11.30.3-next.2 → 11.30.3-next.203
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.md +19 -67
- package/lib/alert-dialog.js +35 -42
- package/lib/alert-dialog.js.map +1 -1
- package/lib/checkbox.js +56 -71
- package/lib/checkbox.js.map +1 -1
- package/lib/choice-configuration/feedback-menu.js +29 -64
- package/lib/choice-configuration/feedback-menu.js.map +1 -1
- package/lib/choice-configuration/index.js +202 -262
- package/lib/choice-configuration/index.js.map +1 -1
- package/lib/choice-utils.js +6 -18
- package/lib/choice-utils.js.map +1 -1
- package/lib/feedback-config/feedback-selector.js +79 -115
- package/lib/feedback-config/feedback-selector.js.map +1 -1
- package/lib/feedback-config/group.js +26 -40
- package/lib/feedback-config/group.js.map +1 -1
- package/lib/feedback-config/index.js +47 -90
- package/lib/feedback-config/index.js.map +1 -1
- package/lib/form-section.js +31 -33
- package/lib/form-section.js.map +1 -1
- package/lib/help.js +39 -80
- package/lib/help.js.map +1 -1
- package/lib/index.js +1 -31
- package/lib/index.js.map +1 -1
- package/lib/input.js +21 -54
- package/lib/input.js.map +1 -1
- package/lib/inputs.js +61 -95
- package/lib/inputs.js.map +1 -1
- package/lib/langs.js +58 -101
- package/lib/langs.js.map +1 -1
- package/lib/layout/config-layout.js +40 -70
- package/lib/layout/config-layout.js.map +1 -1
- package/lib/layout/index.js +0 -3
- package/lib/layout/index.js.map +1 -1
- package/lib/layout/layout-contents.js +72 -103
- package/lib/layout/layout-contents.js.map +1 -1
- package/lib/layout/settings-box.js +27 -56
- package/lib/layout/settings-box.js.map +1 -1
- package/lib/mui-box/index.js +41 -57
- package/lib/mui-box/index.js.map +1 -1
- package/lib/number-text-field-custom.js +79 -161
- package/lib/number-text-field-custom.js.map +1 -1
- package/lib/number-text-field.js +80 -114
- package/lib/number-text-field.js.map +1 -1
- package/lib/radio-with-label.js +30 -31
- package/lib/radio-with-label.js.map +1 -1
- package/lib/settings/display-size.js +16 -32
- package/lib/settings/display-size.js.map +1 -1
- package/lib/settings/index.js +14 -47
- package/lib/settings/index.js.map +1 -1
- package/lib/settings/panel.js +159 -229
- package/lib/settings/panel.js.map +1 -1
- package/lib/settings/settings-radio-label.js +28 -30
- package/lib/settings/settings-radio-label.js.map +1 -1
- package/lib/settings/toggle.js +35 -46
- package/lib/settings/toggle.js.map +1 -1
- package/lib/tabs/index.js +22 -57
- package/lib/tabs/index.js.map +1 -1
- package/lib/tags-input/index.js +50 -99
- package/lib/tags-input/index.js.map +1 -1
- package/lib/two-choice.js +46 -90
- package/lib/two-choice.js.map +1 -1
- package/lib/with-stateful-model.js +8 -31
- package/lib/with-stateful-model.js.map +1 -1
- package/package.json +12 -20
- package/src/__tests__/alert-dialog.test.jsx +283 -0
- package/src/__tests__/checkbox.test.jsx +249 -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 +435 -15
- package/src/__tests__/number-text-field-custom.test.jsx +438 -0
- package/src/__tests__/number-text-field.test.jsx +295 -102
- package/src/__tests__/radio-with-label.test.jsx +259 -0
- package/src/__tests__/settings-panel.test.js +66 -83
- package/src/__tests__/settings.test.jsx +515 -0
- package/src/__tests__/tabs.test.jsx +193 -0
- package/src/__tests__/two-choice.test.js +104 -18
- package/src/__tests__/with-stateful-model.test.jsx +145 -0
- package/src/alert-dialog.jsx +21 -19
- package/src/checkbox.jsx +42 -46
- package/src/choice-configuration/__tests__/feedback-menu.test.jsx +157 -4
- package/src/choice-configuration/__tests__/index.test.jsx +198 -56
- package/src/choice-configuration/feedback-menu.jsx +6 -6
- package/src/choice-configuration/index.jsx +201 -203
- package/src/feedback-config/__tests__/feedback-config.test.jsx +130 -60
- package/src/feedback-config/__tests__/feedback-selector.test.jsx +81 -44
- 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 +34 -50
- package/src/langs.jsx +41 -46
- package/src/layout/__tests__/config.layout.test.jsx +55 -38
- package/src/layout/config-layout.jsx +38 -32
- package/src/layout/layout-contents.jsx +38 -39
- package/src/layout/settings-box.jsx +16 -19
- package/src/mui-box/index.jsx +35 -43
- package/src/number-text-field-custom.jsx +30 -36
- package/src/number-text-field.jsx +45 -29
- package/src/radio-with-label.jsx +25 -13
- package/src/settings/display-size.jsx +12 -11
- package/src/settings/panel.jsx +97 -91
- package/src/settings/settings-radio-label.jsx +25 -13
- package/src/settings/toggle.jsx +30 -29
- package/src/tabs/index.jsx +8 -8
- package/src/tags-input/__tests__/index.test.jsx +88 -37
- package/src/tags-input/index.jsx +35 -38
- package/src/two-choice.jsx +15 -19
- package/esm/index.css +0 -847
- package/esm/index.js +0 -213950
- package/esm/index.js.map +0 -1
- package/esm/package.json +0 -3
- package/src/__tests__/__snapshots__/langs.test.jsx.snap +0 -32
- package/src/__tests__/__snapshots__/settings-panel.test.js.snap +0 -115
- package/src/__tests__/__snapshots__/two-choice.test.js.snap +0 -171
- package/src/choice-configuration/__tests__/__snapshots__/feedback-menu.test.jsx.snap +0 -51
- package/src/choice-configuration/__tests__/__snapshots__/index.test.jsx.snap +0 -519
- package/src/feedback-config/__tests__/__snapshots__/feedback-config.test.jsx.snap +0 -27
- package/src/feedback-config/__tests__/__snapshots__/feedback-selector.test.jsx.snap +0 -38
- package/src/layout/__tests__/__snapshots__/config.layout.test.jsx.snap +0 -59
- package/src/tags-input/__tests__/__snapshots__/index.test.jsx.snap +0 -170
|
@@ -1,117 +1,176 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import {
|
|
4
|
-
import TextField from '@material
|
|
5
|
-
import ActionDelete from '@
|
|
6
|
-
import ArrowRight from '@
|
|
7
|
-
import IconButton from '@material
|
|
8
|
-
import classNames from 'classnames';
|
|
3
|
+
import { styled } from '@mui/material/styles';
|
|
4
|
+
import TextField from '@mui/material/TextField';
|
|
5
|
+
import ActionDelete from '@mui/icons-material/Delete';
|
|
6
|
+
import ArrowRight from '@mui/icons-material/SubdirectoryArrowRight';
|
|
7
|
+
import IconButton from '@mui/material/IconButton';
|
|
9
8
|
import { InputContainer } from '@pie-lib/render-ui';
|
|
10
|
-
import EditableHtml from '@pie-lib/editable-html';
|
|
9
|
+
// import EditableHtml from '@pie-lib/editable-html-tip-tap';
|
|
11
10
|
import { InputCheckbox, InputRadio } from '../inputs';
|
|
12
11
|
import FeedbackMenu from './feedback-menu';
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}))(
|
|
20
|
-
({
|
|
21
|
-
label,
|
|
22
|
-
classes,
|
|
23
|
-
onChange,
|
|
24
|
-
value,
|
|
25
|
-
className,
|
|
26
|
-
imageSupport,
|
|
27
|
-
disableImageAlignmentButtons,
|
|
28
|
-
disabled,
|
|
29
|
-
spellCheck,
|
|
30
|
-
nonEmpty,
|
|
31
|
-
pluginOpts,
|
|
32
|
-
toolbarOpts,
|
|
33
|
-
error,
|
|
34
|
-
maxImageWidth,
|
|
35
|
-
maxImageHeight,
|
|
36
|
-
uploadSoundSupport,
|
|
37
|
-
mathMlOptions = {},
|
|
38
|
-
}) => {
|
|
39
|
-
const names = classNames(classes.labelContainer, className);
|
|
13
|
+
// - mathquill error window not defined
|
|
14
|
+
let EditableHtml;
|
|
15
|
+
if (typeof window !== 'undefined') {
|
|
16
|
+
EditableHtml = require('@pie-lib/editable-html-tip-tap')['default'];
|
|
17
|
+
}
|
|
40
18
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
19
|
+
const StyledEditorHolder = styled('div')(({ theme }) => ({
|
|
20
|
+
marginTop: theme.spacing(2),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
const EditableHtmlContainer = ({
|
|
24
|
+
label,
|
|
25
|
+
onChange,
|
|
26
|
+
value,
|
|
27
|
+
className,
|
|
28
|
+
imageSupport,
|
|
29
|
+
disableImageAlignmentButtons,
|
|
30
|
+
disabled,
|
|
31
|
+
spellCheck,
|
|
32
|
+
nonEmpty,
|
|
33
|
+
pluginOpts,
|
|
34
|
+
toolbarOpts,
|
|
35
|
+
error,
|
|
36
|
+
maxImageWidth,
|
|
37
|
+
maxImageHeight,
|
|
38
|
+
uploadSoundSupport,
|
|
39
|
+
mathMlOptions = {},
|
|
40
|
+
}) => {
|
|
41
|
+
return (
|
|
42
|
+
<InputContainer label={label} className={className}>
|
|
43
|
+
<StyledEditorHolder>
|
|
44
|
+
<EditableHtml
|
|
45
|
+
markup={value || ''}
|
|
46
|
+
disabled={disabled}
|
|
47
|
+
spellCheck={spellCheck}
|
|
48
|
+
nonEmpty={nonEmpty}
|
|
49
|
+
onChange={onChange}
|
|
50
|
+
imageSupport={imageSupport}
|
|
51
|
+
disableImageAlignmentButtons={disableImageAlignmentButtons}
|
|
52
|
+
pluginProps={pluginOpts || {}}
|
|
53
|
+
toolbarOpts={toolbarOpts}
|
|
54
|
+
error={error}
|
|
55
|
+
maxImageWidth={maxImageWidth}
|
|
56
|
+
maxImageHeight={maxImageHeight}
|
|
57
|
+
uploadSoundSupport={uploadSoundSupport}
|
|
58
|
+
languageCharactersProps={[{ language: 'spanish' }, { language: 'special' }]}
|
|
59
|
+
mathMlOptions={mathMlOptions}
|
|
60
|
+
/>
|
|
61
|
+
</StyledEditorHolder>
|
|
62
|
+
</InputContainer>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const StyledFeedbackContainer = styled('div')(() => ({
|
|
67
|
+
position: 'relative',
|
|
68
|
+
}));
|
|
69
|
+
|
|
70
|
+
const StyledArrowIcon = styled(ArrowRight)(({ theme }) => ({
|
|
71
|
+
fill: theme.palette.grey[400],
|
|
72
|
+
left: -56,
|
|
73
|
+
position: 'absolute',
|
|
74
|
+
top: 40,
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
const StyledTextField = styled(TextField)(({ theme }) => ({
|
|
78
|
+
width: '100%',
|
|
79
|
+
marginTop: theme.spacing(2),
|
|
80
|
+
}));
|
|
81
|
+
|
|
82
|
+
const StyledEditableHtmlContainer = styled(EditableHtmlContainer)(({ theme }) => ({
|
|
83
|
+
width: '100%',
|
|
84
|
+
marginTop: theme.spacing(2),
|
|
85
|
+
}));
|
|
86
|
+
|
|
87
|
+
const Feedback = ({ value, onChange, type, correct, defaults, toolbarOpts, mathMlOptions = {} }) => {
|
|
82
88
|
if (!type || type === 'none') {
|
|
83
89
|
return null;
|
|
84
90
|
} else if (type === 'default') {
|
|
85
91
|
return (
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
<
|
|
89
|
-
className={classes.text}
|
|
92
|
+
<StyledFeedbackContainer>
|
|
93
|
+
<StyledArrowIcon />
|
|
94
|
+
<StyledTextField
|
|
90
95
|
label="Feedback Text"
|
|
91
96
|
value={correct ? defaults.correct : defaults.incorrect}
|
|
97
|
+
variant="standard"
|
|
92
98
|
/>
|
|
93
|
-
</
|
|
99
|
+
</StyledFeedbackContainer>
|
|
94
100
|
);
|
|
95
101
|
} else {
|
|
96
102
|
return (
|
|
97
|
-
<
|
|
98
|
-
<
|
|
99
|
-
<
|
|
100
|
-
className={classes.text}
|
|
103
|
+
<StyledFeedbackContainer>
|
|
104
|
+
<StyledArrowIcon />
|
|
105
|
+
<StyledEditableHtmlContainer
|
|
101
106
|
label="Feedback Text"
|
|
102
107
|
value={value}
|
|
103
108
|
onChange={onChange}
|
|
104
109
|
toolbarOpts={toolbarOpts}
|
|
105
110
|
mathMlOptions={mathMlOptions}
|
|
106
111
|
/>
|
|
107
|
-
</
|
|
112
|
+
</StyledFeedbackContainer>
|
|
108
113
|
);
|
|
109
114
|
}
|
|
110
|
-
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const StyledIndex = styled('span')(({ theme }) => ({
|
|
118
|
+
paddingRight: theme.spacing(1),
|
|
119
|
+
paddingTop: theme.spacing(3),
|
|
120
|
+
}));
|
|
121
|
+
|
|
122
|
+
const StyledTopRow = styled('div')(() => ({
|
|
123
|
+
display: 'flex',
|
|
124
|
+
alignItems: 'center',
|
|
125
|
+
}));
|
|
126
|
+
|
|
127
|
+
const StyledToggle = styled('div')(({ theme }) => ({
|
|
128
|
+
flex: '0 1 auto',
|
|
129
|
+
paddingTop: theme.spacing(0.5),
|
|
130
|
+
paddingBottom: 0,
|
|
131
|
+
marginRight: 0,
|
|
132
|
+
marginLeft: theme.spacing(1),
|
|
133
|
+
}));
|
|
134
|
+
|
|
135
|
+
const StyledFeedback = styled('div')(({ theme }) => ({
|
|
136
|
+
flex: '0 1 auto',
|
|
137
|
+
paddingTop: theme.spacing(2),
|
|
138
|
+
paddingLeft: 0,
|
|
139
|
+
marginLeft: 0,
|
|
140
|
+
marginRight: theme.spacing(1),
|
|
141
|
+
}));
|
|
142
|
+
|
|
143
|
+
const StyledFeedbackIcon = styled('div')(() => ({
|
|
144
|
+
margin: 0,
|
|
145
|
+
width: 'inherit',
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
const StyledDeleteIcon = styled('div')(() => ({
|
|
149
|
+
margin: 0,
|
|
150
|
+
width: 'inherit',
|
|
151
|
+
}));
|
|
152
|
+
|
|
153
|
+
const StyledDelete = styled('div')(({ theme }) => ({
|
|
154
|
+
flex: '0 1 auto',
|
|
155
|
+
paddingTop: theme.spacing(2),
|
|
156
|
+
paddingLeft: 0,
|
|
157
|
+
marginLeft: 0,
|
|
158
|
+
}));
|
|
159
|
+
|
|
160
|
+
const StyledMiddleColumn = styled('div')(({ theme }) => ({
|
|
161
|
+
display: 'flex',
|
|
162
|
+
flex: 1,
|
|
163
|
+
flexDirection: 'column',
|
|
164
|
+
marginRight: theme.spacing(1),
|
|
165
|
+
}));
|
|
166
|
+
|
|
167
|
+
const StyledErrorText = styled('div')(({ theme }) => ({
|
|
168
|
+
fontSize: theme.typography.fontSize - 2,
|
|
169
|
+
color: theme.palette.error.main,
|
|
170
|
+
}));
|
|
111
171
|
|
|
112
172
|
export class ChoiceConfiguration extends React.Component {
|
|
113
173
|
static propTypes = {
|
|
114
|
-
classes: PropTypes.object.isRequired,
|
|
115
174
|
noLabels: PropTypes.bool,
|
|
116
175
|
useLetterOrdering: PropTypes.bool,
|
|
117
176
|
className: PropTypes.string,
|
|
@@ -201,7 +260,6 @@ export class ChoiceConfiguration extends React.Component {
|
|
|
201
260
|
render() {
|
|
202
261
|
const {
|
|
203
262
|
data,
|
|
204
|
-
classes,
|
|
205
263
|
mode,
|
|
206
264
|
onDelete,
|
|
207
265
|
defaultFeedback,
|
|
@@ -227,139 +285,79 @@ export class ChoiceConfiguration extends React.Component {
|
|
|
227
285
|
} = this.props;
|
|
228
286
|
|
|
229
287
|
const InputToggle = mode === 'checkbox' ? InputCheckbox : InputRadio;
|
|
230
|
-
const names = classNames(classes.choiceConfiguration, className);
|
|
231
288
|
|
|
232
289
|
return (
|
|
233
|
-
<
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
)}
|
|
290
|
+
<StyledTopRow>
|
|
291
|
+
{index > 0 && (
|
|
292
|
+
<StyledIndex type="title">
|
|
293
|
+
{useLetterOrdering ? String.fromCharCode(96 + index).toUpperCase() : index}
|
|
294
|
+
</StyledIndex>
|
|
295
|
+
)}
|
|
240
296
|
|
|
297
|
+
<StyledToggle>
|
|
241
298
|
<InputToggle
|
|
242
|
-
className={classes.toggle}
|
|
243
299
|
onChange={this.onCheckedChange}
|
|
244
300
|
label={!noLabels ? 'Correct' : ''}
|
|
245
301
|
checked={!!data.correct}
|
|
246
302
|
error={noCorrectAnswerError}
|
|
247
303
|
/>
|
|
304
|
+
</StyledToggle>
|
|
305
|
+
|
|
306
|
+
<StyledMiddleColumn>
|
|
307
|
+
<EditableHtmlContainer
|
|
308
|
+
label={!noLabels ? 'Label' : ''}
|
|
309
|
+
value={data.label}
|
|
310
|
+
onChange={this.onLabelChange}
|
|
311
|
+
imageSupport={imageSupport}
|
|
312
|
+
disableImageAlignmentButtons={disableImageAlignmentButtons}
|
|
313
|
+
disabled={disabled}
|
|
314
|
+
spellCheck={spellCheck}
|
|
315
|
+
nonEmpty={nonEmpty}
|
|
316
|
+
pluginOpts={pluginOpts}
|
|
317
|
+
toolbarOpts={toolbarOpts}
|
|
318
|
+
error={error}
|
|
319
|
+
uploadSoundSupport={uploadSoundSupport}
|
|
320
|
+
mathMlOptions={mathMlOptions}
|
|
321
|
+
maxImageWidth={maxImageWidth}
|
|
322
|
+
maxImageHeight={maxImageHeight}
|
|
323
|
+
/>
|
|
324
|
+
{error && <StyledErrorText>{error}</StyledErrorText>}
|
|
248
325
|
|
|
249
|
-
|
|
250
|
-
<
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
onChange={this.
|
|
255
|
-
imageSupport={imageSupport}
|
|
256
|
-
disableImageAlignmentButtons={disableImageAlignmentButtons}
|
|
257
|
-
disabled={disabled}
|
|
258
|
-
spellCheck={spellCheck}
|
|
259
|
-
nonEmpty={nonEmpty}
|
|
260
|
-
pluginOpts={pluginOpts}
|
|
326
|
+
{allowFeedBack && (
|
|
327
|
+
<Feedback
|
|
328
|
+
{...data.feedback}
|
|
329
|
+
correct={data.correct}
|
|
330
|
+
defaults={defaultFeedback}
|
|
331
|
+
onChange={this.onFeedbackValueChange}
|
|
261
332
|
toolbarOpts={toolbarOpts}
|
|
262
|
-
error={error}
|
|
263
|
-
uploadSoundSupport={uploadSoundSupport}
|
|
264
|
-
mathMlOptions={mathMlOptions}
|
|
265
|
-
maxImageWidth={maxImageWidth}
|
|
266
|
-
maxImageHeight={maxImageHeight}
|
|
267
333
|
/>
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
{allowFeedBack && (
|
|
271
|
-
<Feedback
|
|
272
|
-
{...data.feedback}
|
|
273
|
-
correct={data.correct}
|
|
274
|
-
defaults={defaultFeedback}
|
|
275
|
-
onChange={this.onFeedbackValueChange}
|
|
276
|
-
toolbarOpts={toolbarOpts}
|
|
277
|
-
/>
|
|
278
|
-
)}
|
|
279
|
-
</div>
|
|
334
|
+
)}
|
|
335
|
+
</StyledMiddleColumn>
|
|
280
336
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
value={data.feedback}
|
|
286
|
-
|
|
287
|
-
icon: classes.feedbackIcon,
|
|
288
|
-
}}
|
|
289
|
-
/>
|
|
337
|
+
{allowFeedBack && (
|
|
338
|
+
<StyledFeedback>
|
|
339
|
+
<InputContainer label={!noLabels ? 'Feedback' : ''}>
|
|
340
|
+
<StyledFeedbackIcon>
|
|
341
|
+
<FeedbackMenu onChange={this.onFeedbackTypeChange} value={data.feedback} />
|
|
342
|
+
</StyledFeedbackIcon>
|
|
290
343
|
</InputContainer>
|
|
291
|
-
|
|
344
|
+
</StyledFeedback>
|
|
345
|
+
)}
|
|
292
346
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
347
|
+
{allowDelete && (
|
|
348
|
+
<StyledDelete>
|
|
349
|
+
<InputContainer label={!noLabels ? 'Delete' : ''}>
|
|
350
|
+
<StyledDeleteIcon>
|
|
351
|
+
<IconButton aria-label="delete" onClick={onDelete} size="large">
|
|
352
|
+
<ActionDelete />
|
|
353
|
+
</IconButton>
|
|
354
|
+
</StyledDeleteIcon>
|
|
298
355
|
</InputContainer>
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
</
|
|
356
|
+
</StyledDelete>
|
|
357
|
+
)}
|
|
358
|
+
</StyledTopRow>
|
|
302
359
|
);
|
|
303
360
|
}
|
|
304
361
|
}
|
|
305
362
|
|
|
306
|
-
|
|
307
|
-
index: {
|
|
308
|
-
paddingRight: theme.spacing.unit,
|
|
309
|
-
paddingTop: theme.spacing.unit * 3.5,
|
|
310
|
-
},
|
|
311
|
-
choiceConfiguration: {},
|
|
312
|
-
topRow: {
|
|
313
|
-
display: 'flex',
|
|
314
|
-
},
|
|
315
|
-
value: {
|
|
316
|
-
flex: '0.5',
|
|
317
|
-
paddingRight: theme.spacing.unit,
|
|
318
|
-
},
|
|
319
|
-
editorHolder: {
|
|
320
|
-
marginTop: theme.spacing.unit * 2,
|
|
321
|
-
},
|
|
322
|
-
toggle: {
|
|
323
|
-
flex: '0 1 auto',
|
|
324
|
-
paddingTop: theme.spacing.unit / 2,
|
|
325
|
-
paddingBottom: 0,
|
|
326
|
-
marginRight: 0,
|
|
327
|
-
marginLeft: theme.spacing.unit,
|
|
328
|
-
},
|
|
329
|
-
feedback: {
|
|
330
|
-
flex: '0 1 auto',
|
|
331
|
-
paddingTop: theme.spacing.unit * 2,
|
|
332
|
-
paddingLeft: 0,
|
|
333
|
-
marginLeft: 0,
|
|
334
|
-
marginRight: theme.spacing.unit,
|
|
335
|
-
},
|
|
336
|
-
feedbackIcon: {
|
|
337
|
-
margin: 0,
|
|
338
|
-
width: 'inherit',
|
|
339
|
-
},
|
|
340
|
-
deleteIcon: {
|
|
341
|
-
margin: 0,
|
|
342
|
-
width: 'inherit',
|
|
343
|
-
},
|
|
344
|
-
delete: {
|
|
345
|
-
flex: '0 1 auto',
|
|
346
|
-
paddingTop: theme.spacing.unit * 2,
|
|
347
|
-
paddingLeft: 0,
|
|
348
|
-
marginLeft: 0,
|
|
349
|
-
},
|
|
350
|
-
middleColumn: {
|
|
351
|
-
display: 'flex',
|
|
352
|
-
flex: 1,
|
|
353
|
-
flexDirection: 'column',
|
|
354
|
-
marginRight: theme.spacing.unit,
|
|
355
|
-
},
|
|
356
|
-
input: {
|
|
357
|
-
marginRight: 0,
|
|
358
|
-
},
|
|
359
|
-
errorText: {
|
|
360
|
-
fontSize: theme.typography.fontSize - 2,
|
|
361
|
-
color: theme.palette.error.main,
|
|
362
|
-
},
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
export default withStyles(styles)(ChoiceConfiguration);
|
|
363
|
+
export default ChoiceConfiguration;
|
|
@@ -1,70 +1,140 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import Adapter from 'enzyme-adapter-react-16';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, within } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { FeedbackConfig, buildDefaults } from '../index';
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
// Mock FeedbackSelector to simplify testing
|
|
7
|
+
jest.mock('../feedback-selector', () => {
|
|
8
|
+
return function FeedbackSelector({ label, feedback, onChange }) {
|
|
9
|
+
return (
|
|
10
|
+
<div data-testid="feedback-selector">
|
|
11
|
+
<label>{label}</label>
|
|
12
|
+
<select
|
|
13
|
+
aria-label={label}
|
|
14
|
+
value={feedback.type}
|
|
15
|
+
onChange={(e) => onChange({ ...feedback, type: e.target.value })}
|
|
16
|
+
>
|
|
17
|
+
<option value="default">Default</option>
|
|
18
|
+
<option value="custom">Custom</option>
|
|
19
|
+
<option value="none">None</option>
|
|
20
|
+
</select>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
});
|
|
8
25
|
|
|
9
26
|
describe('FeedbackConfig', () => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const onChange = jest.fn();
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
onChange.mockClear();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('rendering', () => {
|
|
34
|
+
it('renders with default feedback types', () => {
|
|
35
|
+
const feedback = buildDefaults();
|
|
36
|
+
|
|
37
|
+
render(<FeedbackConfig feedback={feedback} onChange={onChange} />);
|
|
38
|
+
|
|
39
|
+
expect(screen.getByText('Feedback')).toBeInTheDocument();
|
|
40
|
+
expect(screen.getByText('If correct, show')).toBeInTheDocument();
|
|
41
|
+
expect(screen.getByText('If partially correct, show')).toBeInTheDocument();
|
|
42
|
+
expect(screen.getByText('If incorrect, show')).toBeInTheDocument();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('renders all three feedback selectors by default', () => {
|
|
46
|
+
const feedback = buildDefaults();
|
|
47
|
+
|
|
48
|
+
render(<FeedbackConfig feedback={feedback} onChange={onChange} />);
|
|
49
|
+
|
|
50
|
+
const selectors = screen.getAllByTestId('feedback-selector');
|
|
51
|
+
expect(selectors).toHaveLength(3);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('does not render partial feedback selector when allowPartial is false', () => {
|
|
55
|
+
const feedback = buildDefaults();
|
|
56
|
+
|
|
57
|
+
render(<FeedbackConfig allowPartial={false} feedback={feedback} onChange={onChange} />);
|
|
58
|
+
|
|
59
|
+
expect(screen.getByText('If correct, show')).toBeInTheDocument();
|
|
60
|
+
expect(screen.queryByText('If partially correct, show')).not.toBeInTheDocument();
|
|
61
|
+
expect(screen.getByText('If incorrect, show')).toBeInTheDocument();
|
|
62
|
+
|
|
63
|
+
const selectors = screen.getAllByTestId('feedback-selector');
|
|
64
|
+
expect(selectors).toHaveLength(2);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('user interactions', () => {
|
|
69
|
+
it('calls onChange when correct feedback type changes', async () => {
|
|
70
|
+
const user = userEvent.setup();
|
|
71
|
+
const feedback = buildDefaults();
|
|
72
|
+
|
|
73
|
+
render(<FeedbackConfig feedback={feedback} onChange={onChange} />);
|
|
74
|
+
|
|
75
|
+
const correctSelect = screen.getByLabelText('If correct, show');
|
|
76
|
+
await user.selectOptions(correctSelect, 'custom');
|
|
77
|
+
|
|
78
|
+
expect(onChange).toHaveBeenCalledWith(
|
|
79
|
+
expect.objectContaining({
|
|
80
|
+
correct: expect.objectContaining({ type: 'custom' }),
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('calls onChange when incorrect feedback type changes', async () => {
|
|
86
|
+
const user = userEvent.setup();
|
|
87
|
+
const feedback = buildDefaults();
|
|
88
|
+
|
|
89
|
+
render(<FeedbackConfig feedback={feedback} onChange={onChange} />);
|
|
90
|
+
|
|
91
|
+
const incorrectSelect = screen.getByLabelText('If incorrect, show');
|
|
92
|
+
await user.selectOptions(incorrectSelect, 'none');
|
|
93
|
+
|
|
94
|
+
expect(onChange).toHaveBeenCalledWith(
|
|
95
|
+
expect.objectContaining({
|
|
96
|
+
incorrect: expect.objectContaining({ type: 'none' }),
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('calls onChange when partial feedback type changes', async () => {
|
|
102
|
+
const user = userEvent.setup();
|
|
103
|
+
const feedback = buildDefaults();
|
|
104
|
+
|
|
105
|
+
render(<FeedbackConfig feedback={feedback} onChange={onChange} />);
|
|
106
|
+
|
|
107
|
+
const partialSelect = screen.getByLabelText('If partially correct, show');
|
|
108
|
+
await user.selectOptions(partialSelect, 'custom');
|
|
109
|
+
|
|
110
|
+
expect(onChange).toHaveBeenCalledWith(
|
|
111
|
+
expect.objectContaining({
|
|
112
|
+
partial: expect.objectContaining({ type: 'custom' }),
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('buildDefaults helper', () => {
|
|
119
|
+
it('returns default feedback configuration', () => {
|
|
120
|
+
const defaults = buildDefaults();
|
|
121
|
+
|
|
122
|
+
expect(defaults).toEqual({
|
|
123
|
+
correct: { type: 'default', default: 'Correct' },
|
|
124
|
+
incorrect: { type: 'default', default: 'Incorrect' },
|
|
125
|
+
partial: { type: 'default', default: 'Nearly' },
|
|
34
126
|
});
|
|
127
|
+
});
|
|
35
128
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<FeedbackConfig
|
|
40
|
-
allowPartial={false}
|
|
41
|
-
feedback={feedback}
|
|
42
|
-
defaults={defaults}
|
|
43
|
-
onChange={jest.fn()}
|
|
44
|
-
classes={{}}
|
|
45
|
-
/>,
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
selectors = component.find(FeedbackSelector);
|
|
49
|
-
|
|
50
|
-
expect(selectors.length).toEqual(2);
|
|
51
|
-
});
|
|
129
|
+
it('merges custom values with defaults', () => {
|
|
130
|
+
const defaults = buildDefaults({
|
|
131
|
+
correct: { type: 'custom', custom: 'Great job!' },
|
|
52
132
|
});
|
|
53
133
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
allowPartial={false}
|
|
59
|
-
feedback={feedback}
|
|
60
|
-
defaults={defaults}
|
|
61
|
-
onChange={jest.fn()}
|
|
62
|
-
classes={{}}
|
|
63
|
-
/>,
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
expect(component).toMatchSnapshot();
|
|
67
|
-
});
|
|
134
|
+
expect(defaults).toEqual({
|
|
135
|
+
correct: { type: 'custom', default: 'Correct', custom: 'Great job!' },
|
|
136
|
+
incorrect: { type: 'default', default: 'Incorrect' },
|
|
137
|
+
partial: { type: 'default', default: 'Nearly' },
|
|
68
138
|
});
|
|
69
139
|
});
|
|
70
140
|
});
|