@khanacademy/perseus-editor 17.8.1 → 17.9.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 +86 -67
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +78 -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 +38 -38
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.1";
|
|
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) {
|
|
@@ -32527,6 +32549,7 @@ class InteractiveGraphEditor extends React.Component {
|
|
|
32527
32549
|
const updates = {
|
|
32528
32550
|
numSides: parsePointCount(newValue),
|
|
32529
32551
|
coords: null,
|
|
32552
|
+
startCoords: undefined,
|
|
32530
32553
|
// reset the snap for UNLIMITED, which
|
|
32531
32554
|
// only supports "grid"
|
|
32532
32555
|
// From: D6578
|
|
@@ -36147,14 +36170,6 @@ class ChoiceEditor extends React.Component {
|
|
|
36147
36170
|
}, clueEditor), this.props.showDelete && deleteLink);
|
|
36148
36171
|
}
|
|
36149
36172
|
}
|
|
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
36173
|
class RadioEditor extends React.Component {
|
|
36159
36174
|
constructor(..._args) {
|
|
36160
36175
|
super(..._args);
|
|
@@ -36192,14 +36207,17 @@ class RadioEditor extends React.Component {
|
|
|
36192
36207
|
this.onChange = ({
|
|
36193
36208
|
checked
|
|
36194
36209
|
}) => {
|
|
36195
|
-
const choices =
|
|
36196
|
-
return
|
|
36210
|
+
const choices = this.props.choices.map((choice, i) => {
|
|
36211
|
+
return _extends({}, choice, {
|
|
36197
36212
|
correct: checked[i],
|
|
36198
36213
|
content: choice.isNoneOfTheAbove && !checked[i] ? "" : choice.content
|
|
36199
36214
|
});
|
|
36200
36215
|
});
|
|
36201
36216
|
this.props.onChange({
|
|
36202
|
-
choices: choices
|
|
36217
|
+
choices: choices,
|
|
36218
|
+
numCorrect: deriveNumCorrect(_extends({}, this.props, {
|
|
36219
|
+
choices
|
|
36220
|
+
}))
|
|
36203
36221
|
});
|
|
36204
36222
|
};
|
|
36205
36223
|
this.onContentChange = (choiceIndex, newContent) => {
|
|
@@ -36211,18 +36229,6 @@ class RadioEditor extends React.Component {
|
|
|
36211
36229
|
choices: choices
|
|
36212
36230
|
});
|
|
36213
36231
|
};
|
|
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
36232
|
this.onDelete = choiceIndex => {
|
|
36227
36233
|
const choices = this.props.choices.slice();
|
|
36228
36234
|
const deleted = choices[choiceIndex];
|
|
@@ -36236,7 +36242,8 @@ class RadioEditor extends React.Component {
|
|
|
36236
36242
|
e.preventDefault();
|
|
36237
36243
|
const choices = this.props.choices.slice();
|
|
36238
36244
|
const newChoice = {
|
|
36239
|
-
isNoneOfTheAbove: noneOfTheAbove
|
|
36245
|
+
isNoneOfTheAbove: noneOfTheAbove,
|
|
36246
|
+
content: ""
|
|
36240
36247
|
};
|
|
36241
36248
|
const addIndex = choices.length - (this.props.hasNoneOfTheAbove ? 1 : 0);
|
|
36242
36249
|
choices.splice(addIndex, 0, newChoice);
|
|
@@ -36266,8 +36273,38 @@ class RadioEditor extends React.Component {
|
|
|
36266
36273
|
}
|
|
36267
36274
|
return [];
|
|
36268
36275
|
};
|
|
36269
|
-
|
|
36270
|
-
|
|
36276
|
+
}
|
|
36277
|
+
onClueChange(choiceIndex, newClue) {
|
|
36278
|
+
const choices = this.props.choices.slice();
|
|
36279
|
+
choices[choiceIndex] = _.extend({}, choices[choiceIndex], {
|
|
36280
|
+
clue: newClue
|
|
36281
|
+
});
|
|
36282
|
+
if (newClue === "") {
|
|
36283
|
+
delete choices[choiceIndex].clue;
|
|
36284
|
+
}
|
|
36285
|
+
this.props.onChange({
|
|
36286
|
+
choices: choices
|
|
36287
|
+
});
|
|
36288
|
+
}
|
|
36289
|
+
serialize() {
|
|
36290
|
+
const {
|
|
36291
|
+
choices,
|
|
36292
|
+
randomize,
|
|
36293
|
+
multipleSelect,
|
|
36294
|
+
countChoices,
|
|
36295
|
+
displayCount,
|
|
36296
|
+
hasNoneOfTheAbove,
|
|
36297
|
+
deselectEnabled
|
|
36298
|
+
} = this.props;
|
|
36299
|
+
return {
|
|
36300
|
+
choices,
|
|
36301
|
+
randomize,
|
|
36302
|
+
multipleSelect,
|
|
36303
|
+
countChoices,
|
|
36304
|
+
displayCount,
|
|
36305
|
+
hasNoneOfTheAbove,
|
|
36306
|
+
deselectEnabled,
|
|
36307
|
+
numCorrect: deriveNumCorrect(this.props)
|
|
36271
36308
|
};
|
|
36272
36309
|
}
|
|
36273
36310
|
render() {
|
|
@@ -36327,12 +36364,12 @@ class RadioEditor extends React.Component {
|
|
|
36327
36364
|
apiOptions: this.props.apiOptions,
|
|
36328
36365
|
choice: choice,
|
|
36329
36366
|
onContentChange: newProps => {
|
|
36330
|
-
if (
|
|
36367
|
+
if (newProps.content != null) {
|
|
36331
36368
|
this.onContentChange(i, newProps.content);
|
|
36332
36369
|
}
|
|
36333
36370
|
},
|
|
36334
36371
|
onClueChange: newProps => {
|
|
36335
|
-
if (
|
|
36372
|
+
if (newProps.content != null) {
|
|
36336
36373
|
this.onClueChange(i, newProps.content);
|
|
36337
36374
|
}
|
|
36338
36375
|
},
|
|
@@ -36361,24 +36398,6 @@ class RadioEditor extends React.Component {
|
|
|
36361
36398
|
}, /*#__PURE__*/React.createElement(InlineIcon, iconPlus), " None of the above", " ")));
|
|
36362
36399
|
}
|
|
36363
36400
|
}
|
|
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
36401
|
RadioEditor.widgetName = "radio";
|
|
36383
36402
|
RadioEditor.defaultProps = radioLogic.defaultWidgetOptions;
|
|
36384
36403
|
|