@khanacademy/perseus 34.0.0 → 34.1.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/dist/es/index.js +287 -165
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +303 -161
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +1 -0
- package/dist/perseus-types.d.ts +1 -0
- package/dist/server-item-renderer.d.ts +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/widgets/__shared__/noop-validator.d.ts +2 -2
- package/dist/widgets/categorizer/categorizer-validator.d.ts +5 -0
- package/dist/widgets/categorizer/categorizer.d.ts +1 -4
- package/dist/widgets/categorizer/categorizer.types.d.ts +5 -0
- package/dist/widgets/definition/definition.d.ts +3 -3
- package/dist/widgets/explanation/explanation.d.ts +3 -5
- package/dist/widgets/expression/expression.d.ts +6 -0
- package/dist/widgets/image/image.d.ts +3 -3
- package/dist/widgets/input-number/input-number-validator.d.ts +41 -0
- package/dist/widgets/input-number/input-number.d.ts +1 -1
- package/dist/widgets/input-number/input-number.types.d.ts +2 -0
- package/dist/widgets/interaction/interaction.d.ts +3 -3
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +7 -5
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-action.d.ts +16 -1
- package/dist/widgets/interactive-graphs/types.d.ts +3 -0
- package/dist/widgets/label-image/label-image.d.ts +2 -0
- package/dist/widgets/molecule/molecule.d.ts +2 -2
- package/dist/widgets/passage/passage.d.ts +3 -3
- package/dist/widgets/passage-ref/passage-ref.d.ts +3 -3
- package/dist/widgets/passage-ref-target/passage-ref-target.d.ts +2 -2
- package/dist/widgets/video/video.d.ts +3 -4
- package/package.json +1 -1
package/dist/es/index.js
CHANGED
|
@@ -21738,6 +21738,47 @@ const answerTypes = {
|
|
|
21738
21738
|
forms: "pi"
|
|
21739
21739
|
}
|
|
21740
21740
|
};
|
|
21741
|
+
function inputNumberValidator(state, rubric, strings, onInputError = () => {}) {
|
|
21742
|
+
if (rubric.answerType == null) {
|
|
21743
|
+
rubric.answerType = "number";
|
|
21744
|
+
}
|
|
21745
|
+
|
|
21746
|
+
// note(matthewc): this will get immediately parsed again by
|
|
21747
|
+
// `KhanAnswerTypes.number.convertToPredicate`, but a string is
|
|
21748
|
+
// expected here
|
|
21749
|
+
const stringValue = `${rubric.value}`;
|
|
21750
|
+
const val = KhanAnswerTypes.number.createValidatorFunctional(stringValue, {
|
|
21751
|
+
simplify: rubric.simplify,
|
|
21752
|
+
inexact: rubric.inexact || undefined,
|
|
21753
|
+
maxError: rubric.maxError,
|
|
21754
|
+
forms: answerTypes[rubric.answerType].forms
|
|
21755
|
+
}, strings);
|
|
21756
|
+
|
|
21757
|
+
// We may have received TeX; try to parse it before grading.
|
|
21758
|
+
// If `currentValue` is not TeX, this should be a no-op.
|
|
21759
|
+
const currentValue = ParseTex$1(state.currentValue);
|
|
21760
|
+
const result = val(currentValue);
|
|
21761
|
+
|
|
21762
|
+
// TODO(eater): Seems silly to translate result to this invalid/points
|
|
21763
|
+
// thing and immediately translate it back in ItemRenderer.scoreInput()
|
|
21764
|
+
if (result.empty) {
|
|
21765
|
+
// TODO(FEI-3867): remove null-check once we have APIOptionsInternal
|
|
21766
|
+
const apiResult = onInputError == null ? void 0 : onInputError(null,
|
|
21767
|
+
// reserved for some widget identifier
|
|
21768
|
+
state.currentValue, result.message);
|
|
21769
|
+
return {
|
|
21770
|
+
type: "invalid",
|
|
21771
|
+
message: apiResult === false ? null : result.message
|
|
21772
|
+
};
|
|
21773
|
+
}
|
|
21774
|
+
return {
|
|
21775
|
+
type: "points",
|
|
21776
|
+
earned: result.correct ? 1 : 0,
|
|
21777
|
+
total: 1,
|
|
21778
|
+
message: result.message
|
|
21779
|
+
};
|
|
21780
|
+
}
|
|
21781
|
+
|
|
21741
21782
|
const formExamples$1 = {
|
|
21742
21783
|
integer: function (options, strings) {
|
|
21743
21784
|
return strings.integerExample;
|
|
@@ -21828,7 +21869,7 @@ class InputNumber extends React.Component {
|
|
|
21828
21869
|
};
|
|
21829
21870
|
this.simpleValidate = (rubric, onInputError) => {
|
|
21830
21871
|
onInputError = onInputError || function () {};
|
|
21831
|
-
return
|
|
21872
|
+
return inputNumberValidator(this.getUserInput(), rubric, this.context.strings, onInputError);
|
|
21832
21873
|
};
|
|
21833
21874
|
this.examples = () => {
|
|
21834
21875
|
const {
|
|
@@ -21841,44 +21882,7 @@ class InputNumber extends React.Component {
|
|
|
21841
21882
|
};
|
|
21842
21883
|
}
|
|
21843
21884
|
static validate(state, rubric, strings, onInputError = () => {}) {
|
|
21844
|
-
|
|
21845
|
-
rubric.answerType = "number";
|
|
21846
|
-
}
|
|
21847
|
-
|
|
21848
|
-
// note(matthewc): this will get immediately parsed again by
|
|
21849
|
-
// `KhanAnswerTypes.number.convertToPredicate`, but a string is
|
|
21850
|
-
// expected here
|
|
21851
|
-
const stringValue = `${rubric.value}`;
|
|
21852
|
-
const val = KhanAnswerTypes.number.createValidatorFunctional(stringValue, {
|
|
21853
|
-
simplify: rubric.simplify,
|
|
21854
|
-
inexact: rubric.inexact || undefined,
|
|
21855
|
-
maxError: rubric.maxError,
|
|
21856
|
-
forms: answerTypes[rubric.answerType].forms
|
|
21857
|
-
}, strings);
|
|
21858
|
-
|
|
21859
|
-
// We may have received TeX; try to parse it before grading.
|
|
21860
|
-
// If `currentValue` is not TeX, this should be a no-op.
|
|
21861
|
-
const currentValue = ParseTex$1(state.currentValue);
|
|
21862
|
-
const result = val(currentValue);
|
|
21863
|
-
|
|
21864
|
-
// TODO(eater): Seems silly to translate result to this invalid/points
|
|
21865
|
-
// thing and immediately translate it back in ItemRenderer.scoreInput()
|
|
21866
|
-
if (result.empty) {
|
|
21867
|
-
// TODO(FEI-3867): remove null-check once we have APIOptionsInternal
|
|
21868
|
-
const apiResult = onInputError == null ? void 0 : onInputError(null,
|
|
21869
|
-
// reserved for some widget identifier
|
|
21870
|
-
state.currentValue, result.message);
|
|
21871
|
-
return {
|
|
21872
|
-
type: "invalid",
|
|
21873
|
-
message: apiResult === false ? null : result.message
|
|
21874
|
-
};
|
|
21875
|
-
}
|
|
21876
|
-
return {
|
|
21877
|
-
type: "points",
|
|
21878
|
-
earned: result.correct ? 1 : 0,
|
|
21879
|
-
total: 1,
|
|
21880
|
-
message: result.message
|
|
21881
|
-
};
|
|
21885
|
+
return inputNumberValidator(state, rubric, strings, onInputError);
|
|
21882
21886
|
}
|
|
21883
21887
|
static getUserInputFromProps(props) {
|
|
21884
21888
|
return {
|
|
@@ -22412,15 +22416,15 @@ var NumericInput$1 = {
|
|
|
22412
22416
|
* Several widgets don't have "right"/"wrong" validation logic,
|
|
22413
22417
|
* so this just says to move on past those widgets
|
|
22414
22418
|
*
|
|
22415
|
-
* TODO
|
|
22419
|
+
* TODO(LEMS-2396) widgets that use this probably shouldn't have any
|
|
22416
22420
|
* validation logic and the thing validating an exercise
|
|
22417
22421
|
* should just know to skip these
|
|
22418
22422
|
*/
|
|
22419
|
-
function noopValidator() {
|
|
22423
|
+
function noopValidator(points = 0) {
|
|
22420
22424
|
return {
|
|
22421
22425
|
type: "points",
|
|
22422
|
-
earned:
|
|
22423
|
-
total:
|
|
22426
|
+
earned: points,
|
|
22427
|
+
total: points,
|
|
22424
22428
|
message: null
|
|
22425
22429
|
};
|
|
22426
22430
|
}
|
|
@@ -22472,11 +22476,9 @@ class PassageRef extends React.Component {
|
|
|
22472
22476
|
}
|
|
22473
22477
|
}
|
|
22474
22478
|
};
|
|
22475
|
-
this.simpleValidate = rubric => {
|
|
22476
|
-
return PassageRef.validate(this.getUserInput(), rubric);
|
|
22477
|
-
};
|
|
22478
22479
|
}
|
|
22479
|
-
|
|
22480
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
22481
|
+
static validate() {
|
|
22480
22482
|
return noopValidator();
|
|
22481
22483
|
}
|
|
22482
22484
|
componentDidMount() {
|
|
@@ -22497,6 +22499,10 @@ class PassageRef extends React.Component {
|
|
|
22497
22499
|
window.removeEventListener("resize", this._throttledUpdateRange);
|
|
22498
22500
|
this._isMounted = false;
|
|
22499
22501
|
}
|
|
22502
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
22503
|
+
simpleValidate() {
|
|
22504
|
+
return noopValidator();
|
|
22505
|
+
}
|
|
22500
22506
|
render() {
|
|
22501
22507
|
const {
|
|
22502
22508
|
strings
|
|
@@ -24426,6 +24432,31 @@ var Radio = {
|
|
|
24426
24432
|
/* eslint-disable import/no-named-as-default */
|
|
24427
24433
|
var basicWidgets = [Radio, InputNumber$1, NumericInput$1, Expression$1];
|
|
24428
24434
|
|
|
24435
|
+
function categorizerValidator(userInput, rubric, strings) {
|
|
24436
|
+
let completed = true;
|
|
24437
|
+
let allCorrect = true;
|
|
24438
|
+
rubric.values.forEach((value, i) => {
|
|
24439
|
+
if (userInput.values[i] == null) {
|
|
24440
|
+
completed = false;
|
|
24441
|
+
}
|
|
24442
|
+
if (userInput.values[i] !== value) {
|
|
24443
|
+
allCorrect = false;
|
|
24444
|
+
}
|
|
24445
|
+
});
|
|
24446
|
+
if (!completed) {
|
|
24447
|
+
return {
|
|
24448
|
+
type: "invalid",
|
|
24449
|
+
message: strings.invalidSelection
|
|
24450
|
+
};
|
|
24451
|
+
}
|
|
24452
|
+
return {
|
|
24453
|
+
type: "points",
|
|
24454
|
+
earned: allCorrect ? 1 : 0,
|
|
24455
|
+
total: 1,
|
|
24456
|
+
message: null
|
|
24457
|
+
};
|
|
24458
|
+
}
|
|
24459
|
+
|
|
24429
24460
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
24430
24461
|
class Categorizer extends React.Component {
|
|
24431
24462
|
constructor(..._args) {
|
|
@@ -24441,32 +24472,11 @@ class Categorizer extends React.Component {
|
|
|
24441
24472
|
return Categorizer.getUserInputFromProps(this.props);
|
|
24442
24473
|
};
|
|
24443
24474
|
this.simpleValidate = rubric => {
|
|
24444
|
-
return
|
|
24475
|
+
return categorizerValidator(this.getUserInput(), rubric, this.context.strings);
|
|
24445
24476
|
};
|
|
24446
24477
|
}
|
|
24447
24478
|
static validate(userInput, rubric, strings) {
|
|
24448
|
-
|
|
24449
|
-
let allCorrect = true;
|
|
24450
|
-
rubric.values.forEach((value, i) => {
|
|
24451
|
-
if (userInput.values[i] == null) {
|
|
24452
|
-
completed = false;
|
|
24453
|
-
}
|
|
24454
|
-
if (userInput.values[i] !== value) {
|
|
24455
|
-
allCorrect = false;
|
|
24456
|
-
}
|
|
24457
|
-
});
|
|
24458
|
-
if (!completed) {
|
|
24459
|
-
return {
|
|
24460
|
-
type: "invalid",
|
|
24461
|
-
message: strings.invalidSelection
|
|
24462
|
-
};
|
|
24463
|
-
}
|
|
24464
|
-
return {
|
|
24465
|
-
type: "points",
|
|
24466
|
-
earned: allCorrect ? 1 : 0,
|
|
24467
|
-
total: 1,
|
|
24468
|
-
message: null
|
|
24469
|
-
};
|
|
24479
|
+
return categorizerValidator(userInput, rubric, strings);
|
|
24470
24480
|
}
|
|
24471
24481
|
static getUserInputFromProps(props) {
|
|
24472
24482
|
return {
|
|
@@ -24851,11 +24861,13 @@ class Definition extends React.Component {
|
|
|
24851
24861
|
this.getUserInput = () => {
|
|
24852
24862
|
return {};
|
|
24853
24863
|
};
|
|
24854
|
-
this.simpleValidate = rubric => {
|
|
24855
|
-
return Definition.validate(this.getUserInput(), rubric);
|
|
24856
|
-
};
|
|
24857
24864
|
}
|
|
24858
|
-
|
|
24865
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24866
|
+
static validate() {
|
|
24867
|
+
return noopValidator();
|
|
24868
|
+
}
|
|
24869
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24870
|
+
simpleValidate() {
|
|
24859
24871
|
return noopValidator();
|
|
24860
24872
|
}
|
|
24861
24873
|
render() {
|
|
@@ -24924,18 +24936,13 @@ class DeprecatedStandin extends React__default.Component {
|
|
|
24924
24936
|
return {};
|
|
24925
24937
|
};
|
|
24926
24938
|
this.simpleValidate = rubric => {
|
|
24927
|
-
return
|
|
24939
|
+
return noopValidator(1);
|
|
24928
24940
|
};
|
|
24929
24941
|
}
|
|
24930
24942
|
static validate(userInput, rubric) {
|
|
24931
24943
|
// Since this mean to replace an existing widget the learner
|
|
24932
24944
|
// WILL earn points for this widget
|
|
24933
|
-
return
|
|
24934
|
-
type: "points",
|
|
24935
|
-
earned: 1,
|
|
24936
|
-
total: 1,
|
|
24937
|
-
message: null
|
|
24938
|
-
};
|
|
24945
|
+
return noopValidator(1);
|
|
24939
24946
|
}
|
|
24940
24947
|
render() {
|
|
24941
24948
|
return /*#__PURE__*/React__default.createElement("div", {
|
|
@@ -25083,11 +25090,9 @@ class Explanation extends React.Component {
|
|
|
25083
25090
|
this.getUserInput = () => {
|
|
25084
25091
|
return {};
|
|
25085
25092
|
};
|
|
25086
|
-
this.simpleValidate = rubric => {
|
|
25087
|
-
return Explanation.validate(this.getUserInput(), rubric);
|
|
25088
|
-
};
|
|
25089
25093
|
}
|
|
25090
|
-
|
|
25094
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
25095
|
+
static validate() {
|
|
25091
25096
|
return noopValidator();
|
|
25092
25097
|
}
|
|
25093
25098
|
componentDidMount() {
|
|
@@ -25096,6 +25101,10 @@ class Explanation extends React.Component {
|
|
|
25096
25101
|
componentWillUnmount() {
|
|
25097
25102
|
this._mounted = false;
|
|
25098
25103
|
}
|
|
25104
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
25105
|
+
simpleValidate() {
|
|
25106
|
+
return noopValidator();
|
|
25107
|
+
}
|
|
25099
25108
|
render() {
|
|
25100
25109
|
const promptText = this.state.expanded ? this.props.hidePrompt : this.props.showPrompt;
|
|
25101
25110
|
const caretIcon = this.state.expanded ? caretUp : caretDown;
|
|
@@ -27252,12 +27261,14 @@ class ImageWidget extends React.Component {
|
|
|
27252
27261
|
this.getUserInput = () => {
|
|
27253
27262
|
return null;
|
|
27254
27263
|
};
|
|
27255
|
-
this.simpleValidate = rubric => {
|
|
27256
|
-
return ImageWidget.validate(this.getUserInput(), rubric);
|
|
27257
|
-
};
|
|
27258
27264
|
this.focus = () => {};
|
|
27259
27265
|
}
|
|
27260
|
-
|
|
27266
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27267
|
+
static validate() {
|
|
27268
|
+
return noopValidator();
|
|
27269
|
+
}
|
|
27270
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27271
|
+
simpleValidate() {
|
|
27261
27272
|
return noopValidator();
|
|
27262
27273
|
}
|
|
27263
27274
|
// no-op
|
|
@@ -27574,11 +27585,9 @@ class Interaction extends React.Component {
|
|
|
27574
27585
|
// anything.
|
|
27575
27586
|
return {};
|
|
27576
27587
|
};
|
|
27577
|
-
this.simpleValidate = rubric => {
|
|
27578
|
-
return Interaction.validate(this.getUserInput(), rubric);
|
|
27579
|
-
};
|
|
27580
27588
|
}
|
|
27581
|
-
|
|
27589
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27590
|
+
static validate() {
|
|
27582
27591
|
return noopValidator();
|
|
27583
27592
|
}
|
|
27584
27593
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
@@ -27599,6 +27608,10 @@ class Interaction extends React.Component {
|
|
|
27599
27608
|
});
|
|
27600
27609
|
}
|
|
27601
27610
|
}
|
|
27611
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27612
|
+
simpleValidate() {
|
|
27613
|
+
return noopValidator();
|
|
27614
|
+
}
|
|
27602
27615
|
render() {
|
|
27603
27616
|
const range = this.props.graph.range;
|
|
27604
27617
|
let labels = this.props.graph.labels;
|
|
@@ -29649,18 +29662,26 @@ function GraphLockedLabelsLayer(props) {
|
|
|
29649
29662
|
lockedFigures
|
|
29650
29663
|
} = props;
|
|
29651
29664
|
return lockedFigures.map((figure, i) => {
|
|
29652
|
-
var _flags$mafs;
|
|
29665
|
+
var _flags$mafs, _flags$mafs2;
|
|
29653
29666
|
if (figure.type === "label") {
|
|
29654
29667
|
return /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
29655
29668
|
key: `label-${i}`
|
|
29656
29669
|
}, figure));
|
|
29657
29670
|
}
|
|
29658
|
-
if (
|
|
29671
|
+
if (
|
|
29672
|
+
// Point flag + point type
|
|
29673
|
+
flags != null && (_flags$mafs = flags["mafs"]) != null && _flags$mafs["locked-point-labels"] && figure.type === "point" ||
|
|
29674
|
+
// Line flag + line type
|
|
29675
|
+
flags != null && (_flags$mafs2 = flags["mafs"]) != null && _flags$mafs2["locked-line-labels"] && figure.type === "line") {
|
|
29659
29676
|
return /*#__PURE__*/React.createElement(React.Fragment, {
|
|
29660
|
-
key:
|
|
29677
|
+
key: i
|
|
29661
29678
|
}, figure.labels.map((label, j) => /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
29662
|
-
key:
|
|
29663
|
-
}, label))))
|
|
29679
|
+
key: `${i}-label-${j}`
|
|
29680
|
+
}, label))), figure.type === "line" && /*#__PURE__*/React.createElement(React.Fragment, null, figure.points[0].labels.map((label, k) => /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
29681
|
+
key: `locked-figure-${i}-point-1-label-${k}`
|
|
29682
|
+
}, label))), figure.points[1].labels.map((label, k) => /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
29683
|
+
key: `locked-figure-${i}-point-2-label-${k}`
|
|
29684
|
+
}, label)))));
|
|
29664
29685
|
}
|
|
29665
29686
|
return null;
|
|
29666
29687
|
});
|
|
@@ -30000,7 +30021,9 @@ const GraphLockedLayer = props => {
|
|
|
30000
30021
|
|
|
30001
30022
|
const actions = {
|
|
30002
30023
|
global: {
|
|
30003
|
-
deleteIntent
|
|
30024
|
+
deleteIntent,
|
|
30025
|
+
changeInteractionMode,
|
|
30026
|
+
changeKeyboardInvitationVisibility
|
|
30004
30027
|
},
|
|
30005
30028
|
angle: {
|
|
30006
30029
|
movePoint
|
|
@@ -30092,6 +30115,20 @@ function clickPoint(index) {
|
|
|
30092
30115
|
index
|
|
30093
30116
|
};
|
|
30094
30117
|
}
|
|
30118
|
+
const CHANGE_INTERACTION_MODE = "point-change-interaction-mode";
|
|
30119
|
+
function changeInteractionMode(mode) {
|
|
30120
|
+
return {
|
|
30121
|
+
type: CHANGE_INTERACTION_MODE,
|
|
30122
|
+
mode
|
|
30123
|
+
};
|
|
30124
|
+
}
|
|
30125
|
+
const CHANGE_KEYBOARD_INVITATION_VISIBILITY = "change-keyboard-interaction-invitation-visibility";
|
|
30126
|
+
function changeKeyboardInvitationVisibility(shouldShow) {
|
|
30127
|
+
return {
|
|
30128
|
+
type: CHANGE_KEYBOARD_INVITATION_VISIBILITY,
|
|
30129
|
+
shouldShow
|
|
30130
|
+
};
|
|
30131
|
+
}
|
|
30095
30132
|
const MOVE_ALL = "move-all";
|
|
30096
30133
|
function moveAll(delta) {
|
|
30097
30134
|
return {
|
|
@@ -31930,16 +31967,18 @@ const MafsGraph = props => {
|
|
|
31930
31967
|
height
|
|
31931
31968
|
},
|
|
31932
31969
|
onKeyUp: event => {
|
|
31933
|
-
|
|
31934
|
-
var _graphRef$current;
|
|
31935
|
-
dispatch(actions.global.deleteIntent());
|
|
31936
|
-
(_graphRef$current = graphRef.current) == null || _graphRef$current.focus();
|
|
31937
|
-
}
|
|
31970
|
+
handleKeyboardEvent(event, state, dispatch);
|
|
31938
31971
|
},
|
|
31939
31972
|
"aria-label": fullGraphAriaLabel,
|
|
31940
31973
|
"aria-describedby": fullGraphAriaDescription ? descriptionId : undefined,
|
|
31941
31974
|
ref: graphRef,
|
|
31942
|
-
tabIndex: 0
|
|
31975
|
+
tabIndex: 0,
|
|
31976
|
+
onFocus: event => {
|
|
31977
|
+
handleFocusEvent(event, state, dispatch);
|
|
31978
|
+
},
|
|
31979
|
+
onBlur: event => {
|
|
31980
|
+
handleBlurEvent(event, state, dispatch);
|
|
31981
|
+
}
|
|
31943
31982
|
}, fullGraphAriaDescription && /*#__PURE__*/React.createElement(View, {
|
|
31944
31983
|
id: descriptionId,
|
|
31945
31984
|
tabIndex: -1,
|
|
@@ -32001,30 +32040,63 @@ const MafsGraph = props => {
|
|
|
32001
32040
|
}, /*#__PURE__*/React.createElement("svg", nestedSVGAttributes, props.showProtractor && /*#__PURE__*/React.createElement(Protractor, null), renderGraph({
|
|
32002
32041
|
state,
|
|
32003
32042
|
dispatch
|
|
32004
|
-
})))))
|
|
32043
|
+
}))))), state.type === "point" && state.showKeyboardInteractionInvitation && /*#__PURE__*/React.createElement(View, {
|
|
32044
|
+
style: {
|
|
32045
|
+
textAlign: "center",
|
|
32046
|
+
backgroundColor: "white",
|
|
32047
|
+
border: "1px solid #21242C52",
|
|
32048
|
+
padding: "16px 0",
|
|
32049
|
+
boxShadow: "0px 8px 8px 0px #21242C14",
|
|
32050
|
+
// This translates the box to the center of the
|
|
32051
|
+
// graph Then backs it off by half of its
|
|
32052
|
+
// overall height so it's perfectly centered
|
|
32053
|
+
top: "50%",
|
|
32054
|
+
transform: "translateY(-50%)"
|
|
32055
|
+
}
|
|
32056
|
+
}, /*#__PURE__*/React.createElement(LabelMedium, null, "Press ", /*#__PURE__*/React.createElement("strong", null, "Shift + Enter"), " to interact with the graph"))), renderGraphControls({
|
|
32005
32057
|
state,
|
|
32006
32058
|
dispatch,
|
|
32007
32059
|
width
|
|
32008
32060
|
})));
|
|
32009
32061
|
};
|
|
32010
|
-
const renderPointGraphControls = props =>
|
|
32011
|
-
|
|
32012
|
-
|
|
32013
|
-
|
|
32014
|
-
|
|
32015
|
-
}
|
|
32016
|
-
|
|
32017
|
-
|
|
32018
|
-
|
|
32019
|
-
|
|
32020
|
-
|
|
32021
|
-
|
|
32022
|
-
|
|
32023
|
-
|
|
32024
|
-
|
|
32025
|
-
|
|
32026
|
-
|
|
32027
|
-
|
|
32062
|
+
const renderPointGraphControls = props => {
|
|
32063
|
+
const {
|
|
32064
|
+
interactionMode,
|
|
32065
|
+
showRemovePointButton,
|
|
32066
|
+
focusedPointIndex
|
|
32067
|
+
} = props.state;
|
|
32068
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
32069
|
+
style: {
|
|
32070
|
+
flexDirection: "row",
|
|
32071
|
+
width: props.width
|
|
32072
|
+
}
|
|
32073
|
+
}, interactionMode === "keyboard" && /*#__PURE__*/React.createElement(Button, {
|
|
32074
|
+
kind: "secondary",
|
|
32075
|
+
style: {
|
|
32076
|
+
width: "100%",
|
|
32077
|
+
marginLeft: "20px"
|
|
32078
|
+
},
|
|
32079
|
+
tabIndex: 0,
|
|
32080
|
+
onClick: () => {
|
|
32081
|
+
props.dispatch(actions.pointGraph.addPoint([0, 0]));
|
|
32082
|
+
}
|
|
32083
|
+
}, "Add Point"), interactionMode === "mouse" && showRemovePointButton && focusedPointIndex !== null && /*#__PURE__*/React.createElement(Button, {
|
|
32084
|
+
id: REMOVE_BUTTON_ID,
|
|
32085
|
+
kind: "secondary",
|
|
32086
|
+
color: "destructive"
|
|
32087
|
+
// This button is meant to be interacted with by the mouse only
|
|
32088
|
+
// Never allow learners to tab to this button
|
|
32089
|
+
,
|
|
32090
|
+
tabIndex: -1,
|
|
32091
|
+
style: {
|
|
32092
|
+
width: "100%",
|
|
32093
|
+
marginLeft: "20px"
|
|
32094
|
+
},
|
|
32095
|
+
onClick: event => {
|
|
32096
|
+
props.dispatch(actions.pointGraph.removePoint(props.state.focusedPointIndex));
|
|
32097
|
+
}
|
|
32098
|
+
}, "Remove Point"));
|
|
32099
|
+
};
|
|
32028
32100
|
const renderGraphControls = props => {
|
|
32029
32101
|
const {
|
|
32030
32102
|
state,
|
|
@@ -32048,6 +32120,34 @@ const renderGraphControls = props => {
|
|
|
32048
32120
|
return null;
|
|
32049
32121
|
}
|
|
32050
32122
|
};
|
|
32123
|
+
function handleFocusEvent(event, state, dispatch) {
|
|
32124
|
+
if (state.type === "point" && state.numPoints === "unlimited") {
|
|
32125
|
+
if (event.target.classList.contains("mafs-graph") && state.interactionMode === "mouse") {
|
|
32126
|
+
dispatch(actions.global.changeKeyboardInvitationVisibility(true));
|
|
32127
|
+
}
|
|
32128
|
+
}
|
|
32129
|
+
}
|
|
32130
|
+
function handleBlurEvent(event, state, dispatch) {
|
|
32131
|
+
if (state.type === "point" && state.numPoints === "unlimited") {
|
|
32132
|
+
dispatch(actions.global.changeKeyboardInvitationVisibility(false));
|
|
32133
|
+
}
|
|
32134
|
+
}
|
|
32135
|
+
function handleKeyboardEvent(event, state, dispatch) {
|
|
32136
|
+
if (state.type === "point" && state.numPoints === "unlimited") {
|
|
32137
|
+
if (event.key === "Backspace") {
|
|
32138
|
+
dispatch(actions.global.deleteIntent());
|
|
32139
|
+
|
|
32140
|
+
// After removing a point blur
|
|
32141
|
+
// It would be nice if this could focus on the graph but doing so
|
|
32142
|
+
// would trigger the message to prompt a learner to enter keyboard mode
|
|
32143
|
+
document.activeElement.blur();
|
|
32144
|
+
} else if (event.shiftKey && event.key === "Enter") {
|
|
32145
|
+
dispatch(actions.global.changeInteractionMode("keyboard"));
|
|
32146
|
+
} else if (state.interactionMode === "keyboard" && event.key === "a") {
|
|
32147
|
+
dispatch(actions.pointGraph.addPoint([0, 0]));
|
|
32148
|
+
}
|
|
32149
|
+
}
|
|
32150
|
+
}
|
|
32051
32151
|
|
|
32052
32152
|
// Calculate the difference between the min and max values of a range
|
|
32053
32153
|
const getRangeDiff = range => {
|
|
@@ -32212,7 +32312,9 @@ function initializeGraphState(params) {
|
|
|
32212
32312
|
coords: getPointCoords(graph, range, step),
|
|
32213
32313
|
numPoints: graph.numPoints || 0,
|
|
32214
32314
|
focusedPointIndex: null,
|
|
32215
|
-
showRemovePointButton: false
|
|
32315
|
+
showRemovePointButton: false,
|
|
32316
|
+
interactionMode: "mouse",
|
|
32317
|
+
showKeyboardInteractionInvitation: false
|
|
32216
32318
|
});
|
|
32217
32319
|
case "circle":
|
|
32218
32320
|
return _extends({}, shared, {
|
|
@@ -32482,6 +32584,10 @@ function interactiveGraphReducer(state, action) {
|
|
|
32482
32584
|
return doDeleteIntent(state);
|
|
32483
32585
|
case CLICK_POINT:
|
|
32484
32586
|
return doClickPoint(state, action);
|
|
32587
|
+
case CHANGE_INTERACTION_MODE:
|
|
32588
|
+
return doChangeInteractionMode(state, action);
|
|
32589
|
+
case CHANGE_KEYBOARD_INVITATION_VISIBILITY:
|
|
32590
|
+
return doChangeKeyboardInvitationVisibility(state, action);
|
|
32485
32591
|
default:
|
|
32486
32592
|
throw new UnreachableCaseError(action);
|
|
32487
32593
|
}
|
|
@@ -32530,6 +32636,31 @@ function doClickPoint(state, action) {
|
|
|
32530
32636
|
}
|
|
32531
32637
|
return state;
|
|
32532
32638
|
}
|
|
32639
|
+
function doChangeInteractionMode(state, action) {
|
|
32640
|
+
if (state.type !== "point") {
|
|
32641
|
+
return state;
|
|
32642
|
+
}
|
|
32643
|
+
if (state.numPoints === "unlimited") {
|
|
32644
|
+
const nextKeyboardInvitation = action.mode === "keyboard" ? false : state.showKeyboardInteractionInvitation;
|
|
32645
|
+
return _extends({}, state, {
|
|
32646
|
+
interactionMode: action.mode,
|
|
32647
|
+
showKeyboardInteractionInvitation: nextKeyboardInvitation
|
|
32648
|
+
});
|
|
32649
|
+
}
|
|
32650
|
+
return state;
|
|
32651
|
+
}
|
|
32652
|
+
function doChangeKeyboardInvitationVisibility(state, action) {
|
|
32653
|
+
if (state.type !== "point") {
|
|
32654
|
+
return state;
|
|
32655
|
+
}
|
|
32656
|
+
if (state.numPoints === "unlimited") {
|
|
32657
|
+
return _extends({}, state, {
|
|
32658
|
+
showKeyboardInteractionInvitation: action.shouldShow,
|
|
32659
|
+
hasBeenInteractedWith: true
|
|
32660
|
+
});
|
|
32661
|
+
}
|
|
32662
|
+
return state;
|
|
32663
|
+
}
|
|
32533
32664
|
function doMovePointInFigure(state, action) {
|
|
32534
32665
|
switch (state.type) {
|
|
32535
32666
|
case "segment":
|
|
@@ -33266,7 +33397,7 @@ const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
33266
33397
|
const snapTo = graph.type === "polygon" ? graph.snapTo : null;
|
|
33267
33398
|
const showAngles = graph.type === "polygon" ? graph.showAngles : null;
|
|
33268
33399
|
const showSides = graph.type === "polygon" ? graph.showSides : null;
|
|
33269
|
-
const startCoords = "startCoords" in graph ? graph.startCoords :
|
|
33400
|
+
const startCoords = "startCoords" in graph ? graph.startCoords : undefined;
|
|
33270
33401
|
const originalPropsRef = useRef(props);
|
|
33271
33402
|
const latestPropsRef = useLatestRef(props);
|
|
33272
33403
|
useEffect(() => {
|
|
@@ -38629,9 +38760,8 @@ const Measurer = createReactClass({
|
|
|
38629
38760
|
getUserInput: function () {
|
|
38630
38761
|
return {};
|
|
38631
38762
|
},
|
|
38632
|
-
simpleValidate: function (
|
|
38633
|
-
|
|
38634
|
-
return Measurer.validate(this.getUserInput(), rubric);
|
|
38763
|
+
simpleValidate: function () {
|
|
38764
|
+
return noopValidator(1);
|
|
38635
38765
|
},
|
|
38636
38766
|
focus: $.noop,
|
|
38637
38767
|
render: function () {
|
|
@@ -38660,14 +38790,7 @@ const Measurer = createReactClass({
|
|
|
38660
38790
|
}
|
|
38661
38791
|
});
|
|
38662
38792
|
_.extend(Measurer, {
|
|
38663
|
-
validate:
|
|
38664
|
-
return {
|
|
38665
|
-
type: "points",
|
|
38666
|
-
earned: 1,
|
|
38667
|
-
total: 1,
|
|
38668
|
-
message: null
|
|
38669
|
-
};
|
|
38670
|
-
}
|
|
38793
|
+
validate: noopValidator(1)
|
|
38671
38794
|
});
|
|
38672
38795
|
const propUpgrades = {
|
|
38673
38796
|
"1": v0props => {
|
|
@@ -39559,23 +39682,17 @@ Molecule.contextType = PerseusI18nContext;
|
|
|
39559
39682
|
class MoleculeWidget extends React.Component {
|
|
39560
39683
|
constructor(...args) {
|
|
39561
39684
|
super(...args);
|
|
39562
|
-
this.simpleValidate = () => {
|
|
39563
|
-
return {
|
|
39564
|
-
type: "points",
|
|
39565
|
-
earned: 0,
|
|
39566
|
-
total: 0,
|
|
39567
|
-
message: null
|
|
39568
|
-
};
|
|
39569
|
-
};
|
|
39570
39685
|
this.getUserInput = () => {
|
|
39571
39686
|
return [];
|
|
39572
39687
|
};
|
|
39573
|
-
|
|
39574
|
-
|
|
39575
|
-
|
|
39576
|
-
|
|
39577
|
-
|
|
39578
|
-
|
|
39688
|
+
}
|
|
39689
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
39690
|
+
simpleValidate() {
|
|
39691
|
+
return noopValidator();
|
|
39692
|
+
}
|
|
39693
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
39694
|
+
validate() {
|
|
39695
|
+
return noopValidator();
|
|
39579
39696
|
}
|
|
39580
39697
|
render() {
|
|
39581
39698
|
return /*#__PURE__*/React.createElement(Molecule, {
|
|
@@ -42539,7 +42656,8 @@ class Passage extends React.Component {
|
|
|
42539
42656
|
});
|
|
42540
42657
|
};
|
|
42541
42658
|
}
|
|
42542
|
-
|
|
42659
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
42660
|
+
static validate() {
|
|
42543
42661
|
return noopValidator();
|
|
42544
42662
|
}
|
|
42545
42663
|
componentDidMount() {
|
|
@@ -42755,8 +42873,10 @@ class Passage extends React.Component {
|
|
|
42755
42873
|
getUserInput() {
|
|
42756
42874
|
return null;
|
|
42757
42875
|
}
|
|
42758
|
-
|
|
42759
|
-
|
|
42876
|
+
|
|
42877
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
42878
|
+
simpleValidate() {
|
|
42879
|
+
return noopValidator();
|
|
42760
42880
|
}
|
|
42761
42881
|
|
|
42762
42882
|
/**
|
|
@@ -42926,12 +43046,13 @@ class PassageRefTarget extends React.Component {
|
|
|
42926
43046
|
this.change = (...args) => {
|
|
42927
43047
|
return change.apply(this, args);
|
|
42928
43048
|
};
|
|
42929
|
-
// TODO passage-ref-target isn't interactive; remove
|
|
42930
|
-
this.simpleValidate = rubric => {
|
|
42931
|
-
return PassageRefTarget.validate(this.getUserInput(), rubric);
|
|
42932
|
-
};
|
|
42933
43049
|
}
|
|
42934
|
-
|
|
43050
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43051
|
+
static validate() {
|
|
43052
|
+
return noopValidator();
|
|
43053
|
+
}
|
|
43054
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43055
|
+
simpleValidate() {
|
|
42935
43056
|
return noopValidator();
|
|
42936
43057
|
}
|
|
42937
43058
|
render() {
|
|
@@ -44529,9 +44650,6 @@ class Video extends React.Component {
|
|
|
44529
44650
|
this.getUserInput = () => {
|
|
44530
44651
|
return null;
|
|
44531
44652
|
};
|
|
44532
|
-
this.simpleValidate = rubric => {
|
|
44533
|
-
return Video.validate(null, rubric);
|
|
44534
|
-
};
|
|
44535
44653
|
this.change = (...args) => {
|
|
44536
44654
|
// @ts-expect-error - TS2345 - Argument of type 'readonly unknown[]' is not assignable to parameter of type 'any[]'.
|
|
44537
44655
|
return change.apply(this, args);
|
|
@@ -44541,8 +44659,12 @@ class Video extends React.Component {
|
|
|
44541
44659
|
* This is the widget's grading function.
|
|
44542
44660
|
* Points for videos are tallied by the embedded video itself, in the case
|
|
44543
44661
|
* of Khan Academy videos.
|
|
44544
|
-
*/
|
|
44545
|
-
static validate(
|
|
44662
|
+
*/ // TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
44663
|
+
static validate() {
|
|
44664
|
+
return noopValidator();
|
|
44665
|
+
}
|
|
44666
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
44667
|
+
simpleValidate() {
|
|
44546
44668
|
return noopValidator();
|
|
44547
44669
|
}
|
|
44548
44670
|
render() {
|
|
@@ -44648,7 +44770,7 @@ const init = function init(options) {
|
|
|
44648
44770
|
|
|
44649
44771
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44650
44772
|
const libName = "@khanacademy/perseus";
|
|
44651
|
-
const libVersion = "34.
|
|
44773
|
+
const libVersion = "34.1.0";
|
|
44652
44774
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44653
44775
|
|
|
44654
44776
|
const apiVersion = {
|