@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 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.8.1";
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$4 = ["component", "shouldDragHighlight"];
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$4);
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$3 = ["label"];
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$3);
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
- }, "--"), _.map(orderedWidgetNames, name => {
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
- this.change({
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 = _.map(this.props.choices, (choice, i) => {
36196
- return _.extend({}, choice, {
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
- this.serialize = () => {
36270
- return _.pick(this.props, "choices", "randomize", "multipleSelect", "countChoices", "displayCount", "hasNoneOfTheAbove", "deselectEnabled");
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 ("content" in newProps) {
36367
+ if (newProps.content != null) {
36331
36368
  this.onContentChange(i, newProps.content);
36332
36369
  }
36333
36370
  },
36334
36371
  onClueChange: newProps => {
36335
- if ("content" in newProps) {
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