@khanacademy/perseus-editor 17.8.1 → 17.9.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 +85 -67
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +77 -56
- package/dist/index.js.map +1 -1
- package/dist/widgets/expression-editor.d.ts +1 -1
- package/dist/widgets/radio/editor.d.ts +17 -16
- package/package.json +8 -8
package/dist/es/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _extends from '@babel/runtime/helpers/extends';
|
|
2
2
|
import { components, Widgets, iconChevronDown, iconTrash, WIDGET_PROP_DENYLIST, Util, Log, PerseusMarkdown, preprocessTex, ApiOptions, itemDataVersion, ClassNames, usePerseusI18n, Renderer, Categorizer as Categorizer$1, Changeable, EditorJsonify, Dependencies, Expression, interactiveSizes, GrapherWidget, containerSizeClass, getInteractiveBoxFromSizeClass, GrapherUtil as GrapherUtil$1, PerseusI18nContext, KhanColors, mathOnlyParser, getAngleCoords, getPolygonCoords, getPointCoords, getQuadraticCoords, getSinusoidCoords, getCircleCoords, getLinearSystemCoords, getSegmentCoords, getLineCoords, InteractiveGraphWidget, bodyXsmallBold, MatrixWidget, makeSafeUrl, PlotterWidget, BaseRadio, TableWidget, widgets } from '@khanacademy/perseus';
|
|
3
3
|
export { widgets } from '@khanacademy/perseus';
|
|
4
|
-
import { upgradeWidgetInfoToLatestVersion, CoreWidgetRegistry, PerseusError, Errors, ItemExtras, categorizerLogic, csProgramLogic, definitionLogic, dropdownLogic, explanationLogic, expressionLogic, PerseusExpressionAnswerFormConsidered, gradedGroupLogic, gradedGroupSetLogic, grapherLogic, GrapherUtil, groupLogic, iframeLogic, imageLogic, inputNumberLogic, interactionLogic, lockedFigureColors, lockedFigureFillStyles, interactiveGraphLogic, labelImageLogic, matcherLogic, matrixLogic, getMatrixSize, measurerLogic, numberLineLogic, numericInputLogic, ordererLogic, passageLogic, passageRefLogic, passageRefTargetLogic, phetSimulationLogic, plotterLogic, plotterPlotTypes, pythonProgramLogic, radioLogic, sorterLogic, tableLogic, videoLogic } from '@khanacademy/perseus-core';
|
|
4
|
+
import { upgradeWidgetInfoToLatestVersion, CoreWidgetRegistry, PerseusError, Errors, ItemExtras, categorizerLogic, csProgramLogic, definitionLogic, dropdownLogic, explanationLogic, expressionLogic, deriveExtraKeys, PerseusExpressionAnswerFormConsidered, gradedGroupLogic, gradedGroupSetLogic, grapherLogic, GrapherUtil, groupLogic, iframeLogic, imageLogic, inputNumberLogic, interactionLogic, lockedFigureColors, lockedFigureFillStyles, interactiveGraphLogic, labelImageLogic, matcherLogic, matrixLogic, getMatrixSize, measurerLogic, numberLineLogic, numericInputLogic, ordererLogic, passageLogic, passageRefLogic, passageRefTargetLogic, phetSimulationLogic, plotterLogic, plotterPlotTypes, pythonProgramLogic, radioLogic, deriveNumCorrect, sorterLogic, tableLogic, videoLogic } from '@khanacademy/perseus-core';
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import { useId, useRef, useEffect, useState } from 'react';
|
|
7
7
|
import _ from 'underscore';
|
|
@@ -94,7 +94,7 @@ const addLibraryVersionToPerseusDebug = (libraryName, libraryVersion) => {
|
|
|
94
94
|
|
|
95
95
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
96
96
|
const libName = "@khanacademy/perseus-editor";
|
|
97
|
-
const libVersion = "17.
|
|
97
|
+
const libVersion = "17.9.0";
|
|
98
98
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
99
99
|
|
|
100
100
|
const devices = {
|
|
@@ -20557,7 +20557,7 @@ katex.__defineMacro("\\pu", function (context) {
|
|
|
20557
20557
|
// a mathematical minus, U+2212. So we need that extra 0.56.
|
|
20558
20558
|
katex.__defineMacro("\\tripledash", "{\\vphantom{-}\\raisebox{2.56mu}{$\\mkern2mu" + "\\tiny\\text{-}\\mkern1mu\\text{-}\\mkern1mu\\text{-}\\mkern2mu$}}");
|
|
20559
20559
|
|
|
20560
|
-
const _excluded$
|
|
20560
|
+
const _excluded$5 = ["component", "shouldDragHighlight"];
|
|
20561
20561
|
class DragTarget extends React.Component {
|
|
20562
20562
|
constructor(props) {
|
|
20563
20563
|
super(props);
|
|
@@ -20605,7 +20605,7 @@ class DragTarget extends React.Component {
|
|
|
20605
20605
|
component: Component
|
|
20606
20606
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
20607
20607
|
} = _this$props,
|
|
20608
|
-
forwardProps = _objectWithoutPropertiesLoose(_this$props, _excluded$
|
|
20608
|
+
forwardProps = _objectWithoutPropertiesLoose(_this$props, _excluded$5);
|
|
20609
20609
|
return /*#__PURE__*/React.createElement(Component, _extends({}, forwardProps, {
|
|
20610
20610
|
style: Object.assign({}, this.props.style, opacity),
|
|
20611
20611
|
onDrop: this.handleDrop,
|
|
@@ -20657,7 +20657,7 @@ const iconTablet = {
|
|
|
20657
20657
|
height: 100
|
|
20658
20658
|
};
|
|
20659
20659
|
|
|
20660
|
-
const _excluded$
|
|
20660
|
+
const _excluded$4 = ["label"];
|
|
20661
20661
|
const {
|
|
20662
20662
|
InlineIcon: InlineIcon$8
|
|
20663
20663
|
} = components;
|
|
@@ -20796,7 +20796,7 @@ function LabeledSwitch$1(props) {
|
|
|
20796
20796
|
const {
|
|
20797
20797
|
label
|
|
20798
20798
|
} = props,
|
|
20799
|
-
switchProps = _objectWithoutPropertiesLoose(props, _excluded$
|
|
20799
|
+
switchProps = _objectWithoutPropertiesLoose(props, _excluded$4);
|
|
20800
20800
|
const id = useId();
|
|
20801
20801
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("label", {
|
|
20802
20802
|
htmlFor: id
|
|
@@ -20833,12 +20833,13 @@ class WidgetSelect extends React.Component {
|
|
|
20833
20833
|
const addWidgetString = "Add a widget\u2026";
|
|
20834
20834
|
return /*#__PURE__*/React.createElement("select", {
|
|
20835
20835
|
value: "",
|
|
20836
|
-
onChange: this.handleChange
|
|
20836
|
+
onChange: this.handleChange,
|
|
20837
|
+
"data-testid": "editor__widget-select"
|
|
20837
20838
|
}, /*#__PURE__*/React.createElement("option", {
|
|
20838
20839
|
value: ""
|
|
20839
20840
|
}, addWidgetString), /*#__PURE__*/React.createElement("option", {
|
|
20840
20841
|
disabled: true
|
|
20841
|
-
}, "--"),
|
|
20842
|
+
}, "--"), orderedWidgetNames.map(name => {
|
|
20842
20843
|
return /*#__PURE__*/React.createElement("option", {
|
|
20843
20844
|
key: name,
|
|
20844
20845
|
value: name
|
|
@@ -25149,6 +25150,7 @@ const styles$O = StyleSheet.create({
|
|
|
25149
25150
|
}
|
|
25150
25151
|
});
|
|
25151
25152
|
|
|
25153
|
+
const _excluded$3 = ["extraKeys"];
|
|
25152
25154
|
const {
|
|
25153
25155
|
InfoTip: InfoTip$l
|
|
25154
25156
|
} = components;
|
|
@@ -25194,17 +25196,6 @@ class ExpressionEditor extends React.Component {
|
|
|
25194
25196
|
this.change = (...args) => {
|
|
25195
25197
|
return Changeable.change.apply(this, args);
|
|
25196
25198
|
};
|
|
25197
|
-
this.serialize = () => {
|
|
25198
|
-
const formSerializables = ["value", "form", "simplify", "considered",
|
|
25199
|
-
// it's a little weird to serialize the react key, but saves some
|
|
25200
|
-
// effort reconstructing them when this item is loaded later.
|
|
25201
|
-
"key"];
|
|
25202
|
-
const serializables = ["answerForms", "buttonSets", "functions", "times", "visibleLabel", "ariaLabel"];
|
|
25203
|
-
const answerForms = this.props.answerForms.map(form => {
|
|
25204
|
-
return _(form).pick(formSerializables);
|
|
25205
|
-
});
|
|
25206
|
-
return lens(this.props).set(["answerForms"], answerForms).mod([], props => _(props).pick(serializables)).freeze();
|
|
25207
|
-
};
|
|
25208
25199
|
this.getSaveWarnings = () => {
|
|
25209
25200
|
const issues = [];
|
|
25210
25201
|
if (this.props.answerForms.length === 0) {
|
|
@@ -25336,13 +25327,44 @@ class ExpressionEditor extends React.Component {
|
|
|
25336
25327
|
functionsInternal: this.props.functions.join(" ")
|
|
25337
25328
|
};
|
|
25338
25329
|
}
|
|
25330
|
+
serialize() {
|
|
25331
|
+
const {
|
|
25332
|
+
answerForms,
|
|
25333
|
+
buttonSets,
|
|
25334
|
+
functions,
|
|
25335
|
+
times,
|
|
25336
|
+
visibleLabel,
|
|
25337
|
+
ariaLabel
|
|
25338
|
+
} = this.props;
|
|
25339
|
+
return {
|
|
25340
|
+
answerForms,
|
|
25341
|
+
buttonSets,
|
|
25342
|
+
functions,
|
|
25343
|
+
times,
|
|
25344
|
+
visibleLabel,
|
|
25345
|
+
ariaLabel,
|
|
25346
|
+
extraKeys: deriveExtraKeys(this.props)
|
|
25347
|
+
};
|
|
25348
|
+
}
|
|
25339
25349
|
// This function is designed to update the answerForm property
|
|
25340
25350
|
// with new data. This function should not be used to update any
|
|
25341
|
-
// other properties within ExpressionEditor
|
|
25351
|
+
// other properties within ExpressionEditor except extraKeys
|
|
25352
|
+
// which is derived from answerForms
|
|
25342
25353
|
updateAnswerForm(i, props) {
|
|
25343
25354
|
const answerForms = lens(this.props.answerForms).merge([i], props).freeze();
|
|
25344
|
-
|
|
25355
|
+
|
|
25356
|
+
// deriveExtraKeys defaults to using the `extraKeys` it was given
|
|
25357
|
+
// which in most case is what we want, but is not what we want
|
|
25358
|
+
// in the editing experience because we should recalculate them
|
|
25359
|
+
// when answers change
|
|
25360
|
+
const _this$props = this.props,
|
|
25361
|
+
restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$3);
|
|
25362
|
+
const extraKeys = deriveExtraKeys(_extends({}, restProps, {
|
|
25345
25363
|
answerForms
|
|
25364
|
+
}));
|
|
25365
|
+
this.change({
|
|
25366
|
+
answerForms,
|
|
25367
|
+
extraKeys
|
|
25346
25368
|
});
|
|
25347
25369
|
}
|
|
25348
25370
|
changeSimplify(key, simplify) {
|
|
@@ -36147,14 +36169,6 @@ class ChoiceEditor extends React.Component {
|
|
|
36147
36169
|
}, clueEditor), this.props.showDelete && deleteLink);
|
|
36148
36170
|
}
|
|
36149
36171
|
}
|
|
36150
|
-
ChoiceEditor.propTypes = {
|
|
36151
|
-
apiOptions: ApiOptions.propTypes,
|
|
36152
|
-
choice: PropTypes.object,
|
|
36153
|
-
showDelete: PropTypes.bool,
|
|
36154
|
-
onClueChange: PropTypes.func,
|
|
36155
|
-
onContentChange: PropTypes.func,
|
|
36156
|
-
onDelete: PropTypes.func
|
|
36157
|
-
};
|
|
36158
36172
|
class RadioEditor extends React.Component {
|
|
36159
36173
|
constructor(..._args) {
|
|
36160
36174
|
super(..._args);
|
|
@@ -36192,14 +36206,17 @@ class RadioEditor extends React.Component {
|
|
|
36192
36206
|
this.onChange = ({
|
|
36193
36207
|
checked
|
|
36194
36208
|
}) => {
|
|
36195
|
-
const choices =
|
|
36196
|
-
return
|
|
36209
|
+
const choices = this.props.choices.map((choice, i) => {
|
|
36210
|
+
return _extends({}, choice, {
|
|
36197
36211
|
correct: checked[i],
|
|
36198
36212
|
content: choice.isNoneOfTheAbove && !checked[i] ? "" : choice.content
|
|
36199
36213
|
});
|
|
36200
36214
|
});
|
|
36201
36215
|
this.props.onChange({
|
|
36202
|
-
choices: choices
|
|
36216
|
+
choices: choices,
|
|
36217
|
+
numCorrect: deriveNumCorrect(_extends({}, this.props, {
|
|
36218
|
+
choices
|
|
36219
|
+
}))
|
|
36203
36220
|
});
|
|
36204
36221
|
};
|
|
36205
36222
|
this.onContentChange = (choiceIndex, newContent) => {
|
|
@@ -36211,18 +36228,6 @@ class RadioEditor extends React.Component {
|
|
|
36211
36228
|
choices: choices
|
|
36212
36229
|
});
|
|
36213
36230
|
};
|
|
36214
|
-
this.onClueChange = (choiceIndex, newClue) => {
|
|
36215
|
-
const choices = this.props.choices.slice();
|
|
36216
|
-
choices[choiceIndex] = _.extend({}, choices[choiceIndex], {
|
|
36217
|
-
clue: newClue
|
|
36218
|
-
});
|
|
36219
|
-
if (newClue === "") {
|
|
36220
|
-
delete choices[choiceIndex].clue;
|
|
36221
|
-
}
|
|
36222
|
-
this.props.onChange({
|
|
36223
|
-
choices: choices
|
|
36224
|
-
});
|
|
36225
|
-
};
|
|
36226
36231
|
this.onDelete = choiceIndex => {
|
|
36227
36232
|
const choices = this.props.choices.slice();
|
|
36228
36233
|
const deleted = choices[choiceIndex];
|
|
@@ -36236,7 +36241,8 @@ class RadioEditor extends React.Component {
|
|
|
36236
36241
|
e.preventDefault();
|
|
36237
36242
|
const choices = this.props.choices.slice();
|
|
36238
36243
|
const newChoice = {
|
|
36239
|
-
isNoneOfTheAbove: noneOfTheAbove
|
|
36244
|
+
isNoneOfTheAbove: noneOfTheAbove,
|
|
36245
|
+
content: ""
|
|
36240
36246
|
};
|
|
36241
36247
|
const addIndex = choices.length - (this.props.hasNoneOfTheAbove ? 1 : 0);
|
|
36242
36248
|
choices.splice(addIndex, 0, newChoice);
|
|
@@ -36266,8 +36272,38 @@ class RadioEditor extends React.Component {
|
|
|
36266
36272
|
}
|
|
36267
36273
|
return [];
|
|
36268
36274
|
};
|
|
36269
|
-
|
|
36270
|
-
|
|
36275
|
+
}
|
|
36276
|
+
onClueChange(choiceIndex, newClue) {
|
|
36277
|
+
const choices = this.props.choices.slice();
|
|
36278
|
+
choices[choiceIndex] = _.extend({}, choices[choiceIndex], {
|
|
36279
|
+
clue: newClue
|
|
36280
|
+
});
|
|
36281
|
+
if (newClue === "") {
|
|
36282
|
+
delete choices[choiceIndex].clue;
|
|
36283
|
+
}
|
|
36284
|
+
this.props.onChange({
|
|
36285
|
+
choices: choices
|
|
36286
|
+
});
|
|
36287
|
+
}
|
|
36288
|
+
serialize() {
|
|
36289
|
+
const {
|
|
36290
|
+
choices,
|
|
36291
|
+
randomize,
|
|
36292
|
+
multipleSelect,
|
|
36293
|
+
countChoices,
|
|
36294
|
+
displayCount,
|
|
36295
|
+
hasNoneOfTheAbove,
|
|
36296
|
+
deselectEnabled
|
|
36297
|
+
} = this.props;
|
|
36298
|
+
return {
|
|
36299
|
+
choices,
|
|
36300
|
+
randomize,
|
|
36301
|
+
multipleSelect,
|
|
36302
|
+
countChoices,
|
|
36303
|
+
displayCount,
|
|
36304
|
+
hasNoneOfTheAbove,
|
|
36305
|
+
deselectEnabled,
|
|
36306
|
+
numCorrect: deriveNumCorrect(this.props)
|
|
36271
36307
|
};
|
|
36272
36308
|
}
|
|
36273
36309
|
render() {
|
|
@@ -36327,12 +36363,12 @@ class RadioEditor extends React.Component {
|
|
|
36327
36363
|
apiOptions: this.props.apiOptions,
|
|
36328
36364
|
choice: choice,
|
|
36329
36365
|
onContentChange: newProps => {
|
|
36330
|
-
if (
|
|
36366
|
+
if (newProps.content != null) {
|
|
36331
36367
|
this.onContentChange(i, newProps.content);
|
|
36332
36368
|
}
|
|
36333
36369
|
},
|
|
36334
36370
|
onClueChange: newProps => {
|
|
36335
|
-
if (
|
|
36371
|
+
if (newProps.content != null) {
|
|
36336
36372
|
this.onClueChange(i, newProps.content);
|
|
36337
36373
|
}
|
|
36338
36374
|
},
|
|
@@ -36361,24 +36397,6 @@ class RadioEditor extends React.Component {
|
|
|
36361
36397
|
}, /*#__PURE__*/React.createElement(InlineIcon, iconPlus), " None of the above", " ")));
|
|
36362
36398
|
}
|
|
36363
36399
|
}
|
|
36364
|
-
RadioEditor.propTypes = _extends({}, Changeable.propTypes, {
|
|
36365
|
-
apiOptions: ApiOptions.propTypes,
|
|
36366
|
-
choices: PropTypes.arrayOf(PropTypes.shape({
|
|
36367
|
-
content: PropTypes.string,
|
|
36368
|
-
clue: PropTypes.string,
|
|
36369
|
-
correct: PropTypes.bool
|
|
36370
|
-
})),
|
|
36371
|
-
displayCount: PropTypes.number,
|
|
36372
|
-
randomize: PropTypes.bool,
|
|
36373
|
-
hasNoneOfTheAbove: PropTypes.bool,
|
|
36374
|
-
multipleSelect: PropTypes.bool,
|
|
36375
|
-
countChoices: PropTypes.bool,
|
|
36376
|
-
// TODO(kevinb): DEPRECATED: This is be used to force deselectEnabled
|
|
36377
|
-
// behavior on mobile but not on desktop. When enabled, the user can
|
|
36378
|
-
// deselect a radio input by tapping on it again.
|
|
36379
|
-
deselectEnabled: PropTypes.bool,
|
|
36380
|
-
static: PropTypes.bool
|
|
36381
|
-
});
|
|
36382
36400
|
RadioEditor.widgetName = "radio";
|
|
36383
36401
|
RadioEditor.defaultProps = radioLogic.defaultWidgetOptions;
|
|
36384
36402
|
|