@khanacademy/perseus 31.0.1 → 32.0.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.
Files changed (90) hide show
  1. package/dist/components/input-with-examples.d.ts +1 -1
  2. package/dist/components/number-input.d.ts +1 -1
  3. package/dist/components/range-input.d.ts +1 -1
  4. package/dist/components/sortable.d.ts +5 -5
  5. package/dist/components/text-input.d.ts +1 -1
  6. package/dist/components/text-list-editor.d.ts +1 -1
  7. package/dist/es/index.css +1 -1
  8. package/dist/es/index.js +615 -535
  9. package/dist/es/index.js.map +1 -1
  10. package/dist/index.css +1 -1
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.js +1450 -1369
  13. package/dist/index.js.map +1 -1
  14. package/dist/perseus-types.d.ts +1 -10
  15. package/dist/widget-container.d.ts +1 -1
  16. package/dist/widgets/__shared__/test-keypad-context-wrapper.d.ts +6 -0
  17. package/dist/widgets/{categorizer.d.ts → categorizer/categorizer.d.ts} +14 -14
  18. package/dist/widgets/categorizer/index.d.ts +1 -0
  19. package/dist/widgets/{cs-program.d.ts → cs-program/cs-program.d.ts} +7 -7
  20. package/dist/widgets/cs-program/index.d.ts +1 -0
  21. package/dist/widgets/{definition.d.ts → definition/definition.d.ts} +11 -11
  22. package/dist/widgets/definition/index.d.ts +1 -0
  23. package/dist/widgets/{dropdown.d.ts → dropdown/dropdown.d.ts} +9 -9
  24. package/dist/widgets/dropdown/index.d.ts +1 -0
  25. package/dist/widgets/{explanation.d.ts → explanation/explanation.d.ts} +14 -14
  26. package/dist/widgets/explanation/index.d.ts +1 -0
  27. package/dist/widgets/{expression.d.ts → expression/expression.d.ts} +66 -66
  28. package/dist/widgets/expression/index.d.ts +1 -0
  29. package/dist/widgets/{graded-group-answer-bar.d.ts → graded-group/graded-group-answer-bar.d.ts} +3 -3
  30. package/dist/widgets/{graded-group.d.ts → graded-group/graded-group.d.ts} +11 -11
  31. package/dist/widgets/graded-group/index.d.ts +1 -0
  32. package/dist/widgets/{graded-group-set.d.ts → graded-group-set/graded-group-set.d.ts} +11 -11
  33. package/dist/widgets/graded-group-set/index.d.ts +1 -0
  34. package/dist/widgets/{grapher.d.ts → grapher/grapher.d.ts} +15 -15
  35. package/dist/widgets/grapher/index.d.ts +1 -0
  36. package/dist/widgets/{group.d.ts → group/group.d.ts} +12 -12
  37. package/dist/widgets/group/index.d.ts +1 -0
  38. package/dist/widgets/{iframe.d.ts → iframe/iframe.d.ts} +10 -10
  39. package/dist/widgets/iframe/index.d.ts +1 -0
  40. package/dist/widgets/{image.d.ts → image/image.d.ts} +12 -12
  41. package/dist/widgets/image/index.d.ts +1 -0
  42. package/dist/widgets/input-number/index.d.ts +1 -0
  43. package/dist/widgets/{input-number.d.ts → input-number/input-number.d.ts} +19 -19
  44. package/dist/widgets/interaction/index.d.ts +1 -0
  45. package/dist/widgets/{interaction.d.ts → interaction/interaction.d.ts} +12 -12
  46. package/dist/widgets/interactive-graphs/graphs/components/movable-point-view.d.ts +8 -4
  47. package/dist/widgets/interactive-graphs/graphs/components/movable-point.d.ts +2 -1
  48. package/dist/widgets/interactive-graphs/reducer/interactive-graph-action.d.ts +29 -1
  49. package/dist/widgets/interactive-graphs/types.d.ts +1 -0
  50. package/dist/widgets/label-image/index.d.ts +1 -0
  51. package/dist/widgets/{label-image.d.ts → label-image/label-image.d.ts} +24 -24
  52. package/dist/widgets/matcher/index.d.ts +1 -0
  53. package/dist/widgets/{matcher.d.ts → matcher/matcher.d.ts} +11 -11
  54. package/dist/widgets/matrix/index.d.ts +1 -0
  55. package/dist/widgets/{matrix.d.ts → matrix/matrix.d.ts} +12 -12
  56. package/dist/widgets/measurer/index.d.ts +1 -0
  57. package/dist/widgets/measurer/measurer.d.ts +21 -0
  58. package/dist/widgets/molecule/index.d.ts +1 -0
  59. package/dist/widgets/{molecule.d.ts → molecule/molecule.d.ts} +10 -10
  60. package/dist/widgets/number-line/index.d.ts +1 -0
  61. package/dist/widgets/{number-line.d.ts → number-line/number-line.d.ts} +11 -11
  62. package/dist/widgets/numeric-input/index.d.ts +1 -0
  63. package/dist/widgets/{numeric-input.d.ts → numeric-input/numeric-input.d.ts} +13 -13
  64. package/dist/widgets/orderer/index.d.ts +1 -0
  65. package/dist/widgets/{orderer.d.ts → orderer/orderer.d.ts} +10 -10
  66. package/dist/widgets/passage/index.d.ts +2 -0
  67. package/dist/widgets/{passage.d.ts → passage/passage.d.ts} +15 -15
  68. package/dist/widgets/passage-ref/index.d.ts +1 -0
  69. package/dist/widgets/{passage-ref.d.ts → passage-ref/passage-ref.d.ts} +16 -16
  70. package/dist/widgets/passage-ref-target/index.d.ts +1 -0
  71. package/dist/widgets/{passage-ref-target.d.ts → passage-ref-target/passage-ref-target.d.ts} +12 -12
  72. package/dist/widgets/phet-simulation/index.d.ts +1 -0
  73. package/dist/widgets/{phet-simulation.d.ts → phet-simulation/phet-simulation.d.ts} +13 -15
  74. package/dist/widgets/plotter/index.d.ts +1 -0
  75. package/dist/widgets/{plotter.d.ts → plotter/plotter.d.ts} +11 -11
  76. package/dist/widgets/python-program/index.d.ts +1 -0
  77. package/dist/widgets/{python-program.d.ts → python-program/python-program.d.ts} +7 -7
  78. package/dist/widgets/radio/index.d.ts +2 -0
  79. package/dist/widgets/radio/radio-component.d.ts +66 -0
  80. package/dist/widgets/radio/radio.d.ts +22 -66
  81. package/dist/widgets/sorter/index.d.ts +1 -0
  82. package/dist/widgets/{sorter.d.ts → sorter/sorter.d.ts} +8 -8
  83. package/dist/widgets/table/index.d.ts +1 -0
  84. package/dist/widgets/{table.d.ts → table/table.d.ts} +10 -10
  85. package/dist/widgets/video/index.d.ts +1 -0
  86. package/dist/widgets/{video.d.ts → video/video.d.ts} +11 -11
  87. package/package.json +45 -45
  88. package/dist/widgets/measurer.d.ts +0 -21
  89. package/dist/widgets/radio.d.ts +0 -22
  90. /package/dist/widgets/{video-transcript-link.d.ts → video/video-transcript-link.d.ts} +0 -0
package/dist/es/index.js CHANGED
@@ -45,31 +45,23 @@ import cornersOutIcon from '@phosphor-icons/core/regular/corners-out.svg';
45
45
  import Link from '@khanacademy/wonder-blocks-link';
46
46
 
47
47
  function _extends() {
48
- _extends = Object.assign ? Object.assign.bind() : function (target) {
49
- for (var i = 1; i < arguments.length; i++) {
50
- var source = arguments[i];
51
- for (var key in source) {
52
- if (Object.prototype.hasOwnProperty.call(source, key)) {
53
- target[key] = source[key];
54
- }
55
- }
48
+ return _extends = Object.assign ? Object.assign.bind() : function (n) {
49
+ for (var e = 1; e < arguments.length; e++) {
50
+ var t = arguments[e];
51
+ for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
56
52
  }
57
- return target;
58
- };
59
- return _extends.apply(this, arguments);
53
+ return n;
54
+ }, _extends.apply(null, arguments);
60
55
  }
61
56
 
62
- function _objectWithoutPropertiesLoose(source, excluded) {
63
- if (source == null) return {};
64
- var target = {};
65
- var sourceKeys = Object.keys(source);
66
- var key, i;
67
- for (i = 0; i < sourceKeys.length; i++) {
68
- key = sourceKeys[i];
69
- if (excluded.indexOf(key) >= 0) continue;
70
- target[key] = source[key];
57
+ function _objectWithoutPropertiesLoose(r, e) {
58
+ if (null == r) return {};
59
+ var t = {};
60
+ for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
61
+ if (e.includes(n)) continue;
62
+ t[n] = r[n];
71
63
  }
72
- return target;
64
+ return t;
73
65
  }
74
66
 
75
67
  /**
@@ -532,6 +524,7 @@ class InnerMathInput extends React.Component {
532
524
  onFocus: () => this.focus(),
533
525
  onBlur: () => this.blur()
534
526
  }), /*#__PURE__*/React.createElement(Popover, {
527
+ rootBoundary: "document",
535
528
  opened: this.state.keypadOpen,
536
529
  onClose: () => this.closeKeypad(),
537
530
  dismissEnabled: true,
@@ -4515,16 +4508,14 @@ const InteractiveUtil = {
4515
4508
  }
4516
4509
  };
4517
4510
 
4518
- function _classPrivateFieldBase(receiver, privateKey) {
4519
- if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
4520
- throw new TypeError("attempted to use private field on non-instance");
4521
- }
4522
- return receiver;
4511
+ function _classPrivateFieldBase(e, t) {
4512
+ if (!{}.hasOwnProperty.call(e, t)) throw new TypeError("attempted to use private field on non-instance");
4513
+ return e;
4523
4514
  }
4524
4515
 
4525
4516
  var id = 0;
4526
- function _classPrivateFieldKey(name) {
4527
- return "__private_" + id++ + "_" + name;
4517
+ function _classPrivateFieldKey(e) {
4518
+ return "__private_" + id++ + "_" + e;
4528
4519
  }
4529
4520
 
4530
4521
  /*!
@@ -19476,6 +19467,14 @@ class WidgetContainer extends React.Component {
19476
19467
  }
19477
19468
  }
19478
19469
 
19470
+ UNSAFE_componentWillReceiveProps(nextProps) {
19471
+ if (this.props.type !== nextProps.type) {
19472
+ throw new Error("WidgetContainer can't change widget type; set a different " + "key instead to recreate the container.");
19473
+ }
19474
+ }
19475
+ shouldComponentUpdate(nextProps, nextState) {
19476
+ return this.props.shouldHighlight !== nextProps.shouldHighlight || this.props.type !== nextProps.type || this.state.widgetProps !== nextState.widgetProps || this.state.sizeClass !== nextState.sizeClass;
19477
+ }
19479
19478
  render() {
19480
19479
  let className = classNames({
19481
19480
  "perseus-widget-container": true,
@@ -19566,14 +19565,6 @@ class WidgetContainer extends React.Component {
19566
19565
  style: staticOverlayStyles
19567
19566
  }))));
19568
19567
  }
19569
- UNSAFE_componentWillReceiveProps(nextProps) {
19570
- if (this.props.type !== nextProps.type) {
19571
- throw new Error("WidgetContainer can't change widget type; set a different " + "key instead to recreate the container.");
19572
- }
19573
- }
19574
- shouldComponentUpdate(nextProps, nextState) {
19575
- return this.props.shouldHighlight !== nextProps.shouldHighlight || this.props.type !== nextProps.type || this.state.widgetProps !== nextState.widgetProps || this.state.sizeClass !== nextState.sizeClass;
19576
- }
19577
19568
  }
19578
19569
  WidgetContainer.defaultProps = {
19579
19570
  linterContext: linterContextDefault
@@ -21334,7 +21325,6 @@ Tooltip.defaultProps = {
21334
21325
  targetContainerStyle: {}
21335
21326
  };
21336
21327
 
21337
- /* eslint-disable react/sort-comp */
21338
21328
  const {
21339
21329
  captureScratchpadTouchStart: captureScratchpadTouchStart$2
21340
21330
  } = Util;
@@ -21690,7 +21680,6 @@ var TexWrangler = {
21690
21680
  modifyTex
21691
21681
  };
21692
21682
 
21693
- /* eslint-disable react/sort-comp */
21694
21683
  const ParseTex$1 = TexWrangler.parseTex;
21695
21684
  const answerTypes = {
21696
21685
  number: {
@@ -21828,55 +21817,6 @@ class InputNumber extends React.Component {
21828
21817
  return [strings.yourAnswer].concat(examples);
21829
21818
  };
21830
21819
  }
21831
- render() {
21832
- if (this.props.apiOptions.customKeypad) {
21833
- // TODO(charlie): Support "Review Mode".
21834
- const input = /*#__PURE__*/React.createElement(SimpleKeypadInput
21835
- // eslint-disable-next-line react/no-string-refs
21836
- , {
21837
- ref: "input",
21838
- value: this.props.currentValue,
21839
- keypadElement: this.props.keypadElement,
21840
- onChange: this.handleChange,
21841
- onFocus: this._handleFocus,
21842
- onBlur: this._handleBlur
21843
- });
21844
- if (this.props.rightAlign) {
21845
- return /*#__PURE__*/React.createElement("div", {
21846
- className: "perseus-input-right-align"
21847
- }, input);
21848
- }
21849
- return input;
21850
- }
21851
- // HACK(johnsullivan): Create a function with shared logic between
21852
- // this and NumericInput.
21853
- // TODO(jeremy): Deprecate this widget and prefer numeric-input.
21854
- const rubric = this.props.reviewModeRubric;
21855
-
21856
- // Note: This is _very_ similar to what `numeric-input.jsx` does. If
21857
- // you modify this, double-check if you also need to modify that
21858
- // component.
21859
- const inputStyles = [styles$A.default, this.props.size === "small" ? styles$A.small : null, this.props.rightAlign ? styles$A.rightAlign : styles$A.leftAlign];
21860
- // Unanswered
21861
- if (rubric && !this.props.currentValue) {
21862
- inputStyles.push(styles$A.answerStateUnanswered);
21863
- }
21864
- return /*#__PURE__*/React.createElement(InputWithExamples
21865
- // eslint-disable-next-line react/no-string-refs
21866
- , {
21867
- ref: "input",
21868
- value: this.props.currentValue,
21869
- onChange: this.handleChange,
21870
- style: inputStyles,
21871
- examples: this.examples(),
21872
- shouldShowExamples: this.shouldShowExamples(),
21873
- onFocus: this._handleFocus,
21874
- onBlur: this._handleBlur,
21875
- id: this.props.widgetId,
21876
- disabled: this.props.apiOptions.readOnly,
21877
- linterContext: this.props.linterContext
21878
- });
21879
- }
21880
21820
  static validate(state, rubric, strings, onInputError = () => {}) {
21881
21821
  if (rubric.answerType == null) {
21882
21822
  rubric.answerType = "number";
@@ -21932,6 +21872,55 @@ class InputNumber extends React.Component {
21932
21872
  }
21933
21873
  return answerString;
21934
21874
  }
21875
+ render() {
21876
+ if (this.props.apiOptions.customKeypad) {
21877
+ // TODO(charlie): Support "Review Mode".
21878
+ const input = /*#__PURE__*/React.createElement(SimpleKeypadInput
21879
+ // eslint-disable-next-line react/no-string-refs
21880
+ , {
21881
+ ref: "input",
21882
+ value: this.props.currentValue,
21883
+ keypadElement: this.props.keypadElement,
21884
+ onChange: this.handleChange,
21885
+ onFocus: this._handleFocus,
21886
+ onBlur: this._handleBlur
21887
+ });
21888
+ if (this.props.rightAlign) {
21889
+ return /*#__PURE__*/React.createElement("div", {
21890
+ className: "perseus-input-right-align"
21891
+ }, input);
21892
+ }
21893
+ return input;
21894
+ }
21895
+ // HACK(johnsullivan): Create a function with shared logic between
21896
+ // this and NumericInput.
21897
+ // TODO(jeremy): Deprecate this widget and prefer numeric-input.
21898
+ const rubric = this.props.reviewModeRubric;
21899
+
21900
+ // Note: This is _very_ similar to what `numeric-input.jsx` does. If
21901
+ // you modify this, double-check if you also need to modify that
21902
+ // component.
21903
+ const inputStyles = [styles$A.default, this.props.size === "small" ? styles$A.small : null, this.props.rightAlign ? styles$A.rightAlign : styles$A.leftAlign];
21904
+ // Unanswered
21905
+ if (rubric && !this.props.currentValue) {
21906
+ inputStyles.push(styles$A.answerStateUnanswered);
21907
+ }
21908
+ return /*#__PURE__*/React.createElement(InputWithExamples
21909
+ // eslint-disable-next-line react/no-string-refs
21910
+ , {
21911
+ ref: "input",
21912
+ value: this.props.currentValue,
21913
+ onChange: this.handleChange,
21914
+ style: inputStyles,
21915
+ examples: this.examples(),
21916
+ shouldShowExamples: this.shouldShowExamples(),
21917
+ onFocus: this._handleFocus,
21918
+ onBlur: this._handleBlur,
21919
+ id: this.props.widgetId,
21920
+ disabled: this.props.apiOptions.readOnly,
21921
+ linterContext: this.props.linterContext
21922
+ });
21923
+ }
21935
21924
  }
21936
21925
  InputNumber.contextType = PerseusI18nContext;
21937
21926
  InputNumber.defaultProps = {
@@ -22393,7 +22382,6 @@ var NumericInput$1 = {
22393
22382
  isLintable: true
22394
22383
  };
22395
22384
 
22396
- /* eslint-disable react/sort-comp */
22397
22385
  const EN_DASH$1 = "\u2013";
22398
22386
  class PassageRef extends React.Component {
22399
22387
  constructor(..._args) {
@@ -22445,9 +22433,32 @@ class PassageRef extends React.Component {
22445
22433
  return PassageRef.validate(this.getUserInput(), rubric);
22446
22434
  };
22447
22435
  }
22436
+ static validate(userInput, rubric) {
22437
+ return {
22438
+ type: "points",
22439
+ earned: 0,
22440
+ total: 0,
22441
+ message: null
22442
+ };
22443
+ }
22444
+ componentDidMount() {
22445
+ // TODO(scottgrant): This is a hack to remove the deprecated call to
22446
+ // this.isMounted() but is still considered an anti-pattern.
22447
+ this._isMounted = true;
22448
+ this._deferredUpdateRange();
22449
+ this._throttledUpdateRange = _.throttle(this._deferredUpdateRange, 500);
22450
+ window.addEventListener("resize", this._throttledUpdateRange);
22451
+ }
22448
22452
  shouldComponentUpdate(nextProps, nextState) {
22449
22453
  return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
22450
22454
  }
22455
+ componentDidUpdate() {
22456
+ this._deferredUpdateRange();
22457
+ }
22458
+ componentWillUnmount() {
22459
+ window.removeEventListener("resize", this._throttledUpdateRange);
22460
+ this._isMounted = false;
22461
+ }
22451
22462
  render() {
22452
22463
  const {
22453
22464
  strings
@@ -22481,29 +22492,6 @@ class PassageRef extends React.Component {
22481
22492
  className: "perseus-sr-only"
22482
22493
  }, this.state.content));
22483
22494
  }
22484
- componentDidMount() {
22485
- // TODO(scottgrant): This is a hack to remove the deprecated call to
22486
- // this.isMounted() but is still considered an anti-pattern.
22487
- this._isMounted = true;
22488
- this._deferredUpdateRange();
22489
- this._throttledUpdateRange = _.throttle(this._deferredUpdateRange, 500);
22490
- window.addEventListener("resize", this._throttledUpdateRange);
22491
- }
22492
- componentDidUpdate() {
22493
- this._deferredUpdateRange();
22494
- }
22495
- componentWillUnmount() {
22496
- window.removeEventListener("resize", this._throttledUpdateRange);
22497
- this._isMounted = false;
22498
- }
22499
- static validate(userInput, rubric) {
22500
- return {
22501
- type: "points",
22502
- earned: 0,
22503
- total: 0,
22504
- message: null
22505
- };
22506
- }
22507
22495
  }
22508
22496
  PassageRef.contextType = PerseusI18nContext;
22509
22497
  PassageRef.defaultProps = {
@@ -24443,6 +24431,40 @@ class Categorizer extends React.Component {
24443
24431
  return Categorizer.validate(this.getUserInput(), rubric, this.context.strings);
24444
24432
  };
24445
24433
  }
24434
+ static validate(userInput, rubric, strings) {
24435
+ let completed = true;
24436
+ let allCorrect = true;
24437
+ rubric.values.forEach((value, i) => {
24438
+ if (userInput.values[i] == null) {
24439
+ completed = false;
24440
+ }
24441
+ if (userInput.values[i] !== value) {
24442
+ allCorrect = false;
24443
+ }
24444
+ });
24445
+ if (!completed) {
24446
+ return {
24447
+ type: "invalid",
24448
+ message: strings.invalidSelection
24449
+ };
24450
+ }
24451
+ return {
24452
+ type: "points",
24453
+ earned: allCorrect ? 1 : 0,
24454
+ total: 1,
24455
+ message: null
24456
+ };
24457
+ }
24458
+ static getUserInputFromProps(props) {
24459
+ return WidgetJsonifyDeprecated.getUserInputFromProps(props);
24460
+ }
24461
+ onChange(itemNum, catNum) {
24462
+ const values = [...this.props.values];
24463
+ // @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'never'.
24464
+ values[itemNum] = catNum;
24465
+ this.change("values", values);
24466
+ this.props.trackInteraction();
24467
+ }
24446
24468
  render() {
24447
24469
  const self = this;
24448
24470
 
@@ -24519,40 +24541,6 @@ class Categorizer extends React.Component {
24519
24541
  className: extraClassNames + " " + css(...inlineStyles)
24520
24542
  }, table);
24521
24543
  }
24522
- onChange(itemNum, catNum) {
24523
- const values = [...this.props.values];
24524
- // @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'never'.
24525
- values[itemNum] = catNum;
24526
- this.change("values", values);
24527
- this.props.trackInteraction();
24528
- }
24529
- static validate(userInput, rubric, strings) {
24530
- let completed = true;
24531
- let allCorrect = true;
24532
- rubric.values.forEach((value, i) => {
24533
- if (userInput.values[i] == null) {
24534
- completed = false;
24535
- }
24536
- if (userInput.values[i] !== value) {
24537
- allCorrect = false;
24538
- }
24539
- });
24540
- if (!completed) {
24541
- return {
24542
- type: "invalid",
24543
- message: strings.invalidSelection
24544
- };
24545
- }
24546
- return {
24547
- type: "points",
24548
- earned: allCorrect ? 1 : 0,
24549
- total: 1,
24550
- message: null
24551
- };
24552
- }
24553
- static getUserInputFromProps(props) {
24554
- return WidgetJsonifyDeprecated.getUserInputFromProps(props);
24555
- }
24556
24544
  }
24557
24545
 
24558
24546
  // TODO(benkomalo): inject page-margin into Perseus instead of hardcoding.
@@ -25062,8 +25050,6 @@ var Dropdown$1 = {
25062
25050
  transform: optionsTransform
25063
25051
  };
25064
25052
 
25065
- /* eslint-disable react/sort-comp */
25066
-
25067
25053
  // transform = _.identity
25068
25054
 
25069
25055
  function mediaQueryIsMatched(mediaQuery) {
@@ -26820,6 +26806,34 @@ class Grapher extends React.Component {
26820
26806
  }
26821
26807
  };
26822
26808
  }
26809
+ static validate(state, rubric) {
26810
+ return validate$1(state, rubric);
26811
+ }
26812
+ static getUserInputFromProps(props) {
26813
+ return props.plot;
26814
+ }
26815
+ _getGridConfig(options) {
26816
+ return options.step.map((step, i) => {
26817
+ return Util.gridDimensionConfig(step, options.range[i], options.box[i], options.gridStep[i]);
26818
+ });
26819
+ }
26820
+ _calculateMobileTickStep(gridStep, step, ranges) {
26821
+ const tickStep = Util.constrainedTickStepsFromTickSteps(step, ranges);
26822
+
26823
+ // According to the graphInit documentation in graphie.js, tickStep is
26824
+ // relative to the grid units so we need to adjust all values by the
26825
+ // grid step.
26826
+ tickStep[0] = tickStep[0] / gridStep[0];
26827
+ tickStep[1] = tickStep[1] / gridStep[1];
26828
+ return tickStep;
26829
+ }
26830
+ simpleValidate(rubric) {
26831
+ return validate$1(this.getUserInput(), rubric);
26832
+ }
26833
+ getUserInput() {
26834
+ return Grapher.getUserInputFromProps(this.props);
26835
+ }
26836
+ focus() {}
26823
26837
  render() {
26824
26838
  const type = this.props.plot.type;
26825
26839
  const coords = this.props.plot.coords;
@@ -26870,34 +26884,6 @@ class Grapher extends React.Component {
26870
26884
  };
26871
26885
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(FunctionGrapher, grapherProps), this.props.availableTypes.length > 1 && typeSelector);
26872
26886
  }
26873
- _getGridConfig(options) {
26874
- return options.step.map((step, i) => {
26875
- return Util.gridDimensionConfig(step, options.range[i], options.box[i], options.gridStep[i]);
26876
- });
26877
- }
26878
- _calculateMobileTickStep(gridStep, step, ranges) {
26879
- const tickStep = Util.constrainedTickStepsFromTickSteps(step, ranges);
26880
-
26881
- // According to the graphInit documentation in graphie.js, tickStep is
26882
- // relative to the grid units so we need to adjust all values by the
26883
- // grid step.
26884
- tickStep[0] = tickStep[0] / gridStep[0];
26885
- tickStep[1] = tickStep[1] / gridStep[1];
26886
- return tickStep;
26887
- }
26888
- simpleValidate(rubric) {
26889
- return validate$1(this.getUserInput(), rubric);
26890
- }
26891
- getUserInput() {
26892
- return Grapher.getUserInputFromProps(this.props);
26893
- }
26894
- focus() {}
26895
- static validate(state, rubric) {
26896
- return validate$1(state, rubric);
26897
- }
26898
- static getUserInputFromProps(props) {
26899
- return props.plot;
26900
- }
26901
26887
  }
26902
26888
  Grapher.defaultProps = DEFAULT_GRAPHER_PROPS;
26903
26889
  const propTransform$2 = editorProps => {
@@ -27243,7 +27229,6 @@ var Iframe$1 = {
27243
27229
  hidden: true
27244
27230
  };
27245
27231
 
27246
- /* eslint-disable react/sort-comp */
27247
27232
  const defaultBoxSize = 400;
27248
27233
  const defaultRange = [0, 10];
27249
27234
  const defaultBackgroundImage$2 = {
@@ -27270,6 +27255,14 @@ class ImageWidget extends React.Component {
27270
27255
  };
27271
27256
  this.focus = () => {};
27272
27257
  }
27258
+ static validate(userInput, rubric) {
27259
+ return {
27260
+ type: "points",
27261
+ earned: 0,
27262
+ total: 0,
27263
+ message: null
27264
+ };
27265
+ }
27273
27266
  // no-op
27274
27267
 
27275
27268
  render() {
@@ -27401,14 +27394,6 @@ class ImageWidget extends React.Component {
27401
27394
  }
27402
27395
  }, title, image, caption);
27403
27396
  }
27404
- static validate(userInput, rubric) {
27405
- return {
27406
- type: "points",
27407
- earned: 0,
27408
- total: 0,
27409
- message: null
27410
- };
27411
- }
27412
27397
  }
27413
27398
  ImageWidget.contextType = PerseusI18nContext;
27414
27399
  ImageWidget.defaultProps = {
@@ -27596,6 +27581,14 @@ class Interaction extends React.Component {
27596
27581
  return Interaction.validate(this.getUserInput(), rubric);
27597
27582
  };
27598
27583
  }
27584
+ static validate(state, rubric) {
27585
+ return {
27586
+ type: "points",
27587
+ earned: 0,
27588
+ total: 0,
27589
+ message: null
27590
+ };
27591
+ }
27599
27592
  UNSAFE_componentWillReceiveProps(nextProps) {
27600
27593
  // HACK(michaelpolyak): This widget is not wired to use the Perseus
27601
27594
  // `onChange` callback to save user changes. Perseus re-rendering of the
@@ -27941,14 +27934,6 @@ class Interaction extends React.Component {
27941
27934
  }
27942
27935
  }, this));
27943
27936
  }
27944
- static validate(state, rubric) {
27945
- return {
27946
- type: "points",
27947
- earned: 0,
27948
- total: 0,
27949
- message: null
27950
- };
27951
- }
27952
27937
  }
27953
27938
  Interaction.defaultProps = {
27954
27939
  graph: {
@@ -29548,6 +29533,11 @@ class NumberInput extends React.Component {
29548
29533
  $(ReactDOM__default.findDOMNode(this.refs.input)).val(toNumericString(val, format));
29549
29534
  };
29550
29535
  }
29536
+ componentDidUpdate(prevProps) {
29537
+ if (!number.equal(this.getValue(), this.props.value)) {
29538
+ this._setValue(this.props.value, this.state.format);
29539
+ }
29540
+ }
29551
29541
  render() {
29552
29542
  let classes = classNames({
29553
29543
  "number-input": true,
@@ -29579,11 +29569,6 @@ class NumberInput extends React.Component {
29579
29569
  value: undefined
29580
29570
  }));
29581
29571
  }
29582
- componentDidUpdate(prevProps) {
29583
- if (!number.equal(this.getValue(), this.props.value)) {
29584
- this._setValue(this.props.value, this.state.format);
29585
- }
29586
- }
29587
29572
  }
29588
29573
  NumberInput.contextType = PerseusI18nContext;
29589
29574
  NumberInput.propTypes = {
@@ -29811,12 +29796,6 @@ const ItemExtras = [
29811
29796
 
29812
29797
  // prettier-ignore
29813
29798
 
29814
- // prettier-ignore
29815
-
29816
- // prettier-ignore
29817
-
29818
- // prettier-ignore
29819
-
29820
29799
  //prettier-ignore
29821
29800
 
29822
29801
  // A background image applied to various widgets.
@@ -30217,6 +30196,9 @@ const GraphLockedLayer = props => {
30217
30196
  };
30218
30197
 
30219
30198
  const actions = {
30199
+ global: {
30200
+ deleteIntent
30201
+ },
30220
30202
  angle: {
30221
30203
  movePoint
30222
30204
  },
@@ -30234,7 +30216,10 @@ const actions = {
30234
30216
  },
30235
30217
  pointGraph: {
30236
30218
  movePoint,
30237
- addPoint
30219
+ addPoint,
30220
+ removePoint,
30221
+ focusPoint,
30222
+ blurPoint
30238
30223
  },
30239
30224
  polygon: {
30240
30225
  movePoint,
@@ -30255,6 +30240,12 @@ const actions = {
30255
30240
  movePoint
30256
30241
  }
30257
30242
  };
30243
+ const DELETE_INTENT = "delete-intent";
30244
+ function deleteIntent() {
30245
+ return {
30246
+ type: DELETE_INTENT
30247
+ };
30248
+ }
30258
30249
  const MOVE_LINE = "move-line";
30259
30250
  function moveLine(itemIndex, delta) {
30260
30251
  return {
@@ -30270,6 +30261,26 @@ function addPoint(location) {
30270
30261
  location
30271
30262
  };
30272
30263
  }
30264
+ const REMOVE_POINT = "remove-point";
30265
+ function removePoint(index) {
30266
+ return {
30267
+ type: REMOVE_POINT,
30268
+ index
30269
+ };
30270
+ }
30271
+ const FOCUS_POINT = "focus-point";
30272
+ function focusPoint(index) {
30273
+ return {
30274
+ type: FOCUS_POINT,
30275
+ index
30276
+ };
30277
+ }
30278
+ const BLUR_POINT = "blur-point";
30279
+ function blurPoint() {
30280
+ return {
30281
+ type: BLUR_POINT
30282
+ };
30283
+ }
30273
30284
  const MOVE_ALL = "move-all";
30274
30285
  function moveAll(delta) {
30275
30286
  return {
@@ -30557,7 +30568,8 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
30557
30568
  color: color$1 = color.blue,
30558
30569
  dragging,
30559
30570
  focusBehavior,
30560
- cursor
30571
+ cursor,
30572
+ onClick = () => {}
30561
30573
  } = props;
30562
30574
 
30563
30575
  // WB Tooltip requires a color name for the background color.
@@ -30592,7 +30604,12 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
30592
30604
  cursor
30593
30605
  },
30594
30606
  "data-testid": "movable-point",
30595
- tabIndex: disableKeyboardInteraction ? -1 : tabIndex(focusBehavior)
30607
+ tabIndex: disableKeyboardInteraction ? -1 : tabIndex(focusBehavior),
30608
+ onFocus: () => {
30609
+ return getOnFocusChangeCallback(focusBehavior)(true);
30610
+ },
30611
+ onBlur: () => getOnFocusChangeCallback(focusBehavior)(false),
30612
+ onClick: onClick
30596
30613
  }, /*#__PURE__*/React.createElement("circle", {
30597
30614
  className: "movable-point-hitbox",
30598
30615
  r: hitboxSizePx / 2,
@@ -30640,6 +30657,12 @@ function tabIndex(config) {
30640
30657
  }
30641
30658
  return undefined;
30642
30659
  }
30660
+ function getOnFocusChangeCallback(config) {
30661
+ if (config.type === "uncontrolled") {
30662
+ return config.onFocusChange;
30663
+ }
30664
+ return () => {};
30665
+ }
30643
30666
 
30644
30667
  const MovableLine = props => {
30645
30668
  const {
@@ -31229,7 +31252,8 @@ const MovablePoint$1 = props => {
31229
31252
  const elementRef = useRef(null);
31230
31253
  const {
31231
31254
  point,
31232
- onMove,
31255
+ onMove = () => {},
31256
+ onFocusChange = () => {},
31233
31257
  cursor,
31234
31258
  color: color$1 = color.blue,
31235
31259
  constrain = p => snap(snapStep, p)
@@ -31249,7 +31273,12 @@ const MovablePoint$1 = props => {
31249
31273
  dragging: dragging,
31250
31274
  focusBehavior: {
31251
31275
  type: "uncontrolled",
31252
- tabIndex: 0
31276
+ tabIndex: 0,
31277
+ onFocusChange
31278
+ },
31279
+ onClick: () => {
31280
+ var _elementRef$current;
31281
+ return (_elementRef$current = elementRef.current) == null ? void 0 : _elementRef$current.focus();
31253
31282
  },
31254
31283
  cursor: cursor
31255
31284
  });
@@ -31846,7 +31875,14 @@ function UnlimitedPointGraph(props) {
31846
31875
  }), props.graphState.coords.map((point, i) => /*#__PURE__*/React.createElement(MovablePoint$1, {
31847
31876
  key: i,
31848
31877
  point: point,
31849
- onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination))
31878
+ onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination)),
31879
+ onFocusChange: isFocused => {
31880
+ if (isFocused) {
31881
+ dispatch(actions.pointGraph.focusPoint(i));
31882
+ } else {
31883
+ dispatch(actions.pointGraph.blurPoint());
31884
+ }
31885
+ }
31850
31886
  })));
31851
31887
  }
31852
31888
  function PointGraph(props) {
@@ -32002,6 +32038,7 @@ const MafsGraph = props => {
32002
32038
  } = props;
32003
32039
  const [width, height] = props.box;
32004
32040
  const tickStep = props.step;
32041
+ const graphRef = React.useRef(null);
32005
32042
  return /*#__PURE__*/React.createElement(GraphConfigContext.Provider, {
32006
32043
  value: {
32007
32044
  range: state.range,
@@ -32019,16 +32056,25 @@ const MafsGraph = props => {
32019
32056
  }, /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(View, {
32020
32057
  className: "mafs-graph",
32021
32058
  style: {
32022
- height,
32023
- width: "intrinsic",
32024
32059
  position: "relative",
32025
32060
  padding: "25px 25px 0 0",
32026
32061
  boxSizing: "content-box",
32027
32062
  marginLeft: "20px",
32028
32063
  marginBottom: "20px",
32029
32064
  pointerEvents: props.static ? "none" : "auto",
32030
- userSelect: "none"
32031
- }
32065
+ userSelect: "none",
32066
+ width,
32067
+ height
32068
+ },
32069
+ onKeyUp: event => {
32070
+ if (event.key === "Backspace") {
32071
+ var _graphRef$current;
32072
+ dispatch(actions.global.deleteIntent());
32073
+ (_graphRef$current = graphRef.current) == null || _graphRef$current.focus();
32074
+ }
32075
+ },
32076
+ ref: graphRef,
32077
+ tabIndex: 0
32032
32078
  }, /*#__PURE__*/React.createElement(LegacyGrid, {
32033
32079
  box: props.box,
32034
32080
  backgroundImage: props.backgroundImage
@@ -32209,7 +32255,8 @@ function initializeGraphState(params) {
32209
32255
  return _extends({}, shared, {
32210
32256
  type: graph.type,
32211
32257
  coords: getPointCoords(graph, range, step),
32212
- numPoints: graph.numPoints || 0
32258
+ numPoints: graph.numPoints || 0,
32259
+ focusedPointIndex: null
32213
32260
  });
32214
32261
  case "circle":
32215
32262
  return _extends({}, shared, {
@@ -32465,10 +32512,49 @@ function interactiveGraphReducer(state, action) {
32465
32512
  return doChangeRange(state, action);
32466
32513
  case ADD_POINT:
32467
32514
  return doAddPoint(state, action);
32515
+ case REMOVE_POINT:
32516
+ return doRemovePoint(state, action);
32517
+ case FOCUS_POINT:
32518
+ return doFocusPoint(state, action);
32519
+ case BLUR_POINT:
32520
+ return doBlurPoint(state);
32521
+ case DELETE_INTENT:
32522
+ return doDeleteIntent(state);
32468
32523
  default:
32469
32524
  throw new UnreachableCaseError(action);
32470
32525
  }
32471
32526
  }
32527
+ function doDeleteIntent(state, action) {
32528
+ // For unlimited point graphs
32529
+ if (state.type === "point" && state.numPoints === "unlimited") {
32530
+ // if there's a focused point
32531
+ if (state.focusedPointIndex !== null) {
32532
+ // Remove the focused focus
32533
+ return doRemovePoint(state, actions.pointGraph.removePoint(state.focusedPointIndex));
32534
+ }
32535
+ }
32536
+ return state;
32537
+ }
32538
+ function doFocusPoint(state, action) {
32539
+ switch (state.type) {
32540
+ case "point":
32541
+ return _extends({}, state, {
32542
+ focusedPointIndex: action.index
32543
+ });
32544
+ default:
32545
+ return state;
32546
+ }
32547
+ }
32548
+ function doBlurPoint(state, action) {
32549
+ switch (state.type) {
32550
+ case "point":
32551
+ return _extends({}, state, {
32552
+ focusedPointIndex: null
32553
+ });
32554
+ default:
32555
+ return state;
32556
+ }
32557
+ }
32472
32558
  function doMovePointInFigure(state, action) {
32473
32559
  switch (state.type) {
32474
32560
  case "segment":
@@ -32812,6 +32898,15 @@ function doAddPoint(state, action) {
32812
32898
  coords: [...state.coords, snappedPoint]
32813
32899
  });
32814
32900
  }
32901
+ function doRemovePoint(state, action) {
32902
+ if (state.type !== "point") {
32903
+ return state;
32904
+ }
32905
+ return _extends({}, state, {
32906
+ coords: state.coords.filter((_, i) => i !== action.index),
32907
+ focusedPointIndex: null
32908
+ });
32909
+ }
32815
32910
  const getDeltaVertex = (maxMoves, minMoves, delta) => {
32816
32911
  const [deltaX, deltaY] = delta;
32817
32912
  const maxXMove = Math.min(...maxMoves.map(move => move[X]));
@@ -37251,6 +37346,27 @@ class Draggable extends React.Component {
37251
37346
  passive: false
37252
37347
  } : false);
37253
37348
  }
37349
+ componentDidUpdate(prevProps) {
37350
+ if (this.props.state === prevProps.state) {
37351
+ return;
37352
+ }
37353
+ if (this.props.state === ItemState.ANIMATING && this.props.endPosition) {
37354
+ // Start animating
37355
+ const current = this.getCurrentPosition();
37356
+ const duration = 15 * Math.sqrt(Math.sqrt(Math.pow(this.props.endPosition.left - current.left, 2) + Math.pow(this.props.endPosition.top - current.top, 2)));
37357
+
37358
+ // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'animate' does not exist on type 'JQueryStatic'.
37359
+ $(ReactDOM__default.findDOMNode(this)).animate(this.props.endPosition, {
37360
+ duration: Math.max(duration, 1),
37361
+ // Animating -> Static
37362
+ complete: this.props.onAnimationEnd
37363
+ });
37364
+ } else if (this.props.state === ItemState.STATIC) {
37365
+ // Ensure that any animations are done
37366
+ // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'finish' does not exist on type 'JQueryStatic'.
37367
+ $(ReactDOM__default.findDOMNode(this)).finish();
37368
+ }
37369
+ }
37254
37370
  componentWillUnmount() {
37255
37371
  this._mounted = false;
37256
37372
  // Event handlers should be unbound before component unmounting, but
@@ -37312,27 +37428,6 @@ class Draggable extends React.Component {
37312
37428
  strings: this.context.strings
37313
37429
  }));
37314
37430
  }
37315
- componentDidUpdate(prevProps) {
37316
- if (this.props.state === prevProps.state) {
37317
- return;
37318
- }
37319
- if (this.props.state === ItemState.ANIMATING && this.props.endPosition) {
37320
- // Start animating
37321
- const current = this.getCurrentPosition();
37322
- const duration = 15 * Math.sqrt(Math.sqrt(Math.pow(this.props.endPosition.left - current.left, 2) + Math.pow(this.props.endPosition.top - current.top, 2)));
37323
-
37324
- // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'animate' does not exist on type 'JQueryStatic'.
37325
- $(ReactDOM__default.findDOMNode(this)).animate(this.props.endPosition, {
37326
- duration: Math.max(duration, 1),
37327
- // Animating -> Static
37328
- complete: this.props.onAnimationEnd
37329
- });
37330
- } else if (this.props.state === ItemState.STATIC) {
37331
- // Ensure that any animations are done
37332
- // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'finish' does not exist on type 'JQueryStatic'.
37333
- $(ReactDOM__default.findDOMNode(this)).finish();
37334
- }
37335
- }
37336
37431
  }
37337
37432
  Draggable.contextType = PerseusI18nContext;
37338
37433
  Draggable.defaultProps = {
@@ -37341,6 +37436,26 @@ Draggable.defaultProps = {
37341
37436
  linterContext: PerseusLinter.linterContextDefault
37342
37437
  };
37343
37438
  class Sortable extends React.Component {
37439
+ static itemsFromProps(props) {
37440
+ const state = props.disabled ? ItemState.DISABLED : ItemState.STATIC;
37441
+ return props.options.map((option, i) => {
37442
+ return {
37443
+ option: option,
37444
+ key: i,
37445
+ state,
37446
+ width: 0,
37447
+ height: 0
37448
+ };
37449
+ });
37450
+ }
37451
+ static clearItemMeasurements(items) {
37452
+ return items.map(item => {
37453
+ return _extends({}, item, {
37454
+ width: 0,
37455
+ height: 0
37456
+ });
37457
+ });
37458
+ }
37344
37459
  constructor(props) {
37345
37460
  super(props);
37346
37461
  // Don't call this.setState() here!
@@ -37380,26 +37495,6 @@ class Sortable extends React.Component {
37380
37495
  }, 0);
37381
37496
  }
37382
37497
  }
37383
- static itemsFromProps(props) {
37384
- const state = props.disabled ? ItemState.DISABLED : ItemState.STATIC;
37385
- return props.options.map((option, i) => {
37386
- return {
37387
- option: option,
37388
- key: i,
37389
- state,
37390
- width: 0,
37391
- height: 0
37392
- };
37393
- });
37394
- }
37395
- static clearItemMeasurements(items) {
37396
- return items.map(item => {
37397
- return _extends({}, item, {
37398
- width: 0,
37399
- height: 0
37400
- });
37401
- });
37402
- }
37403
37498
  measureItems() {
37404
37499
  // Measure all items and cache what their dimensions should be, taking
37405
37500
  // into account constraints and the current layout. This allows syncing
@@ -37451,124 +37546,6 @@ class Sortable extends React.Component {
37451
37546
  });
37452
37547
  });
37453
37548
  }
37454
- render() {
37455
- var _this$props$constrain, _this$props$constrain2;
37456
- // To minimize layout shift, we display a spinner until our math
37457
- // renderer is ready to render the math inside the sortable. To
37458
- // do this, we:
37459
- // - render a dummy TeX component to force the math renderer to load
37460
- // - display a spinner until the TeX component calls its onRender
37461
- // callback, signifying that the math is rendered (from which we can
37462
- // infer that the math renderer has loaded)
37463
- //
37464
- // If we didn't do this, the user might see a sortable with empty
37465
- // cells on first render, and then the math would pop in a few moments
37466
- // later once the rendering library loaded.
37467
- if (this.props.waitForTexRendererToLoad && !this.state.texRendererLoaded) {
37468
- const {
37469
- TeX
37470
- } = getDependencies();
37471
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(CircularSpinner, null), /*#__PURE__*/React.createElement("div", {
37472
- style: {
37473
- display: "none"
37474
- }
37475
- }, /*#__PURE__*/React.createElement(TeX, {
37476
- onRender: () => this.setState({
37477
- texRendererLoaded: true
37478
- })
37479
- }, "1")));
37480
- }
37481
- const cards = [];
37482
- const {
37483
- layout
37484
- } = this.props;
37485
- // We need to keep backwards compatbility with rules specified directly
37486
- // in CSS. See sortable.less for details.
37487
- const className = css(styles$d.sortable) + " perseus-sortable";
37488
- const syncWidth = ((_this$props$constrain = this.props.constraints) == null ? void 0 : _this$props$constrain.width) || layout === Layout.VERTICAL;
37489
- const syncHeight = ((_this$props$constrain2 = this.props.constraints) == null ? void 0 : _this$props$constrain2.height) || layout === Layout.HORIZONTAL;
37490
- _.each(this.state.items, function (item, i, items) {
37491
- const isLast = i === items.length - 1;
37492
- const isStatic = item.state === ItemState.STATIC || item.state === ItemState.DISABLED;
37493
- let margin;
37494
-
37495
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37496
- if (this.props.layout === Layout.HORIZONTAL) {
37497
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37498
- margin = "0 " + this.props.margin + "px 0 0"; // right
37499
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37500
- } else if (this.props.layout === Layout.VERTICAL) {
37501
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37502
- margin = "0 0 " + this.props.margin + "px 0"; // bottom
37503
- }
37504
-
37505
- cards.push( /*#__PURE__*/React.createElement(Draggable, {
37506
- content: item.option,
37507
- key: item.key,
37508
- state: item.state
37509
- // @ts-expect-error - TS2769 - No overload matches this call.
37510
- ,
37511
- ref: item.key,
37512
- width: syncWidth ? item.width : undefined,
37513
- height: syncHeight ? item.height : undefined,
37514
- layout: layout
37515
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37516
- ,
37517
- includePadding: this.props.padding,
37518
- margin: isLast && isStatic ? 0 : margin,
37519
- endPosition: item.endPosition,
37520
- linterContext: PerseusLinter.pushContextStack(
37521
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37522
- this.props.linterContext, "sortable")
37523
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37524
- ,
37525
- onRender: this.remeasureItems
37526
- // eslint-disable-next-line react/jsx-no-bind
37527
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37528
- ,
37529
- onMouseDown: this.onMouseDown.bind(this, item.key)
37530
- // eslint-disable-next-line react/jsx-no-bind
37531
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37532
- ,
37533
- onMouseMove: this.onMouseMove.bind(this, item.key)
37534
- // eslint-disable-next-line react/jsx-no-bind
37535
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37536
- ,
37537
- onMouseUp: this.onMouseUp.bind(this, item.key)
37538
- // eslint-disable-next-line react/jsx-no-bind
37539
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37540
- ,
37541
- onTouchMove: this.onMouseMove.bind(this, item.key)
37542
- // eslint-disable-next-line react/jsx-no-bind
37543
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37544
- ,
37545
- onTouchEnd: this.onMouseUp.bind(this, item.key)
37546
- // eslint-disable-next-line react/jsx-no-bind
37547
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37548
- ,
37549
- onTouchCancel: this.onMouseUp.bind(this, item.key)
37550
- // eslint-disable-next-line react/jsx-no-bind
37551
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37552
- ,
37553
- onAnimationEnd: this.onAnimationEnd.bind(
37554
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37555
- this, item.key)
37556
- }));
37557
- if (item.state === ItemState.DRAGGING || item.state === ItemState.ANIMATING) {
37558
- cards.push( /*#__PURE__*/React.createElement(Placeholder, {
37559
- key: "placeholder_" + item.key,
37560
- ref: "placeholder_" + item.key,
37561
- width: item.width,
37562
- height: item.height,
37563
- layout: layout,
37564
- margin: isLast ? 0 : margin
37565
- }));
37566
- }
37567
- }, this);
37568
- return /*#__PURE__*/React.createElement("ul", {
37569
- className: className
37570
- }, cards);
37571
- }
37572
37549
  onMouseDown(key) {
37573
37550
  // Static -> Dragging
37574
37551
  const items = _.map(this.state.items, function (item) {
@@ -37714,6 +37691,124 @@ class Sortable extends React.Component {
37714
37691
  getOptions() {
37715
37692
  return _.pluck(this.state.items, "option");
37716
37693
  }
37694
+ render() {
37695
+ var _this$props$constrain, _this$props$constrain2;
37696
+ // To minimize layout shift, we display a spinner until our math
37697
+ // renderer is ready to render the math inside the sortable. To
37698
+ // do this, we:
37699
+ // - render a dummy TeX component to force the math renderer to load
37700
+ // - display a spinner until the TeX component calls its onRender
37701
+ // callback, signifying that the math is rendered (from which we can
37702
+ // infer that the math renderer has loaded)
37703
+ //
37704
+ // If we didn't do this, the user might see a sortable with empty
37705
+ // cells on first render, and then the math would pop in a few moments
37706
+ // later once the rendering library loaded.
37707
+ if (this.props.waitForTexRendererToLoad && !this.state.texRendererLoaded) {
37708
+ const {
37709
+ TeX
37710
+ } = getDependencies();
37711
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(CircularSpinner, null), /*#__PURE__*/React.createElement("div", {
37712
+ style: {
37713
+ display: "none"
37714
+ }
37715
+ }, /*#__PURE__*/React.createElement(TeX, {
37716
+ onRender: () => this.setState({
37717
+ texRendererLoaded: true
37718
+ })
37719
+ }, "1")));
37720
+ }
37721
+ const cards = [];
37722
+ const {
37723
+ layout
37724
+ } = this.props;
37725
+ // We need to keep backwards compatbility with rules specified directly
37726
+ // in CSS. See sortable.less for details.
37727
+ const className = css(styles$d.sortable) + " perseus-sortable";
37728
+ const syncWidth = ((_this$props$constrain = this.props.constraints) == null ? void 0 : _this$props$constrain.width) || layout === Layout.VERTICAL;
37729
+ const syncHeight = ((_this$props$constrain2 = this.props.constraints) == null ? void 0 : _this$props$constrain2.height) || layout === Layout.HORIZONTAL;
37730
+ _.each(this.state.items, function (item, i, items) {
37731
+ const isLast = i === items.length - 1;
37732
+ const isStatic = item.state === ItemState.STATIC || item.state === ItemState.DISABLED;
37733
+ let margin;
37734
+
37735
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37736
+ if (this.props.layout === Layout.HORIZONTAL) {
37737
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37738
+ margin = "0 " + this.props.margin + "px 0 0"; // right
37739
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37740
+ } else if (this.props.layout === Layout.VERTICAL) {
37741
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37742
+ margin = "0 0 " + this.props.margin + "px 0"; // bottom
37743
+ }
37744
+
37745
+ cards.push( /*#__PURE__*/React.createElement(Draggable, {
37746
+ content: item.option,
37747
+ key: item.key,
37748
+ state: item.state
37749
+ // @ts-expect-error - TS2769 - No overload matches this call.
37750
+ ,
37751
+ ref: item.key,
37752
+ width: syncWidth ? item.width : undefined,
37753
+ height: syncHeight ? item.height : undefined,
37754
+ layout: layout
37755
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37756
+ ,
37757
+ includePadding: this.props.padding,
37758
+ margin: isLast && isStatic ? 0 : margin,
37759
+ endPosition: item.endPosition,
37760
+ linterContext: PerseusLinter.pushContextStack(
37761
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37762
+ this.props.linterContext, "sortable")
37763
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37764
+ ,
37765
+ onRender: this.remeasureItems
37766
+ // eslint-disable-next-line react/jsx-no-bind
37767
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37768
+ ,
37769
+ onMouseDown: this.onMouseDown.bind(this, item.key)
37770
+ // eslint-disable-next-line react/jsx-no-bind
37771
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37772
+ ,
37773
+ onMouseMove: this.onMouseMove.bind(this, item.key)
37774
+ // eslint-disable-next-line react/jsx-no-bind
37775
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37776
+ ,
37777
+ onMouseUp: this.onMouseUp.bind(this, item.key)
37778
+ // eslint-disable-next-line react/jsx-no-bind
37779
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37780
+ ,
37781
+ onTouchMove: this.onMouseMove.bind(this, item.key)
37782
+ // eslint-disable-next-line react/jsx-no-bind
37783
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37784
+ ,
37785
+ onTouchEnd: this.onMouseUp.bind(this, item.key)
37786
+ // eslint-disable-next-line react/jsx-no-bind
37787
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37788
+ ,
37789
+ onTouchCancel: this.onMouseUp.bind(this, item.key)
37790
+ // eslint-disable-next-line react/jsx-no-bind
37791
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37792
+ ,
37793
+ onAnimationEnd: this.onAnimationEnd.bind(
37794
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37795
+ this, item.key)
37796
+ }));
37797
+ if (item.state === ItemState.DRAGGING || item.state === ItemState.ANIMATING) {
37798
+ cards.push( /*#__PURE__*/React.createElement(Placeholder, {
37799
+ key: "placeholder_" + item.key,
37800
+ ref: "placeholder_" + item.key,
37801
+ width: item.width,
37802
+ height: item.height,
37803
+ layout: layout,
37804
+ margin: isLast ? 0 : margin
37805
+ }));
37806
+ }
37807
+ }, this);
37808
+ return /*#__PURE__*/React.createElement("ul", {
37809
+ className: className
37810
+ }, cards);
37811
+ }
37717
37812
  }
37718
37813
  Sortable.defaultProps = {
37719
37814
  layout: Layout.HORIZONTAL,
@@ -38477,7 +38572,7 @@ var Matrix$1 = {
38477
38572
  isLintable: true
38478
38573
  };
38479
38574
 
38480
- /* eslint-disable @babel/no-invalid-this, react/sort-comp */
38575
+ /* eslint-disable @babel/no-invalid-this */
38481
38576
  const defaultImage = {
38482
38577
  url: null,
38483
38578
  top: 0,
@@ -38519,30 +38614,6 @@ const Measurer = createReactClass({
38519
38614
  getInitialState: function () {
38520
38615
  return {};
38521
38616
  },
38522
- render: function () {
38523
- const image = _.extend({}, defaultImage, this.props.image);
38524
-
38525
- // TODO(scottgrant): This isn't a11y-friendly! We should insist on
38526
- // finding some valid alt text when this widget is used.
38527
- return /*#__PURE__*/React.createElement("div", {
38528
- className: "perseus-widget perseus-widget-measurer " + "graphie-container above-scratchpad",
38529
- style: {
38530
- width: this.props.box[0],
38531
- height: this.props.box[1]
38532
- }
38533
- }, image.url && /*#__PURE__*/React.createElement("div", {
38534
- style: {
38535
- position: "relative",
38536
- top: image.top,
38537
- left: image.left
38538
- }
38539
- }, /*#__PURE__*/React.createElement(SvgImage, {
38540
- src: image.url
38541
- })), /*#__PURE__*/React.createElement("div", {
38542
- className: "graphie",
38543
- ref: "graphieDiv"
38544
- }));
38545
- },
38546
38617
  componentDidMount: function () {
38547
38618
  this.setupGraphie();
38548
38619
  },
@@ -38600,7 +38671,31 @@ const Measurer = createReactClass({
38600
38671
  // TODO(joel) - I don't understand how this is useful!
38601
38672
  return Measurer.validate(this.getUserInput(), rubric);
38602
38673
  },
38603
- focus: $.noop
38674
+ focus: $.noop,
38675
+ render: function () {
38676
+ const image = _.extend({}, defaultImage, this.props.image);
38677
+
38678
+ // TODO(scottgrant): This isn't a11y-friendly! We should insist on
38679
+ // finding some valid alt text when this widget is used.
38680
+ return /*#__PURE__*/React.createElement("div", {
38681
+ className: "perseus-widget perseus-widget-measurer " + "graphie-container above-scratchpad",
38682
+ style: {
38683
+ width: this.props.box[0],
38684
+ height: this.props.box[1]
38685
+ }
38686
+ }, image.url && /*#__PURE__*/React.createElement("div", {
38687
+ style: {
38688
+ position: "relative",
38689
+ top: image.top,
38690
+ left: image.left
38691
+ }
38692
+ }, /*#__PURE__*/React.createElement(SvgImage, {
38693
+ src: image.url
38694
+ })), /*#__PURE__*/React.createElement("div", {
38695
+ className: "graphie",
38696
+ ref: "graphieDiv"
38697
+ }));
38698
+ }
38604
38699
  });
38605
38700
  _.extend(Measurer, {
38606
38701
  validate: function (state, rubric) {
@@ -40201,55 +40296,6 @@ class Card extends React.Component {
40201
40296
  }
40202
40297
  };
40203
40298
  }
40204
- render() {
40205
- let style = {};
40206
- if (this.props.floating) {
40207
- style = {
40208
- position: "absolute",
40209
- left: this.props.startOffset.left,
40210
- top: this.props.startOffset.top
40211
- };
40212
- }
40213
- if (this.props.width) {
40214
- style.width = this.props.width;
40215
- }
40216
- const className = ["card"];
40217
- if (this.props.stack) {
40218
- className.push("stack");
40219
- }
40220
- if (this.props.floating && !this.props.animating) {
40221
- className.push("dragging");
40222
- style.left += this.props.mouse.left - this.props.startMouse.left;
40223
- style.top += this.props.mouse.top - this.props.startMouse.top;
40224
- }
40225
-
40226
- // Pull out the content to get rendered
40227
- const rendererProps = _.pick(this.props, "content");
40228
- const onMouseDown = this.props.animating ? $.noop : this.onMouseDown;
40229
- return /*#__PURE__*/React.createElement("div", {
40230
- className: "card-wrap " + ClassNames.INTERACTIVE,
40231
- style: style,
40232
- onMouseDown: onMouseDown,
40233
- onTouchStart: onMouseDown,
40234
- onTouchEnd: this.onMouseUp,
40235
- onTouchCancel: this.onMouseUp
40236
- }, /*#__PURE__*/React.createElement("div", {
40237
- className: className.join(" ")
40238
- }, /*#__PURE__*/React.createElement(Renderer, _extends({}, rendererProps, {
40239
- linterContext: this.props.linterContext,
40240
- strings: this.context.strings
40241
- }))));
40242
- }
40243
- shouldComponentUpdate(nextProps, nextState) {
40244
- // Cards in the bank or drag list don't usually change -- they only
40245
- // reorder themselves -- so we want to skip the update to things a
40246
- // little faster. We also need to re-render if the content changes,
40247
- // which happens only in the editor. (We do want to update the floating
40248
- // card on mouse move to update its position.)
40249
- return this.props.floating || nextProps.floating || this.props.content !== nextProps.content ||
40250
- // TODO(alpert): Remove ref here after fixing facebook/react#1392.
40251
- this.props.fakeRef !== nextProps.fakeRef;
40252
- }
40253
40299
  componentDidMount() {
40254
40300
  this.mouseMoveUpBound = false;
40255
40301
 
@@ -40268,6 +40314,16 @@ class Card extends React.Component {
40268
40314
  passive: false
40269
40315
  } : false);
40270
40316
  }
40317
+ shouldComponentUpdate(nextProps, nextState) {
40318
+ // Cards in the bank or drag list don't usually change -- they only
40319
+ // reorder themselves -- so we want to skip the update to things a
40320
+ // little faster. We also need to re-render if the content changes,
40321
+ // which happens only in the editor. (We do want to update the floating
40322
+ // card on mouse move to update its position.)
40323
+ return this.props.floating || nextProps.floating || this.props.content !== nextProps.content ||
40324
+ // TODO(alpert): Remove ref here after fixing facebook/react#1392.
40325
+ this.props.fakeRef !== nextProps.fakeRef;
40326
+ }
40271
40327
  componentDidUpdate(prevProps, prevState) {
40272
40328
  if (this.props.animating && !prevProps.animating) {
40273
40329
  // If we just were changed into animating, start the animation.
@@ -40289,6 +40345,45 @@ class Card extends React.Component {
40289
40345
  }
40290
40346
  document.removeEventListener("touchmove", this.onMouseMove);
40291
40347
  }
40348
+ render() {
40349
+ let style = {};
40350
+ if (this.props.floating) {
40351
+ style = {
40352
+ position: "absolute",
40353
+ left: this.props.startOffset.left,
40354
+ top: this.props.startOffset.top
40355
+ };
40356
+ }
40357
+ if (this.props.width) {
40358
+ style.width = this.props.width;
40359
+ }
40360
+ const className = ["card"];
40361
+ if (this.props.stack) {
40362
+ className.push("stack");
40363
+ }
40364
+ if (this.props.floating && !this.props.animating) {
40365
+ className.push("dragging");
40366
+ style.left += this.props.mouse.left - this.props.startMouse.left;
40367
+ style.top += this.props.mouse.top - this.props.startMouse.top;
40368
+ }
40369
+
40370
+ // Pull out the content to get rendered
40371
+ const rendererProps = _.pick(this.props, "content");
40372
+ const onMouseDown = this.props.animating ? $.noop : this.onMouseDown;
40373
+ return /*#__PURE__*/React.createElement("div", {
40374
+ className: "card-wrap " + ClassNames.INTERACTIVE,
40375
+ style: style,
40376
+ onMouseDown: onMouseDown,
40377
+ onTouchStart: onMouseDown,
40378
+ onTouchEnd: this.onMouseUp,
40379
+ onTouchCancel: this.onMouseUp
40380
+ }, /*#__PURE__*/React.createElement("div", {
40381
+ className: className.join(" ")
40382
+ }, /*#__PURE__*/React.createElement(Renderer, _extends({}, rendererProps, {
40383
+ linterContext: this.props.linterContext,
40384
+ strings: this.context.strings
40385
+ }))));
40386
+ }
40292
40387
  }
40293
40388
  Card.contextType = PerseusI18nContext;
40294
40389
  Card.propTypes = {
@@ -41495,7 +41590,6 @@ class HighlightSetRenderer extends React.PureComponent {
41495
41590
  hoveredHighlightKey: null,
41496
41591
  hoveringTooltipFor: null
41497
41592
  };
41498
- // eslint-disable-next-line react/sort-comp
41499
41593
  this._highlightRenderers = {};
41500
41594
  this._handleMouseMove = e => {
41501
41595
  const mouseClientPosition = {
@@ -41839,8 +41933,6 @@ class WordIndexer extends React.PureComponent {
41839
41933
  super(...args);
41840
41934
  this._container = void 0;
41841
41935
  }
41842
- /* eslint-enable react/sort-comp */
41843
-
41844
41936
  componentDidMount() {
41845
41937
  this._sendWordsUpdate();
41846
41938
  }
@@ -42510,6 +42602,14 @@ class Passage extends React.Component {
42510
42602
  });
42511
42603
  };
42512
42604
  }
42605
+ static validate(state, rubric) {
42606
+ return {
42607
+ type: "points",
42608
+ earned: 0,
42609
+ total: 0,
42610
+ message: null
42611
+ };
42612
+ }
42513
42613
  componentDidMount() {
42514
42614
  this._updateState();
42515
42615
 
@@ -42727,17 +42827,6 @@ class Passage extends React.Component {
42727
42827
  return Passage.validate(this.getUserInput(), rubric);
42728
42828
  }
42729
42829
 
42730
- /* eslint-disable react/sort-comp */
42731
- static validate(state, rubric) {
42732
- return {
42733
- type: "points",
42734
- earned: 0,
42735
- total: 0,
42736
- message: null
42737
- };
42738
- }
42739
- /* eslint-enable react/sort-comp */
42740
-
42741
42830
  /**
42742
42831
  * Rendering
42743
42832
  *
@@ -42950,7 +43039,10 @@ var PassageRefTarget$1 = {
42950
43039
  isLintable: true
42951
43040
  };
42952
43041
 
42953
- /* eslint-disable react/forbid-prop-types, react/sort-comp */
43042
+ /**
43043
+ * This is a PhET simulation widget. It is used for rendering simulations
43044
+ * from https://phet.colorado.edu/.
43045
+ */
42954
43046
 
42955
43047
  // For returning user input, but currently the PhET widget
42956
43048
  // does not support accessing user input
@@ -42964,14 +43056,6 @@ class PhetSimulation extends React.Component {
42964
43056
  url: null,
42965
43057
  banner: null
42966
43058
  };
42967
- this.change = (...args) => {
42968
- // @ts-expect-error - TS2345 - Argument of type 'readonly unknown[]' is not assignable to parameter of type 'any[]'.
42969
- return change.apply(this, args);
42970
- };
42971
- this.simpleValidate = rubric => {
42972
- // @ts-expect-error - TS2339 - Property 'validate' does not exist on type 'typeof PhetSimulation'.
42973
- return PhetSimulation.validate(this.getUserInput(), rubric);
42974
- };
42975
43059
  // kaLocales and PhET locales use different formats and abbreviations.
42976
43060
  // PhET accepts different formats, i.e. kaLocale's hyphens, but it does not accept
42977
43061
  // different abbreviations, so in points of divergence of abbreviations, we need to
@@ -43001,9 +43085,6 @@ class PhetSimulation extends React.Component {
43001
43085
  };
43002
43086
  this.locale = this.getPhetCompatibleLocale(getDependencies().kaLocale);
43003
43087
  }
43004
- getUserInput() {
43005
- return null;
43006
- }
43007
43088
  async componentDidMount() {
43008
43089
  await this.updateSimState(this.props.url);
43009
43090
  }
@@ -43013,53 +43094,8 @@ class PhetSimulation extends React.Component {
43013
43094
  await this.updateSimState(this.props.url);
43014
43095
  }
43015
43096
  }
43016
- render() {
43017
- var _this$state$url;
43018
- // We sandbox the iframe so that we allowlist only the functionality
43019
- // that we need. This makes it safer to present third-party content
43020
- // from the PhET website.
43021
- // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
43022
- const sandboxProperties = "allow-same-origin allow-scripts";
43023
- return /*#__PURE__*/React.createElement(View, {
43024
- style: styles$6.container
43025
- }, this.state.banner !== null &&
43026
- /*#__PURE__*/
43027
- // TODO(anna): Make this banner focusable
43028
- React.createElement(View, {
43029
- style: {
43030
- marginBottom: phoneMargin
43031
- }
43032
- }, /*#__PURE__*/React.createElement(Banner, {
43033
- layout: "floating",
43034
- kind: this.state.banner.kind,
43035
- text: this.state.banner.message
43036
- })), /*#__PURE__*/React.createElement("iframe", {
43037
- ref: this.iframeRef,
43038
- title: this.props.description,
43039
- sandbox: sandboxProperties,
43040
- style: {
43041
- minWidth: 400,
43042
- height: 360,
43043
- width: "100%",
43044
- borderWidth: 0
43045
- },
43046
- src: (_this$state$url = this.state.url) == null ? void 0 : _this$state$url.toString(),
43047
- allow: "fullscreen"
43048
- }), /*#__PURE__*/React.createElement(IconButton, {
43049
- icon: cornersOutIcon,
43050
- onClick: () => {
43051
- var _this$iframeRef$curre;
43052
- (_this$iframeRef$curre = this.iframeRef.current) == null || _this$iframeRef$curre.requestFullscreen();
43053
- },
43054
- kind: "secondary",
43055
- "aria-label": "Fullscreen",
43056
- style: {
43057
- marginTop: 5,
43058
- marginBottom: 5,
43059
- alignSelf: "flex-end"
43060
- },
43061
- disabled: this.state.url === null
43062
- }));
43097
+ getUserInput() {
43098
+ return null;
43063
43099
  }
43064
43100
  async updateSimState(urlString) {
43065
43101
  const url = makeSafeUrl(urlString, this.locale);
@@ -43117,6 +43153,53 @@ class PhetSimulation extends React.Component {
43117
43153
  }
43118
43154
  return true;
43119
43155
  }
43156
+ render() {
43157
+ var _this$state$url;
43158
+ // We sandbox the iframe so that we allowlist only the functionality
43159
+ // that we need. This makes it safer to present third-party content
43160
+ // from the PhET website.
43161
+ // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
43162
+ const sandboxProperties = "allow-same-origin allow-scripts";
43163
+ return /*#__PURE__*/React.createElement(View, {
43164
+ style: styles$6.container
43165
+ }, this.state.banner !== null &&
43166
+ /*#__PURE__*/
43167
+ // TODO(anna): Make this banner focusable
43168
+ React.createElement(View, {
43169
+ style: {
43170
+ marginBottom: phoneMargin
43171
+ }
43172
+ }, /*#__PURE__*/React.createElement(Banner, {
43173
+ layout: "floating",
43174
+ kind: this.state.banner.kind,
43175
+ text: this.state.banner.message
43176
+ })), /*#__PURE__*/React.createElement("iframe", {
43177
+ ref: this.iframeRef,
43178
+ title: this.props.description,
43179
+ sandbox: sandboxProperties,
43180
+ style: {
43181
+ height: 225,
43182
+ width: "100%",
43183
+ borderWidth: 0
43184
+ },
43185
+ src: (_this$state$url = this.state.url) == null ? void 0 : _this$state$url.toString(),
43186
+ allow: "fullscreen"
43187
+ }), /*#__PURE__*/React.createElement(IconButton, {
43188
+ icon: cornersOutIcon,
43189
+ onClick: () => {
43190
+ var _this$iframeRef$curre;
43191
+ (_this$iframeRef$curre = this.iframeRef.current) == null || _this$iframeRef$curre.requestFullscreen();
43192
+ },
43193
+ kind: "secondary",
43194
+ "aria-label": "Fullscreen",
43195
+ style: {
43196
+ marginTop: 5,
43197
+ marginBottom: 5,
43198
+ alignSelf: "flex-end"
43199
+ },
43200
+ disabled: this.state.url === null
43201
+ }));
43202
+ }
43120
43203
  }
43121
43204
 
43122
43205
  // Setting URL to null will display an error message in the iframe
@@ -43132,24 +43215,23 @@ const makeSafeUrl = (urlString, locale) => {
43132
43215
  url.searchParams.set("locale", locale);
43133
43216
  return url;
43134
43217
  };
43135
- var PhetSimulation$1 = {
43136
- name: "phet-simulation",
43137
- displayName: "PhET Simulation",
43138
- widget: PhetSimulation,
43139
- // Hides widget from content creators until full release
43140
- hidden: true,
43141
- isLintable: true
43142
- };
43143
43218
  const styles$6 = StyleSheet.create({
43144
43219
  container: {
43145
43220
  borderRadius: borderRadiusLarge,
43146
43221
  borderWidth: 1,
43147
43222
  borderColor: basicBorderColor,
43148
- padding: phoneMargin,
43223
+ padding: spacing.medium_16,
43149
43224
  paddingBottom: 0,
43150
- width: 650
43225
+ // Include space for medium_16 padding on each side
43226
+ width: 400 + spacing.xLarge_32
43151
43227
  }
43152
43228
  });
43229
+ var PhetSimulation$1 = {
43230
+ name: "phet-simulation",
43231
+ displayName: "PhET Simulation",
43232
+ widget: PhetSimulation,
43233
+ isLintable: true
43234
+ };
43153
43235
 
43154
43236
  /* eslint-disable react/no-unsafe */
43155
43237
  const {
@@ -44655,7 +44737,7 @@ const init = function init(options) {
44655
44737
 
44656
44738
  // This file is processed by a Rollup plugin (replace) to inject the production
44657
44739
  const libName = "@khanacademy/perseus";
44658
- const libVersion = "31.0.1";
44740
+ const libVersion = "32.0.0";
44659
44741
  addLibraryVersionToPerseusDebug(libName, libVersion);
44660
44742
 
44661
44743
  const apiVersion = {
@@ -46468,8 +46550,6 @@ class MultiRenderer extends React.Component {
46468
46550
  // Keep state in sync with props.
46469
46551
  this.state = this._tryMakeRendererState(this.props);
46470
46552
  }
46471
- /* eslint-enable react/sort-comp */
46472
-
46473
46553
  UNSAFE_componentWillReceiveProps(nextProps) {
46474
46554
  // Keep state in sync with props.
46475
46555
  if (nextProps.item !== this.props.item) {
@@ -48242,5 +48322,5 @@ const EditorJsonify = {
48242
48322
  }
48243
48323
  };
48244
48324
 
48245
- export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
48325
+ export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, makeSafeUrl, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
48246
48326
  //# sourceMappingURL=index.js.map