@pie-lib/config-ui 12.0.0-beta.4 → 12.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.json +8 -1653
- package/CHANGELOG.md +540 -58
- package/LICENSE.md +5 -0
- package/NEXT.CHANGELOG.json +1 -0
- package/lib/alert-dialog.js +44 -20
- package/lib/alert-dialog.js.map +1 -1
- package/lib/checkbox.js +59 -61
- package/lib/checkbox.js.map +1 -1
- package/lib/choice-configuration/feedback-menu.js +30 -65
- package/lib/choice-configuration/feedback-menu.js.map +1 -1
- package/lib/choice-configuration/index.js +231 -244
- package/lib/choice-configuration/index.js.map +1 -1
- package/lib/choice-utils.js +7 -19
- package/lib/choice-utils.js.map +1 -1
- package/lib/feedback-config/feedback-selector.js +89 -115
- package/lib/feedback-config/feedback-selector.js.map +1 -1
- package/lib/feedback-config/group.js +28 -42
- package/lib/feedback-config/group.js.map +1 -1
- package/lib/feedback-config/index.js +55 -87
- package/lib/feedback-config/index.js.map +1 -1
- package/lib/form-section.js +32 -34
- package/lib/form-section.js.map +1 -1
- package/lib/help.js +41 -80
- package/lib/help.js.map +1 -1
- package/lib/index.js +2 -32
- package/lib/index.js.map +1 -1
- package/lib/input.js +24 -57
- package/lib/input.js.map +1 -1
- package/lib/inputs.js +62 -88
- package/lib/inputs.js.map +1 -1
- package/lib/langs.js +59 -102
- package/lib/langs.js.map +1 -1
- package/lib/layout/config-layout.js +95 -67
- package/lib/layout/config-layout.js.map +1 -1
- package/lib/layout/index.js +1 -4
- package/lib/layout/index.js.map +1 -1
- package/lib/layout/layout-contents.js +130 -75
- package/lib/layout/layout-contents.js.map +1 -1
- package/lib/layout/settings-box.js +28 -58
- package/lib/layout/settings-box.js.map +1 -1
- package/lib/mui-box/index.js +42 -58
- package/lib/mui-box/index.js.map +1 -1
- package/lib/number-text-field-custom.js +164 -152
- package/lib/number-text-field-custom.js.map +1 -1
- package/lib/number-text-field.js +87 -119
- package/lib/number-text-field.js.map +1 -1
- package/lib/radio-with-label.js +33 -26
- package/lib/radio-with-label.js.map +1 -1
- package/lib/settings/display-size.js +17 -33
- package/lib/settings/display-size.js.map +1 -1
- package/lib/settings/index.js +26 -46
- package/lib/settings/index.js.map +1 -1
- package/lib/settings/panel.js +202 -221
- package/lib/settings/panel.js.map +1 -1
- package/lib/settings/settings-radio-label.js +37 -29
- package/lib/settings/settings-radio-label.js.map +1 -1
- package/lib/settings/toggle.js +40 -33
- package/lib/settings/toggle.js.map +1 -1
- package/lib/tabs/index.js +26 -57
- package/lib/tabs/index.js.map +1 -1
- package/lib/tags-input/index.js +51 -100
- package/lib/tags-input/index.js.map +1 -1
- package/lib/two-choice.js +47 -91
- package/lib/two-choice.js.map +1 -1
- package/lib/with-stateful-model.js +11 -34
- package/lib/with-stateful-model.js.map +1 -1
- package/package.json +22 -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 +31 -16
- package/src/checkbox.jsx +45 -39
- 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 +15 -28
- package/src/choice-configuration/index.jsx +233 -182
- package/src/choice-utils.js +1 -1
- package/src/feedback-config/__tests__/feedback-config.test.jsx +141 -0
- package/src/feedback-config/__tests__/feedback-selector.test.jsx +107 -0
- package/src/feedback-config/feedback-selector.jsx +65 -60
- package/src/feedback-config/group.jsx +26 -29
- package/src/feedback-config/index.jsx +59 -47
- package/src/form-section.jsx +26 -18
- package/src/help.jsx +27 -36
- package/src/index.js +2 -5
- package/src/input.jsx +9 -9
- package/src/inputs.jsx +36 -50
- package/src/langs.jsx +57 -73
- 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 +70 -37
- package/src/layout/layout-contents.jsx +96 -39
- package/src/layout/settings-box.jsx +22 -21
- package/src/mui-box/index.jsx +37 -45
- package/src/number-text-field-custom.jsx +136 -81
- package/src/number-text-field.jsx +59 -37
- package/src/radio-with-label.jsx +28 -12
- package/src/settings/display-size.jsx +14 -13
- package/src/settings/index.js +20 -12
- package/src/settings/panel.jsx +147 -110
- package/src/settings/settings-radio-label.jsx +29 -13
- package/src/settings/toggle.jsx +39 -20
- package/src/tabs/index.jsx +15 -19
- package/src/tags-input/__tests__/index.test.jsx +113 -0
- package/src/tags-input/index.jsx +42 -47
- package/src/two-choice.jsx +19 -23
- package/src/with-stateful-model.jsx +5 -5
- package/README.md +0 -12
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { FeedbackSelector } from '../feedback-selector';
|
|
5
|
+
|
|
6
|
+
// Mock the editable-html component to avoid window dependencies in tests
|
|
7
|
+
jest.mock('@pie-lib/editable-html', () => {
|
|
8
|
+
return {
|
|
9
|
+
__esModule: true,
|
|
10
|
+
default: ({ markup, onChange }) => (
|
|
11
|
+
<textarea
|
|
12
|
+
data-testid="editable-html"
|
|
13
|
+
defaultValue={markup || ''}
|
|
14
|
+
onChange={(e) => onChange(e.target.value)}
|
|
15
|
+
/>
|
|
16
|
+
),
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('feedback-selector', () => {
|
|
21
|
+
let onChange;
|
|
22
|
+
|
|
23
|
+
const renderComponent = (feedback = { type: 'default', default: 'hi' }) => {
|
|
24
|
+
return render(
|
|
25
|
+
<FeedbackSelector
|
|
26
|
+
label={'Feedback'}
|
|
27
|
+
onChange={onChange}
|
|
28
|
+
feedback={feedback}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
onChange = jest.fn();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('rendering', () => {
|
|
38
|
+
it('renders feedback type selector', () => {
|
|
39
|
+
renderComponent();
|
|
40
|
+
expect(screen.getByText('Simple Feedback')).toBeInTheDocument();
|
|
41
|
+
expect(screen.getByText('No Feedback')).toBeInTheDocument();
|
|
42
|
+
expect(screen.getByText('Customized Feedback')).toBeInTheDocument();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('shows default feedback text when type is default', () => {
|
|
46
|
+
renderComponent({ type: 'default', default: 'hi' });
|
|
47
|
+
expect(screen.getByText('hi')).toBeInTheDocument();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('shows editable html when type is custom', () => {
|
|
51
|
+
renderComponent({ type: 'custom', default: 'hi', custom: 'custom text' });
|
|
52
|
+
expect(screen.getByTestId('editable-html')).toBeInTheDocument();
|
|
53
|
+
expect(screen.getByTestId('editable-html')).toHaveValue('custom text');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('does not show default feedback when type is none', () => {
|
|
57
|
+
renderComponent({ type: 'none', default: 'hi' });
|
|
58
|
+
expect(screen.queryByText('hi')).not.toBeInTheDocument();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('user interactions', () => {
|
|
63
|
+
it('calls onChange when switching to default feedback', async () => {
|
|
64
|
+
const user = userEvent.setup();
|
|
65
|
+
renderComponent({ type: 'custom', default: 'hi' });
|
|
66
|
+
|
|
67
|
+
await user.click(screen.getByLabelText('Simple Feedback'));
|
|
68
|
+
|
|
69
|
+
expect(onChange).toHaveBeenCalledWith({ type: 'default', default: 'hi' });
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('calls onChange when switching to custom feedback', async () => {
|
|
73
|
+
const user = userEvent.setup();
|
|
74
|
+
renderComponent({ type: 'default', default: 'hi' });
|
|
75
|
+
|
|
76
|
+
await user.click(screen.getByLabelText('Customized Feedback'));
|
|
77
|
+
|
|
78
|
+
expect(onChange).toHaveBeenCalledWith({ type: 'custom', default: 'hi' });
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('calls onChange when switching to no feedback', async () => {
|
|
82
|
+
const user = userEvent.setup();
|
|
83
|
+
renderComponent({ type: 'default', default: 'hi' });
|
|
84
|
+
|
|
85
|
+
await user.click(screen.getByLabelText('No Feedback'));
|
|
86
|
+
|
|
87
|
+
expect(onChange).toHaveBeenCalledWith({ type: 'none', default: 'hi' });
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('calls onChange with custom text when editing custom feedback', async () => {
|
|
91
|
+
const user = userEvent.setup();
|
|
92
|
+
renderComponent({ type: 'custom', default: 'hi', custom: '' });
|
|
93
|
+
|
|
94
|
+
const editor = screen.getByTestId('editable-html');
|
|
95
|
+
await user.clear(editor);
|
|
96
|
+
await user.type(editor, 'text');
|
|
97
|
+
|
|
98
|
+
// user.type triggers onChange for each character, so check that onChange was called
|
|
99
|
+
// and that the last call has 'text' in custom field
|
|
100
|
+
expect(onChange).toHaveBeenCalled();
|
|
101
|
+
const lastCall = onChange.mock.calls[onChange.mock.calls.length - 1][0];
|
|
102
|
+
expect(lastCall.type).toBe('custom');
|
|
103
|
+
expect(lastCall.custom).toBe('text');
|
|
104
|
+
expect(lastCall.default).toBe('hi');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -1,116 +1,121 @@
|
|
|
1
|
-
import EditableHTML from '@pie-lib/editable-html';
|
|
1
|
+
//import EditableHTML from '@pie-lib/editable-html';
|
|
2
2
|
import { InputContainer } from '@pie-lib/render-ui';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import React from 'react';
|
|
5
|
-
import {
|
|
5
|
+
import { styled } from '@mui/material/styles';
|
|
6
6
|
import Group from './group';
|
|
7
7
|
|
|
8
|
+
|
|
9
|
+
// - mathquill error window not defined
|
|
10
|
+
let EditableHtml;
|
|
11
|
+
let StyledEditableHTML;
|
|
12
|
+
if (typeof window !== 'undefined') {
|
|
13
|
+
EditableHtml = require('@pie-lib/editable-html')['default'];
|
|
14
|
+
StyledEditableHTML = styled(EditableHtml)(({ theme }) => ({
|
|
15
|
+
fontFamily: theme.typography.fontFamily,
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
|
|
8
19
|
const feedbackLabels = {
|
|
9
20
|
default: 'Simple Feedback',
|
|
10
21
|
none: 'No Feedback',
|
|
11
|
-
custom: 'Customized Feedback'
|
|
22
|
+
custom: 'Customized Feedback',
|
|
12
23
|
};
|
|
13
24
|
|
|
14
|
-
const
|
|
25
|
+
const StyledFeedbackSelector = styled('div')(({ theme }) => ({
|
|
26
|
+
marginBottom: theme.spacing(1),
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
const StyledInputContainer = styled(InputContainer)(() => ({
|
|
30
|
+
paddingBottom: 0,
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
const StyledCustomHolder = styled('div')(({ theme }) => ({
|
|
15
34
|
marginTop: '0px',
|
|
16
|
-
background:
|
|
17
|
-
padding:
|
|
18
|
-
marginBottom: theme.spacing
|
|
19
|
-
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
customHolder: holder(theme, {
|
|
36
|
-
background: '#e0dee0',
|
|
37
|
-
padding: 0
|
|
38
|
-
}),
|
|
39
|
-
defaultHolder: holder(theme, {
|
|
40
|
-
fontFamily: theme.typography.fontFamily,
|
|
41
|
-
cursor: 'default'
|
|
42
|
-
}),
|
|
43
|
-
editor: {
|
|
44
|
-
fontFamily: theme.typography.fontFamily
|
|
45
|
-
},
|
|
46
|
-
group: {
|
|
47
|
-
paddingTop: theme.spacing.unit
|
|
48
|
-
}
|
|
49
|
-
});
|
|
35
|
+
background: theme.palette.grey[300],
|
|
36
|
+
padding: 0,
|
|
37
|
+
marginBottom: theme.spacing(2),
|
|
38
|
+
borderRadius: '4px',
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
const StyledDefaultHolder = styled('div')(({ theme }) => ({
|
|
42
|
+
marginTop: '0px',
|
|
43
|
+
background: theme.palette.grey[300],
|
|
44
|
+
padding: theme.spacing(2),
|
|
45
|
+
marginBottom: theme.spacing(2),
|
|
46
|
+
borderRadius: '4px',
|
|
47
|
+
fontFamily: theme.typography.fontFamily,
|
|
48
|
+
cursor: 'default',
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
const StyledGroup = styled(Group)(({ theme }) => ({
|
|
52
|
+
paddingTop: theme.spacing(1),
|
|
53
|
+
}));
|
|
50
54
|
|
|
51
55
|
export const FeedbackType = {
|
|
52
56
|
type: PropTypes.oneOf(['default', 'custom', 'none']),
|
|
53
57
|
default: PropTypes.string,
|
|
54
|
-
custom: PropTypes.string
|
|
58
|
+
custom: PropTypes.string,
|
|
55
59
|
};
|
|
56
60
|
|
|
57
61
|
export class FeedbackSelector extends React.Component {
|
|
58
62
|
static propTypes = {
|
|
59
63
|
keys: PropTypes.arrayOf(PropTypes.string),
|
|
60
|
-
classes: PropTypes.object.isRequired,
|
|
61
64
|
label: PropTypes.string.isRequired,
|
|
62
65
|
feedback: PropTypes.shape(FeedbackType).isRequired,
|
|
63
66
|
onChange: PropTypes.func.isRequired,
|
|
64
|
-
toolbarOpts: PropTypes.object
|
|
67
|
+
toolbarOpts: PropTypes.object,
|
|
68
|
+
mathMlOptions: PropTypes.object,
|
|
65
69
|
};
|
|
66
70
|
|
|
67
|
-
changeType = type => {
|
|
71
|
+
changeType = (type) => {
|
|
68
72
|
const { onChange, feedback } = this.props;
|
|
73
|
+
|
|
69
74
|
onChange({ ...feedback, type });
|
|
70
75
|
};
|
|
71
76
|
|
|
72
|
-
changeCustom = custom => {
|
|
77
|
+
changeCustom = (custom) => {
|
|
73
78
|
const { onChange, feedback } = this.props;
|
|
79
|
+
|
|
74
80
|
onChange({ ...feedback, type: 'custom', custom });
|
|
75
81
|
};
|
|
76
82
|
|
|
77
83
|
render() {
|
|
78
|
-
const { keys,
|
|
84
|
+
const { keys, label, feedback, toolbarOpts, mathMlOptions = {} } = this.props;
|
|
79
85
|
|
|
80
86
|
const feedbackKeys = keys || Object.keys(feedbackLabels);
|
|
81
87
|
|
|
82
88
|
return (
|
|
83
|
-
<
|
|
84
|
-
<
|
|
89
|
+
<StyledFeedbackSelector>
|
|
90
|
+
<StyledInputContainer
|
|
85
91
|
label={label}
|
|
86
|
-
|
|
87
|
-
extraClasses={{ label: classes.inputContainerLabel }}
|
|
92
|
+
extraClasses={{ label: { transform: 'translateY(-20%)' } }}
|
|
88
93
|
>
|
|
89
|
-
<
|
|
90
|
-
className={classes.group}
|
|
94
|
+
<StyledGroup
|
|
91
95
|
keys={feedbackKeys}
|
|
92
96
|
label={label}
|
|
93
97
|
value={feedback.type}
|
|
94
98
|
onChange={this.changeType}
|
|
95
99
|
feedbackLabels={feedbackLabels}
|
|
96
100
|
/>
|
|
97
|
-
</
|
|
101
|
+
</StyledInputContainer>
|
|
102
|
+
|
|
98
103
|
{feedback.type === 'custom' && (
|
|
99
|
-
<
|
|
100
|
-
<
|
|
101
|
-
className={classes.editor}
|
|
104
|
+
<StyledCustomHolder>
|
|
105
|
+
<StyledEditableHTML
|
|
102
106
|
onChange={this.changeCustom}
|
|
103
107
|
markup={feedback.custom || ''}
|
|
104
108
|
toolbarOpts={toolbarOpts}
|
|
109
|
+
languageCharactersProps={[{ language: 'spanish' }, { language: 'special' }]}
|
|
110
|
+
mathMlOptions={mathMlOptions}
|
|
105
111
|
/>
|
|
106
|
-
</
|
|
112
|
+
</StyledCustomHolder>
|
|
107
113
|
)}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
</div>
|
|
114
|
+
|
|
115
|
+
{feedback.type === 'default' && <StyledDefaultHolder> {feedback.default}</StyledDefaultHolder>}
|
|
116
|
+
</StyledFeedbackSelector>
|
|
112
117
|
);
|
|
113
118
|
}
|
|
114
119
|
}
|
|
115
120
|
|
|
116
|
-
export default
|
|
121
|
+
export default FeedbackSelector;
|
|
@@ -1,44 +1,42 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
2
|
import RadioWithLabel from '../radio-with-label';
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import {
|
|
5
|
-
import classNames from 'classnames';
|
|
4
|
+
import { styled } from '@mui/material/styles';
|
|
6
5
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
const StyledChoiceHolder = styled('div')(() => ({
|
|
7
|
+
display: 'flex',
|
|
8
|
+
alignItems: 'center',
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const StyledChoice = styled('div')(() => ({
|
|
12
|
+
display: 'flex',
|
|
13
|
+
alignItems: 'center',
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
const StyledRadioWithLabel = styled(RadioWithLabel)(({ theme }) => ({
|
|
17
|
+
'& .MuiFormControlLabel-label': {
|
|
18
|
+
fontSize: theme.typography.fontSize - 2,
|
|
14
19
|
},
|
|
15
|
-
|
|
16
|
-
display: 'flex',
|
|
17
|
-
alignItems: 'center'
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
+
}));
|
|
20
21
|
|
|
21
|
-
const Group = props => {
|
|
22
|
-
const { feedbackLabels, value,
|
|
22
|
+
const Group = (props) => {
|
|
23
|
+
const { feedbackLabels, value, className, onChange, keys } = props;
|
|
23
24
|
|
|
24
25
|
return (
|
|
25
|
-
<
|
|
26
|
-
{keys.map(key => {
|
|
26
|
+
<StyledChoiceHolder className={className}>
|
|
27
|
+
{keys.map((key) => {
|
|
27
28
|
return (
|
|
28
|
-
<
|
|
29
|
-
<
|
|
29
|
+
<StyledChoice key={key}>
|
|
30
|
+
<StyledRadioWithLabel
|
|
30
31
|
value={key}
|
|
31
32
|
checked={value === key}
|
|
32
|
-
|
|
33
|
-
label: classes.radioLabel
|
|
34
|
-
}}
|
|
35
|
-
onChange={e => onChange(e.currentTarget.value)}
|
|
33
|
+
onChange={(e) => onChange(e.currentTarget.value)}
|
|
36
34
|
label={feedbackLabels[key]}
|
|
37
35
|
/>
|
|
38
|
-
</
|
|
36
|
+
</StyledChoice>
|
|
39
37
|
);
|
|
40
38
|
})}
|
|
41
|
-
</
|
|
39
|
+
</StyledChoiceHolder>
|
|
42
40
|
);
|
|
43
41
|
};
|
|
44
42
|
|
|
@@ -46,9 +44,8 @@ Group.propTypes = {
|
|
|
46
44
|
className: PropTypes.string,
|
|
47
45
|
feedbackLabels: PropTypes.object.isRequired,
|
|
48
46
|
value: PropTypes.string.isRequired,
|
|
49
|
-
classes: PropTypes.object.isRequired,
|
|
50
47
|
keys: PropTypes.arrayOf(PropTypes.string),
|
|
51
|
-
onChange: PropTypes.func
|
|
48
|
+
onChange: PropTypes.func,
|
|
52
49
|
};
|
|
53
50
|
|
|
54
|
-
export default
|
|
51
|
+
export default Group;
|
|
@@ -1,98 +1,110 @@
|
|
|
1
1
|
import FeedbackSelector, { FeedbackType } from './feedback-selector';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import Typography from '@material
|
|
9
|
-
import ExpandMoreIcon from '@
|
|
4
|
+
import { styled } from '@mui/material/styles';
|
|
5
|
+
import Accordion from '@mui/material/Accordion';
|
|
6
|
+
import AccordionSummary from '@mui/material/AccordionSummary';
|
|
7
|
+
import AccordionDetails from '@mui/material/AccordionDetails';
|
|
8
|
+
import Typography from '@mui/material/Typography';
|
|
9
|
+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
10
10
|
import merge from 'lodash/merge';
|
|
11
11
|
|
|
12
12
|
export { FeedbackSelector };
|
|
13
13
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
const StyledFeedbackContainer = styled('div')(() => ({
|
|
15
|
+
display: 'flex',
|
|
16
|
+
flex: 1,
|
|
17
|
+
flexDirection: 'column',
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
const StyledAccordionDetails = styled(AccordionDetails)(() => ({
|
|
21
|
+
paddingTop: 0,
|
|
22
|
+
paddingBottom: 0,
|
|
23
|
+
}));
|
|
20
24
|
|
|
21
|
-
export const buildDefaults = input => {
|
|
25
|
+
export const buildDefaults = (input) => {
|
|
22
26
|
return merge(
|
|
23
27
|
{},
|
|
24
28
|
{
|
|
25
29
|
correct: { type: 'default', default: 'Correct' },
|
|
26
30
|
incorrect: { type: 'default', default: 'Incorrect' },
|
|
27
|
-
partial: { type: 'default', default: 'Nearly' }
|
|
31
|
+
partial: { type: 'default', default: 'Nearly' },
|
|
28
32
|
},
|
|
29
|
-
input
|
|
33
|
+
input,
|
|
30
34
|
);
|
|
31
35
|
};
|
|
32
36
|
|
|
33
37
|
export class FeedbackConfig extends React.Component {
|
|
34
38
|
static propTypes = {
|
|
35
39
|
allowPartial: PropTypes.bool,
|
|
40
|
+
className: PropTypes.string,
|
|
36
41
|
feedback: PropTypes.shape({
|
|
37
42
|
correct: PropTypes.shape(FeedbackType),
|
|
38
43
|
incorrect: PropTypes.shape(FeedbackType),
|
|
39
|
-
partial: PropTypes.shape(FeedbackType)
|
|
44
|
+
partial: PropTypes.shape(FeedbackType),
|
|
40
45
|
}),
|
|
41
46
|
onChange: PropTypes.func.isRequired,
|
|
42
|
-
|
|
43
|
-
toolbarOpts: PropTypes.object
|
|
47
|
+
toolbarOpts: PropTypes.object,
|
|
44
48
|
};
|
|
45
49
|
|
|
46
50
|
static defaultProps = {
|
|
47
51
|
allowPartial: true,
|
|
48
|
-
feedback: buildDefaults()
|
|
52
|
+
feedback: buildDefaults(),
|
|
49
53
|
};
|
|
50
54
|
|
|
51
55
|
onChange(key, config) {
|
|
52
56
|
const { feedback, onChange } = this.props;
|
|
53
57
|
const update = { ...feedback, [key]: config };
|
|
58
|
+
|
|
54
59
|
onChange(update);
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
onCorrectChange = this.onChange.bind(this, 'correct');
|
|
63
|
+
|
|
58
64
|
onIncorrectChange = this.onChange.bind(this, 'incorrect');
|
|
65
|
+
|
|
59
66
|
onPartialChange = this.onChange.bind(this, 'partial');
|
|
60
67
|
|
|
61
68
|
render() {
|
|
62
|
-
const {
|
|
69
|
+
const { className, allowPartial, feedback, toolbarOpts } = this.props;
|
|
63
70
|
|
|
64
71
|
return (
|
|
65
|
-
<
|
|
66
|
-
<
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
<div className={className}>
|
|
73
|
+
<Accordion slotProps={{ transition: { timeout: { enter: 225, exit: 195 } } }}>
|
|
74
|
+
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
|
75
|
+
<Typography>Feedback</Typography>
|
|
76
|
+
</AccordionSummary>
|
|
77
|
+
|
|
78
|
+
<StyledAccordionDetails>
|
|
79
|
+
<StyledFeedbackContainer>
|
|
80
|
+
<FeedbackSelector
|
|
81
|
+
label="If correct, show"
|
|
82
|
+
feedback={feedback.correct}
|
|
83
|
+
onChange={this.onCorrectChange}
|
|
84
|
+
toolbarOpts={toolbarOpts}
|
|
85
|
+
/>
|
|
86
|
+
|
|
87
|
+
{allowPartial && (
|
|
88
|
+
<FeedbackSelector
|
|
89
|
+
label="If partially correct, show"
|
|
90
|
+
feedback={feedback.partial}
|
|
91
|
+
onChange={this.onPartialChange}
|
|
92
|
+
toolbarOpts={toolbarOpts}
|
|
93
|
+
/>
|
|
94
|
+
)}
|
|
95
|
+
|
|
78
96
|
<FeedbackSelector
|
|
79
|
-
label="If
|
|
80
|
-
feedback={feedback.
|
|
81
|
-
onChange={this.
|
|
97
|
+
label="If incorrect, show"
|
|
98
|
+
feedback={feedback.incorrect}
|
|
99
|
+
onChange={this.onIncorrectChange}
|
|
82
100
|
toolbarOpts={toolbarOpts}
|
|
83
101
|
/>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
onChange={this.onIncorrectChange}
|
|
89
|
-
toolbarOpts={toolbarOpts}
|
|
90
|
-
/>
|
|
91
|
-
</div>
|
|
92
|
-
</ExpansionPanelDetails>
|
|
93
|
-
</ExpansionPanel>
|
|
102
|
+
</StyledFeedbackContainer>
|
|
103
|
+
</StyledAccordionDetails>
|
|
104
|
+
</Accordion>
|
|
105
|
+
</div>
|
|
94
106
|
);
|
|
95
107
|
}
|
|
96
108
|
}
|
|
97
109
|
|
|
98
|
-
export default
|
|
110
|
+
export default FeedbackConfig;
|
package/src/form-section.jsx
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import Typography from '@mui/material/Typography';
|
|
4
|
+
import { styled } from '@mui/material/styles';
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
},
|
|
11
|
-
label: {
|
|
12
|
-
marginBottom: theme.spacing.unit
|
|
13
|
-
}
|
|
14
|
-
});
|
|
6
|
+
const StyledFormSection = styled('div')(({ theme }) => ({
|
|
7
|
+
marginTop: theme.spacing(2),
|
|
8
|
+
marginBottom: theme.spacing(2),
|
|
9
|
+
}));
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
const StyledTypography = styled(Typography)(({ theme }) => ({
|
|
12
|
+
marginBottom: theme.spacing(1),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
const FormSection = ({ className, label, children, labelExtraStyle }) => (
|
|
16
|
+
<StyledFormSection className={className}>
|
|
17
|
+
<StyledTypography variant="subtitle1" style={labelExtraStyle}>
|
|
19
18
|
{label}
|
|
20
|
-
</
|
|
19
|
+
</StyledTypography>
|
|
21
20
|
{children}
|
|
22
|
-
</
|
|
23
|
-
)
|
|
21
|
+
</StyledFormSection>
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
FormSection.propTypes = {
|
|
25
|
+
className: PropTypes.string,
|
|
26
|
+
label: PropTypes.string,
|
|
27
|
+
children: PropTypes.node,
|
|
28
|
+
labelExtraStyle: PropTypes.object,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default FormSection;
|