@khanacademy/perseus 39.0.0 → 39.0.1
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/dist/es/index.js +89 -124
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +67 -100
- package/dist/index.js.map +1 -1
- package/dist/validation.types.d.ts +16 -8
- package/dist/widgets/iframe/iframe-validator.d.ts +1 -1
- package/dist/widgets/matrix/matrix-validator.d.ts +1 -1
- package/dist/widgets/radio/base-radio.d.ts +3 -9
- package/dist/widgets/radio/focus-ring.d.ts +4 -11
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -21260,7 +21260,14 @@ const Triangle = props => {
|
|
|
21260
21260
|
}
|
|
21261
21261
|
});
|
|
21262
21262
|
};
|
|
21263
|
-
const TooltipArrow =
|
|
21263
|
+
const TooltipArrow = _ref => {
|
|
21264
|
+
let {
|
|
21265
|
+
position = "relative",
|
|
21266
|
+
visibility = "visible",
|
|
21267
|
+
left = 100,
|
|
21268
|
+
top = 0,
|
|
21269
|
+
...props
|
|
21270
|
+
} = _ref;
|
|
21264
21271
|
// TODO(aria): Think about adding a box-shadow to the triangle here
|
|
21265
21272
|
// See http://css-tricks.com/triangle-with-shadow/
|
|
21266
21273
|
|
|
@@ -21271,10 +21278,10 @@ const TooltipArrow = props => {
|
|
|
21271
21278
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
21272
21279
|
style: {
|
|
21273
21280
|
display: "block",
|
|
21274
|
-
position:
|
|
21275
|
-
visibility:
|
|
21276
|
-
left:
|
|
21277
|
-
top:
|
|
21281
|
+
position: position,
|
|
21282
|
+
visibility: visibility,
|
|
21283
|
+
left: left,
|
|
21284
|
+
top: top,
|
|
21278
21285
|
width: props.width + 2,
|
|
21279
21286
|
height: props.height + 1,
|
|
21280
21287
|
marginTop: -1,
|
|
@@ -21300,12 +21307,6 @@ const TooltipArrow = props => {
|
|
|
21300
21307
|
height: props.height
|
|
21301
21308
|
}));
|
|
21302
21309
|
};
|
|
21303
|
-
TooltipArrow.defaultProps = {
|
|
21304
|
-
position: "relative",
|
|
21305
|
-
visibility: "visible",
|
|
21306
|
-
left: 0,
|
|
21307
|
-
top: 0
|
|
21308
|
-
};
|
|
21309
21310
|
const VERTICAL_CORNERS = {
|
|
21310
21311
|
top: {
|
|
21311
21312
|
top: "-100%"
|
|
@@ -22176,48 +22177,35 @@ function numericInputValidator(userInput, rubric, strings) {
|
|
|
22176
22177
|
// We may have received TeX; try to parse it before grading.
|
|
22177
22178
|
// If `currentValue` is not TeX, this should be a no-op.
|
|
22178
22179
|
const currentValue = ParseTex(userInput.currentValue);
|
|
22179
|
-
const
|
|
22180
|
-
const normalizedAnswerExpected = correctAnswers.every(answer => Math.abs(answer.value) <= 1);
|
|
22181
|
-
|
|
22182
|
-
// Look through all correct answers for one that matches either
|
|
22183
|
-
// precisely or approximately and return the appropriate message:
|
|
22184
|
-
// - if precise, return the message that the answer came with
|
|
22185
|
-
// - if it needs to be simplified, etc., show that message
|
|
22186
|
-
let result = correctAnswers.map(answer => {
|
|
22187
|
-
// The coefficient is an attribute of the widget
|
|
22188
|
-
let localValue = currentValue;
|
|
22189
|
-
if (rubric.coefficient) {
|
|
22190
|
-
if (!localValue) {
|
|
22191
|
-
localValue = 1;
|
|
22192
|
-
} else if (localValue === "-") {
|
|
22193
|
-
localValue = -1;
|
|
22194
|
-
}
|
|
22195
|
-
}
|
|
22196
|
-
const validate = createValidator(answer);
|
|
22197
|
-
return validate(maybeParsePercentInput(localValue, normalizedAnswerExpected));
|
|
22198
|
-
}).find(match => match.correct || match.empty);
|
|
22199
|
-
if (!result) {
|
|
22200
|
-
// Otherwise, if the guess is not correct
|
|
22201
|
-
const otherAnswers = [].concat(
|
|
22202
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
22203
|
-
rubric.answers.filter(answer => answer.status === "ungraded"), rubric.answers.filter(answer => answer.status === "wrong"));
|
|
22180
|
+
const normalizedAnswerExpected = rubric.answers.filter(answer => answer.status === "correct").every(answer => Math.abs(answer.value) <= 1);
|
|
22204
22181
|
|
|
22205
|
-
|
|
22206
|
-
|
|
22207
|
-
|
|
22208
|
-
|
|
22209
|
-
|
|
22210
|
-
})
|
|
22211
|
-
|
|
22212
|
-
|
|
22213
|
-
empty: match ? match.status === "ungraded" : false,
|
|
22214
|
-
// @ts-expect-error - TS2339 - Property 'status' does not exist on type 'never'.
|
|
22215
|
-
correct: match ? match.status === "correct" : false,
|
|
22216
|
-
// @ts-expect-error - TS2339 - Property 'message' does not exist on type 'never'.
|
|
22217
|
-
message: match ? match.message : null,
|
|
22218
|
-
guess: currentValue
|
|
22219
|
-
};
|
|
22182
|
+
// The coefficient is an attribute of the widget
|
|
22183
|
+
let localValue = currentValue;
|
|
22184
|
+
if (rubric.coefficient) {
|
|
22185
|
+
if (!localValue) {
|
|
22186
|
+
localValue = 1;
|
|
22187
|
+
} else if (localValue === "-") {
|
|
22188
|
+
localValue = -1;
|
|
22189
|
+
}
|
|
22220
22190
|
}
|
|
22191
|
+
const matchedAnswer = rubric.answers.map(answer => {
|
|
22192
|
+
const validateFn = createValidator(answer);
|
|
22193
|
+
const score = validateFn(maybeParsePercentInput(localValue, normalizedAnswerExpected));
|
|
22194
|
+
return {
|
|
22195
|
+
...answer,
|
|
22196
|
+
score
|
|
22197
|
+
};
|
|
22198
|
+
}).find(answer => {
|
|
22199
|
+
// NOTE: "answer.score.correct" indicates a match via the validate function.
|
|
22200
|
+
// It does NOT indicate that the answer itself is correct.
|
|
22201
|
+
return answer.score.correct || answer.status === "correct" && answer.score.empty;
|
|
22202
|
+
});
|
|
22203
|
+
const result = matchedAnswer?.status === "correct" ? matchedAnswer.score : {
|
|
22204
|
+
empty: matchedAnswer?.status === "ungraded",
|
|
22205
|
+
correct: matchedAnswer?.status === "correct",
|
|
22206
|
+
message: matchedAnswer?.message ?? null,
|
|
22207
|
+
guess: localValue
|
|
22208
|
+
};
|
|
22221
22209
|
|
|
22222
22210
|
// TODO(eater): Seems silly to translate result to this
|
|
22223
22211
|
// invalid/points thing and immediately translate it
|
|
@@ -25191,13 +25179,13 @@ function getA11yText(letter, checked, correct, crossedOut, showCorrectness, stri
|
|
|
25191
25179
|
/**
|
|
25192
25180
|
* Renders a circular selection ring around the child.
|
|
25193
25181
|
*/
|
|
25194
|
-
const FocusRing = function (
|
|
25195
|
-
|
|
25196
|
-
visible,
|
|
25197
|
-
color,
|
|
25198
|
-
|
|
25199
|
-
|
|
25200
|
-
} =
|
|
25182
|
+
const FocusRing = function (_ref) {
|
|
25183
|
+
let {
|
|
25184
|
+
visible = true,
|
|
25185
|
+
color = kaGreen$1,
|
|
25186
|
+
multipleSelect = false,
|
|
25187
|
+
children
|
|
25188
|
+
} = _ref;
|
|
25201
25189
|
const borderColor = visible ? color : "transparent";
|
|
25202
25190
|
const borderRadius = multipleSelect ? 5 : "50%";
|
|
25203
25191
|
const style = {
|
|
@@ -25210,11 +25198,6 @@ const FocusRing = function (props) {
|
|
|
25210
25198
|
style: style
|
|
25211
25199
|
}, children);
|
|
25212
25200
|
};
|
|
25213
|
-
FocusRing.defaultProps = {
|
|
25214
|
-
visible: true,
|
|
25215
|
-
color: kaGreen$1,
|
|
25216
|
-
multipleSelect: false
|
|
25217
|
-
};
|
|
25218
25201
|
const styles$v = aphrodite.StyleSheet.create({
|
|
25219
25202
|
ring: {
|
|
25220
25203
|
margin: "auto",
|
|
@@ -25753,13 +25736,13 @@ var Choice$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PUR
|
|
|
25753
25736
|
forwardedRef: ref
|
|
25754
25737
|
})));
|
|
25755
25738
|
|
|
25756
|
-
const ChoiceNoneAbove = function (
|
|
25757
|
-
|
|
25758
|
-
showContent,
|
|
25739
|
+
const ChoiceNoneAbove = function (_ref) {
|
|
25740
|
+
let {
|
|
25759
25741
|
content,
|
|
25760
25742
|
forwardedRef,
|
|
25743
|
+
showContent = true,
|
|
25761
25744
|
...rest
|
|
25762
|
-
} =
|
|
25745
|
+
} = _ref;
|
|
25763
25746
|
const {
|
|
25764
25747
|
strings
|
|
25765
25748
|
} = usePerseusI18n();
|
|
@@ -25787,9 +25770,6 @@ const ChoiceNoneAbove = function (props) {
|
|
|
25787
25770
|
ref: forwardedRef
|
|
25788
25771
|
}));
|
|
25789
25772
|
};
|
|
25790
|
-
ChoiceNoneAbove.defaultProps = {
|
|
25791
|
-
showContent: true
|
|
25792
|
-
};
|
|
25793
25773
|
var ChoiceNoneAbove$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(ChoiceNoneAbove, _extends({}, props, {
|
|
25794
25774
|
forwardedRef: ref
|
|
25795
25775
|
})));
|
|
@@ -25811,20 +25791,21 @@ function getInstructionsText(multipleSelect, countChoices, numCorrect, strings)
|
|
|
25811
25791
|
}
|
|
25812
25792
|
return strings.chooseOneAnswer;
|
|
25813
25793
|
}
|
|
25814
|
-
const BaseRadio = function (
|
|
25815
|
-
|
|
25794
|
+
const BaseRadio = function (_ref) {
|
|
25795
|
+
let {
|
|
25816
25796
|
apiOptions,
|
|
25817
25797
|
reviewModeRubric,
|
|
25818
25798
|
reviewMode,
|
|
25819
25799
|
choices,
|
|
25820
|
-
editMode,
|
|
25821
|
-
multipleSelect,
|
|
25800
|
+
editMode = false,
|
|
25801
|
+
multipleSelect = false,
|
|
25822
25802
|
labelWrap,
|
|
25823
25803
|
countChoices,
|
|
25824
25804
|
numCorrect,
|
|
25825
25805
|
isLastUsedWidget,
|
|
25806
|
+
onChange,
|
|
25826
25807
|
registerFocusFunction
|
|
25827
|
-
} =
|
|
25808
|
+
} = _ref;
|
|
25828
25809
|
const {
|
|
25829
25810
|
strings
|
|
25830
25811
|
} = usePerseusI18n();
|
|
@@ -25881,12 +25862,6 @@ const BaseRadio = function (props) {
|
|
|
25881
25862
|
// contains a boolean value specifying the new checked and crossed-out
|
|
25882
25863
|
// value of this choice.
|
|
25883
25864
|
function updateChoice(choiceIndex, newValues) {
|
|
25884
|
-
const {
|
|
25885
|
-
multipleSelect,
|
|
25886
|
-
choices,
|
|
25887
|
-
onChange
|
|
25888
|
-
} = props;
|
|
25889
|
-
|
|
25890
25865
|
// Get the baseline `checked` values. If we're checking a new answer
|
|
25891
25866
|
// and multiple-select is not on, we should clear all choices to be
|
|
25892
25867
|
// unchecked. Otherwise, we should copy the old checked values.
|
|
@@ -26053,10 +26028,6 @@ const BaseRadio = function (props) {
|
|
|
26053
26028
|
className: aphrodite.css(styles$p.responsiveContainer)
|
|
26054
26029
|
}, fieldset);
|
|
26055
26030
|
};
|
|
26056
|
-
BaseRadio.defaultProps = {
|
|
26057
|
-
editMode: false,
|
|
26058
|
-
multipleSelect: false
|
|
26059
|
-
};
|
|
26060
26031
|
const styles$p = aphrodite.StyleSheet.create({
|
|
26061
26032
|
instructions: {
|
|
26062
26033
|
display: "block",
|
|
@@ -26155,7 +26126,7 @@ function radioValidator(userInput, rubric, strings) {
|
|
|
26155
26126
|
};
|
|
26156
26127
|
}
|
|
26157
26128
|
|
|
26158
|
-
// TODO: should numCorrect actually be on the rubric
|
|
26129
|
+
// TODO(LEMS-2541): should numCorrect actually be on the rubric
|
|
26159
26130
|
// instead of the userInput?
|
|
26160
26131
|
if (userInput.numCorrect && userInput.numCorrect > 1 && numSelected !== userInput.numCorrect) {
|
|
26161
26132
|
return {
|
|
@@ -26165,7 +26136,7 @@ function radioValidator(userInput, rubric, strings) {
|
|
|
26165
26136
|
// If NOTA and some other answer are checked, ...
|
|
26166
26137
|
}
|
|
26167
26138
|
|
|
26168
|
-
// TODO: should noneOfTheAboveSelected be replaced with a
|
|
26139
|
+
// TODO(LEMS-2541): should noneOfTheAboveSelected be replaced with a
|
|
26169
26140
|
// combination of choicesSelected and noneOfTheAboveIndex?
|
|
26170
26141
|
if (userInput.noneOfTheAboveSelected && numSelected > 1) {
|
|
26171
26142
|
return {
|
|
@@ -26175,7 +26146,7 @@ function radioValidator(userInput, rubric, strings) {
|
|
|
26175
26146
|
}
|
|
26176
26147
|
const correct = userInput.choicesSelected.every((selected, i) => {
|
|
26177
26148
|
let isCorrect;
|
|
26178
|
-
// TODO: should noneOfTheAboveIndex actually be on the rubric
|
|
26149
|
+
// TODO(LEMS-2541): should noneOfTheAboveIndex actually be on the rubric
|
|
26179
26150
|
// instead of the userInput?
|
|
26180
26151
|
if (userInput.noneOfTheAboveIndex === i) {
|
|
26181
26152
|
isCorrect = rubric.choices.every((choice, j) => {
|
|
@@ -26217,7 +26188,6 @@ class Radio$1 extends React__namespace.Component {
|
|
|
26217
26188
|
let noneOfTheAboveSelected = false;
|
|
26218
26189
|
const choiceStates = props.choiceStates;
|
|
26219
26190
|
const choicesSelected = choiceStates.map(() => false);
|
|
26220
|
-
const countChoices = props.countChoices;
|
|
26221
26191
|
const numCorrect = props.numCorrect;
|
|
26222
26192
|
for (let i = 0; i < choicesSelected.length; i++) {
|
|
26223
26193
|
const index = props.choices[i].originalIndex;
|
|
@@ -26231,7 +26201,6 @@ class Radio$1 extends React__namespace.Component {
|
|
|
26231
26201
|
}
|
|
26232
26202
|
}
|
|
26233
26203
|
return {
|
|
26234
|
-
countChoices,
|
|
26235
26204
|
choicesSelected,
|
|
26236
26205
|
numCorrect,
|
|
26237
26206
|
noneOfTheAboveIndex,
|
|
@@ -26247,7 +26216,6 @@ class Radio$1 extends React__namespace.Component {
|
|
|
26247
26216
|
let noneOfTheAboveIndex = null;
|
|
26248
26217
|
let noneOfTheAboveSelected = false;
|
|
26249
26218
|
const choicesSelected = [...values];
|
|
26250
|
-
const countChoices = props.countChoices;
|
|
26251
26219
|
const numCorrect = props.numCorrect;
|
|
26252
26220
|
const valuesLength = values.length;
|
|
26253
26221
|
for (let i = 0; i < valuesLength; i++) {
|
|
@@ -26265,7 +26233,6 @@ class Radio$1 extends React__namespace.Component {
|
|
|
26265
26233
|
choicesSelected,
|
|
26266
26234
|
noneOfTheAboveIndex,
|
|
26267
26235
|
noneOfTheAboveSelected,
|
|
26268
|
-
countChoices,
|
|
26269
26236
|
numCorrect
|
|
26270
26237
|
};
|
|
26271
26238
|
}
|
|
@@ -29349,23 +29316,23 @@ var Group$1 = {
|
|
|
29349
29316
|
isLintable: true
|
|
29350
29317
|
};
|
|
29351
29318
|
|
|
29352
|
-
function iframeValidator(
|
|
29319
|
+
function iframeValidator(userInput) {
|
|
29353
29320
|
// The iframe can tell us whether it's correct or incorrect,
|
|
29354
29321
|
// and pass an optional message
|
|
29355
|
-
if (
|
|
29322
|
+
if (userInput.status === "correct") {
|
|
29356
29323
|
return {
|
|
29357
29324
|
type: "points",
|
|
29358
29325
|
earned: 1,
|
|
29359
29326
|
total: 1,
|
|
29360
|
-
message:
|
|
29327
|
+
message: userInput.message || null
|
|
29361
29328
|
};
|
|
29362
29329
|
}
|
|
29363
|
-
if (
|
|
29330
|
+
if (userInput.status === "incorrect") {
|
|
29364
29331
|
return {
|
|
29365
29332
|
type: "points",
|
|
29366
29333
|
earned: 0,
|
|
29367
29334
|
total: 1,
|
|
29368
|
-
message:
|
|
29335
|
+
message: userInput.message || null
|
|
29369
29336
|
};
|
|
29370
29337
|
}
|
|
29371
29338
|
return {
|
|
@@ -40749,9 +40716,9 @@ var Matcher$1 = {
|
|
|
40749
40716
|
validator: matcherValidator
|
|
40750
40717
|
};
|
|
40751
40718
|
|
|
40752
|
-
function matrixValidator(
|
|
40719
|
+
function matrixValidator(userInput, rubric, strings) {
|
|
40753
40720
|
const solution = rubric.answers;
|
|
40754
|
-
const supplied =
|
|
40721
|
+
const supplied = userInput.answers;
|
|
40755
40722
|
const solutionSize = getMatrixSize(solution);
|
|
40756
40723
|
const suppliedSize = getMatrixSize(supplied);
|
|
40757
40724
|
const incorrectSize = solutionSize[0] !== suppliedSize[0] || solutionSize[1] !== suppliedSize[1];
|
|
@@ -45101,7 +45068,7 @@ const init = function (options) {
|
|
|
45101
45068
|
|
|
45102
45069
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45103
45070
|
const libName = "@khanacademy/perseus";
|
|
45104
|
-
const libVersion = "39.0.
|
|
45071
|
+
const libVersion = "39.0.1";
|
|
45105
45072
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45106
45073
|
|
|
45107
45074
|
const apiVersion = {
|