@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/es/index.js
CHANGED
|
@@ -20968,7 +20968,17 @@ TextInput.defaultProps = {
|
|
|
20968
20968
|
disabled: false
|
|
20969
20969
|
};
|
|
20970
20970
|
|
|
20971
|
-
|
|
20971
|
+
function _objectWithoutPropertiesLoose(r, e) {
|
|
20972
|
+
if (null == r) return {};
|
|
20973
|
+
var t = {};
|
|
20974
|
+
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
|
|
20975
|
+
if (e.includes(n)) continue;
|
|
20976
|
+
t[n] = r[n];
|
|
20977
|
+
}
|
|
20978
|
+
return t;
|
|
20979
|
+
}
|
|
20980
|
+
|
|
20981
|
+
const _excluded$5 = ["position", "visibility", "left", "top"];
|
|
20972
20982
|
const zIndex = 10;
|
|
20973
20983
|
let HorizontalDirection = /*#__PURE__*/function (HorizontalDirection) {
|
|
20974
20984
|
HorizontalDirection["Left"] = "left";
|
|
@@ -21012,7 +21022,14 @@ const Triangle = props => {
|
|
|
21012
21022
|
}
|
|
21013
21023
|
});
|
|
21014
21024
|
};
|
|
21015
|
-
const TooltipArrow =
|
|
21025
|
+
const TooltipArrow = _ref => {
|
|
21026
|
+
let {
|
|
21027
|
+
position = "relative",
|
|
21028
|
+
visibility = "visible",
|
|
21029
|
+
left = 100,
|
|
21030
|
+
top = 0
|
|
21031
|
+
} = _ref,
|
|
21032
|
+
props = _objectWithoutPropertiesLoose(_ref, _excluded$5);
|
|
21016
21033
|
// TODO(aria): Think about adding a box-shadow to the triangle here
|
|
21017
21034
|
// See http://css-tricks.com/triangle-with-shadow/
|
|
21018
21035
|
|
|
@@ -21023,10 +21040,10 @@ const TooltipArrow = props => {
|
|
|
21023
21040
|
return /*#__PURE__*/React.createElement("div", {
|
|
21024
21041
|
style: {
|
|
21025
21042
|
display: "block",
|
|
21026
|
-
position:
|
|
21027
|
-
visibility:
|
|
21028
|
-
left:
|
|
21029
|
-
top:
|
|
21043
|
+
position: position,
|
|
21044
|
+
visibility: visibility,
|
|
21045
|
+
left: left,
|
|
21046
|
+
top: top,
|
|
21030
21047
|
width: props.width + 2,
|
|
21031
21048
|
height: props.height + 1,
|
|
21032
21049
|
marginTop: -1,
|
|
@@ -21052,12 +21069,6 @@ const TooltipArrow = props => {
|
|
|
21052
21069
|
height: props.height
|
|
21053
21070
|
}));
|
|
21054
21071
|
};
|
|
21055
|
-
TooltipArrow.defaultProps = {
|
|
21056
|
-
position: "relative",
|
|
21057
|
-
visibility: "visible",
|
|
21058
|
-
left: 0,
|
|
21059
|
-
top: 0
|
|
21060
|
-
};
|
|
21061
21072
|
const VERTICAL_CORNERS = {
|
|
21062
21073
|
top: {
|
|
21063
21074
|
top: "-100%"
|
|
@@ -21340,16 +21351,6 @@ InputWithExamples.defaultProps = {
|
|
|
21340
21351
|
className: ""
|
|
21341
21352
|
};
|
|
21342
21353
|
|
|
21343
|
-
function _objectWithoutPropertiesLoose(r, e) {
|
|
21344
|
-
if (null == r) return {};
|
|
21345
|
-
var t = {};
|
|
21346
|
-
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
|
|
21347
|
-
if (e.includes(n)) continue;
|
|
21348
|
-
t[n] = r[n];
|
|
21349
|
-
}
|
|
21350
|
-
return t;
|
|
21351
|
-
}
|
|
21352
|
-
|
|
21353
21354
|
const _excluded$4 = ["keypadElement", "onFocus", "value"];
|
|
21354
21355
|
class SimpleKeypadInput extends React.Component {
|
|
21355
21356
|
constructor(...args) {
|
|
@@ -21927,6 +21928,7 @@ function maybeParsePercentInput(inputValue, normalizedAnswerExpected) {
|
|
|
21927
21928
|
return value;
|
|
21928
21929
|
}
|
|
21929
21930
|
function numericInputValidator(userInput, rubric, strings) {
|
|
21931
|
+
var _matchedAnswer$messag;
|
|
21930
21932
|
const defaultAnswerForms = answerFormButtons.map(e => e["value"])
|
|
21931
21933
|
// Don't default to validating the answer as a pi answer
|
|
21932
21934
|
// if answerForm isn't set on the answer
|
|
@@ -21959,48 +21961,34 @@ function numericInputValidator(userInput, rubric, strings) {
|
|
|
21959
21961
|
// We may have received TeX; try to parse it before grading.
|
|
21960
21962
|
// If `currentValue` is not TeX, this should be a no-op.
|
|
21961
21963
|
const currentValue = ParseTex(userInput.currentValue);
|
|
21962
|
-
const
|
|
21963
|
-
|
|
21964
|
-
|
|
21965
|
-
|
|
21966
|
-
|
|
21967
|
-
|
|
21968
|
-
|
|
21969
|
-
|
|
21970
|
-
|
|
21971
|
-
|
|
21972
|
-
|
|
21973
|
-
|
|
21974
|
-
|
|
21975
|
-
|
|
21976
|
-
|
|
21977
|
-
|
|
21978
|
-
}
|
|
21979
|
-
const validate = createValidator(answer);
|
|
21980
|
-
return validate(maybeParsePercentInput(localValue, normalizedAnswerExpected));
|
|
21981
|
-
}).find(match => match.correct || match.empty);
|
|
21982
|
-
if (!result) {
|
|
21983
|
-
// Otherwise, if the guess is not correct
|
|
21984
|
-
const otherAnswers = [].concat(
|
|
21985
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
21986
|
-
rubric.answers.filter(answer => answer.status === "ungraded"), rubric.answers.filter(answer => answer.status === "wrong"));
|
|
21987
|
-
|
|
21988
|
-
// Look through all other answers and if one matches either
|
|
21989
|
-
// precisely or approximately return the answer's message
|
|
21990
|
-
const match = otherAnswers.find(answer => {
|
|
21991
|
-
const validate = createValidator(answer);
|
|
21992
|
-
return validate(maybeParsePercentInput(currentValue, normalizedAnswerExpected)).correct;
|
|
21964
|
+
const normalizedAnswerExpected = rubric.answers.filter(answer => answer.status === "correct").every(answer => Math.abs(answer.value) <= 1);
|
|
21965
|
+
|
|
21966
|
+
// The coefficient is an attribute of the widget
|
|
21967
|
+
let localValue = currentValue;
|
|
21968
|
+
if (rubric.coefficient) {
|
|
21969
|
+
if (!localValue) {
|
|
21970
|
+
localValue = 1;
|
|
21971
|
+
} else if (localValue === "-") {
|
|
21972
|
+
localValue = -1;
|
|
21973
|
+
}
|
|
21974
|
+
}
|
|
21975
|
+
const matchedAnswer = rubric.answers.map(answer => {
|
|
21976
|
+
const validateFn = createValidator(answer);
|
|
21977
|
+
const score = validateFn(maybeParsePercentInput(localValue, normalizedAnswerExpected));
|
|
21978
|
+
return _extends({}, answer, {
|
|
21979
|
+
score
|
|
21993
21980
|
});
|
|
21994
|
-
|
|
21995
|
-
|
|
21996
|
-
|
|
21997
|
-
|
|
21998
|
-
|
|
21999
|
-
|
|
22000
|
-
|
|
22001
|
-
|
|
22002
|
-
|
|
22003
|
-
|
|
21981
|
+
}).find(answer => {
|
|
21982
|
+
// NOTE: "answer.score.correct" indicates a match via the validate function.
|
|
21983
|
+
// It does NOT indicate that the answer itself is correct.
|
|
21984
|
+
return answer.score.correct || answer.status === "correct" && answer.score.empty;
|
|
21985
|
+
});
|
|
21986
|
+
const result = (matchedAnswer == null ? void 0 : matchedAnswer.status) === "correct" ? matchedAnswer.score : {
|
|
21987
|
+
empty: (matchedAnswer == null ? void 0 : matchedAnswer.status) === "ungraded",
|
|
21988
|
+
correct: (matchedAnswer == null ? void 0 : matchedAnswer.status) === "correct",
|
|
21989
|
+
message: (_matchedAnswer$messag = matchedAnswer == null ? void 0 : matchedAnswer.message) != null ? _matchedAnswer$messag : null,
|
|
21990
|
+
guess: localValue
|
|
21991
|
+
};
|
|
22004
21992
|
|
|
22005
21993
|
// TODO(eater): Seems silly to translate result to this
|
|
22006
21994
|
// invalid/points thing and immediately translate it
|
|
@@ -24972,13 +24960,12 @@ function getA11yText(letter, checked, correct, crossedOut, showCorrectness, stri
|
|
|
24972
24960
|
/**
|
|
24973
24961
|
* Renders a circular selection ring around the child.
|
|
24974
24962
|
*/
|
|
24975
|
-
const FocusRing = function FocusRing(
|
|
24976
|
-
|
|
24977
|
-
|
|
24978
|
-
|
|
24979
|
-
|
|
24980
|
-
|
|
24981
|
-
} = props;
|
|
24963
|
+
const FocusRing = function FocusRing({
|
|
24964
|
+
visible = true,
|
|
24965
|
+
color = kaGreen$1,
|
|
24966
|
+
multipleSelect = false,
|
|
24967
|
+
children
|
|
24968
|
+
}) {
|
|
24982
24969
|
const borderColor = visible ? color : "transparent";
|
|
24983
24970
|
const borderRadius = multipleSelect ? 5 : "50%";
|
|
24984
24971
|
const style = {
|
|
@@ -24991,11 +24978,6 @@ const FocusRing = function FocusRing(props) {
|
|
|
24991
24978
|
style: style
|
|
24992
24979
|
}, children);
|
|
24993
24980
|
};
|
|
24994
|
-
FocusRing.defaultProps = {
|
|
24995
|
-
visible: true,
|
|
24996
|
-
color: kaGreen$1,
|
|
24997
|
-
multipleSelect: false
|
|
24998
|
-
};
|
|
24999
24981
|
const styles$v = StyleSheet.create({
|
|
25000
24982
|
ring: {
|
|
25001
24983
|
margin: "auto",
|
|
@@ -25528,14 +25510,14 @@ var Choice$1 = /*#__PURE__*/React.forwardRef((props, ref) => /*#__PURE__*/React.
|
|
|
25528
25510
|
forwardedRef: ref
|
|
25529
25511
|
})));
|
|
25530
25512
|
|
|
25531
|
-
const _excluded$3 = ["
|
|
25532
|
-
const ChoiceNoneAbove = function ChoiceNoneAbove(
|
|
25533
|
-
|
|
25534
|
-
showContent,
|
|
25513
|
+
const _excluded$3 = ["content", "forwardedRef", "showContent"];
|
|
25514
|
+
const ChoiceNoneAbove = function ChoiceNoneAbove(_ref) {
|
|
25515
|
+
let {
|
|
25535
25516
|
content,
|
|
25536
|
-
forwardedRef
|
|
25537
|
-
|
|
25538
|
-
|
|
25517
|
+
forwardedRef,
|
|
25518
|
+
showContent = true
|
|
25519
|
+
} = _ref,
|
|
25520
|
+
rest = _objectWithoutPropertiesLoose(_ref, _excluded$3);
|
|
25539
25521
|
const {
|
|
25540
25522
|
strings
|
|
25541
25523
|
} = usePerseusI18n();
|
|
@@ -25562,9 +25544,6 @@ const ChoiceNoneAbove = function ChoiceNoneAbove(props) {
|
|
|
25562
25544
|
ref: forwardedRef
|
|
25563
25545
|
}));
|
|
25564
25546
|
};
|
|
25565
|
-
ChoiceNoneAbove.defaultProps = {
|
|
25566
|
-
showContent: true
|
|
25567
|
-
};
|
|
25568
25547
|
var ChoiceNoneAbove$1 = /*#__PURE__*/React.forwardRef((props, ref) => /*#__PURE__*/React.createElement(ChoiceNoneAbove, _extends({}, props, {
|
|
25569
25548
|
forwardedRef: ref
|
|
25570
25549
|
})));
|
|
@@ -25586,20 +25565,20 @@ function getInstructionsText(multipleSelect, countChoices, numCorrect, strings)
|
|
|
25586
25565
|
}
|
|
25587
25566
|
return strings.chooseOneAnswer;
|
|
25588
25567
|
}
|
|
25589
|
-
const BaseRadio = function BaseRadio(
|
|
25590
|
-
|
|
25591
|
-
|
|
25592
|
-
|
|
25593
|
-
|
|
25594
|
-
|
|
25595
|
-
|
|
25596
|
-
|
|
25597
|
-
|
|
25598
|
-
|
|
25599
|
-
|
|
25600
|
-
|
|
25601
|
-
|
|
25602
|
-
|
|
25568
|
+
const BaseRadio = function BaseRadio({
|
|
25569
|
+
apiOptions,
|
|
25570
|
+
reviewModeRubric,
|
|
25571
|
+
reviewMode,
|
|
25572
|
+
choices,
|
|
25573
|
+
editMode = false,
|
|
25574
|
+
multipleSelect = false,
|
|
25575
|
+
labelWrap,
|
|
25576
|
+
countChoices,
|
|
25577
|
+
numCorrect,
|
|
25578
|
+
isLastUsedWidget,
|
|
25579
|
+
onChange,
|
|
25580
|
+
registerFocusFunction
|
|
25581
|
+
}) {
|
|
25603
25582
|
const {
|
|
25604
25583
|
strings
|
|
25605
25584
|
} = usePerseusI18n();
|
|
@@ -25656,12 +25635,6 @@ const BaseRadio = function BaseRadio(props) {
|
|
|
25656
25635
|
// contains a boolean value specifying the new checked and crossed-out
|
|
25657
25636
|
// value of this choice.
|
|
25658
25637
|
function updateChoice(choiceIndex, newValues) {
|
|
25659
|
-
const {
|
|
25660
|
-
multipleSelect,
|
|
25661
|
-
choices,
|
|
25662
|
-
onChange
|
|
25663
|
-
} = props;
|
|
25664
|
-
|
|
25665
25638
|
// Get the baseline `checked` values. If we're checking a new answer
|
|
25666
25639
|
// and multiple-select is not on, we should clear all choices to be
|
|
25667
25640
|
// unchecked. Otherwise, we should copy the old checked values.
|
|
@@ -25828,10 +25801,6 @@ const BaseRadio = function BaseRadio(props) {
|
|
|
25828
25801
|
className: css(styles$p.responsiveContainer)
|
|
25829
25802
|
}, fieldset);
|
|
25830
25803
|
};
|
|
25831
|
-
BaseRadio.defaultProps = {
|
|
25832
|
-
editMode: false,
|
|
25833
|
-
multipleSelect: false
|
|
25834
|
-
};
|
|
25835
25804
|
const styles$p = StyleSheet.create({
|
|
25836
25805
|
instructions: {
|
|
25837
25806
|
display: "block",
|
|
@@ -25930,7 +25899,7 @@ function radioValidator(userInput, rubric, strings) {
|
|
|
25930
25899
|
};
|
|
25931
25900
|
}
|
|
25932
25901
|
|
|
25933
|
-
// TODO: should numCorrect actually be on the rubric
|
|
25902
|
+
// TODO(LEMS-2541): should numCorrect actually be on the rubric
|
|
25934
25903
|
// instead of the userInput?
|
|
25935
25904
|
if (userInput.numCorrect && userInput.numCorrect > 1 && numSelected !== userInput.numCorrect) {
|
|
25936
25905
|
return {
|
|
@@ -25940,7 +25909,7 @@ function radioValidator(userInput, rubric, strings) {
|
|
|
25940
25909
|
// If NOTA and some other answer are checked, ...
|
|
25941
25910
|
}
|
|
25942
25911
|
|
|
25943
|
-
// TODO: should noneOfTheAboveSelected be replaced with a
|
|
25912
|
+
// TODO(LEMS-2541): should noneOfTheAboveSelected be replaced with a
|
|
25944
25913
|
// combination of choicesSelected and noneOfTheAboveIndex?
|
|
25945
25914
|
if (userInput.noneOfTheAboveSelected && numSelected > 1) {
|
|
25946
25915
|
return {
|
|
@@ -25950,7 +25919,7 @@ function radioValidator(userInput, rubric, strings) {
|
|
|
25950
25919
|
}
|
|
25951
25920
|
const correct = userInput.choicesSelected.every((selected, i) => {
|
|
25952
25921
|
let isCorrect;
|
|
25953
|
-
// TODO: should noneOfTheAboveIndex actually be on the rubric
|
|
25922
|
+
// TODO(LEMS-2541): should noneOfTheAboveIndex actually be on the rubric
|
|
25954
25923
|
// instead of the userInput?
|
|
25955
25924
|
if (userInput.noneOfTheAboveIndex === i) {
|
|
25956
25925
|
isCorrect = rubric.choices.every((choice, j) => {
|
|
@@ -26131,7 +26100,6 @@ class Radio$1 extends React.Component {
|
|
|
26131
26100
|
let noneOfTheAboveSelected = false;
|
|
26132
26101
|
const choiceStates = props.choiceStates;
|
|
26133
26102
|
const choicesSelected = choiceStates.map(() => false);
|
|
26134
|
-
const countChoices = props.countChoices;
|
|
26135
26103
|
const numCorrect = props.numCorrect;
|
|
26136
26104
|
for (let i = 0; i < choicesSelected.length; i++) {
|
|
26137
26105
|
const index = props.choices[i].originalIndex;
|
|
@@ -26145,7 +26113,6 @@ class Radio$1 extends React.Component {
|
|
|
26145
26113
|
}
|
|
26146
26114
|
}
|
|
26147
26115
|
return {
|
|
26148
|
-
countChoices,
|
|
26149
26116
|
choicesSelected,
|
|
26150
26117
|
numCorrect,
|
|
26151
26118
|
noneOfTheAboveIndex,
|
|
@@ -26161,7 +26128,6 @@ class Radio$1 extends React.Component {
|
|
|
26161
26128
|
let noneOfTheAboveIndex = null;
|
|
26162
26129
|
let noneOfTheAboveSelected = false;
|
|
26163
26130
|
const choicesSelected = [...values];
|
|
26164
|
-
const countChoices = props.countChoices;
|
|
26165
26131
|
const numCorrect = props.numCorrect;
|
|
26166
26132
|
const valuesLength = values.length;
|
|
26167
26133
|
for (let i = 0; i < valuesLength; i++) {
|
|
@@ -26179,7 +26145,6 @@ class Radio$1 extends React.Component {
|
|
|
26179
26145
|
choicesSelected,
|
|
26180
26146
|
noneOfTheAboveIndex,
|
|
26181
26147
|
noneOfTheAboveSelected,
|
|
26182
|
-
countChoices,
|
|
26183
26148
|
numCorrect
|
|
26184
26149
|
};
|
|
26185
26150
|
}
|
|
@@ -29084,23 +29049,23 @@ var Group$1 = {
|
|
|
29084
29049
|
isLintable: true
|
|
29085
29050
|
};
|
|
29086
29051
|
|
|
29087
|
-
function iframeValidator(
|
|
29052
|
+
function iframeValidator(userInput) {
|
|
29088
29053
|
// The iframe can tell us whether it's correct or incorrect,
|
|
29089
29054
|
// and pass an optional message
|
|
29090
|
-
if (
|
|
29055
|
+
if (userInput.status === "correct") {
|
|
29091
29056
|
return {
|
|
29092
29057
|
type: "points",
|
|
29093
29058
|
earned: 1,
|
|
29094
29059
|
total: 1,
|
|
29095
|
-
message:
|
|
29060
|
+
message: userInput.message || null
|
|
29096
29061
|
};
|
|
29097
29062
|
}
|
|
29098
|
-
if (
|
|
29063
|
+
if (userInput.status === "incorrect") {
|
|
29099
29064
|
return {
|
|
29100
29065
|
type: "points",
|
|
29101
29066
|
earned: 0,
|
|
29102
29067
|
total: 1,
|
|
29103
|
-
message:
|
|
29068
|
+
message: userInput.message || null
|
|
29104
29069
|
};
|
|
29105
29070
|
}
|
|
29106
29071
|
return {
|
|
@@ -40400,9 +40365,9 @@ var Matcher$1 = {
|
|
|
40400
40365
|
validator: matcherValidator
|
|
40401
40366
|
};
|
|
40402
40367
|
|
|
40403
|
-
function matrixValidator(
|
|
40368
|
+
function matrixValidator(userInput, rubric, strings) {
|
|
40404
40369
|
const solution = rubric.answers;
|
|
40405
|
-
const supplied =
|
|
40370
|
+
const supplied = userInput.answers;
|
|
40406
40371
|
const solutionSize = getMatrixSize(solution);
|
|
40407
40372
|
const suppliedSize = getMatrixSize(supplied);
|
|
40408
40373
|
const incorrectSize = solutionSize[0] !== suppliedSize[0] || solutionSize[1] !== suppliedSize[1];
|
|
@@ -44752,7 +44717,7 @@ const init = function init(options) {
|
|
|
44752
44717
|
|
|
44753
44718
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44754
44719
|
const libName = "@khanacademy/perseus";
|
|
44755
|
-
const libVersion = "39.0.
|
|
44720
|
+
const libVersion = "39.0.1";
|
|
44756
44721
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44757
44722
|
|
|
44758
44723
|
const apiVersion = {
|