@pie-lib/rubric 0.28.3-next.2 → 0.28.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.
@@ -1,18 +1,41 @@
1
- import { shallow, mount } from 'enzyme';
1
+ import { render, screen } from '@testing-library/react';
2
2
  import React from 'react';
3
3
  import { RawAuthoring } from '../authoring';
4
- import { Draggable } from 'react-beautiful-dnd';
5
4
  import _ from 'lodash';
5
+ import { ThemeProvider, createTheme } from '@mui/material/styles';
6
6
 
7
- jest.mock('@pie-lib/editable-html', () => () => <div />);
7
+ // Mock dependencies
8
+ jest.mock('@pie-lib/editable-html-tip-tap', () => {
9
+ return function EditableHtml(props) {
10
+ return <div data-testid="editable-html" data-markup={props.markup} />;
11
+ };
12
+ });
8
13
 
9
- describe('Rubric', () => {
10
- let w;
14
+ jest.mock('@pie-lib/config-ui', () => ({
15
+ FeedbackConfig: ({ feedback }) => <div data-testid="feedback-config">{JSON.stringify(feedback)}</div>,
16
+ }));
11
17
 
18
+ jest.mock('@hello-pangea/dnd', () => ({
19
+ DragDropContext: ({ children }) => <div data-testid="drag-drop-context">{children}</div>,
20
+ Droppable: ({ children }) => children({ droppableProps: {}, innerRef: () => {} }, {}),
21
+ Draggable: ({ children, index }) =>
22
+ children(
23
+ {
24
+ innerRef: () => {},
25
+ draggableProps: { 'data-draggable-index': index },
26
+ dragHandleProps: {},
27
+ },
28
+ {},
29
+ ),
30
+ }));
31
+
32
+ describe('Rubric', () => {
12
33
  const points = ['nothing right', 'a teeny bit right', 'mostly right', 'bingo'];
13
34
  const sampleAnswers = [null, 'just right', 'not left', null];
14
- const wrapper = (value, opts) => {
15
- const props = {
35
+ const theme = createTheme();
36
+
37
+ const renderComponent = (value = {}, props = {}) => {
38
+ const defaultProps = {
16
39
  classes: {},
17
40
  onChange: jest.fn(),
18
41
  className: 'className',
@@ -22,38 +45,93 @@ describe('Rubric', () => {
22
45
  sampleAnswers,
23
46
  ...value,
24
47
  },
48
+ ...props,
49
+ };
50
+
51
+ return {
52
+ ...render(
53
+ <ThemeProvider theme={theme}>
54
+ <RawAuthoring {...defaultProps} />
55
+ </ThemeProvider>,
56
+ ),
57
+ onChange: defaultProps.onChange,
58
+ props: defaultProps,
25
59
  };
26
- const fn = opts && opts.mount ? mount : shallow;
27
- return fn(<RawAuthoring {...props} />, opts);
28
60
  };
29
61
 
30
62
  describe('render', () => {
31
- it('snapshot', () => {
32
- w = wrapper();
33
- expect(w).toMatchSnapshot();
63
+ it('renders rubric title and main structure', () => {
64
+ renderComponent();
65
+ expect(screen.getByText('Rubric')).toBeInTheDocument();
66
+ expect(screen.getByLabelText('Max Points')).toBeInTheDocument();
67
+ expect(screen.getByLabelText('Exclude zeros')).toBeInTheDocument();
68
+ });
69
+
70
+ it('renders all point configurations', () => {
71
+ const { container } = renderComponent();
72
+ // Verify DragDropContext is rendered
73
+ expect(container.querySelector('[data-testid="drag-drop-context"]')).toBeInTheDocument();
74
+
75
+ // Check that point labels are rendered (4 points = "3 pts", "2 pts", "1 pt", "0 pt")
76
+ // Note: The PointConfig component uses singular "pt" for 0 and 1, plural "pts" for 2+
77
+ expect(screen.getByText('3 pts')).toBeInTheDocument();
78
+ expect(screen.getByText('2 pts')).toBeInTheDocument();
79
+ expect(screen.getByText('1 pt')).toBeInTheDocument();
80
+ expect(screen.getByText('0 pt')).toBeInTheDocument();
34
81
  });
35
82
 
36
83
  describe('draggable', () => {
37
- it('renders correctly for excluded zeroes', () => {
38
- let w = wrapper({ excludeZero: true }, { mount: true });
39
- expect(w.find(Draggable).length).toEqual(3);
84
+ it('renders 3 draggable items when excludeZero is true', () => {
85
+ const { container } = renderComponent({ excludeZero: true });
86
+
87
+ // When excludeZero is true, the last point (0 pts) should not be rendered
88
+ // So we should have 3 draggable items
89
+ const draggableItems = container.querySelectorAll('[data-draggable-index]');
90
+ expect(draggableItems.length).toEqual(3);
91
+
92
+ // Verify the 0 pt label is not rendered
93
+ expect(screen.queryByText('0 pt')).not.toBeInTheDocument();
40
94
  });
41
- it('renders correctly for excluded zeroes', () => {
42
- let w = wrapper({ excludeZero: false }, { mount: true });
43
- expect(w.find(Draggable).length).toEqual(4);
95
+
96
+ it('renders 4 draggable items when excludeZero is false', () => {
97
+ const { container } = renderComponent({ excludeZero: false });
98
+
99
+ // When excludeZero is false, all points including 0 should be rendered
100
+ const draggableItems = container.querySelectorAll('[data-draggable-index]');
101
+ expect(draggableItems.length).toEqual(4);
102
+
103
+ // Verify all point labels are rendered
104
+ expect(screen.getByText('3 pts')).toBeInTheDocument();
105
+ expect(screen.getByText('2 pts')).toBeInTheDocument();
106
+ expect(screen.getByText('1 pt')).toBeInTheDocument();
107
+ expect(screen.getByText('0 pt')).toBeInTheDocument();
44
108
  });
45
109
  });
46
110
  });
47
111
 
48
112
  describe('logic', () => {
49
- describe('rendering', () => {});
50
-
51
113
  describe('changeMaxPoints', () => {
52
- const assertChangeMax = (points, excludeZero, expectedPoints, expectedSampleAnswers) => {
53
- it(`${points} calls onChange with: ${expectedPoints} and ${expectedSampleAnswers}`, () => {
54
- let w = wrapper({ excludeZero });
55
- w.instance().changeMaxPoints(points);
56
- expect(w.instance().props.onChange).toHaveBeenCalledWith({
114
+ const testChangeMaxPoints = (maxPoints, excludeZero, expectedPoints, expectedSampleAnswers) => {
115
+ it(`maxPoints=${maxPoints}, excludeZero=${excludeZero} calls onChange correctly`, () => {
116
+ const { onChange, container } = renderComponent({ excludeZero });
117
+
118
+ // Get the component instance through the container
119
+ // We need to call the method directly since we're testing internal behavior
120
+ const instance = container.querySelector('[class*="MuiBox-root"]')?._owner;
121
+
122
+ // Since we can't easily access instance methods in RTL, we'll test the behavior
123
+ // by verifying the onChange prop receives the correct values
124
+ // For now, we'll directly test the logic
125
+ const component = new RawAuthoring({
126
+ value: { excludeZero, points, sampleAnswers },
127
+ onChange,
128
+ classes: {},
129
+ className: 'className',
130
+ });
131
+
132
+ component.changeMaxPoints(maxPoints);
133
+
134
+ expect(onChange).toHaveBeenCalledWith({
57
135
  excludeZero,
58
136
  points: expectedPoints,
59
137
  sampleAnswers: expectedSampleAnswers,
@@ -62,19 +140,29 @@ describe('Rubric', () => {
62
140
  });
63
141
  };
64
142
 
65
- assertChangeMax(1, false, _.takeRight(points, 2), _.takeRight(sampleAnswers, 2));
66
- assertChangeMax(1, true, _.takeRight(points, 2), _.takeRight(sampleAnswers, 2));
67
- assertChangeMax(2, true, _.takeRight(points, 3), _.takeRight(sampleAnswers, 3));
68
- assertChangeMax(2, false, _.takeRight(points, 3), _.takeRight(sampleAnswers, 3));
69
- assertChangeMax(5, false, ['', ''].concat(points), [null, null].concat(sampleAnswers));
143
+ testChangeMaxPoints(1, false, _.takeRight(points, 2), _.takeRight(sampleAnswers, 2));
144
+ testChangeMaxPoints(1, true, _.takeRight(points, 2), _.takeRight(sampleAnswers, 2));
145
+ testChangeMaxPoints(2, true, _.takeRight(points, 3), _.takeRight(sampleAnswers, 3));
146
+ testChangeMaxPoints(2, false, _.takeRight(points, 3), _.takeRight(sampleAnswers, 3));
147
+ testChangeMaxPoints(5, false, ['', ''].concat(points), [null, null].concat(sampleAnswers));
70
148
  });
71
149
 
72
150
  describe('changeSampleResponse', () => {
73
- const assertChangeSample = (index, clickedItem, excludeZero, expectedPoints, expectedSampleAnswers) => {
74
- it(`Point ${index} calls onChange with: ${expectedPoints} and ${expectedSampleAnswers}`, () => {
75
- let w = wrapper({ excludeZero });
76
- w.instance().onPointMenuChange(index, clickedItem);
77
- expect(w.instance().props.onChange).toHaveBeenCalledWith({
151
+ const testChangeSampleResponse = (index, clickedItem, excludeZero, expectedPoints, expectedSampleAnswers) => {
152
+ it(`Point ${index} with clickedItem="${clickedItem}" calls onChange correctly`, () => {
153
+ const { onChange } = renderComponent({ excludeZero });
154
+
155
+ // Test the logic by creating a component instance and calling the method
156
+ const component = new RawAuthoring({
157
+ value: { excludeZero, points, sampleAnswers },
158
+ onChange,
159
+ classes: {},
160
+ className: 'className',
161
+ });
162
+
163
+ component.onPointMenuChange(index, clickedItem);
164
+
165
+ expect(onChange).toHaveBeenCalledWith({
78
166
  excludeZero,
79
167
  points: expectedPoints,
80
168
  sampleAnswers: expectedSampleAnswers,
@@ -82,10 +170,10 @@ describe('Rubric', () => {
82
170
  });
83
171
  };
84
172
 
85
- assertChangeSample(0, 'sample', false, points, ['', 'just right', 'not left', null]);
86
- assertChangeSample(3, 'sample', false, points, [null, 'just right', 'not left', '']);
87
- assertChangeSample(1, 'sample', true, points, [null, null, 'not left', null]);
88
- assertChangeSample(3, 'sample', true, points, [null, 'just right', 'not left', '']);
173
+ testChangeSampleResponse(0, 'sample', false, points, ['', 'just right', 'not left', null]);
174
+ testChangeSampleResponse(3, 'sample', false, points, [null, 'just right', 'not left', '']);
175
+ testChangeSampleResponse(1, 'sample', true, points, [null, null, 'not left', null]);
176
+ testChangeSampleResponse(3, 'sample', true, points, [null, 'just right', 'not left', '']);
89
177
  });
90
178
  });
91
179
  });
package/src/authoring.jsx CHANGED
@@ -1,27 +1,26 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { withStyles } from '@material-ui/core/styles';
4
- import classNames from 'classnames';
5
- import OutlinedInput from '@material-ui/core/OutlinedInput';
6
- import InputLabel from '@material-ui/core/InputLabel';
7
- import Select from '@material-ui/core/Select';
8
- import FormControl from '@material-ui/core/FormControl';
9
- import MenuItem from '@material-ui/core/MenuItem';
3
+ import { styled } from '@mui/material/styles';
4
+
5
+ import InputLabel from '@mui/material/InputLabel';
6
+ import OutlinedInput from '@mui/material/OutlinedInput';
7
+ import Select from '@mui/material/Select';
8
+ import FormControl from '@mui/material/FormControl';
9
+ import MenuItem from '@mui/material/MenuItem';
10
10
  import times from 'lodash/times';
11
- import Checkbox from '@material-ui/core/Checkbox';
12
- import FormGroup from '@material-ui/core/FormGroup';
13
- import FormControlLabel from '@material-ui/core/FormControlLabel';
14
- import grey from '@material-ui/core/colors/grey';
15
- import Typography from '@material-ui/core/Typography';
16
- import DragIndicator from '@material-ui/icons/DragIndicator';
17
- import EditableHtml from '@pie-lib/editable-html';
18
- import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
11
+ import Checkbox from '@mui/material/Checkbox';
12
+ import FormGroup from '@mui/material/FormGroup';
13
+ import FormControlLabel from '@mui/material/FormControlLabel';
14
+ import Typography from '@mui/material/Typography';
15
+ import DragIndicator from '@mui/icons-material/DragIndicator';
16
+ import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
19
17
  import debug from 'debug';
20
18
  import takeRight from 'lodash/takeRight';
21
19
  import PointMenu from './point-menu';
22
-
23
20
  import range from 'lodash/range';
21
+ import EditableHtml from '@pie-lib/editable-html-tip-tap';
24
22
  import { InputContainer } from '@pie-lib/config-ui';
23
+ import { grey } from '@mui/material/colors';
25
24
 
26
25
  const log = debug('pie-lib:rubric:authoring');
27
26
 
@@ -42,20 +41,21 @@ export const RubricType = PropTypes.shape({
42
41
  rubriclessInstruction: PropTypes.string,
43
42
  });
44
43
 
45
- const MaxPoints = withStyles((theme) => ({
46
- formControl: {
47
- minWidth: '120px',
48
- margin: theme.spacing.unit,
49
- },
50
- }))((props) => {
51
- const { value, onChange, max, classes } = props;
44
+ const MaxPoints = (props) => {
45
+ const { value, onChange, max } = props;
46
+ const labelId = 'max-points-label';
52
47
 
53
48
  return (
54
- <FormControl className={classes.formControl} variant="outlined">
55
- <InputLabel width={100} htmlFor="...">
56
- Max Points
57
- </InputLabel>
58
- <Select value={value} onChange={(e) => onChange(e.target.value)} input={<OutlinedInput labelWidth={80} />}>
49
+ <FormControl sx={{ minWidth: 120, m: 1 }} variant="outlined">
50
+ <InputLabel id={labelId}>Max Points</InputLabel>
51
+ <Select
52
+ labelId={labelId}
53
+ label="Max Points"
54
+ value={value}
55
+ onChange={(e) => onChange(e.target.value)}
56
+ input={<OutlinedInput label="Max Points" />}
57
+ MenuProps={{ transitionDuration: { enter: 225, exit: 195 } }}
58
+ >
59
59
  {range(1, max + 1).map((v) => (
60
60
  <MenuItem key={`${v}`} value={v}>
61
61
  {v}
@@ -64,97 +64,98 @@ const MaxPoints = withStyles((theme) => ({
64
64
  </Select>
65
65
  </FormControl>
66
66
  );
67
- });
67
+ };
68
68
 
69
69
  // if the value is null or 'null', the Sample Answer input field for that point will not be dispalyed
70
70
  // if the value is '', the Sample Answer input field will be empty
71
71
  const checkSampleAnswer = (sampleAnswer) => sampleAnswer === null || sampleAnswer === 'null';
72
72
 
73
- export const PointConfig = withStyles((theme) => ({
74
- pointConfig: {},
75
- row: {
76
- display: 'flex',
77
- width: '100%',
78
- position: 'relative',
79
- },
80
- editor: {
81
- width: '100%',
82
- backgroundColor: `${theme.palette.common.white} !important`,
83
- },
84
- dragIndicator: {
85
- paddingTop: theme.spacing.unit,
86
- color: grey[500],
87
- },
88
- pointsLabel: {
89
- color: grey[500],
90
- paddingBottom: theme.spacing.unit,
91
- textTransform: 'uppercase',
92
- },
93
- sampleAnswersEditor: {
94
- paddingLeft: theme.spacing.unit * 3,
95
- },
96
- pointMenu: {
97
- position: 'absolute',
98
- right: 0,
99
- },
100
- errorText: {
101
- fontSize: theme.typography.fontSize - 2,
102
- color: theme.palette.error.main,
103
- paddingLeft: theme.spacing.unit * 3,
104
- paddingTop: theme.spacing.unit,
105
- },
106
- }))((props) => {
107
- const { points, content, classes, sampleAnswer, mathMlOptions = {}, error, pluginOpts = {} } = props;
73
+ const Row = styled('div')(() => ({ display: 'flex', width: '100%', position: 'relative' }));
74
+
75
+ const EditorDiv = styled('div')(({ theme }) => ({ width: '100%', backgroundColor: `${theme.palette.common.white}` }));
76
+
77
+ const DragIndicatorStyled = styled(DragIndicator)(({ theme }) => ({ paddingTop: theme.spacing(1), color: grey[500] }));
78
+
79
+ const PointsLabel = styled(Typography)(({ theme }) => ({
80
+ color: grey[500],
81
+ paddingBottom: theme.spacing(1),
82
+ textTransform: 'uppercase',
83
+ }));
84
+
85
+ const SampleAnswersEditor = styled('div')(({ theme }) => ({ paddingLeft: theme.spacing(3) }));
86
+
87
+ const ErrorText = styled('div')(({ theme }) => ({
88
+ fontSize: theme.typography.fontSize - 2,
89
+ color: theme.palette.error.main,
90
+ paddingLeft: theme.spacing(3),
91
+ paddingTop: theme.spacing(1),
92
+ }));
93
+
94
+ const PointMenuWrapper = styled('div')(() => ({ position: 'absolute', right: 0 }));
95
+
96
+ export const PointConfig = (props) => {
97
+ const { points, content, sampleAnswer, mathMlOptions = {}, error, pluginOpts = {} } = props;
108
98
  const pointsLabel = `${points} ${points <= 1 ? 'pt' : 'pts'}`;
109
99
  const showSampleAnswer = checkSampleAnswer(sampleAnswer);
110
100
 
111
101
  return (
112
- <div className={classes.pointConfig}>
113
- <Typography variant="overline" className={classes.pointsLabel}>
114
- {pointsLabel}
115
- </Typography>
116
-
117
- <div className={classes.row}>
118
- <DragIndicator className={classes.dragIndicator} />
119
- <EditableHtml
120
- className={classes.editor}
121
- error={error}
122
- pluginProps={pluginOpts}
123
- markup={content}
124
- onChange={props.onChange}
125
- mathMlOptions={mathMlOptions}
126
- />
127
- <PointMenu
128
- classes={{
129
- icon: classes.pointMenu,
130
- }}
131
- showSampleAnswer={showSampleAnswer}
132
- onChange={props.onMenuChange}
133
- />
134
- </div>
135
- {error && <div className={classes.errorText}>{error}</div>}
136
- {!showSampleAnswer && (
137
- <div className={classes.sampleAnswersEditor}>
138
- <Typography variant="overline" className={classes.dragIndicator}>
139
- Sample Response
140
- </Typography>
102
+ <div>
103
+ <PointsLabel variant="overline">{pointsLabel}</PointsLabel>
104
+ <Row>
105
+ <DragIndicatorStyled />
106
+ <EditorDiv>
141
107
  <EditableHtml
142
- className={classes.editor}
143
- markup={sampleAnswer}
108
+ error={error}
144
109
  pluginProps={pluginOpts}
145
- onChange={props.onSampleChange}
110
+ markup={content}
111
+ onChange={props.onChange}
146
112
  mathMlOptions={mathMlOptions}
147
113
  />
148
- </div>
114
+ </EditorDiv>
115
+ <PointMenuWrapper>
116
+ <PointMenu showSampleAnswer={showSampleAnswer} onChange={props.onMenuChange} />
117
+ </PointMenuWrapper>
118
+ </Row>
119
+ {error && <ErrorText>{error}</ErrorText>}
120
+ {!showSampleAnswer && (
121
+ <SampleAnswersEditor>
122
+ <DragIndicatorStyled as={Typography} variant="overline">
123
+ Sample Response
124
+ </DragIndicatorStyled>
125
+ <EditorDiv>
126
+ <EditableHtml
127
+ markup={sampleAnswer}
128
+ pluginProps={pluginOpts}
129
+ onChange={props.onSampleChange}
130
+ mathMlOptions={mathMlOptions}
131
+ />
132
+ </EditorDiv>
133
+ </SampleAnswersEditor>
149
134
  )}
150
135
  </div>
151
136
  );
152
- });
137
+ };
138
+
139
+ const Container = styled('div')(({ theme }) => ({
140
+ backgroundColor: grey[200],
141
+ borderWidth: 1,
142
+ borderStyle: 'solid',
143
+ borderColor: grey[300],
144
+ padding: theme.spacing(2),
145
+ margin: theme.spacing(1),
146
+ }));
147
+ const InputContainerWrapper = styled('div')(({ theme }) => ({
148
+ width: '100%',
149
+ paddingTop: theme.spacing(2),
150
+ marginBottom: theme.spacing(2),
151
+ '& MuiFormControl-root': { width: '100%' },
152
+ }));
153
+ const Rubricless = styled('div')(() => ({ display: 'none' }));
154
+ const ConfigHolder = styled('div')(({ theme }) => ({ paddingTop: theme.spacing(1), paddingBottom: theme.spacing(1) }));
155
+ const RubricTitle = styled(Typography)(({ theme }) => ({ paddingLeft: theme.spacing(1), margin: theme.spacing(1) }));
153
156
 
154
157
  export class RawAuthoring extends React.Component {
155
158
  static propTypes = {
156
- classes: PropTypes.object.isRequired,
157
- className: PropTypes.string,
158
159
  value: RubricType,
159
160
  config: PropTypes.object,
160
161
  pluginOpts: PropTypes.object,
@@ -264,15 +265,7 @@ export class RawAuthoring extends React.Component {
264
265
  };
265
266
 
266
267
  render() {
267
- const {
268
- classes,
269
- className,
270
- value,
271
- mathMlOptions = {},
272
- config = {},
273
- rubricless = false,
274
- pluginOpts = {},
275
- } = this.props;
268
+ const { value, mathMlOptions = {}, config = {}, rubricless = false, pluginOpts = {} } = this.props;
276
269
  let {
277
270
  excludeZeroEnabled = true,
278
271
  maxPointsEnabled = true,
@@ -292,10 +285,8 @@ export class RawAuthoring extends React.Component {
292
285
  const maxPointsValue = !rubricless ? value.points.length - 1 : maxPoints;
293
286
 
294
287
  return (
295
- <div className={classNames(classes.class, className)}>
296
- <Typography variant="h5" className={classes.rubricTitle}>
297
- Rubric
298
- </Typography>
288
+ <div>
289
+ <RubricTitle variant="h5">Rubric</RubricTitle>
299
290
  <FormGroup row>
300
291
  {maxPointsEnabled && (
301
292
  <MaxPoints
@@ -314,93 +305,73 @@ export class RawAuthoring extends React.Component {
314
305
  </FormGroup>
315
306
 
316
307
  {rubriclessInstructionEnabled && rubricless && (
317
- <InputContainer label={rubriclessInstruction.label} className={classes.inputContainer}>
318
- <EditableHtml
319
- className={classes.input}
320
- markup={value.rubriclessInstruction || ''}
321
- onChange={this.changeRubriclessInstruction}
322
- pluginProps={pluginOpts}
323
- nonEmpty={false}
324
- disableUnderline
325
- languageCharactersProps={[{ language: 'spanish' }, { language: 'special' }]}
326
- mathMlOptions={mathMlOptions}
327
- />
328
- </InputContainer>
308
+ <InputContainerWrapper>
309
+ <InputContainer label={rubriclessInstruction.label}>
310
+ <EditableHtml
311
+ markup={value.rubriclessInstruction || ''}
312
+ onChange={this.changeRubriclessInstruction}
313
+ pluginProps={pluginOpts}
314
+ nonEmpty={false}
315
+ disableUnderline
316
+ languageCharactersProps={[{ language: 'spanish' }, { language: 'special' }]}
317
+ mathMlOptions={mathMlOptions}
318
+ />
319
+ </InputContainer>
320
+ </InputContainerWrapper>
329
321
  )}
330
322
 
331
- <div className={rubricless ? classes.rubricless : classes.container}>
332
- <DragDropContext onDragEnd={this.dragEnd}>
333
- <Droppable droppableId="droppable">
334
- {(provided) => (
335
- <div {...provided.droppableProps} ref={provided.innerRef}>
336
- {value.points.map(
337
- (p, index) =>
338
- this.shouldRenderPoint(index, value) && (
339
- <Draggable key={`${p.points}-${index}`} index={index} draggableId={index.toString()}>
340
- {(provided) => (
341
- <div
342
- className={classes.configHolder}
343
- ref={provided.innerRef}
344
- {...provided.draggableProps}
345
- {...provided.dragHandleProps}
346
- >
347
- <PointConfig
348
- points={value.points.length - 1 - index}
349
- content={p}
350
- error={
351
- pointsDescriptorsErrors && pointsDescriptorsErrors[value.points.length - 1 - index]
352
- }
353
- sampleAnswer={value.sampleAnswers && value.sampleAnswers[index]}
354
- onChange={(content) => this.changeContent(index, content, 'points')}
355
- onSampleChange={(content) => this.changeContent(index, content, 'sampleAnswers')}
356
- onMenuChange={(clickedItem) => this.onPointMenuChange(index, clickedItem)}
357
- mathMlOptions={mathMlOptions}
358
- pluginOpts={pluginOpts}
359
- />
360
- </div>
361
- )}
362
- </Draggable>
363
- ),
323
+ <div>
324
+ {rubricless ? (
325
+ <Rubricless />
326
+ ) : (
327
+ <Container>
328
+ <DragDropContext onDragEnd={this.dragEnd}>
329
+ <Droppable droppableId="droppable">
330
+ {(provided) => (
331
+ <div {...provided.droppableProps} ref={provided.innerRef}>
332
+ {value.points.map(
333
+ (p, index) =>
334
+ this.shouldRenderPoint(index, value) && (
335
+ <Draggable key={`${p.points}-${index}`} index={index} draggableId={index.toString()}>
336
+ {(provided) => (
337
+ <ConfigHolder
338
+ ref={provided.innerRef}
339
+ {...provided.draggableProps}
340
+ {...provided.dragHandleProps}
341
+ >
342
+ <PointConfig
343
+ points={value.points.length - 1 - index}
344
+ content={p}
345
+ error={
346
+ pointsDescriptorsErrors &&
347
+ pointsDescriptorsErrors[value.points.length - 1 - index]
348
+ }
349
+ sampleAnswer={value.sampleAnswers && value.sampleAnswers[index]}
350
+ onChange={(content) => this.changeContent(index, content, 'points')}
351
+ onSampleChange={(content) => this.changeContent(index, content, 'sampleAnswers')}
352
+ onMenuChange={(clickedItem) => this.onPointMenuChange(index, clickedItem)}
353
+ mathMlOptions={mathMlOptions}
354
+ pluginOpts={pluginOpts}
355
+ />
356
+ </ConfigHolder>
357
+ )}
358
+ </Draggable>
359
+ ),
360
+ )}
361
+ {provided.placeholder}
362
+ </div>
364
363
  )}
365
- {provided.placeholder}
366
- </div>
367
- )}
368
- </Droppable>
369
- </DragDropContext>
364
+ </Droppable>
365
+ </DragDropContext>
366
+ </Container>
367
+ )}
370
368
  </div>
371
369
  </div>
372
370
  );
373
371
  }
374
372
  }
375
373
 
376
- const styles = (theme) => ({
377
- container: {
378
- backgroundColor: grey[200],
379
- borderWidth: 1,
380
- borderStyle: 'solid',
381
- borderColor: grey[300],
382
- padding: theme.spacing.unit * 2,
383
- margin: theme.spacing.unit,
384
- },
385
- inputContainer: {
386
- width: '100%',
387
- paddingTop: theme.spacing.unit * 2,
388
- marginBottom: theme.spacing.unit * 2,
389
- },
390
- rubricless: {
391
- display: 'none',
392
- },
393
- configHolder: {
394
- paddingTop: theme.spacing.unit,
395
- paddingBottom: theme.spacing.unit,
396
- },
397
- rubricTitle: {
398
- paddingLeft: theme.spacing.unit,
399
- margin: theme.spacing.unit,
400
- },
401
- });
402
-
403
- const StyledRawAuthoring = withStyles(styles)(RawAuthoring);
374
+ // styles migrated to styled-components above
404
375
 
405
376
  const Reverse = (props) => {
406
377
  const { rubricless = false, config = {}, pluginOpts = {} } = props || {};
@@ -424,13 +395,7 @@ const Reverse = (props) => {
424
395
  };
425
396
 
426
397
  return (
427
- <StyledRawAuthoring
428
- value={value}
429
- config={config}
430
- onChange={onChange}
431
- rubricless={rubricless}
432
- pluginOpts={pluginOpts}
433
- />
398
+ <RawAuthoring value={value} config={config} onChange={onChange} rubricless={rubricless} pluginOpts={pluginOpts} />
434
399
  );
435
400
  };
436
401