@pie-lib/rubric 0.25.6-esmbeta.2 → 0.26.0-mui-update.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.md +37 -0
- package/lib/authoring.js +218 -298
- package/lib/authoring.js.map +1 -1
- package/lib/index.js +1 -5
- package/lib/index.js.map +1 -1
- package/lib/point-menu.js +31 -68
- package/lib/point-menu.js.map +1 -1
- package/package.json +10 -15
- package/src/authoring.jsx +143 -183
- package/src/point-menu.jsx +9 -9
- package/esm/index.css +0 -847
- package/esm/index.js +0 -63686
- package/esm/index.js.map +0 -1
- package/esm/package.json +0 -1
package/src/authoring.jsx
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import Select from '@material
|
|
8
|
-
import FormControl from '@material
|
|
9
|
-
import MenuItem from '@material
|
|
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
|
|
12
|
-
import FormGroup from '@material
|
|
13
|
-
import FormControlLabel from '@material
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
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';
|
|
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,20 @@ export const RubricType = PropTypes.shape({
|
|
|
42
41
|
rubriclessInstruction: PropTypes.string,
|
|
43
42
|
});
|
|
44
43
|
|
|
45
|
-
const MaxPoints =
|
|
46
|
-
|
|
47
|
-
|
|
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
|
|
55
|
-
<InputLabel
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
+
>
|
|
59
58
|
{range(1, max + 1).map((v) => (
|
|
60
59
|
<MenuItem key={`${v}`} value={v}>
|
|
61
60
|
{v}
|
|
@@ -64,96 +63,79 @@ const MaxPoints = withStyles((theme) => ({
|
|
|
64
63
|
</Select>
|
|
65
64
|
</FormControl>
|
|
66
65
|
);
|
|
67
|
-
}
|
|
66
|
+
};
|
|
68
67
|
|
|
69
68
|
// if the value is null or 'null', the Sample Answer input field for that point will not be dispalyed
|
|
70
69
|
// if the value is '', the Sample Answer input field will be empty
|
|
71
70
|
const checkSampleAnswer = (sampleAnswer) => sampleAnswer === null || sampleAnswer === 'null';
|
|
72
71
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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;
|
|
72
|
+
const PCContainer = styled('div')(() => ({}));
|
|
73
|
+
const Row = styled('div')(() => ({ display: 'flex', width: '100%', position: 'relative' }));
|
|
74
|
+
const EditorDiv = styled('div')(({ theme }) => ({ width: '100%', backgroundColor: `${theme.palette.common.white}` }));
|
|
75
|
+
const DragIndicatorStyled = styled(DragIndicator)(({ theme }) => ({ paddingTop: theme.spacing(1), color: grey[500] }));
|
|
76
|
+
const PointsLabel = styled(Typography)(({ theme }) => ({ color: grey[500], paddingBottom: theme.spacing(1), textTransform: 'uppercase' }));
|
|
77
|
+
const SampleAnswersEditor = styled('div')(({ theme }) => ({ paddingLeft: theme.spacing(3) }));
|
|
78
|
+
const ErrorText = styled('div')(({ theme }) => ({ fontSize: theme.typography.fontSize - 2, color: theme.palette.error.main, paddingLeft: theme.spacing(3), paddingTop: theme.spacing(1) }));
|
|
79
|
+
const PointMenuWrapper = styled('div')(() => ({ position: 'absolute', right: 0 }));
|
|
80
|
+
|
|
81
|
+
export const PointConfig = (props) => {
|
|
82
|
+
const { points, content, sampleAnswer, mathMlOptions = {}, error, pluginOpts = {} } = props;
|
|
108
83
|
const pointsLabel = `${points} ${points <= 1 ? 'pt' : 'pts'}`;
|
|
109
84
|
const showSampleAnswer = checkSampleAnswer(sampleAnswer);
|
|
110
85
|
|
|
111
86
|
return (
|
|
112
|
-
<
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
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>
|
|
87
|
+
<PCContainer>
|
|
88
|
+
<PointsLabel variant="overline">{pointsLabel}</PointsLabel>
|
|
89
|
+
<Row>
|
|
90
|
+
<DragIndicatorStyled />
|
|
91
|
+
<EditorDiv>
|
|
141
92
|
<EditableHtml
|
|
142
|
-
|
|
143
|
-
markup={sampleAnswer}
|
|
93
|
+
error={error}
|
|
144
94
|
pluginProps={pluginOpts}
|
|
145
|
-
|
|
95
|
+
markup={content}
|
|
96
|
+
onChange={props.onChange}
|
|
146
97
|
mathMlOptions={mathMlOptions}
|
|
147
98
|
/>
|
|
148
|
-
</
|
|
99
|
+
</EditorDiv>
|
|
100
|
+
<PointMenuWrapper>
|
|
101
|
+
<PointMenu showSampleAnswer={showSampleAnswer} onChange={props.onMenuChange} />
|
|
102
|
+
</PointMenuWrapper>
|
|
103
|
+
</Row>
|
|
104
|
+
{error && <ErrorText>{error}</ErrorText>}
|
|
105
|
+
{!showSampleAnswer && (
|
|
106
|
+
<SampleAnswersEditor>
|
|
107
|
+
<DragIndicatorStyled as={Typography} variant="overline">
|
|
108
|
+
Sample Response
|
|
109
|
+
</DragIndicatorStyled>
|
|
110
|
+
<EditorDiv>
|
|
111
|
+
<EditableHtml
|
|
112
|
+
markup={sampleAnswer}
|
|
113
|
+
pluginProps={pluginOpts}
|
|
114
|
+
onChange={props.onSampleChange}
|
|
115
|
+
mathMlOptions={mathMlOptions}
|
|
116
|
+
/>
|
|
117
|
+
</EditorDiv>
|
|
118
|
+
</SampleAnswersEditor>
|
|
149
119
|
)}
|
|
150
|
-
</
|
|
120
|
+
</PCContainer>
|
|
151
121
|
);
|
|
152
|
-
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const Container = styled('div')(({ theme }) => ({
|
|
125
|
+
backgroundColor: grey[200],
|
|
126
|
+
borderWidth: 1,
|
|
127
|
+
borderStyle: 'solid',
|
|
128
|
+
borderColor: grey[300],
|
|
129
|
+
padding: theme.spacing(2),
|
|
130
|
+
margin: theme.spacing(1),
|
|
131
|
+
}));
|
|
132
|
+
const InputContainerWrapper = styled('div')(({ theme }) => ({ width: '100%', paddingTop: theme.spacing(2), marginBottom: theme.spacing(2) }));
|
|
133
|
+
const Rubricless = styled('div')(() => ({ display: 'none' }));
|
|
134
|
+
const ConfigHolder = styled('div')(({ theme }) => ({ paddingTop: theme.spacing(1), paddingBottom: theme.spacing(1) }));
|
|
135
|
+
const RubricTitle = styled(Typography)(({ theme }) => ({ paddingLeft: theme.spacing(1), margin: theme.spacing(1) }));
|
|
153
136
|
|
|
154
137
|
export class RawAuthoring extends React.Component {
|
|
155
138
|
static propTypes = {
|
|
156
|
-
classes: PropTypes.object.isRequired,
|
|
157
139
|
className: PropTypes.string,
|
|
158
140
|
value: RubricType,
|
|
159
141
|
config: PropTypes.object,
|
|
@@ -265,7 +247,6 @@ export class RawAuthoring extends React.Component {
|
|
|
265
247
|
|
|
266
248
|
render() {
|
|
267
249
|
const {
|
|
268
|
-
classes,
|
|
269
250
|
className,
|
|
270
251
|
value,
|
|
271
252
|
mathMlOptions = {},
|
|
@@ -292,10 +273,10 @@ export class RawAuthoring extends React.Component {
|
|
|
292
273
|
const maxPointsValue = !rubricless ? value.points.length - 1 : maxPoints;
|
|
293
274
|
|
|
294
275
|
return (
|
|
295
|
-
<div className={
|
|
296
|
-
<
|
|
276
|
+
<div className={className}>
|
|
277
|
+
<RubricTitle variant="h5">
|
|
297
278
|
Rubric
|
|
298
|
-
</
|
|
279
|
+
</RubricTitle>
|
|
299
280
|
<FormGroup row>
|
|
300
281
|
{maxPointsEnabled && (
|
|
301
282
|
<MaxPoints
|
|
@@ -314,93 +295,72 @@ export class RawAuthoring extends React.Component {
|
|
|
314
295
|
</FormGroup>
|
|
315
296
|
|
|
316
297
|
{rubriclessInstructionEnabled && rubricless && (
|
|
317
|
-
<
|
|
318
|
-
<
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
298
|
+
<InputContainerWrapper>
|
|
299
|
+
<InputContainer label={rubriclessInstruction.label}>
|
|
300
|
+
<EditableHtml
|
|
301
|
+
markup={value.rubriclessInstruction || ''}
|
|
302
|
+
onChange={this.changeRubriclessInstruction}
|
|
303
|
+
pluginProps={pluginOpts}
|
|
304
|
+
nonEmpty={false}
|
|
305
|
+
disableUnderline
|
|
306
|
+
languageCharactersProps={[{ language: 'spanish' }, { language: 'special' }]}
|
|
307
|
+
mathMlOptions={mathMlOptions}
|
|
308
|
+
/>
|
|
309
|
+
</InputContainer>
|
|
310
|
+
</InputContainerWrapper>
|
|
329
311
|
)}
|
|
330
312
|
|
|
331
|
-
<div className={rubricless ?
|
|
332
|
-
|
|
333
|
-
<
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
{
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
313
|
+
<div className={rubricless ? undefined : undefined}>
|
|
314
|
+
{rubricless ? (
|
|
315
|
+
<Rubricless />
|
|
316
|
+
) : (
|
|
317
|
+
<Container>
|
|
318
|
+
<DragDropContext onDragEnd={this.dragEnd}>
|
|
319
|
+
<Droppable droppableId="droppable">
|
|
320
|
+
{(provided) => (
|
|
321
|
+
<div {...provided.droppableProps} ref={provided.innerRef}>
|
|
322
|
+
{value.points.map(
|
|
323
|
+
(p, index) =>
|
|
324
|
+
this.shouldRenderPoint(index, value) && (
|
|
325
|
+
<Draggable key={`${p.points}-${index}`} index={index} draggableId={index.toString()}>
|
|
326
|
+
{(provided) => (
|
|
327
|
+
<ConfigHolder
|
|
328
|
+
ref={provided.innerRef}
|
|
329
|
+
{...provided.draggableProps}
|
|
330
|
+
{...provided.dragHandleProps}
|
|
331
|
+
>
|
|
332
|
+
<PointConfig
|
|
333
|
+
points={value.points.length - 1 - index}
|
|
334
|
+
content={p}
|
|
335
|
+
error={
|
|
336
|
+
pointsDescriptorsErrors && pointsDescriptorsErrors[value.points.length - 1 - index]
|
|
337
|
+
}
|
|
338
|
+
sampleAnswer={value.sampleAnswers && value.sampleAnswers[index]}
|
|
339
|
+
onChange={(content) => this.changeContent(index, content, 'points')}
|
|
340
|
+
onSampleChange={(content) => this.changeContent(index, content, 'sampleAnswers')}
|
|
341
|
+
onMenuChange={(clickedItem) => this.onPointMenuChange(index, clickedItem)}
|
|
342
|
+
mathMlOptions={mathMlOptions}
|
|
343
|
+
pluginOpts={pluginOpts}
|
|
344
|
+
/>
|
|
345
|
+
</ConfigHolder>
|
|
346
|
+
)}
|
|
347
|
+
</Draggable>
|
|
348
|
+
),
|
|
349
|
+
)}
|
|
350
|
+
{provided.placeholder}
|
|
351
|
+
</div>
|
|
364
352
|
)}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
</DragDropContext>
|
|
353
|
+
</Droppable>
|
|
354
|
+
</DragDropContext>
|
|
355
|
+
</Container>
|
|
356
|
+
)}
|
|
370
357
|
</div>
|
|
371
358
|
</div>
|
|
372
359
|
);
|
|
373
360
|
}
|
|
374
361
|
}
|
|
375
362
|
|
|
376
|
-
|
|
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);
|
|
363
|
+
// styles migrated to styled-components above
|
|
404
364
|
|
|
405
365
|
const Reverse = (props) => {
|
|
406
366
|
const { rubricless = false, config = {}, pluginOpts = {} } = props || {};
|
|
@@ -424,7 +384,7 @@ const Reverse = (props) => {
|
|
|
424
384
|
};
|
|
425
385
|
|
|
426
386
|
return (
|
|
427
|
-
<
|
|
387
|
+
<RawAuthoring
|
|
428
388
|
value={value}
|
|
429
389
|
config={config}
|
|
430
390
|
onChange={onChange}
|
package/src/point-menu.jsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import Menu from '@material
|
|
2
|
-
import MenuItem from '@material
|
|
3
|
-
import MoreVertIcon from '@
|
|
4
|
-
import MoreHorizIcon from '@
|
|
5
|
-
import IconButton from '@material
|
|
1
|
+
import Menu from '@mui/material/Menu';
|
|
2
|
+
import MenuItem from '@mui/material/MenuItem';
|
|
3
|
+
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
|
4
|
+
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
|
|
5
|
+
import IconButton from '@mui/material/IconButton';
|
|
6
6
|
import PropTypes from 'prop-types';
|
|
7
7
|
import React from 'react';
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ export class IconMenu extends React.Component {
|
|
|
10
10
|
static propTypes = {
|
|
11
11
|
opts: PropTypes.object,
|
|
12
12
|
onClick: PropTypes.func.isRequired,
|
|
13
|
-
classes: PropTypes.object
|
|
13
|
+
classes: PropTypes.object,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
constructor(props) {
|
|
@@ -26,7 +26,7 @@ export class IconMenu extends React.Component {
|
|
|
26
26
|
handleRequestClose = () => this.setState({ open: false });
|
|
27
27
|
|
|
28
28
|
render() {
|
|
29
|
-
const { opts, onClick, classes } = this.props;
|
|
29
|
+
const { opts, onClick, classes = {} } = this.props;
|
|
30
30
|
const { open, anchorEl } = this.state;
|
|
31
31
|
const keys = Object.keys(opts) || [];
|
|
32
32
|
|
|
@@ -40,7 +40,7 @@ export class IconMenu extends React.Component {
|
|
|
40
40
|
return (
|
|
41
41
|
<div>
|
|
42
42
|
<div onClick={this.handleClick}>
|
|
43
|
-
<IconButton className={classes.icon}>
|
|
43
|
+
<IconButton className={classes.icon} size="large">
|
|
44
44
|
{open ? <MoreVertIcon color={iconColor} /> : <MoreHorizIcon color={iconColor} />}
|
|
45
45
|
</IconButton>
|
|
46
46
|
</div>
|
|
@@ -69,7 +69,7 @@ export class IconMenu extends React.Component {
|
|
|
69
69
|
export default class PointMenu extends React.Component {
|
|
70
70
|
static propTypes = {
|
|
71
71
|
onChange: PropTypes.func.isRequired,
|
|
72
|
-
classes: PropTypes.object
|
|
72
|
+
classes: PropTypes.object,
|
|
73
73
|
showSampleAnswer: PropTypes.bool.isRequired,
|
|
74
74
|
};
|
|
75
75
|
|