@pie-lib/rubric 2.0.4-next.31 → 2.0.4-next.34

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.
Files changed (31) hide show
  1. package/CHANGELOG.json +1 -0
  2. package/CHANGELOG.md +1448 -0
  3. package/LICENSE.md +5 -0
  4. package/lib/authoring.js +496 -0
  5. package/lib/authoring.js.map +1 -0
  6. package/lib/index.js +20 -0
  7. package/lib/index.js.map +1 -0
  8. package/lib/point-menu.js +125 -0
  9. package/lib/point-menu.js.map +1 -0
  10. package/package.json +12 -35
  11. package/src/__tests__/rubric.test.jsx +373 -0
  12. package/src/authoring.jsx +413 -0
  13. package/src/index.js +9 -0
  14. package/src/point-menu.jsx +87 -0
  15. package/dist/_virtual/_rolldown/runtime.js +0 -7
  16. package/dist/authoring.d.ts +0 -62
  17. package/dist/authoring.js +0 -298
  18. package/dist/index.d.ts +0 -15
  19. package/dist/index.js +0 -9
  20. package/dist/node_modules/.bun/@babel_runtime@7.29.7/node_modules/@babel/runtime/helpers/esm/extends.js +0 -12
  21. package/dist/node_modules/.bun/@hello-pangea_dnd@18.0.1_d0d44917b9a63a72/node_modules/@hello-pangea/dnd/dist/dnd.esm.js +0 -4451
  22. package/dist/node_modules/.bun/css-box-model@1.2.1/node_modules/css-box-model/dist/css-box-model.esm.js +0 -102
  23. package/dist/node_modules/.bun/raf-schd@4.0.3/node_modules/raf-schd/dist/raf-schd.esm.js +0 -13
  24. package/dist/node_modules/.bun/react-redux@9.3.0_9e2203c65d1d5fa1/node_modules/react-redux/dist/react-redux.js +0 -471
  25. package/dist/node_modules/.bun/redux@5.0.1/node_modules/redux/dist/redux.js +0 -159
  26. package/dist/node_modules/.bun/tiny-invariant@1.3.3/node_modules/tiny-invariant/dist/esm/tiny-invariant.js +0 -11
  27. package/dist/node_modules/.bun/use-sync-external-store@1.6.0_f4eacebf2041cd4f/node_modules/use-sync-external-store/cjs/use-sync-external-store-with-selector.development.js +0 -53
  28. package/dist/node_modules/.bun/use-sync-external-store@1.6.0_f4eacebf2041cd4f/node_modules/use-sync-external-store/cjs/use-sync-external-store-with-selector.production.js +0 -51
  29. package/dist/node_modules/.bun/use-sync-external-store@1.6.0_f4eacebf2041cd4f/node_modules/use-sync-external-store/with-selector.js +0 -10
  30. package/dist/point-menu.d.ts +0 -27
  31. package/dist/point-menu.js +0 -73
@@ -0,0 +1,413 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
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
+ import { range, takeRight, times } from 'lodash-es';
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, Draggable, Droppable } from '@hello-pangea/dnd';
17
+ import debug from 'debug';
18
+ import PointMenu from './point-menu';
19
+ import EditableHtml from '@pie-lib/editable-html-tip-tap';
20
+ import { InputContainer } from '@pie-lib/config-ui';
21
+ import { grey } from '@mui/material/colors';
22
+
23
+ const log = debug('pie-lib:rubric:authoring');
24
+
25
+ const reorder = (list, startIndex, endIndex) => {
26
+ const result = Array.from(list);
27
+ const [removed] = result.splice(startIndex, 1);
28
+
29
+ result.splice(endIndex, 0, removed);
30
+
31
+ return result;
32
+ };
33
+
34
+ export const RubricType = PropTypes.shape({
35
+ excludeZero: PropTypes.bool,
36
+ points: PropTypes.arrayOf(PropTypes.string),
37
+ sampleAnswers: PropTypes.arrayOf(PropTypes.string),
38
+ maxPoints: PropTypes.number,
39
+ rubriclessInstruction: PropTypes.string,
40
+ });
41
+
42
+ const MaxPoints = (props) => {
43
+ const { value, onChange, max } = props;
44
+ const labelId = 'max-points-label';
45
+
46
+ return (
47
+ <FormControl sx={{ minWidth: 120, m: 1 }} variant="outlined">
48
+ <InputLabel id={labelId}>Max Points</InputLabel>
49
+ <Select
50
+ labelId={labelId}
51
+ label="Max Points"
52
+ value={value}
53
+ onChange={(e) => onChange(e.target.value)}
54
+ input={<OutlinedInput label="Max Points" />}
55
+ MenuProps={{ transitionDuration: { enter: 225, exit: 195 } }}
56
+ >
57
+ {range(1, max + 1).map((v) => (
58
+ <MenuItem key={`${v}`} value={v}>
59
+ {v}
60
+ </MenuItem>
61
+ ))}
62
+ </Select>
63
+ </FormControl>
64
+ );
65
+ };
66
+
67
+ // if the value is null or 'null', the Sample Answer input field for that point will not be dispalyed
68
+ // if the value is '', the Sample Answer input field will be empty
69
+ const checkSampleAnswer = (sampleAnswer) => sampleAnswer === null || sampleAnswer === 'null';
70
+
71
+ const Row = styled('div')(() => ({ display: 'flex', width: '100%', position: 'relative' }));
72
+
73
+ const EditorDiv = styled('div')(({ theme }) => ({ width: '100%', backgroundColor: `${theme.palette.common.white}` }));
74
+
75
+ const DragIndicatorStyled = styled(DragIndicator)(({ theme }) => ({ paddingTop: theme.spacing(1), color: grey[500] }));
76
+
77
+ const PointsLabel = styled(Typography)(({ theme }) => ({
78
+ color: grey[500],
79
+ paddingBottom: theme.spacing(1),
80
+ textTransform: 'uppercase',
81
+ }));
82
+
83
+ const SampleAnswersEditor = styled('div')(({ theme }) => ({ paddingLeft: theme.spacing(3) }));
84
+
85
+ const ErrorText = styled('div')(({ theme }) => ({
86
+ fontSize: theme.typography.fontSize - 2,
87
+ color: theme.palette.error.main,
88
+ paddingLeft: theme.spacing(3),
89
+ paddingTop: theme.spacing(1),
90
+ }));
91
+
92
+ const PointMenuWrapper = styled('div')(() => ({ position: 'absolute', right: 0 }));
93
+
94
+ export const PointConfig = (props) => {
95
+ const { points, content, sampleAnswer, mathMlOptions = {}, error, pluginOpts = {} } = props;
96
+ const pointsLabel = `${points} ${points <= 1 ? 'pt' : 'pts'}`;
97
+ const showSampleAnswer = checkSampleAnswer(sampleAnswer);
98
+
99
+ return (
100
+ <div>
101
+ <PointsLabel variant="overline">{pointsLabel}</PointsLabel>
102
+ <Row>
103
+ <DragIndicatorStyled />
104
+ <EditorDiv>
105
+ <EditableHtml
106
+ error={error}
107
+ pluginProps={pluginOpts}
108
+ markup={content}
109
+ onChange={props.onChange}
110
+ mathMlOptions={mathMlOptions}
111
+ />
112
+ </EditorDiv>
113
+ <PointMenuWrapper>
114
+ <PointMenu showSampleAnswer={showSampleAnswer} onChange={props.onMenuChange} />
115
+ </PointMenuWrapper>
116
+ </Row>
117
+ {error && <ErrorText>{error}</ErrorText>}
118
+ {!showSampleAnswer && (
119
+ <SampleAnswersEditor>
120
+ <DragIndicatorStyled as={Typography} variant="overline">
121
+ Sample Response
122
+ </DragIndicatorStyled>
123
+ <EditorDiv>
124
+ <EditableHtml
125
+ markup={sampleAnswer}
126
+ pluginProps={pluginOpts}
127
+ onChange={props.onSampleChange}
128
+ mathMlOptions={mathMlOptions}
129
+ />
130
+ </EditorDiv>
131
+ </SampleAnswersEditor>
132
+ )}
133
+ </div>
134
+ );
135
+ };
136
+
137
+ const Container = styled('div')(({ theme }) => ({
138
+ backgroundColor: grey[200],
139
+ borderWidth: 1,
140
+ borderStyle: 'solid',
141
+ borderColor: grey[300],
142
+ padding: theme.spacing(2),
143
+ margin: theme.spacing(1),
144
+ }));
145
+
146
+ const StyledInputContainer = styled(InputContainer)(({ theme }) => ({
147
+ width: '100%',
148
+ paddingTop: theme.spacing(2.5),
149
+ marginBottom: theme.spacing(2),
150
+ marginTop: theme.spacing(1),
151
+ '& .MuiFormControl-root': { width: '100%' },
152
+ '& > .MuiFormLabel-root.MuiInputLabel-shrink': {
153
+ fontSize: theme.typography.fontSize + 2,
154
+ transform: 'translate(0, 1.5px) scale(0.75)',
155
+ },
156
+ }));
157
+
158
+ const Rubricless = styled('div')(() => ({ display: 'none' }));
159
+ const ConfigHolder = styled('div')(({ theme }) => ({ paddingTop: theme.spacing(1), paddingBottom: theme.spacing(1) }));
160
+ const RubricTitle = styled(Typography)(({ theme }) => ({ paddingLeft: theme.spacing(1), margin: theme.spacing(1) }));
161
+
162
+ export class RawAuthoring extends React.Component {
163
+ static propTypes = {
164
+ value: RubricType,
165
+ config: PropTypes.object,
166
+ pluginOpts: PropTypes.object,
167
+ rubricless: PropTypes.bool,
168
+ onChange: PropTypes.func,
169
+ };
170
+
171
+ static defaultProps = {};
172
+
173
+ dragEnd = (result) => {
174
+ if (!result.destination) {
175
+ return;
176
+ }
177
+
178
+ const { value, onChange } = this.props;
179
+
180
+ const points = reorder(value.points, result.source.index, result.destination.index);
181
+ const sampleAnswers = reorder(value.sampleAnswers, result.source.index, result.destination.index);
182
+
183
+ onChange({ ...value, points, sampleAnswers });
184
+ };
185
+
186
+ changeRubriclessInstruction = (input) => {
187
+ const { value, onChange } = this.props;
188
+ onChange({ ...value, rubriclessInstruction: input });
189
+ };
190
+
191
+ changeMaxPoints = (maxPoints) => {
192
+ const { value, onChange, rubricless } = this.props;
193
+ const currentMax = value.points.length - 1;
194
+
195
+ log('current', currentMax, 'new: ', maxPoints);
196
+
197
+ let points, sampleAnswers;
198
+ if (maxPoints > currentMax) {
199
+ points = times(maxPoints - currentMax)
200
+ .map(() => '')
201
+ .concat(value.points);
202
+ sampleAnswers = times(maxPoints - currentMax)
203
+ .map(() => null)
204
+ .concat(value.sampleAnswers);
205
+ }
206
+
207
+ if (maxPoints < currentMax) {
208
+ log('less than');
209
+ points = takeRight(value.points, maxPoints + 1);
210
+ sampleAnswers = takeRight(value.sampleAnswers, maxPoints + 1);
211
+ }
212
+
213
+ if (points && !rubricless) {
214
+ onChange({ ...value, points, sampleAnswers, maxPoints });
215
+ } else {
216
+ onChange({ ...value, maxPoints });
217
+ }
218
+ };
219
+
220
+ changeContent = (index, content, type) => {
221
+ // type could be 'points' or 'sampleAnswers'
222
+ log(`changeModel[${type}]:`, index, content);
223
+
224
+ if (type !== 'points' && type !== 'sampleAnswers') {
225
+ return;
226
+ }
227
+
228
+ const { value, onChange } = this.props;
229
+ const items = value[type] && Array.from(value[type]);
230
+
231
+ items.splice(index, 1, content);
232
+ log(`changeModel[${type}]:`, items);
233
+
234
+ onChange({ ...value, [type]: items });
235
+ };
236
+
237
+ excludeZeros = () => {
238
+ const { value, onChange } = this.props;
239
+
240
+ onChange({ ...value, excludeZero: !value.excludeZero });
241
+ };
242
+
243
+ getPointForIndex = (index, value) => {
244
+ const maxPoint = value.excludeZero ? value.points.length - 1 + 1 : value.points.length - 1;
245
+ return maxPoint - index;
246
+ };
247
+
248
+ getMaxPoint = (value) => (value.excludeZero ? value.points.length : value.points.length - 1);
249
+
250
+ shouldRenderPoint = (index, value) => {
251
+ const point = this.getPointForIndex(index, value);
252
+ return point > 0 || !value.excludeZero;
253
+ };
254
+
255
+ onPointMenuChange = (index, clickedItem) => {
256
+ if (clickedItem === 'sample') {
257
+ const { value } = this.props;
258
+ const sampleAnswers = Array.from(value.sampleAnswers || []);
259
+
260
+ if (checkSampleAnswer(sampleAnswers[index])) {
261
+ // an empty string will display an empty Sample Answer input field
262
+ this.changeContent(index, '', 'sampleAnswers');
263
+ } else {
264
+ // when the content is null or 'null', the Sample Answer input field will not be displayed
265
+ this.changeContent(index, null, 'sampleAnswers');
266
+ }
267
+ }
268
+ };
269
+
270
+ render() {
271
+ const { value, mathMlOptions = {}, config = {}, rubricless = false, pluginOpts = {} } = this.props;
272
+ let {
273
+ excludeZeroEnabled = true,
274
+ maxPointsEnabled = true,
275
+ errors = {},
276
+ rubriclessInstructionEnabled = false,
277
+ maxPoints = 10,
278
+ } = value || {};
279
+ // rubric will contain a max value for maxPoints
280
+ const { rubriclessInstruction = {}, maxMaxPoints = 10 } = config || {};
281
+ const { pointsDescriptorsErrors } = errors || {};
282
+ if (value && Number.isFinite(value.maxPoints)) {
283
+ // eslint-disable-next-line no-console
284
+ console.warn('maxPoints is deprecated - remove from model');
285
+ }
286
+
287
+ // for rubric value is computed based on points
288
+ const maxPointsValue = rubricless ? maxPoints : value.excludeZero ? value.points.length : value.points.length - 1;
289
+
290
+ return (
291
+ <div>
292
+ <RubricTitle variant="h5">Rubric</RubricTitle>
293
+ <FormGroup row>
294
+ {maxPointsEnabled && (
295
+ <MaxPoints
296
+ max={maxMaxPoints < 100 ? maxMaxPoints : 100}
297
+ value={maxPointsValue}
298
+ onChange={this.changeMaxPoints}
299
+ pluginOpts={pluginOpts}
300
+ />
301
+ )}
302
+ {excludeZeroEnabled && (
303
+ <FormControlLabel
304
+ label="Exclude zeros"
305
+ control={<Checkbox checked={value.excludeZero} onChange={this.excludeZeros} />}
306
+ />
307
+ )}
308
+ </FormGroup>
309
+
310
+ {rubriclessInstructionEnabled && rubricless && (
311
+ <StyledInputContainer label={rubriclessInstruction.label}>
312
+ <EditableHtml
313
+ markup={value.rubriclessInstruction || ''}
314
+ onChange={this.changeRubriclessInstruction}
315
+ pluginProps={pluginOpts}
316
+ nonEmpty={false}
317
+ disableUnderline
318
+ languageCharactersProps={[{ language: 'spanish' }, { language: 'special' }]}
319
+ mathMlOptions={mathMlOptions}
320
+ autoWidthToolbar
321
+ />
322
+ </StyledInputContainer>
323
+ )}
324
+
325
+ <div>
326
+ {rubricless ? (
327
+ <Rubricless />
328
+ ) : (
329
+ <Container>
330
+ <DragDropContext onDragEnd={this.dragEnd}>
331
+ <Droppable droppableId="droppable">
332
+ {(provided) => (
333
+ <div {...provided.droppableProps} ref={provided.innerRef}>
334
+ {value.points.map(
335
+ (p, index) =>
336
+ this.shouldRenderPoint(index, value) && (
337
+ <Draggable key={`${p.points}-${index}`} index={index} draggableId={index.toString()}>
338
+ {(provided) => (
339
+ <ConfigHolder
340
+ ref={provided.innerRef}
341
+ {...provided.draggableProps}
342
+ {...provided.dragHandleProps}
343
+ >
344
+ <PointConfig
345
+ points={this.getPointForIndex(index, value)}
346
+ content={p}
347
+ error={
348
+ pointsDescriptorsErrors &&
349
+ pointsDescriptorsErrors[value.points.length - 1 - index]
350
+ }
351
+ sampleAnswer={value.sampleAnswers && value.sampleAnswers[index]}
352
+ onChange={(content) => this.changeContent(index, content, 'points')}
353
+ onSampleChange={(content) => this.changeContent(index, content, 'sampleAnswers')}
354
+ onMenuChange={(clickedItem) => this.onPointMenuChange(index, clickedItem)}
355
+ mathMlOptions={mathMlOptions}
356
+ pluginOpts={pluginOpts}
357
+ />
358
+ </ConfigHolder>
359
+ )}
360
+ </Draggable>
361
+ ),
362
+ )}
363
+ {provided.placeholder}
364
+ </div>
365
+ )}
366
+ </Droppable>
367
+ </DragDropContext>
368
+ </Container>
369
+ )}
370
+ </div>
371
+ </div>
372
+ );
373
+ }
374
+ }
375
+
376
+ // styles migrated to styled-components above
377
+
378
+ const Reverse = (props) => {
379
+ const { rubricless = false, config = {}, pluginOpts = {} } = props || {};
380
+ const points = Array.from(props.value.points || []).reverse();
381
+ let sampleAnswers = Array.from(props.value.sampleAnswers || []).reverse();
382
+
383
+ if (points.length > sampleAnswers.length) {
384
+ sampleAnswers = times(points.length - sampleAnswers.length)
385
+ .map(() => null)
386
+ .concat(sampleAnswers);
387
+ }
388
+
389
+ const value = { ...props.value, points, sampleAnswers };
390
+
391
+ const onChange = (value) => {
392
+ props.onChange({
393
+ ...value,
394
+ points: Array.from(value.points || []).reverse(),
395
+ sampleAnswers: Array.from(value.sampleAnswers || []).reverse(),
396
+ });
397
+ };
398
+
399
+ return (
400
+ <RawAuthoring value={value} config={config} onChange={onChange} rubricless={rubricless} pluginOpts={pluginOpts} />
401
+ );
402
+ };
403
+
404
+ Reverse.propTypes = {
405
+ value: RubricType,
406
+ config: PropTypes.object,
407
+ pluginOpts: PropTypes.object,
408
+ rubricless: PropTypes.bool,
409
+ getIndex: PropTypes.func,
410
+ onChange: PropTypes.func,
411
+ };
412
+
413
+ export default Reverse;
package/src/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import Authoring from './authoring';
2
+
3
+ const RUBRIC_TYPES = {
4
+ SIMPLE_RUBRIC: 'simpleRubric',
5
+ MULTI_TRAIT_RUBRIC: 'multiTraitRubric',
6
+ RUBRICLESS: 'rubricless',
7
+ };
8
+
9
+ export { Authoring, RUBRIC_TYPES };
@@ -0,0 +1,87 @@
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
+ import PropTypes from 'prop-types';
7
+ import React from 'react';
8
+
9
+ export class IconMenu extends React.Component {
10
+ static propTypes = {
11
+ opts: PropTypes.object,
12
+ onClick: PropTypes.func.isRequired,
13
+ };
14
+
15
+ constructor(props) {
16
+ super(props);
17
+ this.state = {
18
+ anchorEl: undefined,
19
+ open: false,
20
+ };
21
+ }
22
+
23
+ handleClick = (event) => this.setState({ open: true, anchorEl: event.currentTarget });
24
+
25
+ handleRequestClose = () => this.setState({ open: false });
26
+
27
+ render() {
28
+ const { opts, onClick } = this.props;
29
+ const { open, anchorEl } = this.state;
30
+ const keys = Object.keys(opts) || [];
31
+
32
+ const handleMenuClick = (key) => () => {
33
+ onClick(key);
34
+ this.handleRequestClose();
35
+ };
36
+
37
+ const iconColor = open ? 'inherit' : 'disabled';
38
+
39
+ return (
40
+ <div>
41
+ <div onClick={this.handleClick}>
42
+ <IconButton size="large">
43
+ {open ? <MoreVertIcon color={iconColor} /> : <MoreHorizIcon color={iconColor} />}
44
+ </IconButton>
45
+ </div>
46
+ <Menu
47
+ id="point-menu"
48
+ anchorEl={anchorEl}
49
+ open={open}
50
+ onClose={this.handleRequestClose}
51
+ style={{ transform: 'translate(-15px, -15px)' }}
52
+ transformOrigin={{
53
+ vertical: 'center',
54
+ horizontal: 'right',
55
+ }}
56
+ >
57
+ {keys.map((k, index) => (
58
+ <MenuItem key={index} onClick={handleMenuClick(k)}>
59
+ {opts[k]}
60
+ </MenuItem>
61
+ ))}
62
+ </Menu>
63
+ </div>
64
+ );
65
+ }
66
+ }
67
+
68
+ export default class PointMenu extends React.Component {
69
+ static propTypes = {
70
+ onChange: PropTypes.func.isRequired,
71
+ showSampleAnswer: PropTypes.bool.isRequired,
72
+ };
73
+
74
+ render() {
75
+ const { onChange, showSampleAnswer } = this.props;
76
+ const sampleText = showSampleAnswer ? 'Provide Sample Response' : 'Remove Sample Response';
77
+
78
+ return (
79
+ <IconMenu
80
+ onClick={(key) => onChange(key)}
81
+ opts={{
82
+ sample: sampleText,
83
+ }}
84
+ />
85
+ );
86
+ }
87
+ }
@@ -1,7 +0,0 @@
1
- //#region \0rolldown/runtime.js
2
- var e = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), t = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy < "u" ? new Proxy(e, { get: (e, t) => (typeof require < "u" ? require : e)[t] }) : e)(function(e) {
3
- if (typeof require < "u") return require.apply(this, arguments);
4
- throw Error("Calling `require` for \"" + e + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
5
- });
6
- //#endregion
7
- export { e as __commonJSMin, t as __require };
@@ -1,62 +0,0 @@
1
- /**
2
- * @synced-from pie-lib/packages/rubric/src/authoring.jsx
3
- * @auto-generated
4
- *
5
- * This file is automatically synced from pie-elements and converted to TypeScript.
6
- * Manual edits will be overwritten on next sync.
7
- * To make changes, edit the upstream JavaScript file and run sync again.
8
- */
9
- import React from 'react';
10
- import PropTypes from 'prop-types';
11
- export declare const RubricType: PropTypes.Requireable<PropTypes.InferProps<{
12
- excludeZero: PropTypes.Requireable<boolean>;
13
- points: PropTypes.Requireable<(string | null | undefined)[]>;
14
- sampleAnswers: PropTypes.Requireable<(string | null | undefined)[]>;
15
- maxPoints: PropTypes.Requireable<number>;
16
- rubriclessInstruction: PropTypes.Requireable<string>;
17
- }>>;
18
- export declare const PointConfig: (props: any) => React.JSX.Element;
19
- export declare class RawAuthoring extends React.Component {
20
- static propTypes: {
21
- value: PropTypes.Requireable<PropTypes.InferProps<{
22
- excludeZero: PropTypes.Requireable<boolean>;
23
- points: PropTypes.Requireable<(string | null | undefined)[]>;
24
- sampleAnswers: PropTypes.Requireable<(string | null | undefined)[]>;
25
- maxPoints: PropTypes.Requireable<number>;
26
- rubriclessInstruction: PropTypes.Requireable<string>;
27
- }>>;
28
- config: PropTypes.Requireable<object>;
29
- pluginOpts: PropTypes.Requireable<object>;
30
- rubricless: PropTypes.Requireable<boolean>;
31
- onChange: PropTypes.Requireable<(...args: any[]) => any>;
32
- };
33
- static defaultProps: {};
34
- dragEnd: any;
35
- changeRubriclessInstruction: any;
36
- changeMaxPoints: any;
37
- changeContent: any;
38
- excludeZeros: any;
39
- getPointForIndex: any;
40
- getMaxPoint: (value: any) => any;
41
- shouldRenderPoint: any;
42
- onPointMenuChange: any;
43
- render(): React.JSX.Element;
44
- }
45
- declare const Reverse: {
46
- (props: any): React.JSX.Element;
47
- propTypes: {
48
- value: PropTypes.Requireable<PropTypes.InferProps<{
49
- excludeZero: PropTypes.Requireable<boolean>;
50
- points: PropTypes.Requireable<(string | null | undefined)[]>;
51
- sampleAnswers: PropTypes.Requireable<(string | null | undefined)[]>;
52
- maxPoints: PropTypes.Requireable<number>;
53
- rubriclessInstruction: PropTypes.Requireable<string>;
54
- }>>;
55
- config: PropTypes.Requireable<object>;
56
- pluginOpts: PropTypes.Requireable<object>;
57
- rubricless: PropTypes.Requireable<boolean>;
58
- getIndex: PropTypes.Requireable<(...args: any[]) => any>;
59
- onChange: PropTypes.Requireable<(...args: any[]) => any>;
60
- };
61
- };
62
- export default Reverse;