@khanacademy/perseus 1.3.3 → 1.3.5
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 +13 -0
- package/dist/es/index.js +119 -66
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +119 -66
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/item-renderer_test.jsx.snap +1 -1
- package/src/__tests__/__snapshots__/perseus-markdown_test.jsx.snap +111 -111
- package/src/__tests__/__snapshots__/server-item-renderer_test.jsx.snap +1 -1
- package/src/__tests__/item-renderer_test.jsx +9 -9
- package/src/__tests__/jipt-paragraphs_test.js +3 -3
- package/src/__tests__/renderer_test.jsx +22 -22
- package/src/__tests__/server-item-renderer_test.jsx +7 -7
- package/src/components/__tests__/sortable_test.jsx +7 -7
- package/src/components/input-with-examples.jsx +12 -13
- package/src/index.js +1 -0
- package/src/multi-items/__tests__/__snapshots__/multi-renderer_test.js.snap +6 -6
- package/src/multi-items/__tests__/multi-renderer_test.js +90 -90
- package/src/perseus-types.js +5 -4
- package/src/renderer.jsx +2 -2
- package/src/util.js +1 -1
- package/src/widgets/__stories__/input-number.stories.jsx +29 -3
- package/src/widgets/__tests__/__snapshots__/grapher_test.jsx.snap +68 -68
- package/src/widgets/__tests__/__snapshots__/group_test.jsx.snap +5 -5
- package/src/widgets/__tests__/__snapshots__/input-number_test.jsx.snap +1 -1
- package/src/widgets/__tests__/__snapshots__/interaction_test.jsx.snap +5 -5
- package/src/widgets/__tests__/__snapshots__/interactive-graph_test.jsx.snap +2 -2
- package/src/widgets/__tests__/__snapshots__/passage_test.jsx.snap +2 -2
- package/src/widgets/__tests__/__snapshots__/radio_test.jsx.snap +52 -52
- package/src/widgets/__tests__/categorizer_test.jsx +5 -5
- package/src/widgets/__tests__/explanation_test.js +5 -5
- package/src/widgets/__tests__/graded-group-set_test.jsx +2 -2
- package/src/widgets/__tests__/group_test.jsx +49 -49
- package/src/widgets/__tests__/numeric-input_test.jsx +5 -5
- package/src/widgets/__tests__/passage_test.jsx +1 -1
- package/src/widgets/__tests__/radio/base-radio_test.jsx +28 -1
- package/src/widgets/categorizer.jsx +1 -1
- package/src/widgets/expression.jsx +6 -6
- package/src/widgets/input-number.jsx +69 -15
- package/src/widgets/numeric-input.jsx +8 -5
- package/src/widgets/radio/base-radio.jsx +8 -3
- package/src/widgets/radio/choice-icon/library-choice-icon.jsx +2 -2
- package/src/widgets/radio/choice.jsx +1 -1
- package/src/widgets/radio/widget.jsx +2 -2
|
@@ -169,10 +169,10 @@ describe("group widget", () => {
|
|
|
169
169
|
|
|
170
170
|
// Assert
|
|
171
171
|
expect(userInput).toMatchInlineSnapshot(`
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
"choicesSelected":
|
|
172
|
+
[
|
|
173
|
+
[
|
|
174
|
+
{
|
|
175
|
+
"choicesSelected": [
|
|
176
176
|
false,
|
|
177
177
|
false,
|
|
178
178
|
false,
|
|
@@ -181,11 +181,11 @@ describe("group widget", () => {
|
|
|
181
181
|
],
|
|
182
182
|
},
|
|
183
183
|
],
|
|
184
|
-
|
|
185
|
-
|
|
184
|
+
[
|
|
185
|
+
{
|
|
186
186
|
"currentValue": "99",
|
|
187
187
|
},
|
|
188
|
-
|
|
188
|
+
{
|
|
189
189
|
"currentValue": "",
|
|
190
190
|
},
|
|
191
191
|
null,
|
|
@@ -204,32 +204,32 @@ describe("group widget", () => {
|
|
|
204
204
|
|
|
205
205
|
// Assert
|
|
206
206
|
expect(state).toMatchInlineSnapshot(`
|
|
207
|
-
|
|
208
|
-
"group 1":
|
|
209
|
-
"radio 1":
|
|
210
|
-
"choices":
|
|
211
|
-
|
|
207
|
+
{
|
|
208
|
+
"group 1": {
|
|
209
|
+
"radio 1": {
|
|
210
|
+
"choices": [
|
|
211
|
+
{
|
|
212
212
|
"content": "$45$",
|
|
213
213
|
"correct": false,
|
|
214
214
|
"originalIndex": 0,
|
|
215
215
|
},
|
|
216
|
-
|
|
216
|
+
{
|
|
217
217
|
"content": "$42$",
|
|
218
218
|
"correct": false,
|
|
219
219
|
"originalIndex": 1,
|
|
220
220
|
},
|
|
221
|
-
|
|
221
|
+
{
|
|
222
222
|
"clue": "Here's a clue, this isn't the correct answer!",
|
|
223
223
|
"content": "$30$",
|
|
224
224
|
"correct": false,
|
|
225
225
|
"originalIndex": 2,
|
|
226
226
|
},
|
|
227
|
-
|
|
227
|
+
{
|
|
228
228
|
"content": "$18$",
|
|
229
229
|
"correct": false,
|
|
230
230
|
"originalIndex": 3,
|
|
231
231
|
},
|
|
232
|
-
|
|
232
|
+
{
|
|
233
233
|
"content": "$15$",
|
|
234
234
|
"correct": true,
|
|
235
235
|
"originalIndex": 4,
|
|
@@ -240,7 +240,7 @@ describe("group widget", () => {
|
|
|
240
240
|
"hasNoneOfTheAbove": false,
|
|
241
241
|
"multipleSelect": false,
|
|
242
242
|
"numCorrect": 1,
|
|
243
|
-
"selectedChoices":
|
|
243
|
+
"selectedChoices": [
|
|
244
244
|
false,
|
|
245
245
|
false,
|
|
246
246
|
false,
|
|
@@ -249,26 +249,26 @@ describe("group widget", () => {
|
|
|
249
249
|
],
|
|
250
250
|
},
|
|
251
251
|
},
|
|
252
|
-
"group 2":
|
|
253
|
-
"image 1":
|
|
252
|
+
"group 2": {
|
|
253
|
+
"image 1": {
|
|
254
254
|
"alt": "A number line labeled 200 to 300 with tick marks at every 5 units. The tick marks at 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, and 300 are labeled. A red circle labeled A is between 220 tick mark and 230 tick mark.",
|
|
255
|
-
"backgroundImage":
|
|
255
|
+
"backgroundImage": {
|
|
256
256
|
"height": 80,
|
|
257
257
|
"url": "web+graphie://ka-perseus-graphie.s3.amazonaws.com/3351ccf19e60c28a1d08664f5c16defa76ed0348",
|
|
258
258
|
"width": 380,
|
|
259
259
|
},
|
|
260
|
-
"box":
|
|
260
|
+
"box": [
|
|
261
261
|
380,
|
|
262
262
|
80,
|
|
263
263
|
],
|
|
264
264
|
"caption": "",
|
|
265
|
-
"labels":
|
|
266
|
-
"range":
|
|
267
|
-
|
|
265
|
+
"labels": [],
|
|
266
|
+
"range": [
|
|
267
|
+
[
|
|
268
268
|
0,
|
|
269
269
|
10,
|
|
270
270
|
],
|
|
271
|
-
|
|
271
|
+
[
|
|
272
272
|
0,
|
|
273
273
|
10,
|
|
274
274
|
],
|
|
@@ -276,8 +276,8 @@ describe("group widget", () => {
|
|
|
276
276
|
"static": false,
|
|
277
277
|
"title": "",
|
|
278
278
|
},
|
|
279
|
-
"numeric-input 1":
|
|
280
|
-
"answerForms":
|
|
279
|
+
"numeric-input 1": {
|
|
280
|
+
"answerForms": [],
|
|
281
281
|
"coefficient": false,
|
|
282
282
|
"currentValue": "99",
|
|
283
283
|
"labelText": "value rounded to the nearest ten",
|
|
@@ -286,8 +286,8 @@ describe("group widget", () => {
|
|
|
286
286
|
"size": "normal",
|
|
287
287
|
"static": false,
|
|
288
288
|
},
|
|
289
|
-
"numeric-input 2":
|
|
290
|
-
"answerForms":
|
|
289
|
+
"numeric-input 2": {
|
|
290
|
+
"answerForms": [],
|
|
291
291
|
"coefficient": false,
|
|
292
292
|
"labelText": "value rounded to the nearest hundred",
|
|
293
293
|
"multipleNumberInput": false,
|
|
@@ -296,29 +296,29 @@ describe("group widget", () => {
|
|
|
296
296
|
"static": false,
|
|
297
297
|
},
|
|
298
298
|
},
|
|
299
|
-
"radio 1":
|
|
300
|
-
"choices":
|
|
301
|
-
|
|
299
|
+
"radio 1": {
|
|
300
|
+
"choices": [
|
|
301
|
+
{
|
|
302
302
|
"content": "",
|
|
303
303
|
"correct": false,
|
|
304
304
|
"originalIndex": 0,
|
|
305
305
|
},
|
|
306
|
-
|
|
306
|
+
{
|
|
307
307
|
"content": "",
|
|
308
308
|
"correct": false,
|
|
309
309
|
"originalIndex": 1,
|
|
310
310
|
},
|
|
311
|
-
|
|
311
|
+
{
|
|
312
312
|
"content": "",
|
|
313
313
|
"correct": false,
|
|
314
314
|
"originalIndex": 2,
|
|
315
315
|
},
|
|
316
|
-
|
|
316
|
+
{
|
|
317
317
|
"content": "",
|
|
318
318
|
"correct": false,
|
|
319
319
|
"originalIndex": 3,
|
|
320
320
|
},
|
|
321
|
-
|
|
321
|
+
{
|
|
322
322
|
"content": "",
|
|
323
323
|
"correct": true,
|
|
324
324
|
"originalIndex": 4,
|
|
@@ -329,7 +329,7 @@ describe("group widget", () => {
|
|
|
329
329
|
"hasNoneOfTheAbove": false,
|
|
330
330
|
"multipleSelect": false,
|
|
331
331
|
"numCorrect": 1,
|
|
332
|
-
"selectedChoices":
|
|
332
|
+
"selectedChoices": [
|
|
333
333
|
false,
|
|
334
334
|
false,
|
|
335
335
|
false,
|
|
@@ -377,11 +377,11 @@ describe("group widget", () => {
|
|
|
377
377
|
|
|
378
378
|
// Assert
|
|
379
379
|
expect(guessAndScore).toMatchInlineSnapshot(`
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
"choicesSelected":
|
|
380
|
+
[
|
|
381
|
+
[
|
|
382
|
+
[
|
|
383
|
+
{
|
|
384
|
+
"choicesSelected": [
|
|
385
385
|
false,
|
|
386
386
|
false,
|
|
387
387
|
false,
|
|
@@ -394,17 +394,17 @@ describe("group widget", () => {
|
|
|
394
394
|
"numCorrect": 1,
|
|
395
395
|
},
|
|
396
396
|
],
|
|
397
|
-
|
|
398
|
-
|
|
397
|
+
[
|
|
398
|
+
{
|
|
399
399
|
"currentValue": "230",
|
|
400
400
|
},
|
|
401
|
-
|
|
401
|
+
{
|
|
402
402
|
"currentValue": "200",
|
|
403
403
|
},
|
|
404
404
|
null,
|
|
405
405
|
],
|
|
406
406
|
],
|
|
407
|
-
|
|
407
|
+
{
|
|
408
408
|
"earned": 3,
|
|
409
409
|
"message": null,
|
|
410
410
|
"total": 3,
|
|
@@ -423,12 +423,12 @@ describe("group widget", () => {
|
|
|
423
423
|
|
|
424
424
|
// Assert
|
|
425
425
|
expect(paths).toMatchInlineSnapshot(`
|
|
426
|
-
|
|
427
|
-
|
|
426
|
+
[
|
|
427
|
+
[
|
|
428
428
|
"group 2",
|
|
429
429
|
"numeric-input 1",
|
|
430
430
|
],
|
|
431
|
-
|
|
431
|
+
[
|
|
432
432
|
"group 2",
|
|
433
433
|
"numeric-input 2",
|
|
434
434
|
],
|
|
@@ -218,7 +218,7 @@ describe("static function validate", () => {
|
|
|
218
218
|
const score = NumericInput.validate(useInput, rubric);
|
|
219
219
|
|
|
220
220
|
expect(score).toMatchInlineSnapshot(`
|
|
221
|
-
|
|
221
|
+
{
|
|
222
222
|
"earned": 1,
|
|
223
223
|
"message": null,
|
|
224
224
|
"total": 1,
|
|
@@ -252,7 +252,7 @@ describe("static function validate", () => {
|
|
|
252
252
|
const score = NumericInput.validate(useInput, rubric);
|
|
253
253
|
|
|
254
254
|
expect(score).toMatchInlineSnapshot(`
|
|
255
|
-
|
|
255
|
+
{
|
|
256
256
|
"message": "We could not understand your answer. Please check your answer for extra text or symbols.",
|
|
257
257
|
"type": "invalid",
|
|
258
258
|
}
|
|
@@ -284,7 +284,7 @@ describe("static function validate", () => {
|
|
|
284
284
|
const score = NumericInput.validate(useInput, rubric);
|
|
285
285
|
|
|
286
286
|
expect(score).toMatchInlineSnapshot(`
|
|
287
|
-
|
|
287
|
+
{
|
|
288
288
|
"earned": 1,
|
|
289
289
|
"message": null,
|
|
290
290
|
"total": 1,
|
|
@@ -318,7 +318,7 @@ describe("static function validate", () => {
|
|
|
318
318
|
const score = NumericInput.validate(useInput, rubric);
|
|
319
319
|
|
|
320
320
|
expect(score).toMatchInlineSnapshot(`
|
|
321
|
-
|
|
321
|
+
{
|
|
322
322
|
"earned": 0,
|
|
323
323
|
"message": null,
|
|
324
324
|
"total": 1,
|
|
@@ -352,7 +352,7 @@ describe("static function validate", () => {
|
|
|
352
352
|
const score = NumericInput.validate(useInput, rubric);
|
|
353
353
|
|
|
354
354
|
expect(score).toMatchInlineSnapshot(`
|
|
355
|
-
|
|
355
|
+
{
|
|
356
356
|
"earned": 1,
|
|
357
357
|
"message": null,
|
|
358
358
|
"total": 1,
|
|
@@ -132,7 +132,7 @@ describe("base-radio", () => {
|
|
|
132
132
|
expect(screen.getAllByRole("listitem")).toHaveLength(4);
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
-
it("should toggle choice when inner element clicked", () => {
|
|
135
|
+
it("should not toggle choice when inner element clicked", () => {
|
|
136
136
|
// Arrange
|
|
137
137
|
let updatedValues = null;
|
|
138
138
|
const onChangeHandler = (newValues) => {
|
|
@@ -155,6 +155,33 @@ describe("base-radio", () => {
|
|
|
155
155
|
screen.getByRole("radio", {name: "(Choice C) Option Gamma"}),
|
|
156
156
|
);
|
|
157
157
|
|
|
158
|
+
// Assert
|
|
159
|
+
expect(updatedValues).toBeNull();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("should toggle choice when choice icon clicked", () => {
|
|
163
|
+
// Arrange
|
|
164
|
+
let updatedValues = null;
|
|
165
|
+
const onChangeHandler = (newValues) => {
|
|
166
|
+
updatedValues = newValues;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
renderBaseRadio({
|
|
170
|
+
editMode: true,
|
|
171
|
+
choices: [
|
|
172
|
+
generateChoice({content: "Option 1", correct: false}),
|
|
173
|
+
generateChoice({content: "Option B", correct: false}),
|
|
174
|
+
generateChoice({content: "Option Gamma", correct: true}),
|
|
175
|
+
generateChoice({content: "Option Delta", correct: false}),
|
|
176
|
+
],
|
|
177
|
+
onChange: onChangeHandler,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Act
|
|
181
|
+
userEvent.click(
|
|
182
|
+
screen.getAllByTestId("choice-icon__library-choice-icon")[2],
|
|
183
|
+
);
|
|
184
|
+
|
|
158
185
|
// Assert
|
|
159
186
|
expect(updatedValues).toMatchObject({
|
|
160
187
|
checked: [false, false, true, false],
|
|
@@ -257,7 +257,7 @@ export class Categorizer extends React.Component<Props, State> {
|
|
|
257
257
|
const pageMargin = 16;
|
|
258
258
|
|
|
259
259
|
// Stylesheets aren't directly testable
|
|
260
|
-
/*
|
|
260
|
+
/* c8 ignore next */
|
|
261
261
|
const styles = StyleSheet.create({
|
|
262
262
|
mobileTable: {
|
|
263
263
|
[mediaQueries.smOrSmaller]: {
|
|
@@ -122,7 +122,7 @@ export class Expression extends React.Component<Props, ExpressionState> {
|
|
|
122
122
|
// incorrectly. For example if the answer is using a symbol defined
|
|
123
123
|
// in the function variables list for the expression.
|
|
124
124
|
if (!expression.parsed) {
|
|
125
|
-
/*
|
|
125
|
+
/* c8 ignore next */
|
|
126
126
|
Log.error(
|
|
127
127
|
"Unable to parse solution answer for expression",
|
|
128
128
|
PerseusErrors.InvalidInput,
|
|
@@ -365,12 +365,12 @@ export class Expression extends React.Component<Props, ExpressionState> {
|
|
|
365
365
|
};
|
|
366
366
|
|
|
367
367
|
_handleFocus: () => void = () => {
|
|
368
|
-
/*
|
|
368
|
+
/* c8 ignore next */
|
|
369
369
|
this.props.onFocus([]);
|
|
370
370
|
};
|
|
371
371
|
|
|
372
372
|
_handleBlur: () => void = () => {
|
|
373
|
-
/*
|
|
373
|
+
/* c8 ignore next */
|
|
374
374
|
this.props.onBlur([]);
|
|
375
375
|
};
|
|
376
376
|
|
|
@@ -407,7 +407,7 @@ export class Expression extends React.Component<Props, ExpressionState> {
|
|
|
407
407
|
getInputPaths: () => $ReadOnlyArray<$ReadOnlyArray<any>> = () => {
|
|
408
408
|
// The widget itself is an input, so we return a single empty list to
|
|
409
409
|
// indicate this.
|
|
410
|
-
/*
|
|
410
|
+
/* c8 ignore next */
|
|
411
411
|
return [[]];
|
|
412
412
|
};
|
|
413
413
|
|
|
@@ -415,7 +415,7 @@ export class Expression extends React.Component<Props, ExpressionState> {
|
|
|
415
415
|
getGrammarTypeForPath: (inputPath: string) => string = (
|
|
416
416
|
inputPath: string,
|
|
417
417
|
) => {
|
|
418
|
-
/*
|
|
418
|
+
/* c8 ignore next */
|
|
419
419
|
return "expression";
|
|
420
420
|
};
|
|
421
421
|
|
|
@@ -600,7 +600,7 @@ const keypadConfigurationForProps = (
|
|
|
600
600
|
};
|
|
601
601
|
|
|
602
602
|
const propUpgrades = {
|
|
603
|
-
/*
|
|
603
|
+
/* c8 ignore next */
|
|
604
604
|
"1": (v0props: $FlowFixMe): PerseusExpressionWidgetOptions => ({
|
|
605
605
|
times: v0props.times,
|
|
606
606
|
buttonSets: v0props.buttonSets,
|
|
@@ -3,14 +3,23 @@
|
|
|
3
3
|
// @flow
|
|
4
4
|
import {linterContextDefault} from "@khanacademy/perseus-linter";
|
|
5
5
|
import * as i18n from "@khanacademy/wonder-blocks-i18n";
|
|
6
|
-
import
|
|
6
|
+
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
7
|
+
import {StyleSheet} from "aphrodite";
|
|
7
8
|
import * as React from "react";
|
|
8
9
|
import _ from "underscore";
|
|
9
10
|
|
|
10
11
|
import InputWithExamples from "../components/input-with-examples.jsx";
|
|
11
12
|
import PossibleAnswers from "../components/possible-answers.jsx";
|
|
12
13
|
import SimpleKeypadInput from "../components/simple-keypad-input.jsx";
|
|
13
|
-
import {
|
|
14
|
+
import {ApiOptions} from "../perseus-api.jsx";
|
|
15
|
+
import {
|
|
16
|
+
satCorrectBackgroundColor,
|
|
17
|
+
satCorrectBorderColor,
|
|
18
|
+
satCorrectColor,
|
|
19
|
+
satIncorrectBackgroundColor,
|
|
20
|
+
satIncorrectBorderColor,
|
|
21
|
+
satIncorrectColor,
|
|
22
|
+
} from "../styles/constants.js";
|
|
14
23
|
import TexWrangler from "../tex-wrangler.js";
|
|
15
24
|
import KhanAnswerTypes from "../util/answer-types.js";
|
|
16
25
|
|
|
@@ -170,7 +179,7 @@ class InputNumber extends React.Component<Props> {
|
|
|
170
179
|
let answerBlurb = null;
|
|
171
180
|
|
|
172
181
|
// SAT is deprecated and not testable
|
|
173
|
-
/*
|
|
182
|
+
/* c8 ignore if */
|
|
174
183
|
if (this.props.apiOptions.satStyling && rubric) {
|
|
175
184
|
const score = this.simpleValidate(rubric);
|
|
176
185
|
correct = score.type === "points" && score.earned === score.total;
|
|
@@ -187,14 +196,26 @@ class InputNumber extends React.Component<Props> {
|
|
|
187
196
|
}
|
|
188
197
|
}
|
|
189
198
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
199
|
+
// Note: This is _very_ similar to what `numeric-input.jsx` does. If
|
|
200
|
+
// you modify this, double-check if you also need to modify that
|
|
201
|
+
// component.
|
|
202
|
+
const inputStyles = [
|
|
203
|
+
styles.default,
|
|
204
|
+
this.props.size === "small" ? styles.small : null,
|
|
205
|
+
this.props.rightAlign ? styles.rightAlign : styles.leftAlign,
|
|
206
|
+
];
|
|
207
|
+
// Correct
|
|
208
|
+
if (rubric && correct && this.props.currentValue) {
|
|
209
|
+
inputStyles.push(styles.answerStateCorrect);
|
|
210
|
+
}
|
|
211
|
+
// Incorrect
|
|
212
|
+
if (rubric && !correct && this.props.currentValue) {
|
|
213
|
+
inputStyles.push(styles.answerStateIncorrect);
|
|
214
|
+
}
|
|
215
|
+
// Unanswered
|
|
216
|
+
if (rubric && !this.props.currentValue) {
|
|
217
|
+
inputStyles.push(styles.answerStateUnanswered);
|
|
218
|
+
}
|
|
198
219
|
|
|
199
220
|
const input = (
|
|
200
221
|
<InputWithExamples
|
|
@@ -202,7 +223,7 @@ class InputNumber extends React.Component<Props> {
|
|
|
202
223
|
ref="input"
|
|
203
224
|
value={this.props.currentValue}
|
|
204
225
|
onChange={this.handleChange}
|
|
205
|
-
|
|
226
|
+
style={inputStyles}
|
|
206
227
|
type={this._getInputType()}
|
|
207
228
|
examples={this.examples()}
|
|
208
229
|
shouldShowExamples={this.shouldShowExamples()}
|
|
@@ -215,7 +236,7 @@ class InputNumber extends React.Component<Props> {
|
|
|
215
236
|
);
|
|
216
237
|
|
|
217
238
|
// SAT is deprecated, answer blurb is an SAT feature
|
|
218
|
-
/*
|
|
239
|
+
/* c8 ignore if */
|
|
219
240
|
if (answerBlurb) {
|
|
220
241
|
return (
|
|
221
242
|
<span className="perseus-input-with-answer-blurb">
|
|
@@ -272,14 +293,14 @@ class InputNumber extends React.Component<Props> {
|
|
|
272
293
|
getInputPaths: () => $ReadOnlyArray<Path> = () => {
|
|
273
294
|
// The widget itself is an input, so we return a single empty list to
|
|
274
295
|
// indicate this.
|
|
275
|
-
/*
|
|
296
|
+
/* c8 ignore next */
|
|
276
297
|
return [[]];
|
|
277
298
|
};
|
|
278
299
|
|
|
279
300
|
// Note: We believe that this isn't used anywhere but are leaving it during
|
|
280
301
|
// the initial refactor
|
|
281
302
|
getGrammarTypeForPath: (Path) => string = (path) => {
|
|
282
|
-
/*
|
|
303
|
+
/* c8 ignore next */
|
|
283
304
|
return "number";
|
|
284
305
|
};
|
|
285
306
|
|
|
@@ -393,6 +414,39 @@ class InputNumber extends React.Component<Props> {
|
|
|
393
414
|
}
|
|
394
415
|
}
|
|
395
416
|
|
|
417
|
+
const styles = StyleSheet.create({
|
|
418
|
+
default: {
|
|
419
|
+
width: 80,
|
|
420
|
+
height: "auto",
|
|
421
|
+
},
|
|
422
|
+
small: {
|
|
423
|
+
width: 40,
|
|
424
|
+
},
|
|
425
|
+
leftAlign: {
|
|
426
|
+
paddingLeft: Spacing.xxxSmall_4,
|
|
427
|
+
paddingRight: 0,
|
|
428
|
+
},
|
|
429
|
+
rightAlign: {
|
|
430
|
+
textAlign: "right",
|
|
431
|
+
paddingLeft: 0,
|
|
432
|
+
paddingRight: Spacing.xxxSmall_4,
|
|
433
|
+
},
|
|
434
|
+
answerStateCorrect: {
|
|
435
|
+
color: satCorrectColor,
|
|
436
|
+
backgroundColor: satCorrectBackgroundColor,
|
|
437
|
+
border: `solid 1px ${satCorrectBorderColor}`,
|
|
438
|
+
},
|
|
439
|
+
answerStateIncorrect: {
|
|
440
|
+
color: satIncorrectColor,
|
|
441
|
+
backgroundColor: satIncorrectBackgroundColor,
|
|
442
|
+
border: `solid 1px ${satIncorrectBorderColor}`,
|
|
443
|
+
},
|
|
444
|
+
answerStateUnanswered: {
|
|
445
|
+
backgroundColor: "#eee",
|
|
446
|
+
border: "solid 1px #999",
|
|
447
|
+
},
|
|
448
|
+
});
|
|
449
|
+
|
|
396
450
|
const propTransform = (
|
|
397
451
|
widgetOptions: PerseusInputNumberWidgetOptions,
|
|
398
452
|
): RenderProps => {
|
|
@@ -267,7 +267,7 @@ export class NumericInput extends React.Component<Props, State> {
|
|
|
267
267
|
let answerBlurb;
|
|
268
268
|
|
|
269
269
|
/* Ignore this block because SAT is deprecated */
|
|
270
|
-
/*
|
|
270
|
+
/* c8 ignore next */
|
|
271
271
|
if (this.props.apiOptions.satStyling && rubric) {
|
|
272
272
|
const score = this.simpleValidate(rubric);
|
|
273
273
|
correct = score.type === "points" && score.earned === score.total;
|
|
@@ -361,12 +361,12 @@ export class NumericInput extends React.Component<Props, State> {
|
|
|
361
361
|
getInputPaths: () => $ReadOnlyArray<$ReadOnlyArray<string>> = () => {
|
|
362
362
|
// The widget itself is an input, so we return a single empty list to
|
|
363
363
|
// indicate this.
|
|
364
|
-
/*
|
|
364
|
+
/* c8 ignore next */
|
|
365
365
|
return [[]];
|
|
366
366
|
};
|
|
367
367
|
|
|
368
368
|
getGrammarTypeForPath: (FocusPath) => string = (inputPath) => {
|
|
369
|
-
/*
|
|
369
|
+
/* c8 ignore next */
|
|
370
370
|
return "number";
|
|
371
371
|
};
|
|
372
372
|
|
|
@@ -375,7 +375,7 @@ export class NumericInput extends React.Component<Props, State> {
|
|
|
375
375
|
newValue,
|
|
376
376
|
cb,
|
|
377
377
|
) => {
|
|
378
|
-
/*
|
|
378
|
+
/* c8 ignore next */
|
|
379
379
|
this.props.onChange(
|
|
380
380
|
{
|
|
381
381
|
currentValue: newValue,
|
|
@@ -448,6 +448,9 @@ export class NumericInput extends React.Component<Props, State> {
|
|
|
448
448
|
);
|
|
449
449
|
}
|
|
450
450
|
|
|
451
|
+
// Note: This is _very_ similar to what `input-number.jsx` does. If
|
|
452
|
+
// you modify this, double-check if you also need to modify that
|
|
453
|
+
// component.
|
|
451
454
|
const styles = StyleSheet.create({
|
|
452
455
|
input: {
|
|
453
456
|
textAlign: this.props.rightAlign ? "right" : "left",
|
|
@@ -475,7 +478,7 @@ export class NumericInput extends React.Component<Props, State> {
|
|
|
475
478
|
);
|
|
476
479
|
|
|
477
480
|
/* This only gets used with SAT Content */
|
|
478
|
-
/*
|
|
481
|
+
/* c8 ignore next if */
|
|
479
482
|
if (answerBlurb) {
|
|
480
483
|
return (
|
|
481
484
|
<span className="perseus-input-with-answer-blurb">
|
|
@@ -256,7 +256,7 @@ function BaseRadio(props: Props): React.Node {
|
|
|
256
256
|
</div>
|
|
257
257
|
)}
|
|
258
258
|
<ul className={className} style={{listStyle: "none"}}>
|
|
259
|
-
{choices.map(
|
|
259
|
+
{choices.map((choice, i) => {
|
|
260
260
|
let Element = Choice;
|
|
261
261
|
const ref = React.createRef();
|
|
262
262
|
choiceRefs.current[i] = ref;
|
|
@@ -277,6 +277,11 @@ function BaseRadio(props: Props): React.Node {
|
|
|
277
277
|
(reviewMode || choice.showRationale),
|
|
278
278
|
pos: i,
|
|
279
279
|
onChange: (newValues) => {
|
|
280
|
+
// editMode selection is handled in clickHandler
|
|
281
|
+
if (editMode) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
280
285
|
updateChoice(i, newValues);
|
|
281
286
|
},
|
|
282
287
|
ref,
|
|
@@ -379,7 +384,7 @@ function BaseRadio(props: Props): React.Node {
|
|
|
379
384
|
// radio icon, then we want to trigger the
|
|
380
385
|
// check by flipping the choice of the icon.
|
|
381
386
|
if (elem.getAttribute("data-is-radio-icon")) {
|
|
382
|
-
|
|
387
|
+
updateChoice(i, {
|
|
383
388
|
checked: !choice.checked,
|
|
384
389
|
crossedOut: choice.crossedOut,
|
|
385
390
|
});
|
|
@@ -408,7 +413,7 @@ function BaseRadio(props: Props): React.Node {
|
|
|
408
413
|
<Element {...elementProps} />
|
|
409
414
|
</li>
|
|
410
415
|
);
|
|
411
|
-
}
|
|
416
|
+
})}
|
|
412
417
|
</ul>
|
|
413
418
|
</fieldset>
|
|
414
419
|
);
|
|
@@ -149,8 +149,8 @@ function LibraryChoiceIcon(props: LibraryChoiceIconProps): React.Node {
|
|
|
149
149
|
(checked || previouslyAnswered) &&
|
|
150
150
|
styles.circleIncorrectAnswered,
|
|
151
151
|
)}
|
|
152
|
-
// used in BaseRadio to check
|
|
153
|
-
// radio icon
|
|
152
|
+
// used in BaseRadio editMode to check
|
|
153
|
+
// if we actually clicked on the radio icon
|
|
154
154
|
data-is-radio-icon={true}
|
|
155
155
|
>
|
|
156
156
|
<div className={css(styles.innerWrapper)}>
|
|
@@ -228,7 +228,7 @@ function Choice(props: ChoicePropsWithForwardRef): React.Node {
|
|
|
228
228
|
apiOptions.staticRender ||
|
|
229
229
|
apiOptions.readOnly
|
|
230
230
|
}
|
|
231
|
-
style={{flex: 1, color: Color.offBlack}}
|
|
231
|
+
style={{flex: 1, color: Color.offBlack, userSelect: "text"}}
|
|
232
232
|
ref={(forwardedRef: any)}
|
|
233
233
|
aria-hidden="true"
|
|
234
234
|
>
|
|
@@ -157,7 +157,7 @@ class Radio extends React.Component<Props> {
|
|
|
157
157
|
};
|
|
158
158
|
// Support legacy choiceState implementation
|
|
159
159
|
}
|
|
160
|
-
/*
|
|
160
|
+
/* c8 ignore if - props.values is deprecated */
|
|
161
161
|
const {values} = props;
|
|
162
162
|
if (values) {
|
|
163
163
|
let noneOfTheAboveIndex = null;
|
|
@@ -414,7 +414,7 @@ class Radio extends React.Component<Props> {
|
|
|
414
414
|
choiceStates = this.props.choiceStates;
|
|
415
415
|
} else if (this.props.values) {
|
|
416
416
|
// Support legacy choiceStates implementation
|
|
417
|
-
/*
|
|
417
|
+
/* c8 ignore next - props.values is deprecated */
|
|
418
418
|
choiceStates = this.props.values.map((val) => ({
|
|
419
419
|
selected: val,
|
|
420
420
|
crossedOut: false,
|