@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/index.js
CHANGED
|
@@ -21972,6 +21972,48 @@ const answerTypes = {
|
|
|
21972
21972
|
forms: "pi"
|
|
21973
21973
|
}
|
|
21974
21974
|
};
|
|
21975
|
+
function inputNumberValidator(state, rubric, strings) {
|
|
21976
|
+
let onInputError = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : () => {};
|
|
21977
|
+
if (rubric.answerType == null) {
|
|
21978
|
+
rubric.answerType = "number";
|
|
21979
|
+
}
|
|
21980
|
+
|
|
21981
|
+
// note(matthewc): this will get immediately parsed again by
|
|
21982
|
+
// `KhanAnswerTypes.number.convertToPredicate`, but a string is
|
|
21983
|
+
// expected here
|
|
21984
|
+
const stringValue = `${rubric.value}`;
|
|
21985
|
+
const val = KhanAnswerTypes.number.createValidatorFunctional(stringValue, {
|
|
21986
|
+
simplify: rubric.simplify,
|
|
21987
|
+
inexact: rubric.inexact || undefined,
|
|
21988
|
+
maxError: rubric.maxError,
|
|
21989
|
+
forms: answerTypes[rubric.answerType].forms
|
|
21990
|
+
}, strings);
|
|
21991
|
+
|
|
21992
|
+
// We may have received TeX; try to parse it before grading.
|
|
21993
|
+
// If `currentValue` is not TeX, this should be a no-op.
|
|
21994
|
+
const currentValue = ParseTex$1(state.currentValue);
|
|
21995
|
+
const result = val(currentValue);
|
|
21996
|
+
|
|
21997
|
+
// TODO(eater): Seems silly to translate result to this invalid/points
|
|
21998
|
+
// thing and immediately translate it back in ItemRenderer.scoreInput()
|
|
21999
|
+
if (result.empty) {
|
|
22000
|
+
// TODO(FEI-3867): remove null-check once we have APIOptionsInternal
|
|
22001
|
+
const apiResult = onInputError?.(null,
|
|
22002
|
+
// reserved for some widget identifier
|
|
22003
|
+
state.currentValue, result.message);
|
|
22004
|
+
return {
|
|
22005
|
+
type: "invalid",
|
|
22006
|
+
message: apiResult === false ? null : result.message
|
|
22007
|
+
};
|
|
22008
|
+
}
|
|
22009
|
+
return {
|
|
22010
|
+
type: "points",
|
|
22011
|
+
earned: result.correct ? 1 : 0,
|
|
22012
|
+
total: 1,
|
|
22013
|
+
message: result.message
|
|
22014
|
+
};
|
|
22015
|
+
}
|
|
22016
|
+
|
|
21975
22017
|
const formExamples$1 = {
|
|
21976
22018
|
integer: function (options, strings) {
|
|
21977
22019
|
return strings.integerExample;
|
|
@@ -22015,44 +22057,7 @@ class InputNumber extends React__namespace.Component {
|
|
|
22015
22057
|
};
|
|
22016
22058
|
static validate(state, rubric, strings) {
|
|
22017
22059
|
let onInputError = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : () => {};
|
|
22018
|
-
|
|
22019
|
-
rubric.answerType = "number";
|
|
22020
|
-
}
|
|
22021
|
-
|
|
22022
|
-
// note(matthewc): this will get immediately parsed again by
|
|
22023
|
-
// `KhanAnswerTypes.number.convertToPredicate`, but a string is
|
|
22024
|
-
// expected here
|
|
22025
|
-
const stringValue = `${rubric.value}`;
|
|
22026
|
-
const val = KhanAnswerTypes.number.createValidatorFunctional(stringValue, {
|
|
22027
|
-
simplify: rubric.simplify,
|
|
22028
|
-
inexact: rubric.inexact || undefined,
|
|
22029
|
-
maxError: rubric.maxError,
|
|
22030
|
-
forms: answerTypes[rubric.answerType].forms
|
|
22031
|
-
}, strings);
|
|
22032
|
-
|
|
22033
|
-
// We may have received TeX; try to parse it before grading.
|
|
22034
|
-
// If `currentValue` is not TeX, this should be a no-op.
|
|
22035
|
-
const currentValue = ParseTex$1(state.currentValue);
|
|
22036
|
-
const result = val(currentValue);
|
|
22037
|
-
|
|
22038
|
-
// TODO(eater): Seems silly to translate result to this invalid/points
|
|
22039
|
-
// thing and immediately translate it back in ItemRenderer.scoreInput()
|
|
22040
|
-
if (result.empty) {
|
|
22041
|
-
// TODO(FEI-3867): remove null-check once we have APIOptionsInternal
|
|
22042
|
-
const apiResult = onInputError?.(null,
|
|
22043
|
-
// reserved for some widget identifier
|
|
22044
|
-
state.currentValue, result.message);
|
|
22045
|
-
return {
|
|
22046
|
-
type: "invalid",
|
|
22047
|
-
message: apiResult === false ? null : result.message
|
|
22048
|
-
};
|
|
22049
|
-
}
|
|
22050
|
-
return {
|
|
22051
|
-
type: "points",
|
|
22052
|
-
earned: result.correct ? 1 : 0,
|
|
22053
|
-
total: 1,
|
|
22054
|
-
message: result.message
|
|
22055
|
-
};
|
|
22060
|
+
return inputNumberValidator(state, rubric, strings, onInputError);
|
|
22056
22061
|
}
|
|
22057
22062
|
static getUserInputFromProps(props) {
|
|
22058
22063
|
return {
|
|
@@ -22126,7 +22131,7 @@ class InputNumber extends React__namespace.Component {
|
|
|
22126
22131
|
};
|
|
22127
22132
|
simpleValidate = (rubric, onInputError) => {
|
|
22128
22133
|
onInputError = onInputError || function () {};
|
|
22129
|
-
return
|
|
22134
|
+
return inputNumberValidator(this.getUserInput(), rubric, this.context.strings, onInputError);
|
|
22130
22135
|
};
|
|
22131
22136
|
examples = () => {
|
|
22132
22137
|
const {
|
|
@@ -22635,15 +22640,16 @@ var NumericInput$1 = {
|
|
|
22635
22640
|
* Several widgets don't have "right"/"wrong" validation logic,
|
|
22636
22641
|
* so this just says to move on past those widgets
|
|
22637
22642
|
*
|
|
22638
|
-
* TODO
|
|
22643
|
+
* TODO(LEMS-2396) widgets that use this probably shouldn't have any
|
|
22639
22644
|
* validation logic and the thing validating an exercise
|
|
22640
22645
|
* should just know to skip these
|
|
22641
22646
|
*/
|
|
22642
22647
|
function noopValidator() {
|
|
22648
|
+
let points = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
22643
22649
|
return {
|
|
22644
22650
|
type: "points",
|
|
22645
|
-
earned:
|
|
22646
|
-
total:
|
|
22651
|
+
earned: points,
|
|
22652
|
+
total: points,
|
|
22647
22653
|
message: null
|
|
22648
22654
|
};
|
|
22649
22655
|
}
|
|
@@ -22665,7 +22671,9 @@ class PassageRef extends React__namespace.Component {
|
|
|
22665
22671
|
lineRange: null,
|
|
22666
22672
|
content: null
|
|
22667
22673
|
};
|
|
22668
|
-
|
|
22674
|
+
|
|
22675
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
22676
|
+
static validate() {
|
|
22669
22677
|
return noopValidator();
|
|
22670
22678
|
}
|
|
22671
22679
|
componentDidMount() {
|
|
@@ -22727,9 +22735,11 @@ class PassageRef extends React__namespace.Component {
|
|
|
22727
22735
|
}
|
|
22728
22736
|
}
|
|
22729
22737
|
};
|
|
22730
|
-
|
|
22731
|
-
|
|
22732
|
-
|
|
22738
|
+
|
|
22739
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
22740
|
+
simpleValidate() {
|
|
22741
|
+
return noopValidator();
|
|
22742
|
+
}
|
|
22733
22743
|
render() {
|
|
22734
22744
|
const {
|
|
22735
22745
|
strings
|
|
@@ -24676,6 +24686,31 @@ var Radio = {
|
|
|
24676
24686
|
/* eslint-disable import/no-named-as-default */
|
|
24677
24687
|
var basicWidgets = [Radio, InputNumber$1, NumericInput$1, Expression$1];
|
|
24678
24688
|
|
|
24689
|
+
function categorizerValidator(userInput, rubric, strings) {
|
|
24690
|
+
let completed = true;
|
|
24691
|
+
let allCorrect = true;
|
|
24692
|
+
rubric.values.forEach((value, i) => {
|
|
24693
|
+
if (userInput.values[i] == null) {
|
|
24694
|
+
completed = false;
|
|
24695
|
+
}
|
|
24696
|
+
if (userInput.values[i] !== value) {
|
|
24697
|
+
allCorrect = false;
|
|
24698
|
+
}
|
|
24699
|
+
});
|
|
24700
|
+
if (!completed) {
|
|
24701
|
+
return {
|
|
24702
|
+
type: "invalid",
|
|
24703
|
+
message: strings.invalidSelection
|
|
24704
|
+
};
|
|
24705
|
+
}
|
|
24706
|
+
return {
|
|
24707
|
+
type: "points",
|
|
24708
|
+
earned: allCorrect ? 1 : 0,
|
|
24709
|
+
total: 1,
|
|
24710
|
+
message: null
|
|
24711
|
+
};
|
|
24712
|
+
}
|
|
24713
|
+
|
|
24679
24714
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
24680
24715
|
class Categorizer extends React__namespace.Component {
|
|
24681
24716
|
static contextType = PerseusI18nContext;
|
|
@@ -24689,28 +24724,7 @@ class Categorizer extends React__namespace.Component {
|
|
|
24689
24724
|
uniqueId: ___default["default"].uniqueId("perseus_radio_")
|
|
24690
24725
|
};
|
|
24691
24726
|
static validate(userInput, rubric, strings) {
|
|
24692
|
-
|
|
24693
|
-
let allCorrect = true;
|
|
24694
|
-
rubric.values.forEach((value, i) => {
|
|
24695
|
-
if (userInput.values[i] == null) {
|
|
24696
|
-
completed = false;
|
|
24697
|
-
}
|
|
24698
|
-
if (userInput.values[i] !== value) {
|
|
24699
|
-
allCorrect = false;
|
|
24700
|
-
}
|
|
24701
|
-
});
|
|
24702
|
-
if (!completed) {
|
|
24703
|
-
return {
|
|
24704
|
-
type: "invalid",
|
|
24705
|
-
message: strings.invalidSelection
|
|
24706
|
-
};
|
|
24707
|
-
}
|
|
24708
|
-
return {
|
|
24709
|
-
type: "points",
|
|
24710
|
-
earned: allCorrect ? 1 : 0,
|
|
24711
|
-
total: 1,
|
|
24712
|
-
message: null
|
|
24713
|
-
};
|
|
24727
|
+
return categorizerValidator(userInput, rubric, strings);
|
|
24714
24728
|
}
|
|
24715
24729
|
static getUserInputFromProps(props) {
|
|
24716
24730
|
return {
|
|
@@ -24738,7 +24752,7 @@ class Categorizer extends React__namespace.Component {
|
|
|
24738
24752
|
this.props.trackInteraction();
|
|
24739
24753
|
}
|
|
24740
24754
|
simpleValidate = rubric => {
|
|
24741
|
-
return
|
|
24755
|
+
return categorizerValidator(this.getUserInput(), rubric, this.context.strings);
|
|
24742
24756
|
};
|
|
24743
24757
|
render() {
|
|
24744
24758
|
const self = this;
|
|
@@ -25108,15 +25122,19 @@ class Definition extends React__namespace.Component {
|
|
|
25108
25122
|
togglePrompt: "define me",
|
|
25109
25123
|
definition: "definition goes here"
|
|
25110
25124
|
};
|
|
25111
|
-
|
|
25125
|
+
|
|
25126
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
25127
|
+
static validate() {
|
|
25112
25128
|
return noopValidator();
|
|
25113
25129
|
}
|
|
25114
25130
|
getUserInput = () => {
|
|
25115
25131
|
return {};
|
|
25116
25132
|
};
|
|
25117
|
-
|
|
25118
|
-
|
|
25119
|
-
|
|
25133
|
+
|
|
25134
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
25135
|
+
simpleValidate() {
|
|
25136
|
+
return noopValidator();
|
|
25137
|
+
}
|
|
25120
25138
|
render() {
|
|
25121
25139
|
return /*#__PURE__*/React__namespace.createElement(DefinitionConsumer, null, _ref => {
|
|
25122
25140
|
let {
|
|
@@ -25182,18 +25200,13 @@ class DeprecatedStandin extends React__default["default"].Component {
|
|
|
25182
25200
|
static validate(userInput, rubric) {
|
|
25183
25201
|
// Since this mean to replace an existing widget the learner
|
|
25184
25202
|
// WILL earn points for this widget
|
|
25185
|
-
return
|
|
25186
|
-
type: "points",
|
|
25187
|
-
earned: 1,
|
|
25188
|
-
total: 1,
|
|
25189
|
-
message: null
|
|
25190
|
-
};
|
|
25203
|
+
return noopValidator(1);
|
|
25191
25204
|
}
|
|
25192
25205
|
getUserInput = () => {
|
|
25193
25206
|
return {};
|
|
25194
25207
|
};
|
|
25195
25208
|
simpleValidate = rubric => {
|
|
25196
|
-
return
|
|
25209
|
+
return noopValidator(1);
|
|
25197
25210
|
};
|
|
25198
25211
|
render() {
|
|
25199
25212
|
return /*#__PURE__*/React__default["default"].createElement("div", {
|
|
@@ -25331,7 +25344,9 @@ class Explanation extends React__namespace.Component {
|
|
|
25331
25344
|
widgets: {},
|
|
25332
25345
|
linterContext: PerseusLinter.linterContextDefault
|
|
25333
25346
|
};
|
|
25334
|
-
|
|
25347
|
+
|
|
25348
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
25349
|
+
static validate() {
|
|
25335
25350
|
return noopValidator();
|
|
25336
25351
|
}
|
|
25337
25352
|
componentDidMount() {
|
|
@@ -25358,9 +25373,11 @@ class Explanation extends React__namespace.Component {
|
|
|
25358
25373
|
getUserInput = () => {
|
|
25359
25374
|
return {};
|
|
25360
25375
|
};
|
|
25361
|
-
|
|
25362
|
-
|
|
25363
|
-
|
|
25376
|
+
|
|
25377
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
25378
|
+
simpleValidate() {
|
|
25379
|
+
return noopValidator();
|
|
25380
|
+
}
|
|
25364
25381
|
render() {
|
|
25365
25382
|
const promptText = this.state.expanded ? this.props.hidePrompt : this.props.showPrompt;
|
|
25366
25383
|
const caretIcon = this.state.expanded ? caretUp__default["default"] : caretDown__default["default"];
|
|
@@ -27538,7 +27555,9 @@ class ImageWidget extends React__namespace.Component {
|
|
|
27538
27555
|
caption: "",
|
|
27539
27556
|
linterContext: PerseusLinter.linterContextDefault
|
|
27540
27557
|
};
|
|
27541
|
-
|
|
27558
|
+
|
|
27559
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27560
|
+
static validate() {
|
|
27542
27561
|
return noopValidator();
|
|
27543
27562
|
}
|
|
27544
27563
|
change = (() => {
|
|
@@ -27553,9 +27572,11 @@ class ImageWidget extends React__namespace.Component {
|
|
|
27553
27572
|
getUserInput = () => {
|
|
27554
27573
|
return null;
|
|
27555
27574
|
};
|
|
27556
|
-
|
|
27557
|
-
|
|
27558
|
-
|
|
27575
|
+
|
|
27576
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27577
|
+
simpleValidate() {
|
|
27578
|
+
return noopValidator();
|
|
27579
|
+
}
|
|
27559
27580
|
focus = () => {}; // no-op
|
|
27560
27581
|
|
|
27561
27582
|
render() {
|
|
@@ -27781,7 +27802,9 @@ class Interaction extends React__namespace.Component {
|
|
|
27781
27802
|
},
|
|
27782
27803
|
elements: []
|
|
27783
27804
|
};
|
|
27784
|
-
|
|
27805
|
+
|
|
27806
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27807
|
+
static validate() {
|
|
27785
27808
|
return noopValidator();
|
|
27786
27809
|
}
|
|
27787
27810
|
state = {
|
|
@@ -27898,9 +27921,11 @@ class Interaction extends React__namespace.Component {
|
|
|
27898
27921
|
// anything.
|
|
27899
27922
|
return {};
|
|
27900
27923
|
};
|
|
27901
|
-
|
|
27902
|
-
|
|
27903
|
-
|
|
27924
|
+
|
|
27925
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27926
|
+
simpleValidate() {
|
|
27927
|
+
return noopValidator();
|
|
27928
|
+
}
|
|
27904
27929
|
render() {
|
|
27905
27930
|
const range = this.props.graph.range;
|
|
27906
27931
|
let labels = this.props.graph.labels;
|
|
@@ -29963,12 +29988,20 @@ function GraphLockedLabelsLayer(props) {
|
|
|
29963
29988
|
key: `label-${i}`
|
|
29964
29989
|
}, figure));
|
|
29965
29990
|
}
|
|
29966
|
-
if (
|
|
29991
|
+
if (
|
|
29992
|
+
// Point flag + point type
|
|
29993
|
+
flags?.["mafs"]?.["locked-point-labels"] && figure.type === "point" ||
|
|
29994
|
+
// Line flag + line type
|
|
29995
|
+
flags?.["mafs"]?.["locked-line-labels"] && figure.type === "line") {
|
|
29967
29996
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, {
|
|
29968
|
-
key:
|
|
29997
|
+
key: i
|
|
29969
29998
|
}, figure.labels.map((label, j) => /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends({
|
|
29970
|
-
key:
|
|
29971
|
-
}, label))))
|
|
29999
|
+
key: `${i}-label-${j}`
|
|
30000
|
+
}, label))), figure.type === "line" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, figure.points[0].labels.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends({
|
|
30001
|
+
key: `locked-figure-${i}-point-1-label-${k}`
|
|
30002
|
+
}, label))), figure.points[1].labels.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends({
|
|
30003
|
+
key: `locked-figure-${i}-point-2-label-${k}`
|
|
30004
|
+
}, label)))));
|
|
29972
30005
|
}
|
|
29973
30006
|
return null;
|
|
29974
30007
|
});
|
|
@@ -30308,7 +30341,9 @@ const GraphLockedLayer = props => {
|
|
|
30308
30341
|
|
|
30309
30342
|
const actions = {
|
|
30310
30343
|
global: {
|
|
30311
|
-
deleteIntent
|
|
30344
|
+
deleteIntent,
|
|
30345
|
+
changeInteractionMode,
|
|
30346
|
+
changeKeyboardInvitationVisibility
|
|
30312
30347
|
},
|
|
30313
30348
|
angle: {
|
|
30314
30349
|
movePoint
|
|
@@ -30400,6 +30435,20 @@ function clickPoint(index) {
|
|
|
30400
30435
|
index
|
|
30401
30436
|
};
|
|
30402
30437
|
}
|
|
30438
|
+
const CHANGE_INTERACTION_MODE = "point-change-interaction-mode";
|
|
30439
|
+
function changeInteractionMode(mode) {
|
|
30440
|
+
return {
|
|
30441
|
+
type: CHANGE_INTERACTION_MODE,
|
|
30442
|
+
mode
|
|
30443
|
+
};
|
|
30444
|
+
}
|
|
30445
|
+
const CHANGE_KEYBOARD_INVITATION_VISIBILITY = "change-keyboard-interaction-invitation-visibility";
|
|
30446
|
+
function changeKeyboardInvitationVisibility(shouldShow) {
|
|
30447
|
+
return {
|
|
30448
|
+
type: CHANGE_KEYBOARD_INVITATION_VISIBILITY,
|
|
30449
|
+
shouldShow
|
|
30450
|
+
};
|
|
30451
|
+
}
|
|
30403
30452
|
const MOVE_ALL = "move-all";
|
|
30404
30453
|
function moveAll(delta) {
|
|
30405
30454
|
return {
|
|
@@ -32257,15 +32306,18 @@ const MafsGraph = props => {
|
|
|
32257
32306
|
height
|
|
32258
32307
|
},
|
|
32259
32308
|
onKeyUp: event => {
|
|
32260
|
-
|
|
32261
|
-
dispatch(actions.global.deleteIntent());
|
|
32262
|
-
graphRef.current?.focus();
|
|
32263
|
-
}
|
|
32309
|
+
handleKeyboardEvent(event, state, dispatch);
|
|
32264
32310
|
},
|
|
32265
32311
|
"aria-label": fullGraphAriaLabel,
|
|
32266
32312
|
"aria-describedby": fullGraphAriaDescription ? descriptionId : undefined,
|
|
32267
32313
|
ref: graphRef,
|
|
32268
|
-
tabIndex: 0
|
|
32314
|
+
tabIndex: 0,
|
|
32315
|
+
onFocus: event => {
|
|
32316
|
+
handleFocusEvent(event, state, dispatch);
|
|
32317
|
+
},
|
|
32318
|
+
onBlur: event => {
|
|
32319
|
+
handleBlurEvent(event, state, dispatch);
|
|
32320
|
+
}
|
|
32269
32321
|
}, fullGraphAriaDescription && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
32270
32322
|
id: descriptionId,
|
|
32271
32323
|
tabIndex: -1,
|
|
@@ -32327,30 +32379,63 @@ const MafsGraph = props => {
|
|
|
32327
32379
|
}, /*#__PURE__*/React__namespace.createElement("svg", nestedSVGAttributes, props.showProtractor && /*#__PURE__*/React__namespace.createElement(Protractor, null), renderGraph({
|
|
32328
32380
|
state,
|
|
32329
32381
|
dispatch
|
|
32330
|
-
})))))
|
|
32382
|
+
}))))), state.type === "point" && state.showKeyboardInteractionInvitation && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
32383
|
+
style: {
|
|
32384
|
+
textAlign: "center",
|
|
32385
|
+
backgroundColor: "white",
|
|
32386
|
+
border: "1px solid #21242C52",
|
|
32387
|
+
padding: "16px 0",
|
|
32388
|
+
boxShadow: "0px 8px 8px 0px #21242C14",
|
|
32389
|
+
// This translates the box to the center of the
|
|
32390
|
+
// graph Then backs it off by half of its
|
|
32391
|
+
// overall height so it's perfectly centered
|
|
32392
|
+
top: "50%",
|
|
32393
|
+
transform: "translateY(-50%)"
|
|
32394
|
+
}
|
|
32395
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, null, "Press ", /*#__PURE__*/React__namespace.createElement("strong", null, "Shift + Enter"), " to interact with the graph"))), renderGraphControls({
|
|
32331
32396
|
state,
|
|
32332
32397
|
dispatch,
|
|
32333
32398
|
width
|
|
32334
32399
|
})));
|
|
32335
32400
|
};
|
|
32336
|
-
const renderPointGraphControls = props =>
|
|
32337
|
-
|
|
32338
|
-
|
|
32339
|
-
|
|
32340
|
-
|
|
32341
|
-
}
|
|
32342
|
-
|
|
32343
|
-
|
|
32344
|
-
|
|
32345
|
-
|
|
32346
|
-
|
|
32347
|
-
|
|
32348
|
-
|
|
32349
|
-
|
|
32350
|
-
|
|
32351
|
-
|
|
32352
|
-
|
|
32353
|
-
|
|
32401
|
+
const renderPointGraphControls = props => {
|
|
32402
|
+
const {
|
|
32403
|
+
interactionMode,
|
|
32404
|
+
showRemovePointButton,
|
|
32405
|
+
focusedPointIndex
|
|
32406
|
+
} = props.state;
|
|
32407
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
32408
|
+
style: {
|
|
32409
|
+
flexDirection: "row",
|
|
32410
|
+
width: props.width
|
|
32411
|
+
}
|
|
32412
|
+
}, interactionMode === "keyboard" && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
32413
|
+
kind: "secondary",
|
|
32414
|
+
style: {
|
|
32415
|
+
width: "100%",
|
|
32416
|
+
marginLeft: "20px"
|
|
32417
|
+
},
|
|
32418
|
+
tabIndex: 0,
|
|
32419
|
+
onClick: () => {
|
|
32420
|
+
props.dispatch(actions.pointGraph.addPoint([0, 0]));
|
|
32421
|
+
}
|
|
32422
|
+
}, "Add Point"), interactionMode === "mouse" && showRemovePointButton && focusedPointIndex !== null && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
32423
|
+
id: REMOVE_BUTTON_ID,
|
|
32424
|
+
kind: "secondary",
|
|
32425
|
+
color: "destructive"
|
|
32426
|
+
// This button is meant to be interacted with by the mouse only
|
|
32427
|
+
// Never allow learners to tab to this button
|
|
32428
|
+
,
|
|
32429
|
+
tabIndex: -1,
|
|
32430
|
+
style: {
|
|
32431
|
+
width: "100%",
|
|
32432
|
+
marginLeft: "20px"
|
|
32433
|
+
},
|
|
32434
|
+
onClick: event => {
|
|
32435
|
+
props.dispatch(actions.pointGraph.removePoint(props.state.focusedPointIndex));
|
|
32436
|
+
}
|
|
32437
|
+
}, "Remove Point"));
|
|
32438
|
+
};
|
|
32354
32439
|
const renderGraphControls = props => {
|
|
32355
32440
|
const {
|
|
32356
32441
|
state,
|
|
@@ -32374,6 +32459,34 @@ const renderGraphControls = props => {
|
|
|
32374
32459
|
return null;
|
|
32375
32460
|
}
|
|
32376
32461
|
};
|
|
32462
|
+
function handleFocusEvent(event, state, dispatch) {
|
|
32463
|
+
if (state.type === "point" && state.numPoints === "unlimited") {
|
|
32464
|
+
if (event.target.classList.contains("mafs-graph") && state.interactionMode === "mouse") {
|
|
32465
|
+
dispatch(actions.global.changeKeyboardInvitationVisibility(true));
|
|
32466
|
+
}
|
|
32467
|
+
}
|
|
32468
|
+
}
|
|
32469
|
+
function handleBlurEvent(event, state, dispatch) {
|
|
32470
|
+
if (state.type === "point" && state.numPoints === "unlimited") {
|
|
32471
|
+
dispatch(actions.global.changeKeyboardInvitationVisibility(false));
|
|
32472
|
+
}
|
|
32473
|
+
}
|
|
32474
|
+
function handleKeyboardEvent(event, state, dispatch) {
|
|
32475
|
+
if (state.type === "point" && state.numPoints === "unlimited") {
|
|
32476
|
+
if (event.key === "Backspace") {
|
|
32477
|
+
dispatch(actions.global.deleteIntent());
|
|
32478
|
+
|
|
32479
|
+
// After removing a point blur
|
|
32480
|
+
// It would be nice if this could focus on the graph but doing so
|
|
32481
|
+
// would trigger the message to prompt a learner to enter keyboard mode
|
|
32482
|
+
document.activeElement.blur();
|
|
32483
|
+
} else if (event.shiftKey && event.key === "Enter") {
|
|
32484
|
+
dispatch(actions.global.changeInteractionMode("keyboard"));
|
|
32485
|
+
} else if (state.interactionMode === "keyboard" && event.key === "a") {
|
|
32486
|
+
dispatch(actions.pointGraph.addPoint([0, 0]));
|
|
32487
|
+
}
|
|
32488
|
+
}
|
|
32489
|
+
}
|
|
32377
32490
|
|
|
32378
32491
|
// Calculate the difference between the min and max values of a range
|
|
32379
32492
|
const getRangeDiff = range => {
|
|
@@ -32543,7 +32656,9 @@ function initializeGraphState(params) {
|
|
|
32543
32656
|
coords: getPointCoords(graph, range, step),
|
|
32544
32657
|
numPoints: graph.numPoints || 0,
|
|
32545
32658
|
focusedPointIndex: null,
|
|
32546
|
-
showRemovePointButton: false
|
|
32659
|
+
showRemovePointButton: false,
|
|
32660
|
+
interactionMode: "mouse",
|
|
32661
|
+
showKeyboardInteractionInvitation: false
|
|
32547
32662
|
};
|
|
32548
32663
|
case "circle":
|
|
32549
32664
|
return {
|
|
@@ -32816,6 +32931,10 @@ function interactiveGraphReducer(state, action) {
|
|
|
32816
32931
|
return doDeleteIntent(state);
|
|
32817
32932
|
case CLICK_POINT:
|
|
32818
32933
|
return doClickPoint(state, action);
|
|
32934
|
+
case CHANGE_INTERACTION_MODE:
|
|
32935
|
+
return doChangeInteractionMode(state, action);
|
|
32936
|
+
case CHANGE_KEYBOARD_INVITATION_VISIBILITY:
|
|
32937
|
+
return doChangeKeyboardInvitationVisibility(state, action);
|
|
32819
32938
|
default:
|
|
32820
32939
|
throw new wonderStuffCore.UnreachableCaseError(action);
|
|
32821
32940
|
}
|
|
@@ -32867,6 +32986,33 @@ function doClickPoint(state, action) {
|
|
|
32867
32986
|
}
|
|
32868
32987
|
return state;
|
|
32869
32988
|
}
|
|
32989
|
+
function doChangeInteractionMode(state, action) {
|
|
32990
|
+
if (state.type !== "point") {
|
|
32991
|
+
return state;
|
|
32992
|
+
}
|
|
32993
|
+
if (state.numPoints === "unlimited") {
|
|
32994
|
+
const nextKeyboardInvitation = action.mode === "keyboard" ? false : state.showKeyboardInteractionInvitation;
|
|
32995
|
+
return {
|
|
32996
|
+
...state,
|
|
32997
|
+
interactionMode: action.mode,
|
|
32998
|
+
showKeyboardInteractionInvitation: nextKeyboardInvitation
|
|
32999
|
+
};
|
|
33000
|
+
}
|
|
33001
|
+
return state;
|
|
33002
|
+
}
|
|
33003
|
+
function doChangeKeyboardInvitationVisibility(state, action) {
|
|
33004
|
+
if (state.type !== "point") {
|
|
33005
|
+
return state;
|
|
33006
|
+
}
|
|
33007
|
+
if (state.numPoints === "unlimited") {
|
|
33008
|
+
return {
|
|
33009
|
+
...state,
|
|
33010
|
+
showKeyboardInteractionInvitation: action.shouldShow,
|
|
33011
|
+
hasBeenInteractedWith: true
|
|
33012
|
+
};
|
|
33013
|
+
}
|
|
33014
|
+
return state;
|
|
33015
|
+
}
|
|
32870
33016
|
function doMovePointInFigure(state, action) {
|
|
32871
33017
|
switch (state.type) {
|
|
32872
33018
|
case "segment":
|
|
@@ -33635,7 +33781,7 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
|
|
|
33635
33781
|
const snapTo = graph.type === "polygon" ? graph.snapTo : null;
|
|
33636
33782
|
const showAngles = graph.type === "polygon" ? graph.showAngles : null;
|
|
33637
33783
|
const showSides = graph.type === "polygon" ? graph.showSides : null;
|
|
33638
|
-
const startCoords = "startCoords" in graph ? graph.startCoords :
|
|
33784
|
+
const startCoords = "startCoords" in graph ? graph.startCoords : undefined;
|
|
33639
33785
|
const originalPropsRef = React.useRef(props);
|
|
33640
33786
|
const latestPropsRef = wonderBlocksCore.useLatestRef(props);
|
|
33641
33787
|
React.useEffect(() => {
|
|
@@ -38981,9 +39127,8 @@ const Measurer = createReactClass__default["default"]({
|
|
|
38981
39127
|
getUserInput: function () {
|
|
38982
39128
|
return {};
|
|
38983
39129
|
},
|
|
38984
|
-
simpleValidate: function (
|
|
38985
|
-
|
|
38986
|
-
return Measurer.validate(this.getUserInput(), rubric);
|
|
39130
|
+
simpleValidate: function () {
|
|
39131
|
+
return noopValidator(1);
|
|
38987
39132
|
},
|
|
38988
39133
|
focus: $__default["default"].noop,
|
|
38989
39134
|
render: function () {
|
|
@@ -39012,14 +39157,7 @@ const Measurer = createReactClass__default["default"]({
|
|
|
39012
39157
|
}
|
|
39013
39158
|
});
|
|
39014
39159
|
___default["default"].extend(Measurer, {
|
|
39015
|
-
validate:
|
|
39016
|
-
return {
|
|
39017
|
-
type: "points",
|
|
39018
|
-
earned: 1,
|
|
39019
|
-
total: 1,
|
|
39020
|
-
message: null
|
|
39021
|
-
};
|
|
39022
|
-
}
|
|
39160
|
+
validate: noopValidator(1)
|
|
39023
39161
|
});
|
|
39024
39162
|
const propUpgrades = {
|
|
39025
39163
|
"1": v0props => {
|
|
@@ -39914,23 +40052,19 @@ class MoleculeWidget extends React__namespace.Component {
|
|
|
39914
40052
|
static defaultProps = {
|
|
39915
40053
|
rotationAngle: 0
|
|
39916
40054
|
};
|
|
39917
|
-
|
|
39918
|
-
|
|
39919
|
-
|
|
39920
|
-
|
|
39921
|
-
|
|
39922
|
-
message: null
|
|
39923
|
-
};
|
|
39924
|
-
};
|
|
40055
|
+
|
|
40056
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
40057
|
+
simpleValidate() {
|
|
40058
|
+
return noopValidator();
|
|
40059
|
+
}
|
|
39925
40060
|
getUserInput = () => {
|
|
39926
40061
|
return [];
|
|
39927
40062
|
};
|
|
39928
|
-
|
|
39929
|
-
|
|
39930
|
-
|
|
39931
|
-
// return.
|
|
40063
|
+
|
|
40064
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
40065
|
+
validate() {
|
|
39932
40066
|
return noopValidator();
|
|
39933
|
-
}
|
|
40067
|
+
}
|
|
39934
40068
|
render() {
|
|
39935
40069
|
return /*#__PURE__*/React__namespace.createElement(Molecule, {
|
|
39936
40070
|
widgetId: this.props.widgetId,
|
|
@@ -42896,7 +43030,9 @@ class Passage extends React__namespace.Component {
|
|
|
42896
43030
|
startLineNumbersAfter: 0,
|
|
42897
43031
|
stylesAreApplied: false
|
|
42898
43032
|
};
|
|
42899
|
-
|
|
43033
|
+
|
|
43034
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43035
|
+
static validate() {
|
|
42900
43036
|
return noopValidator();
|
|
42901
43037
|
}
|
|
42902
43038
|
componentDidMount() {
|
|
@@ -43116,8 +43252,10 @@ class Passage extends React__namespace.Component {
|
|
|
43116
43252
|
getUserInput() {
|
|
43117
43253
|
return null;
|
|
43118
43254
|
}
|
|
43119
|
-
|
|
43120
|
-
|
|
43255
|
+
|
|
43256
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43257
|
+
simpleValidate() {
|
|
43258
|
+
return noopValidator();
|
|
43121
43259
|
}
|
|
43122
43260
|
|
|
43123
43261
|
/**
|
|
@@ -43273,7 +43411,9 @@ class PassageRefTarget extends React__namespace.Component {
|
|
|
43273
43411
|
content: "",
|
|
43274
43412
|
linterContext: PerseusLinter.linterContextDefault
|
|
43275
43413
|
};
|
|
43276
|
-
|
|
43414
|
+
|
|
43415
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43416
|
+
static validate() {
|
|
43277
43417
|
return noopValidator();
|
|
43278
43418
|
}
|
|
43279
43419
|
|
|
@@ -43293,10 +43433,10 @@ class PassageRefTarget extends React__namespace.Component {
|
|
|
43293
43433
|
};
|
|
43294
43434
|
})();
|
|
43295
43435
|
|
|
43296
|
-
// TODO
|
|
43297
|
-
simpleValidate
|
|
43298
|
-
return
|
|
43299
|
-
}
|
|
43436
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43437
|
+
simpleValidate() {
|
|
43438
|
+
return noopValidator();
|
|
43439
|
+
}
|
|
43300
43440
|
render() {
|
|
43301
43441
|
return /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
43302
43442
|
content: this.props.content
|
|
@@ -44880,16 +45020,18 @@ class Video extends React__namespace.Component {
|
|
|
44880
45020
|
* This is the widget's grading function.
|
|
44881
45021
|
* Points for videos are tallied by the embedded video itself, in the case
|
|
44882
45022
|
* of Khan Academy videos.
|
|
44883
|
-
*/
|
|
44884
|
-
static validate(
|
|
45023
|
+
*/ // TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
45024
|
+
static validate() {
|
|
44885
45025
|
return noopValidator();
|
|
44886
45026
|
}
|
|
44887
45027
|
getUserInput = () => {
|
|
44888
45028
|
return null;
|
|
44889
45029
|
};
|
|
44890
|
-
|
|
44891
|
-
|
|
44892
|
-
|
|
45030
|
+
|
|
45031
|
+
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
45032
|
+
simpleValidate() {
|
|
45033
|
+
return noopValidator();
|
|
45034
|
+
}
|
|
44893
45035
|
change = (() => {
|
|
44894
45036
|
var _this = this;
|
|
44895
45037
|
return function () {
|
|
@@ -45002,7 +45144,7 @@ const init = function (options) {
|
|
|
45002
45144
|
|
|
45003
45145
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45004
45146
|
const libName = "@khanacademy/perseus";
|
|
45005
|
-
const libVersion = "34.
|
|
45147
|
+
const libVersion = "34.1.0";
|
|
45006
45148
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45007
45149
|
|
|
45008
45150
|
const apiVersion = {
|