@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/index.js CHANGED
@@ -650,6 +650,7 @@ class InnerMathInput extends React__namespace.Component {
650
650
  onFocus: () => this.focus(),
651
651
  onBlur: () => this.blur()
652
652
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.Popover, {
653
+ rootBoundary: "document",
653
654
  opened: this.state.keypadOpen,
654
655
  onClose: () => this.closeKeypad(),
655
656
  dismissEnabled: true,
@@ -1008,32 +1009,6 @@ class TextListEditor extends React__namespace.Component {
1008
1009
  items: nextProps.options.concat("")
1009
1010
  });
1010
1011
  }
1011
- render() {
1012
- const className = ["perseus-text-list-editor", "perseus-clearfix", "layout-" + this.props.layout].join(" ");
1013
- const inputs = ___default["default"].map(this.state.items, function (item, i) {
1014
- return /*#__PURE__*/React__namespace.createElement("li", {
1015
- key: i
1016
- }, /*#__PURE__*/React__namespace.createElement("input", {
1017
- ref: "input_" + i,
1018
- type: "text",
1019
- value: item
1020
- // eslint-disable-next-line react/jsx-no-bind
1021
- // @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.
1022
- ,
1023
- onChange: this.onChange.bind(this, i)
1024
- // eslint-disable-next-line react/jsx-no-bind
1025
- // @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.
1026
- ,
1027
- onKeyDown: this.onKeyDown.bind(this, i),
1028
- style: {
1029
- width: getTextWidth(item)
1030
- }
1031
- }));
1032
- }, this);
1033
- return /*#__PURE__*/React__namespace.createElement("ul", {
1034
- className: className
1035
- }, inputs);
1036
- }
1037
1012
  onChange = (index, event) => {
1038
1013
  let items = ___default["default"].clone(this.state.items);
1039
1014
  items[index] = event.target.value;
@@ -1109,6 +1084,32 @@ class TextListEditor extends React__namespace.Component {
1109
1084
  }
1110
1085
  }
1111
1086
  };
1087
+ render() {
1088
+ const className = ["perseus-text-list-editor", "perseus-clearfix", "layout-" + this.props.layout].join(" ");
1089
+ const inputs = ___default["default"].map(this.state.items, function (item, i) {
1090
+ return /*#__PURE__*/React__namespace.createElement("li", {
1091
+ key: i
1092
+ }, /*#__PURE__*/React__namespace.createElement("input", {
1093
+ ref: "input_" + i,
1094
+ type: "text",
1095
+ value: item
1096
+ // eslint-disable-next-line react/jsx-no-bind
1097
+ // @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.
1098
+ ,
1099
+ onChange: this.onChange.bind(this, i)
1100
+ // eslint-disable-next-line react/jsx-no-bind
1101
+ // @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.
1102
+ ,
1103
+ onKeyDown: this.onKeyDown.bind(this, i),
1104
+ style: {
1105
+ width: getTextWidth(item)
1106
+ }
1107
+ }));
1108
+ }, this);
1109
+ return /*#__PURE__*/React__namespace.createElement("ul", {
1110
+ className: className
1111
+ }, inputs);
1112
+ }
1112
1113
  }
1113
1114
 
1114
1115
  /**
@@ -19650,6 +19651,22 @@ class WidgetContainer extends React__namespace.Component {
19650
19651
  }
19651
19652
  }
19652
19653
 
19654
+ UNSAFE_componentWillReceiveProps(nextProps) {
19655
+ if (this.props.type !== nextProps.type) {
19656
+ throw new Error("WidgetContainer can't change widget type; set a different " + "key instead to recreate the container.");
19657
+ }
19658
+ }
19659
+ shouldComponentUpdate(nextProps, nextState) {
19660
+ return this.props.shouldHighlight !== nextProps.shouldHighlight || this.props.type !== nextProps.type || this.state.widgetProps !== nextState.widgetProps || this.state.sizeClass !== nextState.sizeClass;
19661
+ }
19662
+ getWidget = () => {
19663
+ return this.widgetRef.current;
19664
+ };
19665
+ replaceWidgetProps = newWidgetProps => {
19666
+ this.setState({
19667
+ widgetProps: newWidgetProps
19668
+ });
19669
+ };
19653
19670
  render() {
19654
19671
  let className = classNames__default["default"]({
19655
19672
  "perseus-widget-container": true,
@@ -19744,22 +19761,6 @@ class WidgetContainer extends React__namespace.Component {
19744
19761
  }));
19745
19762
  }));
19746
19763
  }
19747
- UNSAFE_componentWillReceiveProps(nextProps) {
19748
- if (this.props.type !== nextProps.type) {
19749
- throw new Error("WidgetContainer can't change widget type; set a different " + "key instead to recreate the container.");
19750
- }
19751
- }
19752
- shouldComponentUpdate(nextProps, nextState) {
19753
- return this.props.shouldHighlight !== nextProps.shouldHighlight || this.props.type !== nextProps.type || this.state.widgetProps !== nextState.widgetProps || this.state.sizeClass !== nextState.sizeClass;
19754
- }
19755
- getWidget = () => {
19756
- return this.widgetRef.current;
19757
- };
19758
- replaceWidgetProps = newWidgetProps => {
19759
- this.setState({
19760
- widgetProps: newWidgetProps
19761
- });
19762
- };
19763
19764
  }
19764
19765
 
19765
19766
  const {
@@ -21260,6 +21261,34 @@ class TextInput extends React__namespace.Component {
21260
21261
  this.id = uniqueIdForInput();
21261
21262
  }
21262
21263
  }
21264
+ focus = () => {
21265
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'focus' does not exist on type 'Element | Text'.
21266
+ ReactDOM__default["default"].findDOMNode(this).focus();
21267
+ };
21268
+ blur = () => {
21269
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'blur' does not exist on type 'Element | Text'.
21270
+ ReactDOM__default["default"].findDOMNode(this).blur();
21271
+ };
21272
+ getValue = () => {
21273
+ // @ts-expect-error - TS2339 - Property 'value' does not exist on type 'Element | Text'.
21274
+ return ReactDOM__default["default"].findDOMNode(this)?.value;
21275
+ };
21276
+ getStringValue = () => {
21277
+ // @ts-expect-error - TS2339 - Property 'value' does not exist on type 'Element | Text'.
21278
+ return ReactDOM__default["default"].findDOMNode(this)?.value.toString();
21279
+ };
21280
+ setSelectionRange = (selectionStart, selectionEnd) => {
21281
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'setSelectionRange' does not exist on type 'Element | Text'.
21282
+ ReactDOM__default["default"].findDOMNode(this).setSelectionRange(selectionStart, selectionEnd);
21283
+ };
21284
+ getSelectionStart = () => {
21285
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionStart' does not exist on type 'Element | Text'.
21286
+ return ReactDOM__default["default"].findDOMNode(this).selectionStart;
21287
+ };
21288
+ getSelectionEnd = () => {
21289
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionEnd' does not exist on type 'Element | Text'.
21290
+ return ReactDOM__default["default"].findDOMNode(this).selectionEnd;
21291
+ };
21263
21292
  render() {
21264
21293
  const {
21265
21294
  labelText,
@@ -21291,34 +21320,6 @@ class TextInput extends React__namespace.Component {
21291
21320
  autoComplete: "off"
21292
21321
  });
21293
21322
  }
21294
- focus = () => {
21295
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'focus' does not exist on type 'Element | Text'.
21296
- ReactDOM__default["default"].findDOMNode(this).focus();
21297
- };
21298
- blur = () => {
21299
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'blur' does not exist on type 'Element | Text'.
21300
- ReactDOM__default["default"].findDOMNode(this).blur();
21301
- };
21302
- getValue = () => {
21303
- // @ts-expect-error - TS2339 - Property 'value' does not exist on type 'Element | Text'.
21304
- return ReactDOM__default["default"].findDOMNode(this)?.value;
21305
- };
21306
- getStringValue = () => {
21307
- // @ts-expect-error - TS2339 - Property 'value' does not exist on type 'Element | Text'.
21308
- return ReactDOM__default["default"].findDOMNode(this)?.value.toString();
21309
- };
21310
- setSelectionRange = (selectionStart, selectionEnd) => {
21311
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'setSelectionRange' does not exist on type 'Element | Text'.
21312
- ReactDOM__default["default"].findDOMNode(this).setSelectionRange(selectionStart, selectionEnd);
21313
- };
21314
- getSelectionStart = () => {
21315
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionStart' does not exist on type 'Element | Text'.
21316
- return ReactDOM__default["default"].findDOMNode(this).selectionStart;
21317
- };
21318
- getSelectionEnd = () => {
21319
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionEnd' does not exist on type 'Element | Text'.
21320
- return ReactDOM__default["default"].findDOMNode(this).selectionEnd;
21321
- };
21322
21323
  }
21323
21324
 
21324
21325
  /* eslint-disable react/no-unsafe */
@@ -21568,7 +21569,6 @@ class Tooltip extends React__namespace.Component {
21568
21569
  }
21569
21570
  }
21570
21571
 
21571
- /* eslint-disable react/sort-comp */
21572
21572
  const {
21573
21573
  captureScratchpadTouchStart: captureScratchpadTouchStart$2
21574
21574
  } = Util;
@@ -21622,31 +21622,6 @@ class InputWithExamples extends React__namespace.Component {
21622
21622
  };
21623
21623
  return /*#__PURE__*/React__namespace.createElement(TextInput, inputProps);
21624
21624
  };
21625
- render() {
21626
- const input = this._renderInput();
21627
- const examplesContent = ___default["default"].map(this.props.examples, example => {
21628
- return "- " + example;
21629
- }).join("\n");
21630
- const showExamples = this.props.shouldShowExamples && this.state.showExamples;
21631
- return /*#__PURE__*/React__namespace.createElement(Tooltip
21632
- // eslint-disable-next-line react/no-string-refs
21633
- , {
21634
- ref: "tooltip",
21635
- className: "perseus-formats-tooltip preview-measure",
21636
- horizontalPosition: HorizontalDirection.Left,
21637
- horizontalAlign: HorizontalDirection.Left,
21638
- verticalPosition: VerticalDirection.Bottom,
21639
- arrowSize: 10,
21640
- borderColor: "#ccc",
21641
- show: showExamples
21642
- }, input, /*#__PURE__*/React__namespace.createElement("div", {
21643
- id: this._getUniqueId()
21644
- }, /*#__PURE__*/React__namespace.createElement(Renderer, {
21645
- content: examplesContent,
21646
- linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "input-with-examples"),
21647
- strings: this.context.strings
21648
- })));
21649
- }
21650
21625
  _handleFocus = () => {
21651
21626
  this.props.onFocus();
21652
21627
  this.setState({
@@ -21684,6 +21659,31 @@ class InputWithExamples extends React__namespace.Component {
21684
21659
  handleChange = e => {
21685
21660
  this.props.onChange(e.target.value);
21686
21661
  };
21662
+ render() {
21663
+ const input = this._renderInput();
21664
+ const examplesContent = ___default["default"].map(this.props.examples, example => {
21665
+ return "- " + example;
21666
+ }).join("\n");
21667
+ const showExamples = this.props.shouldShowExamples && this.state.showExamples;
21668
+ return /*#__PURE__*/React__namespace.createElement(Tooltip
21669
+ // eslint-disable-next-line react/no-string-refs
21670
+ , {
21671
+ ref: "tooltip",
21672
+ className: "perseus-formats-tooltip preview-measure",
21673
+ horizontalPosition: HorizontalDirection.Left,
21674
+ horizontalAlign: HorizontalDirection.Left,
21675
+ verticalPosition: VerticalDirection.Bottom,
21676
+ arrowSize: 10,
21677
+ borderColor: "#ccc",
21678
+ show: showExamples
21679
+ }, input, /*#__PURE__*/React__namespace.createElement("div", {
21680
+ id: this._getUniqueId()
21681
+ }, /*#__PURE__*/React__namespace.createElement(Renderer, {
21682
+ content: examplesContent,
21683
+ linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "input-with-examples"),
21684
+ strings: this.context.strings
21685
+ })));
21686
+ }
21687
21687
  }
21688
21688
 
21689
21689
  class SimpleKeypadInput extends React__namespace.Component {
@@ -21914,7 +21914,6 @@ var TexWrangler = {
21914
21914
  modifyTex
21915
21915
  };
21916
21916
 
21917
- /* eslint-disable react/sort-comp */
21918
21917
  const ParseTex$1 = TexWrangler.parseTex;
21919
21918
  const answerTypes = {
21920
21919
  number: {
@@ -21991,58 +21990,65 @@ class InputNumber extends React__namespace.Component {
21991
21990
  apiOptions: ApiOptions.defaults,
21992
21991
  linterContext: PerseusLinter.linterContextDefault
21993
21992
  };
21994
- shouldShowExamples = () => {
21995
- return this.props.answerType !== "number";
21996
- };
21997
- render() {
21998
- if (this.props.apiOptions.customKeypad) {
21999
- // TODO(charlie): Support "Review Mode".
22000
- const input = /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput
22001
- // eslint-disable-next-line react/no-string-refs
22002
- , {
22003
- ref: "input",
22004
- value: this.props.currentValue,
22005
- keypadElement: this.props.keypadElement,
22006
- onChange: this.handleChange,
22007
- onFocus: this._handleFocus,
22008
- onBlur: this._handleBlur
22009
- });
22010
- if (this.props.rightAlign) {
22011
- return /*#__PURE__*/React__namespace.createElement("div", {
22012
- className: "perseus-input-right-align"
22013
- }, input);
22014
- }
22015
- return input;
21993
+ static validate(state, rubric, strings) {
21994
+ let onInputError = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : () => {};
21995
+ if (rubric.answerType == null) {
21996
+ rubric.answerType = "number";
22016
21997
  }
22017
- // HACK(johnsullivan): Create a function with shared logic between
22018
- // this and NumericInput.
22019
- // TODO(jeremy): Deprecate this widget and prefer numeric-input.
22020
- const rubric = this.props.reviewModeRubric;
22021
21998
 
22022
- // Note: This is _very_ similar to what `numeric-input.jsx` does. If
22023
- // you modify this, double-check if you also need to modify that
22024
- // component.
22025
- const inputStyles = [styles$A.default, this.props.size === "small" ? styles$A.small : null, this.props.rightAlign ? styles$A.rightAlign : styles$A.leftAlign];
22026
- // Unanswered
22027
- if (rubric && !this.props.currentValue) {
22028
- inputStyles.push(styles$A.answerStateUnanswered);
21999
+ // note(matthewc): this will get immediately parsed again by
22000
+ // `KhanAnswerTypes.number.convertToPredicate`, but a string is
22001
+ // expected here
22002
+ const stringValue = `${rubric.value}`;
22003
+ const val = KhanAnswerTypes.number.createValidatorFunctional(stringValue, {
22004
+ simplify: rubric.simplify,
22005
+ inexact: rubric.inexact || undefined,
22006
+ maxError: rubric.maxError,
22007
+ forms: answerTypes[rubric.answerType].forms
22008
+ }, strings);
22009
+
22010
+ // We may have received TeX; try to parse it before grading.
22011
+ // If `currentValue` is not TeX, this should be a no-op.
22012
+ const currentValue = ParseTex$1(state.currentValue);
22013
+ const result = val(currentValue);
22014
+
22015
+ // TODO(eater): Seems silly to translate result to this invalid/points
22016
+ // thing and immediately translate it back in ItemRenderer.scoreInput()
22017
+ if (result.empty) {
22018
+ // TODO(FEI-3867): remove null-check once we have APIOptionsInternal
22019
+ const apiResult = onInputError?.(null,
22020
+ // reserved for some widget identifier
22021
+ state.currentValue, result.message);
22022
+ return {
22023
+ type: "invalid",
22024
+ message: apiResult === false ? null : result.message
22025
+ };
22029
22026
  }
22030
- return /*#__PURE__*/React__namespace.createElement(InputWithExamples
22031
- // eslint-disable-next-line react/no-string-refs
22032
- , {
22033
- ref: "input",
22034
- value: this.props.currentValue,
22035
- onChange: this.handleChange,
22036
- style: inputStyles,
22037
- examples: this.examples(),
22038
- shouldShowExamples: this.shouldShowExamples(),
22039
- onFocus: this._handleFocus,
22040
- onBlur: this._handleBlur,
22041
- id: this.props.widgetId,
22042
- disabled: this.props.apiOptions.readOnly,
22043
- linterContext: this.props.linterContext
22044
- });
22027
+ return {
22028
+ type: "points",
22029
+ earned: result.correct ? 1 : 0,
22030
+ total: 1,
22031
+ message: result.message
22032
+ };
22045
22033
  }
22034
+ static getUserInputFromProps(props) {
22035
+ return {
22036
+ currentValue: props.currentValue
22037
+ };
22038
+ }
22039
+ static getOneCorrectAnswerFromRubric(rubric) {
22040
+ if (rubric.value == null) {
22041
+ return;
22042
+ }
22043
+ let answerString = String(rubric.value);
22044
+ if (rubric.inexact && rubric.maxError) {
22045
+ answerString += " \u00B1 " + rubric.maxError;
22046
+ }
22047
+ return answerString;
22048
+ }
22049
+ shouldShowExamples = () => {
22050
+ return this.props.answerType !== "number";
22051
+ };
22046
22052
  handleChange = (newValue, cb) => {
22047
22053
  this.props.onChange({
22048
22054
  currentValue: newValue
@@ -22108,61 +22114,54 @@ class InputNumber extends React__namespace.Component {
22108
22114
  const examples = ___default["default"].map(forms, form => formExamples$1[form](this.props, strings));
22109
22115
  return [strings.yourAnswer].concat(examples);
22110
22116
  };
22111
- static validate(state, rubric, strings) {
22112
- let onInputError = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : () => {};
22113
- if (rubric.answerType == null) {
22114
- rubric.answerType = "number";
22117
+ render() {
22118
+ if (this.props.apiOptions.customKeypad) {
22119
+ // TODO(charlie): Support "Review Mode".
22120
+ const input = /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput
22121
+ // eslint-disable-next-line react/no-string-refs
22122
+ , {
22123
+ ref: "input",
22124
+ value: this.props.currentValue,
22125
+ keypadElement: this.props.keypadElement,
22126
+ onChange: this.handleChange,
22127
+ onFocus: this._handleFocus,
22128
+ onBlur: this._handleBlur
22129
+ });
22130
+ if (this.props.rightAlign) {
22131
+ return /*#__PURE__*/React__namespace.createElement("div", {
22132
+ className: "perseus-input-right-align"
22133
+ }, input);
22134
+ }
22135
+ return input;
22115
22136
  }
22137
+ // HACK(johnsullivan): Create a function with shared logic between
22138
+ // this and NumericInput.
22139
+ // TODO(jeremy): Deprecate this widget and prefer numeric-input.
22140
+ const rubric = this.props.reviewModeRubric;
22116
22141
 
22117
- // note(matthewc): this will get immediately parsed again by
22118
- // `KhanAnswerTypes.number.convertToPredicate`, but a string is
22119
- // expected here
22120
- const stringValue = `${rubric.value}`;
22121
- const val = KhanAnswerTypes.number.createValidatorFunctional(stringValue, {
22122
- simplify: rubric.simplify,
22123
- inexact: rubric.inexact || undefined,
22124
- maxError: rubric.maxError,
22125
- forms: answerTypes[rubric.answerType].forms
22126
- }, strings);
22127
-
22128
- // We may have received TeX; try to parse it before grading.
22129
- // If `currentValue` is not TeX, this should be a no-op.
22130
- const currentValue = ParseTex$1(state.currentValue);
22131
- const result = val(currentValue);
22132
-
22133
- // TODO(eater): Seems silly to translate result to this invalid/points
22134
- // thing and immediately translate it back in ItemRenderer.scoreInput()
22135
- if (result.empty) {
22136
- // TODO(FEI-3867): remove null-check once we have APIOptionsInternal
22137
- const apiResult = onInputError?.(null,
22138
- // reserved for some widget identifier
22139
- state.currentValue, result.message);
22140
- return {
22141
- type: "invalid",
22142
- message: apiResult === false ? null : result.message
22143
- };
22144
- }
22145
- return {
22146
- type: "points",
22147
- earned: result.correct ? 1 : 0,
22148
- total: 1,
22149
- message: result.message
22150
- };
22151
- }
22152
- static getUserInputFromProps(props) {
22153
- return {
22154
- currentValue: props.currentValue
22155
- };
22156
- }
22157
- static getOneCorrectAnswerFromRubric(rubric) {
22158
- if (rubric.value == null) {
22159
- return;
22160
- }
22161
- let answerString = String(rubric.value);
22162
- if (rubric.inexact && rubric.maxError) {
22163
- answerString += " \u00B1 " + rubric.maxError;
22142
+ // Note: This is _very_ similar to what `numeric-input.jsx` does. If
22143
+ // you modify this, double-check if you also need to modify that
22144
+ // component.
22145
+ const inputStyles = [styles$A.default, this.props.size === "small" ? styles$A.small : null, this.props.rightAlign ? styles$A.rightAlign : styles$A.leftAlign];
22146
+ // Unanswered
22147
+ if (rubric && !this.props.currentValue) {
22148
+ inputStyles.push(styles$A.answerStateUnanswered);
22164
22149
  }
22165
- return answerString;
22150
+ return /*#__PURE__*/React__namespace.createElement(InputWithExamples
22151
+ // eslint-disable-next-line react/no-string-refs
22152
+ , {
22153
+ ref: "input",
22154
+ value: this.props.currentValue,
22155
+ onChange: this.handleChange,
22156
+ style: inputStyles,
22157
+ examples: this.examples(),
22158
+ shouldShowExamples: this.shouldShowExamples(),
22159
+ onFocus: this._handleFocus,
22160
+ onBlur: this._handleBlur,
22161
+ id: this.props.widgetId,
22162
+ disabled: this.props.apiOptions.readOnly,
22163
+ linterContext: this.props.linterContext
22164
+ });
22166
22165
  }
22167
22166
  }
22168
22167
  const styles$A = aphrodite.StyleSheet.create({
@@ -22606,7 +22605,6 @@ var NumericInput$1 = {
22606
22605
  isLintable: true
22607
22606
  };
22608
22607
 
22609
- /* eslint-disable react/sort-comp */
22610
22608
  const EN_DASH$1 = "\u2013";
22611
22609
  class PassageRef extends React__namespace.Component {
22612
22610
  static contextType = PerseusI18nContext;
@@ -22624,48 +22622,38 @@ class PassageRef extends React__namespace.Component {
22624
22622
  lineRange: null,
22625
22623
  content: null
22626
22624
  };
22625
+ static validate(userInput, rubric) {
22626
+ return {
22627
+ type: "points",
22628
+ earned: 0,
22629
+ total: 0,
22630
+ message: null
22631
+ };
22632
+ }
22633
+ componentDidMount() {
22634
+ // TODO(scottgrant): This is a hack to remove the deprecated call to
22635
+ // this.isMounted() but is still considered an anti-pattern.
22636
+ this._isMounted = true;
22637
+ this._deferredUpdateRange();
22638
+ this._throttledUpdateRange = ___default["default"].throttle(this._deferredUpdateRange, 500);
22639
+ window.addEventListener("resize", this._throttledUpdateRange);
22640
+ }
22627
22641
  shouldComponentUpdate(nextProps, nextState) {
22628
22642
  return !___default["default"].isEqual(this.props, nextProps) || !___default["default"].isEqual(this.state, nextState);
22629
22643
  }
22644
+ componentDidUpdate() {
22645
+ this._deferredUpdateRange();
22646
+ }
22647
+ componentWillUnmount() {
22648
+ window.removeEventListener("resize", this._throttledUpdateRange);
22649
+ this._isMounted = false;
22650
+ }
22630
22651
 
22631
22652
  // TODO(tamarab): getUserInput needs to be updated to only return
22632
22653
  // props input by the user. Currently returns all the widget's props.
22633
22654
  getUserInput = () => {
22634
22655
  return removeDenylistProps(this.props);
22635
22656
  };
22636
- render() {
22637
- const {
22638
- strings
22639
- } = this.context;
22640
- const lineRange = this.state.lineRange;
22641
- let lineRangeOutput;
22642
- if (!lineRange) {
22643
- lineRangeOutput = strings.lineRange({
22644
- lineRange: `?${EN_DASH$1}?`
22645
- });
22646
- } else if (lineRange[0] === lineRange[1]) {
22647
- lineRangeOutput = strings.lineNumber({
22648
- lineNumber: String(lineRange[0])
22649
- });
22650
- } else {
22651
- lineRangeOutput = strings.lineRange({
22652
- lineRange: lineRange[0] + EN_DASH$1 + lineRange[1]
22653
- });
22654
- }
22655
- let summaryOutput;
22656
- if (this.props.summaryText) {
22657
- // @ts-expect-error - TS2554 - Expected 2 arguments, but got 1.
22658
- const summaryTree = PerseusMarkdown.parseInline(this.props.summaryText);
22659
- summaryOutput = /*#__PURE__*/React__namespace.createElement("span", {
22660
- "aria-hidden": true
22661
- }, " ", "(\u201C", PerseusMarkdown.basicOutput(summaryTree), "\u201D)");
22662
- } else {
22663
- summaryOutput = null;
22664
- }
22665
- return /*#__PURE__*/React__namespace.createElement("span", null, lineRangeOutput, summaryOutput, lineRange && /*#__PURE__*/React__namespace.createElement("div", {
22666
- className: "perseus-sr-only"
22667
- }, this.state.content));
22668
- }
22669
22657
  change = (() => {
22670
22658
  var _this = this;
22671
22659
  return function () {
@@ -22675,21 +22663,6 @@ class PassageRef extends React__namespace.Component {
22675
22663
  return change.apply(_this, args);
22676
22664
  };
22677
22665
  })();
22678
- componentDidMount() {
22679
- // TODO(scottgrant): This is a hack to remove the deprecated call to
22680
- // this.isMounted() but is still considered an anti-pattern.
22681
- this._isMounted = true;
22682
- this._deferredUpdateRange();
22683
- this._throttledUpdateRange = ___default["default"].throttle(this._deferredUpdateRange, 500);
22684
- window.addEventListener("resize", this._throttledUpdateRange);
22685
- }
22686
- componentDidUpdate() {
22687
- this._deferredUpdateRange();
22688
- }
22689
- componentWillUnmount() {
22690
- window.removeEventListener("resize", this._throttledUpdateRange);
22691
- this._isMounted = false;
22692
- }
22693
22666
  _deferredUpdateRange = () => {
22694
22667
  ___default["default"].defer(this._updateRange);
22695
22668
  };
@@ -22719,13 +22692,38 @@ class PassageRef extends React__namespace.Component {
22719
22692
  simpleValidate = rubric => {
22720
22693
  return PassageRef.validate(this.getUserInput(), rubric);
22721
22694
  };
22722
- static validate(userInput, rubric) {
22723
- return {
22724
- type: "points",
22725
- earned: 0,
22726
- total: 0,
22727
- message: null
22728
- };
22695
+ render() {
22696
+ const {
22697
+ strings
22698
+ } = this.context;
22699
+ const lineRange = this.state.lineRange;
22700
+ let lineRangeOutput;
22701
+ if (!lineRange) {
22702
+ lineRangeOutput = strings.lineRange({
22703
+ lineRange: `?${EN_DASH$1}?`
22704
+ });
22705
+ } else if (lineRange[0] === lineRange[1]) {
22706
+ lineRangeOutput = strings.lineNumber({
22707
+ lineNumber: String(lineRange[0])
22708
+ });
22709
+ } else {
22710
+ lineRangeOutput = strings.lineRange({
22711
+ lineRange: lineRange[0] + EN_DASH$1 + lineRange[1]
22712
+ });
22713
+ }
22714
+ let summaryOutput;
22715
+ if (this.props.summaryText) {
22716
+ // @ts-expect-error - TS2554 - Expected 2 arguments, but got 1.
22717
+ const summaryTree = PerseusMarkdown.parseInline(this.props.summaryText);
22718
+ summaryOutput = /*#__PURE__*/React__namespace.createElement("span", {
22719
+ "aria-hidden": true
22720
+ }, " ", "(\u201C", PerseusMarkdown.basicOutput(summaryTree), "\u201D)");
22721
+ } else {
22722
+ summaryOutput = null;
22723
+ }
22724
+ return /*#__PURE__*/React__namespace.createElement("span", null, lineRangeOutput, summaryOutput, lineRange && /*#__PURE__*/React__namespace.createElement("div", {
22725
+ className: "perseus-sr-only"
22726
+ }, this.state.content));
22729
22727
  }
22730
22728
  }
22731
22729
  var PassageRef$1 = {
@@ -24677,6 +24675,33 @@ class Categorizer extends React__namespace.Component {
24677
24675
  state = {
24678
24676
  uniqueId: ___default["default"].uniqueId("perseus_radio_")
24679
24677
  };
24678
+ static validate(userInput, rubric, strings) {
24679
+ let completed = true;
24680
+ let allCorrect = true;
24681
+ rubric.values.forEach((value, i) => {
24682
+ if (userInput.values[i] == null) {
24683
+ completed = false;
24684
+ }
24685
+ if (userInput.values[i] !== value) {
24686
+ allCorrect = false;
24687
+ }
24688
+ });
24689
+ if (!completed) {
24690
+ return {
24691
+ type: "invalid",
24692
+ message: strings.invalidSelection
24693
+ };
24694
+ }
24695
+ return {
24696
+ type: "points",
24697
+ earned: allCorrect ? 1 : 0,
24698
+ total: 1,
24699
+ message: null
24700
+ };
24701
+ }
24702
+ static getUserInputFromProps(props) {
24703
+ return WidgetJsonifyDeprecated.getUserInputFromProps(props);
24704
+ }
24680
24705
  change = (() => {
24681
24706
  var _this = this;
24682
24707
  return function () {
@@ -24690,6 +24715,16 @@ class Categorizer extends React__namespace.Component {
24690
24715
  getUserInput = () => {
24691
24716
  return Categorizer.getUserInputFromProps(this.props);
24692
24717
  };
24718
+ onChange(itemNum, catNum) {
24719
+ const values = [...this.props.values];
24720
+ // @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'never'.
24721
+ values[itemNum] = catNum;
24722
+ this.change("values", values);
24723
+ this.props.trackInteraction();
24724
+ }
24725
+ simpleValidate = rubric => {
24726
+ return Categorizer.validate(this.getUserInput(), rubric, this.context.strings);
24727
+ };
24693
24728
  render() {
24694
24729
  const self = this;
24695
24730
 
@@ -24766,43 +24801,6 @@ class Categorizer extends React__namespace.Component {
24766
24801
  className: extraClassNames + " " + aphrodite.css(...inlineStyles)
24767
24802
  }, table);
24768
24803
  }
24769
- onChange(itemNum, catNum) {
24770
- const values = [...this.props.values];
24771
- // @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'never'.
24772
- values[itemNum] = catNum;
24773
- this.change("values", values);
24774
- this.props.trackInteraction();
24775
- }
24776
- simpleValidate = rubric => {
24777
- return Categorizer.validate(this.getUserInput(), rubric, this.context.strings);
24778
- };
24779
- static validate(userInput, rubric, strings) {
24780
- let completed = true;
24781
- let allCorrect = true;
24782
- rubric.values.forEach((value, i) => {
24783
- if (userInput.values[i] == null) {
24784
- completed = false;
24785
- }
24786
- if (userInput.values[i] !== value) {
24787
- allCorrect = false;
24788
- }
24789
- });
24790
- if (!completed) {
24791
- return {
24792
- type: "invalid",
24793
- message: strings.invalidSelection
24794
- };
24795
- }
24796
- return {
24797
- type: "points",
24798
- earned: allCorrect ? 1 : 0,
24799
- total: 1,
24800
- message: null
24801
- };
24802
- }
24803
- static getUserInputFromProps(props) {
24804
- return WidgetJsonifyDeprecated.getUserInputFromProps(props);
24805
- }
24806
24804
  }
24807
24805
 
24808
24806
  // TODO(benkomalo): inject page-margin into Perseus instead of hardcoding.
@@ -25310,8 +25308,6 @@ var Dropdown$1 = {
25310
25308
  transform: optionsTransform
25311
25309
  };
25312
25310
 
25313
- /* eslint-disable react/sort-comp */
25314
-
25315
25311
  // transform = _.identity
25316
25312
 
25317
25313
  function mediaQueryIsMatched(mediaQuery) {
@@ -25322,6 +25318,10 @@ function mediaQueryIsMatched(mediaQuery) {
25322
25318
  }
25323
25319
  class Explanation extends React__namespace.Component {
25324
25320
  static contextType = PerseusI18nContext;
25321
+ state = {
25322
+ expanded: false
25323
+ };
25324
+ _mounted = false;
25325
25325
  static defaultProps = {
25326
25326
  showPrompt: "Explain",
25327
25327
  hidePrompt: "Hide explanation",
@@ -25337,10 +25337,6 @@ class Explanation extends React__namespace.Component {
25337
25337
  message: null
25338
25338
  };
25339
25339
  }
25340
- state = {
25341
- expanded: false
25342
- };
25343
- _mounted = false;
25344
25340
  componentDidMount() {
25345
25341
  this._mounted = true;
25346
25342
  }
@@ -25362,6 +25358,12 @@ class Explanation extends React__namespace.Component {
25362
25358
  });
25363
25359
  this.props.trackInteraction();
25364
25360
  };
25361
+ getUserInput = () => {
25362
+ return {};
25363
+ };
25364
+ simpleValidate = rubric => {
25365
+ return Explanation.validate(this.getUserInput(), rubric);
25366
+ };
25365
25367
  render() {
25366
25368
  const promptText = this.state.expanded ? this.props.hidePrompt : this.props.showPrompt;
25367
25369
  const caretIcon = this.state.expanded ? caretUp__default["default"] : caretDown__default["default"];
@@ -25417,12 +25419,6 @@ class Explanation extends React__namespace.Component {
25417
25419
  strings: this.context.strings
25418
25420
  })))));
25419
25421
  }
25420
- getUserInput = () => {
25421
- return {};
25422
- };
25423
- simpleValidate = rubric => {
25424
- return Explanation.validate(this.getUserInput(), rubric);
25425
- };
25426
25422
  }
25427
25423
  const leftBorderSpacing = 23;
25428
25424
  const verticalContentPadding = 10;
@@ -26846,6 +26842,70 @@ class FunctionGrapher extends React__namespace.Component {
26846
26842
  return change.apply(_this, args);
26847
26843
  };
26848
26844
  })();
26845
+ renderPlot = () => {
26846
+ const model = this.props.model;
26847
+ const xRange = this.props.graph.range[0];
26848
+ const style = {
26849
+ stroke: this.props.isMobile ? KhanColors.BLUE_C : KhanColors.DYNAMIC,
26850
+ ...(this.props.isMobile ? {
26851
+ "stroke-width": 3
26852
+ } : {})
26853
+ };
26854
+ const coeffs = model.getCoefficients(this._coords(), this._asymptote());
26855
+ if (!coeffs) {
26856
+ return;
26857
+ }
26858
+ const functionProps = model.getPropsForCoeffs(coeffs, xRange);
26859
+ return /*#__PURE__*/React__namespace.createElement(model.Movable, _extends({}, functionProps, {
26860
+ key: this.props.model.url,
26861
+ range: xRange,
26862
+ style: style
26863
+ }));
26864
+ };
26865
+ renderAsymptote = () => {
26866
+ const model = this.props.model;
26867
+ const graph = this.props.graph;
26868
+ const asymptote = this._asymptote();
26869
+ const dashed = {
26870
+ strokeDasharray: "- "
26871
+ };
26872
+ return asymptote && /*#__PURE__*/React__namespace.createElement(MovableLine$2, {
26873
+ onMove: (newCoord, oldCoord) => {
26874
+ // Calculate and apply displacement
26875
+ const delta = kmath.vector.subtract(newCoord, oldCoord);
26876
+ const newAsymptote = ___default["default"].map(this._asymptote(), coord => kmath.vector.add(coord, delta));
26877
+ this.props.onChange({
26878
+ asymptote: newAsymptote
26879
+ });
26880
+ },
26881
+ constraints: [
26882
+ // @ts-expect-error - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => void'.
26883
+ Interactive2.MovableLine.constraints.bound(),
26884
+ // @ts-expect-error - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => void'.
26885
+ Interactive2.MovableLine.constraints.snap(), (newCoord, oldCoord) => {
26886
+ // Calculate and apply proposed displacement
26887
+ const delta = kmath.vector.subtract(newCoord, oldCoord);
26888
+ const proposedAsymptote = ___default["default"].map(this._asymptote(), coord => kmath.vector.add(coord, delta));
26889
+ // Verify that resulting asymptote is valid for graph
26890
+ if (model.extraAsymptoteConstraint) {
26891
+ return model.extraAsymptoteConstraint(newCoord, oldCoord, this._coords(), proposedAsymptote, graph);
26892
+ }
26893
+ return true;
26894
+ }],
26895
+ normalStyle: dashed,
26896
+ highlightStyle: dashed
26897
+ }, ___default["default"].map(asymptote, (coord, i) => /*#__PURE__*/React__namespace.createElement(MovablePoint$3, {
26898
+ key: `asymptoteCoord-${i}`,
26899
+ coord: coord,
26900
+ static: true,
26901
+ draw: null,
26902
+ extendLine: true,
26903
+ showHairlines: this.props.showHairlines,
26904
+ hideHairlines: this.props.hideHairlines,
26905
+ showTooltips: this.props.showTooltips,
26906
+ isMobile: this.props.isMobile
26907
+ })));
26908
+ };
26849
26909
  render() {
26850
26910
  const pointForCoord = (coord, i) => {
26851
26911
  return /*#__PURE__*/React__namespace.createElement(MovablePoint$3, {
@@ -26933,70 +26993,6 @@ class FunctionGrapher extends React__namespace.Component {
26933
26993
  setDrawingAreaAvailable: this.props.setDrawingAreaAvailable
26934
26994
  }), this.props.model && this.renderPlot(), this.props.model && this.renderAsymptote(), this.props.model && points)));
26935
26995
  }
26936
- renderPlot = () => {
26937
- const model = this.props.model;
26938
- const xRange = this.props.graph.range[0];
26939
- const style = {
26940
- stroke: this.props.isMobile ? KhanColors.BLUE_C : KhanColors.DYNAMIC,
26941
- ...(this.props.isMobile ? {
26942
- "stroke-width": 3
26943
- } : {})
26944
- };
26945
- const coeffs = model.getCoefficients(this._coords(), this._asymptote());
26946
- if (!coeffs) {
26947
- return;
26948
- }
26949
- const functionProps = model.getPropsForCoeffs(coeffs, xRange);
26950
- return /*#__PURE__*/React__namespace.createElement(model.Movable, _extends({}, functionProps, {
26951
- key: this.props.model.url,
26952
- range: xRange,
26953
- style: style
26954
- }));
26955
- };
26956
- renderAsymptote = () => {
26957
- const model = this.props.model;
26958
- const graph = this.props.graph;
26959
- const asymptote = this._asymptote();
26960
- const dashed = {
26961
- strokeDasharray: "- "
26962
- };
26963
- return asymptote && /*#__PURE__*/React__namespace.createElement(MovableLine$2, {
26964
- onMove: (newCoord, oldCoord) => {
26965
- // Calculate and apply displacement
26966
- const delta = kmath.vector.subtract(newCoord, oldCoord);
26967
- const newAsymptote = ___default["default"].map(this._asymptote(), coord => kmath.vector.add(coord, delta));
26968
- this.props.onChange({
26969
- asymptote: newAsymptote
26970
- });
26971
- },
26972
- constraints: [
26973
- // @ts-expect-error - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => void'.
26974
- Interactive2.MovableLine.constraints.bound(),
26975
- // @ts-expect-error - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => void'.
26976
- Interactive2.MovableLine.constraints.snap(), (newCoord, oldCoord) => {
26977
- // Calculate and apply proposed displacement
26978
- const delta = kmath.vector.subtract(newCoord, oldCoord);
26979
- const proposedAsymptote = ___default["default"].map(this._asymptote(), coord => kmath.vector.add(coord, delta));
26980
- // Verify that resulting asymptote is valid for graph
26981
- if (model.extraAsymptoteConstraint) {
26982
- return model.extraAsymptoteConstraint(newCoord, oldCoord, this._coords(), proposedAsymptote, graph);
26983
- }
26984
- return true;
26985
- }],
26986
- normalStyle: dashed,
26987
- highlightStyle: dashed
26988
- }, ___default["default"].map(asymptote, (coord, i) => /*#__PURE__*/React__namespace.createElement(MovablePoint$3, {
26989
- key: `asymptoteCoord-${i}`,
26990
- coord: coord,
26991
- static: true,
26992
- draw: null,
26993
- extendLine: true,
26994
- showHairlines: this.props.showHairlines,
26995
- hideHairlines: this.props.hideHairlines,
26996
- showTooltips: this.props.showTooltips,
26997
- isMobile: this.props.isMobile
26998
- })));
26999
- };
27000
26996
  }
27001
26997
 
27002
26998
  // Really this is props.plot, I think
@@ -27006,6 +27002,118 @@ class Grapher extends React__namespace.Component {
27006
27002
  horizHairline;
27007
27003
  vertHairline;
27008
27004
  static defaultProps = DEFAULT_GRAPHER_PROPS;
27005
+ static validate(state, rubric) {
27006
+ return validate$1(state, rubric);
27007
+ }
27008
+ static getUserInputFromProps(props) {
27009
+ return props.plot;
27010
+ }
27011
+ handlePlotChanges = newPlot => {
27012
+ const plot = ___default["default"].extend({}, this.props.plot, newPlot);
27013
+ this.props.onChange({
27014
+ plot: plot
27015
+ });
27016
+ this.props.trackInteraction();
27017
+ };
27018
+ handleActiveTypeChange = newType => {
27019
+ const graph = this.props.graph;
27020
+ const plot = ___default["default"].extend({}, this.props.plot, defaultPlotProps(newType, graph));
27021
+ this.props.onChange({
27022
+ plot: plot
27023
+ });
27024
+ };
27025
+ _getGridConfig(options) {
27026
+ return options.step.map((step, i) => {
27027
+ return Util.gridDimensionConfig(step, options.range[i], options.box[i], options.gridStep[i]);
27028
+ });
27029
+ }
27030
+ _calculateMobileTickStep(gridStep, step, ranges) {
27031
+ const tickStep = Util.constrainedTickStepsFromTickSteps(step, ranges);
27032
+
27033
+ // According to the graphInit documentation in graphie.js, tickStep is
27034
+ // relative to the grid units so we need to adjust all values by the
27035
+ // grid step.
27036
+ tickStep[0] = tickStep[0] / gridStep[0];
27037
+ tickStep[1] = tickStep[1] / gridStep[1];
27038
+ return tickStep;
27039
+ }
27040
+ _setupGraphie = (graphie, options) => {
27041
+ const isMobile = this.props.apiOptions.isMobile;
27042
+ if (options.markings === "graph") {
27043
+ graphie.graphInit({
27044
+ range: options.range,
27045
+ scale: ___default["default"].pluck(options.gridConfig, "scale"),
27046
+ axisArrows: "<->",
27047
+ labelFormat: function (s) {
27048
+ return "\\small{" + s + "}";
27049
+ },
27050
+ gridStep: options.gridStep,
27051
+ snapStep: options.snapStep,
27052
+ tickStep: isMobile ? this._calculateMobileTickStep(options.gridStep, options.step, options.range) : ___default["default"].pluck(options.gridConfig, "tickStep"),
27053
+ labelStep: 1,
27054
+ unityLabels: ___default["default"].pluck(options.gridConfig, "unityLabel"),
27055
+ isMobile: isMobile
27056
+ });
27057
+ graphie.label([0, options.range[1][1]], options.labels[1], isMobile ? "below right" : "above");
27058
+ graphie.label([options.range[0][1], 0], options.labels[0], isMobile ? "above left" : "right");
27059
+ } else if (options.markings === "grid") {
27060
+ graphie.graphInit({
27061
+ range: options.range,
27062
+ scale: ___default["default"].pluck(options.gridConfig, "scale"),
27063
+ gridStep: options.gridStep,
27064
+ axes: false,
27065
+ ticks: false,
27066
+ labels: false,
27067
+ isMobile: isMobile
27068
+ });
27069
+ } else if (options.markings === "none") {
27070
+ graphie.init({
27071
+ range: options.range,
27072
+ scale: ___default["default"].pluck(options.gridConfig, "scale")
27073
+ });
27074
+ }
27075
+ if (this.props.apiOptions.isMobile) {
27076
+ const hairlineStyle = {
27077
+ normalStyle: {
27078
+ strokeWidth: 1
27079
+ }
27080
+ };
27081
+ this.horizHairline = new WrappedLine(graphie, [0, 0], [0, 0], hairlineStyle);
27082
+ this.horizHairline.attr({
27083
+ stroke: KhanColors.INTERACTIVE
27084
+ });
27085
+ this.horizHairline.hide();
27086
+ this.vertHairline = new WrappedLine(graphie, [0, 0], [0, 0], hairlineStyle);
27087
+ this.vertHairline.attr({
27088
+ stroke: KhanColors.INTERACTIVE
27089
+ });
27090
+ this.vertHairline.hide();
27091
+ }
27092
+ };
27093
+ showHairlines = point => {
27094
+ if (this.props.apiOptions.isMobile && this.props.markings !== "none") {
27095
+ // Hairlines are already initialized when the graph is loaded, so
27096
+ // here we just move them to the updated location and make them
27097
+ // visible.
27098
+ this.horizHairline.moveTo([this.props.graph.range[0][0], point[1]], [this.props.graph.range[0][1], point[1]]);
27099
+ this.horizHairline.show();
27100
+ this.vertHairline.moveTo([point[0], this.props.graph.range[1][0]], [point[0], this.props.graph.range[1][1]]);
27101
+ this.vertHairline.show();
27102
+ }
27103
+ };
27104
+ hideHairlines = () => {
27105
+ if (this.props.apiOptions.isMobile) {
27106
+ this.horizHairline.hide();
27107
+ this.vertHairline.hide();
27108
+ }
27109
+ };
27110
+ simpleValidate(rubric) {
27111
+ return validate$1(this.getUserInput(), rubric);
27112
+ }
27113
+ getUserInput() {
27114
+ return Grapher.getUserInputFromProps(this.props);
27115
+ }
27116
+ focus() {}
27009
27117
  render() {
27010
27118
  const type = this.props.plot.type;
27011
27119
  const coords = this.props.plot.coords;
@@ -27060,118 +27168,6 @@ class Grapher extends React__namespace.Component {
27060
27168
  };
27061
27169
  return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(FunctionGrapher, grapherProps), this.props.availableTypes.length > 1 && typeSelector);
27062
27170
  }
27063
- handlePlotChanges = newPlot => {
27064
- const plot = ___default["default"].extend({}, this.props.plot, newPlot);
27065
- this.props.onChange({
27066
- plot: plot
27067
- });
27068
- this.props.trackInteraction();
27069
- };
27070
- handleActiveTypeChange = newType => {
27071
- const graph = this.props.graph;
27072
- const plot = ___default["default"].extend({}, this.props.plot, defaultPlotProps(newType, graph));
27073
- this.props.onChange({
27074
- plot: plot
27075
- });
27076
- };
27077
- _getGridConfig(options) {
27078
- return options.step.map((step, i) => {
27079
- return Util.gridDimensionConfig(step, options.range[i], options.box[i], options.gridStep[i]);
27080
- });
27081
- }
27082
- _calculateMobileTickStep(gridStep, step, ranges) {
27083
- const tickStep = Util.constrainedTickStepsFromTickSteps(step, ranges);
27084
-
27085
- // According to the graphInit documentation in graphie.js, tickStep is
27086
- // relative to the grid units so we need to adjust all values by the
27087
- // grid step.
27088
- tickStep[0] = tickStep[0] / gridStep[0];
27089
- tickStep[1] = tickStep[1] / gridStep[1];
27090
- return tickStep;
27091
- }
27092
- _setupGraphie = (graphie, options) => {
27093
- const isMobile = this.props.apiOptions.isMobile;
27094
- if (options.markings === "graph") {
27095
- graphie.graphInit({
27096
- range: options.range,
27097
- scale: ___default["default"].pluck(options.gridConfig, "scale"),
27098
- axisArrows: "<->",
27099
- labelFormat: function (s) {
27100
- return "\\small{" + s + "}";
27101
- },
27102
- gridStep: options.gridStep,
27103
- snapStep: options.snapStep,
27104
- tickStep: isMobile ? this._calculateMobileTickStep(options.gridStep, options.step, options.range) : ___default["default"].pluck(options.gridConfig, "tickStep"),
27105
- labelStep: 1,
27106
- unityLabels: ___default["default"].pluck(options.gridConfig, "unityLabel"),
27107
- isMobile: isMobile
27108
- });
27109
- graphie.label([0, options.range[1][1]], options.labels[1], isMobile ? "below right" : "above");
27110
- graphie.label([options.range[0][1], 0], options.labels[0], isMobile ? "above left" : "right");
27111
- } else if (options.markings === "grid") {
27112
- graphie.graphInit({
27113
- range: options.range,
27114
- scale: ___default["default"].pluck(options.gridConfig, "scale"),
27115
- gridStep: options.gridStep,
27116
- axes: false,
27117
- ticks: false,
27118
- labels: false,
27119
- isMobile: isMobile
27120
- });
27121
- } else if (options.markings === "none") {
27122
- graphie.init({
27123
- range: options.range,
27124
- scale: ___default["default"].pluck(options.gridConfig, "scale")
27125
- });
27126
- }
27127
- if (this.props.apiOptions.isMobile) {
27128
- const hairlineStyle = {
27129
- normalStyle: {
27130
- strokeWidth: 1
27131
- }
27132
- };
27133
- this.horizHairline = new WrappedLine(graphie, [0, 0], [0, 0], hairlineStyle);
27134
- this.horizHairline.attr({
27135
- stroke: KhanColors.INTERACTIVE
27136
- });
27137
- this.horizHairline.hide();
27138
- this.vertHairline = new WrappedLine(graphie, [0, 0], [0, 0], hairlineStyle);
27139
- this.vertHairline.attr({
27140
- stroke: KhanColors.INTERACTIVE
27141
- });
27142
- this.vertHairline.hide();
27143
- }
27144
- };
27145
- showHairlines = point => {
27146
- if (this.props.apiOptions.isMobile && this.props.markings !== "none") {
27147
- // Hairlines are already initialized when the graph is loaded, so
27148
- // here we just move them to the updated location and make them
27149
- // visible.
27150
- this.horizHairline.moveTo([this.props.graph.range[0][0], point[1]], [this.props.graph.range[0][1], point[1]]);
27151
- this.horizHairline.show();
27152
- this.vertHairline.moveTo([point[0], this.props.graph.range[1][0]], [point[0], this.props.graph.range[1][1]]);
27153
- this.vertHairline.show();
27154
- }
27155
- };
27156
- hideHairlines = () => {
27157
- if (this.props.apiOptions.isMobile) {
27158
- this.horizHairline.hide();
27159
- this.vertHairline.hide();
27160
- }
27161
- };
27162
- simpleValidate(rubric) {
27163
- return validate$1(this.getUserInput(), rubric);
27164
- }
27165
- getUserInput() {
27166
- return Grapher.getUserInputFromProps(this.props);
27167
- }
27168
- focus() {}
27169
- static validate(state, rubric) {
27170
- return validate$1(state, rubric);
27171
- }
27172
- static getUserInputFromProps(props) {
27173
- return props.plot;
27174
- }
27175
27171
  }
27176
27172
  const propTransform$2 = editorProps => {
27177
27173
  const widgetProps = {
@@ -27354,7 +27350,7 @@ var Group$1 = {
27354
27350
  isLintable: true
27355
27351
  };
27356
27352
 
27357
- /* eslint-disable react/forbid-prop-types, react/sort-comp */
27353
+ /* eslint-disable react/forbid-prop-types */
27358
27354
  const {
27359
27355
  updateQueryString
27360
27356
  } = Util;
@@ -27379,6 +27375,12 @@ class Iframe extends React__namespace.Component {
27379
27375
  allowFullScreen: false,
27380
27376
  allowTopNavigation: false
27381
27377
  };
27378
+ componentDidMount() {
27379
+ $__default["default"](window).on("message", this.handleMessageEvent);
27380
+ }
27381
+ componentWillUnmount() {
27382
+ $__default["default"](window).off("message", this.handleMessageEvent);
27383
+ }
27382
27384
  getUserInput = () => {
27383
27385
  return WidgetJsonifyDeprecated.getUserInput.call(this);
27384
27386
  };
@@ -27401,12 +27403,20 @@ class Iframe extends React__namespace.Component {
27401
27403
  message: data.message
27402
27404
  });
27403
27405
  };
27404
- componentDidMount() {
27405
- $__default["default"](window).on("message", this.handleMessageEvent);
27406
- }
27407
- componentWillUnmount() {
27408
- $__default["default"](window).off("message", this.handleMessageEvent);
27409
- }
27406
+ change = (() => {
27407
+ var _this = this;
27408
+ return function () {
27409
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
27410
+ args[_key] = arguments[_key];
27411
+ }
27412
+ // @ts-expect-error - TS2345 - Argument of type 'readonly unknown[]' is not assignable to parameter of type 'any[]'.
27413
+ return change.apply(_this, args);
27414
+ };
27415
+ })();
27416
+ simpleValidate = rubric => {
27417
+ // @ts-expect-error - TS2339 - Property 'validate' does not exist on type 'typeof Iframe'.
27418
+ return Iframe.validate(this.getUserInput(), rubric);
27419
+ };
27410
27420
  render() {
27411
27421
  const style = {
27412
27422
  width: String(this.props.width),
@@ -27468,20 +27478,6 @@ class Iframe extends React__namespace.Component {
27468
27478
  allowFullScreen: this.props.allowFullScreen
27469
27479
  });
27470
27480
  }
27471
- change = (() => {
27472
- var _this = this;
27473
- return function () {
27474
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
27475
- args[_key] = arguments[_key];
27476
- }
27477
- // @ts-expect-error - TS2345 - Argument of type 'readonly unknown[]' is not assignable to parameter of type 'any[]'.
27478
- return change.apply(_this, args);
27479
- };
27480
- })();
27481
- simpleValidate = rubric => {
27482
- // @ts-expect-error - TS2339 - Property 'validate' does not exist on type 'typeof Iframe'.
27483
- return Iframe.validate(this.getUserInput(), rubric);
27484
- };
27485
27481
  }
27486
27482
 
27487
27483
  /**
@@ -27521,7 +27517,6 @@ var Iframe$1 = {
27521
27517
  hidden: true
27522
27518
  };
27523
27519
 
27524
- /* eslint-disable react/sort-comp */
27525
27520
  const defaultBoxSize = 400;
27526
27521
  const defaultRange = [0, 10];
27527
27522
  const defaultBackgroundImage$2 = {
@@ -27547,6 +27542,14 @@ class ImageWidget extends React__namespace.Component {
27547
27542
  caption: "",
27548
27543
  linterContext: PerseusLinter.linterContextDefault
27549
27544
  };
27545
+ static validate(userInput, rubric) {
27546
+ return {
27547
+ type: "points",
27548
+ earned: 0,
27549
+ total: 0,
27550
+ message: null
27551
+ };
27552
+ }
27550
27553
  change = (() => {
27551
27554
  var _this = this;
27552
27555
  return function () {
@@ -27696,14 +27699,6 @@ class ImageWidget extends React__namespace.Component {
27696
27699
  }
27697
27700
  }, title, image, caption);
27698
27701
  }
27699
- static validate(userInput, rubric) {
27700
- return {
27701
- type: "points",
27702
- earned: 0,
27703
- total: 0,
27704
- message: null
27705
- };
27706
- }
27707
27702
  }
27708
27703
  var Image$1 = {
27709
27704
  name: "image",
@@ -27795,6 +27790,14 @@ class Interaction extends React__namespace.Component {
27795
27790
  },
27796
27791
  elements: []
27797
27792
  };
27793
+ static validate(state, rubric) {
27794
+ return {
27795
+ type: "points",
27796
+ earned: 0,
27797
+ total: 0,
27798
+ message: null
27799
+ };
27800
+ }
27798
27801
  state = {
27799
27802
  variables: _getInitialVariables(this.props.elements),
27800
27803
  functions: _getInitialFunctions(this.props.elements)
@@ -27902,6 +27905,16 @@ class Interaction extends React__namespace.Component {
27902
27905
  return change.apply(_this, args);
27903
27906
  };
27904
27907
  })();
27908
+ getUserInput = () => {
27909
+ // TODO(eater): Perhaps we want to be able to record the state of the
27910
+ // user's interaction. Unfortunately sending all the props will
27911
+ // probably make the attempt payload too large. So for now, don't send
27912
+ // anything.
27913
+ return {};
27914
+ };
27915
+ simpleValidate = rubric => {
27916
+ return Interaction.validate(this.getUserInput(), rubric);
27917
+ };
27905
27918
  render() {
27906
27919
  const range = this.props.graph.range;
27907
27920
  let labels = this.props.graph.labels;
@@ -28229,24 +28242,6 @@ class Interaction extends React__namespace.Component {
28229
28242
  }
28230
28243
  }, this));
28231
28244
  }
28232
- getUserInput = () => {
28233
- // TODO(eater): Perhaps we want to be able to record the state of the
28234
- // user's interaction. Unfortunately sending all the props will
28235
- // probably make the attempt payload too large. So for now, don't send
28236
- // anything.
28237
- return {};
28238
- };
28239
- simpleValidate = rubric => {
28240
- return Interaction.validate(this.getUserInput(), rubric);
28241
- };
28242
- static validate(state, rubric) {
28243
- return {
28244
- type: "points",
28245
- earned: 0,
28246
- total: 0,
28247
- message: null
28248
- };
28249
- }
28250
28245
  }
28251
28246
  const _getInitialVariables = elements => {
28252
28247
  const variables = {};
@@ -29755,44 +29750,6 @@ class NumberInput extends React__namespace.Component {
29755
29750
  state = {
29756
29751
  format: this.props.format
29757
29752
  };
29758
- render() {
29759
- let classes = classNames__default["default"]({
29760
- "number-input": true,
29761
- "invalid-input": !this._checkValidity(this.props.value),
29762
- mini: this.props.size === "mini",
29763
- small: this.props.size === "small",
29764
- normal: this.props.size === "normal"
29765
- });
29766
- if (this.props.className != null) {
29767
- classes = classes + " " + this.props.className;
29768
- }
29769
- const {
29770
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
29771
- onFormatChange,
29772
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
29773
- checkValidity,
29774
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
29775
- useArrowKeys,
29776
- ...restProps
29777
- } = this.props;
29778
- return /*#__PURE__*/React__namespace.createElement("input", _extends({}, restProps, {
29779
- className: classes,
29780
- type: "text"
29781
- // eslint-disable-next-line react/no-string-refs
29782
- ,
29783
- ref: "input",
29784
- onChange: this._handleChange,
29785
- onFocus: this._handleFocus,
29786
- onBlur: this._handleBlur,
29787
- onKeyPress: this._handleBlur,
29788
- onKeyDown: this._onKeyDown
29789
- // @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLInputElement>'.
29790
- ,
29791
- onTouchStart: captureScratchpadTouchStart,
29792
- defaultValue: toNumericString(this.props.value, this.state.format),
29793
- value: undefined
29794
- }));
29795
- }
29796
29753
  componentDidUpdate(prevProps) {
29797
29754
  if (!kmath.number.equal(this.getValue(), this.props.value)) {
29798
29755
  this._setValue(this.props.value, this.state.format);
@@ -29909,6 +29866,44 @@ class NumberInput extends React__namespace.Component {
29909
29866
  // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'val' does not exist on type 'JQueryStatic'.
29910
29867
  $__default["default"](ReactDOM__default["default"].findDOMNode(this.refs.input)).val(toNumericString(val, format));
29911
29868
  };
29869
+ render() {
29870
+ let classes = classNames__default["default"]({
29871
+ "number-input": true,
29872
+ "invalid-input": !this._checkValidity(this.props.value),
29873
+ mini: this.props.size === "mini",
29874
+ small: this.props.size === "small",
29875
+ normal: this.props.size === "normal"
29876
+ });
29877
+ if (this.props.className != null) {
29878
+ classes = classes + " " + this.props.className;
29879
+ }
29880
+ const {
29881
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
29882
+ onFormatChange,
29883
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
29884
+ checkValidity,
29885
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
29886
+ useArrowKeys,
29887
+ ...restProps
29888
+ } = this.props;
29889
+ return /*#__PURE__*/React__namespace.createElement("input", _extends({}, restProps, {
29890
+ className: classes,
29891
+ type: "text"
29892
+ // eslint-disable-next-line react/no-string-refs
29893
+ ,
29894
+ ref: "input",
29895
+ onChange: this._handleChange,
29896
+ onFocus: this._handleFocus,
29897
+ onBlur: this._handleBlur,
29898
+ onKeyPress: this._handleBlur,
29899
+ onKeyDown: this._onKeyDown
29900
+ // @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLInputElement>'.
29901
+ ,
29902
+ onTouchStart: captureScratchpadTouchStart,
29903
+ defaultValue: toNumericString(this.props.value, this.state.format),
29904
+ value: undefined
29905
+ }));
29906
+ }
29912
29907
  }
29913
29908
 
29914
29909
  const truth = () => true;
@@ -29926,6 +29921,14 @@ class RangeInput extends React__namespace.Component {
29926
29921
  static defaultProps = {
29927
29922
  placeholder: [null, null]
29928
29923
  };
29924
+ onChange = (i, newVal) => {
29925
+ const value = this.props.value;
29926
+ if (i === 0) {
29927
+ this.props.onChange([newVal, value[1]]);
29928
+ } else {
29929
+ this.props.onChange([value[0], newVal]);
29930
+ }
29931
+ };
29929
29932
  render() {
29930
29933
  const value = this.props.value;
29931
29934
  const checkValidity = this.props.checkValidity || truth;
@@ -29947,14 +29950,6 @@ class RangeInput extends React__namespace.Component {
29947
29950
  placeholder: this.props.placeholder[1]
29948
29951
  })));
29949
29952
  }
29950
- onChange = (i, newVal) => {
29951
- const value = this.props.value;
29952
- if (i === 0) {
29953
- this.props.onChange([newVal, value[1]]);
29954
- } else {
29955
- this.props.onChange([value[0], newVal]);
29956
- }
29957
- };
29958
29953
  }
29959
29954
 
29960
29955
  var components = /*#__PURE__*/Object.freeze({
@@ -30118,12 +30113,6 @@ const ItemExtras = [
30118
30113
 
30119
30114
  // prettier-ignore
30120
30115
 
30121
- // prettier-ignore
30122
-
30123
- // prettier-ignore
30124
-
30125
- // prettier-ignore
30126
-
30127
30116
  //prettier-ignore
30128
30117
 
30129
30118
  // A background image applied to various widgets.
@@ -30524,6 +30513,9 @@ const GraphLockedLayer = props => {
30524
30513
  };
30525
30514
 
30526
30515
  const actions = {
30516
+ global: {
30517
+ deleteIntent
30518
+ },
30527
30519
  angle: {
30528
30520
  movePoint
30529
30521
  },
@@ -30541,7 +30533,10 @@ const actions = {
30541
30533
  },
30542
30534
  pointGraph: {
30543
30535
  movePoint,
30544
- addPoint
30536
+ addPoint,
30537
+ removePoint,
30538
+ focusPoint,
30539
+ blurPoint
30545
30540
  },
30546
30541
  polygon: {
30547
30542
  movePoint,
@@ -30562,6 +30557,12 @@ const actions = {
30562
30557
  movePoint
30563
30558
  }
30564
30559
  };
30560
+ const DELETE_INTENT = "delete-intent";
30561
+ function deleteIntent() {
30562
+ return {
30563
+ type: DELETE_INTENT
30564
+ };
30565
+ }
30565
30566
  const MOVE_LINE = "move-line";
30566
30567
  function moveLine(itemIndex, delta) {
30567
30568
  return {
@@ -30577,6 +30578,26 @@ function addPoint(location) {
30577
30578
  location
30578
30579
  };
30579
30580
  }
30581
+ const REMOVE_POINT = "remove-point";
30582
+ function removePoint(index) {
30583
+ return {
30584
+ type: REMOVE_POINT,
30585
+ index
30586
+ };
30587
+ }
30588
+ const FOCUS_POINT = "focus-point";
30589
+ function focusPoint(index) {
30590
+ return {
30591
+ type: FOCUS_POINT,
30592
+ index
30593
+ };
30594
+ }
30595
+ const BLUR_POINT = "blur-point";
30596
+ function blurPoint() {
30597
+ return {
30598
+ type: BLUR_POINT
30599
+ };
30600
+ }
30580
30601
  const MOVE_ALL = "move-all";
30581
30602
  function moveAll(delta) {
30582
30603
  return {
@@ -30865,7 +30886,8 @@ const MovablePointView = /*#__PURE__*/React.forwardRef((props, hitboxRef) => {
30865
30886
  color = wonderBlocksTokens.color.blue,
30866
30887
  dragging,
30867
30888
  focusBehavior,
30868
- cursor
30889
+ cursor,
30890
+ onClick = () => {}
30869
30891
  } = props;
30870
30892
 
30871
30893
  // WB Tooltip requires a color name for the background color.
@@ -30903,7 +30925,12 @@ const MovablePointView = /*#__PURE__*/React.forwardRef((props, hitboxRef) => {
30903
30925
  cursor
30904
30926
  },
30905
30927
  "data-testid": "movable-point",
30906
- tabIndex: disableKeyboardInteraction ? -1 : tabIndex(focusBehavior)
30928
+ tabIndex: disableKeyboardInteraction ? -1 : tabIndex(focusBehavior),
30929
+ onFocus: () => {
30930
+ return getOnFocusChangeCallback(focusBehavior)(true);
30931
+ },
30932
+ onBlur: () => getOnFocusChangeCallback(focusBehavior)(false),
30933
+ onClick: onClick
30907
30934
  }, /*#__PURE__*/React__namespace.createElement("circle", {
30908
30935
  className: "movable-point-hitbox",
30909
30936
  r: hitboxSizePx / 2,
@@ -30951,6 +30978,12 @@ function tabIndex(config) {
30951
30978
  }
30952
30979
  return undefined;
30953
30980
  }
30981
+ function getOnFocusChangeCallback(config) {
30982
+ if (config.type === "uncontrolled") {
30983
+ return config.onFocusChange;
30984
+ }
30985
+ return () => {};
30986
+ }
30954
30987
 
30955
30988
  const MovableLine = props => {
30956
30989
  const {
@@ -31548,7 +31581,8 @@ const MovablePoint$1 = props => {
31548
31581
  const elementRef = React.useRef(null);
31549
31582
  const {
31550
31583
  point,
31551
- onMove,
31584
+ onMove = () => {},
31585
+ onFocusChange = () => {},
31552
31586
  cursor,
31553
31587
  color = wonderBlocksTokens.color.blue,
31554
31588
  constrain = p => snap(snapStep, p)
@@ -31568,8 +31602,10 @@ const MovablePoint$1 = props => {
31568
31602
  dragging: dragging,
31569
31603
  focusBehavior: {
31570
31604
  type: "uncontrolled",
31571
- tabIndex: 0
31605
+ tabIndex: 0,
31606
+ onFocusChange
31572
31607
  },
31608
+ onClick: () => elementRef.current?.focus(),
31573
31609
  cursor: cursor
31574
31610
  });
31575
31611
  };
@@ -32175,7 +32211,14 @@ function UnlimitedPointGraph(props) {
32175
32211
  }), props.graphState.coords.map((point, i) => /*#__PURE__*/React__namespace.createElement(MovablePoint$1, {
32176
32212
  key: i,
32177
32213
  point: point,
32178
- onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination))
32214
+ onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination)),
32215
+ onFocusChange: isFocused => {
32216
+ if (isFocused) {
32217
+ dispatch(actions.pointGraph.focusPoint(i));
32218
+ } else {
32219
+ dispatch(actions.pointGraph.blurPoint());
32220
+ }
32221
+ }
32179
32222
  })));
32180
32223
  }
32181
32224
  function PointGraph(props) {
@@ -32331,6 +32374,7 @@ const MafsGraph = props => {
32331
32374
  } = props;
32332
32375
  const [width, height] = props.box;
32333
32376
  const tickStep = props.step;
32377
+ const graphRef = React__namespace.useRef(null);
32334
32378
  return /*#__PURE__*/React__namespace.createElement(GraphConfigContext.Provider, {
32335
32379
  value: {
32336
32380
  range: state.range,
@@ -32348,16 +32392,24 @@ const MafsGraph = props => {
32348
32392
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32349
32393
  className: "mafs-graph",
32350
32394
  style: {
32351
- height,
32352
- width: "intrinsic",
32353
32395
  position: "relative",
32354
32396
  padding: "25px 25px 0 0",
32355
32397
  boxSizing: "content-box",
32356
32398
  marginLeft: "20px",
32357
32399
  marginBottom: "20px",
32358
32400
  pointerEvents: props.static ? "none" : "auto",
32359
- userSelect: "none"
32360
- }
32401
+ userSelect: "none",
32402
+ width,
32403
+ height
32404
+ },
32405
+ onKeyUp: event => {
32406
+ if (event.key === "Backspace") {
32407
+ dispatch(actions.global.deleteIntent());
32408
+ graphRef.current?.focus();
32409
+ }
32410
+ },
32411
+ ref: graphRef,
32412
+ tabIndex: 0
32361
32413
  }, /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
32362
32414
  box: props.box,
32363
32415
  backgroundImage: props.backgroundImage
@@ -32543,7 +32595,8 @@ function initializeGraphState(params) {
32543
32595
  ...shared,
32544
32596
  type: graph.type,
32545
32597
  coords: getPointCoords(graph, range, step),
32546
- numPoints: graph.numPoints || 0
32598
+ numPoints: graph.numPoints || 0,
32599
+ focusedPointIndex: null
32547
32600
  };
32548
32601
  case "circle":
32549
32602
  return {
@@ -32801,10 +32854,51 @@ function interactiveGraphReducer(state, action) {
32801
32854
  return doChangeRange(state, action);
32802
32855
  case ADD_POINT:
32803
32856
  return doAddPoint(state, action);
32857
+ case REMOVE_POINT:
32858
+ return doRemovePoint(state, action);
32859
+ case FOCUS_POINT:
32860
+ return doFocusPoint(state, action);
32861
+ case BLUR_POINT:
32862
+ return doBlurPoint(state);
32863
+ case DELETE_INTENT:
32864
+ return doDeleteIntent(state);
32804
32865
  default:
32805
32866
  throw new wonderStuffCore.UnreachableCaseError(action);
32806
32867
  }
32807
32868
  }
32869
+ function doDeleteIntent(state, action) {
32870
+ // For unlimited point graphs
32871
+ if (state.type === "point" && state.numPoints === "unlimited") {
32872
+ // if there's a focused point
32873
+ if (state.focusedPointIndex !== null) {
32874
+ // Remove the focused focus
32875
+ return doRemovePoint(state, actions.pointGraph.removePoint(state.focusedPointIndex));
32876
+ }
32877
+ }
32878
+ return state;
32879
+ }
32880
+ function doFocusPoint(state, action) {
32881
+ switch (state.type) {
32882
+ case "point":
32883
+ return {
32884
+ ...state,
32885
+ focusedPointIndex: action.index
32886
+ };
32887
+ default:
32888
+ return state;
32889
+ }
32890
+ }
32891
+ function doBlurPoint(state, action) {
32892
+ switch (state.type) {
32893
+ case "point":
32894
+ return {
32895
+ ...state,
32896
+ focusedPointIndex: null
32897
+ };
32898
+ default:
32899
+ return state;
32900
+ }
32901
+ }
32808
32902
  function doMovePointInFigure(state, action) {
32809
32903
  switch (state.type) {
32810
32904
  case "segment":
@@ -33164,6 +33258,16 @@ function doAddPoint(state, action) {
33164
33258
  coords: [...state.coords, snappedPoint]
33165
33259
  };
33166
33260
  }
33261
+ function doRemovePoint(state, action) {
33262
+ if (state.type !== "point") {
33263
+ return state;
33264
+ }
33265
+ return {
33266
+ ...state,
33267
+ coords: state.coords.filter((_, i) => i !== action.index),
33268
+ focusedPointIndex: null
33269
+ };
33270
+ }
33167
33271
  const getDeltaVertex = (maxMoves, minMoves, delta) => {
33168
33272
  const [deltaX, deltaY] = delta;
33169
33273
  const maxXMove = Math.min(...maxMoves.map(move => move[X]));
@@ -37517,73 +37621,6 @@ class Draggable extends React__namespace.Component {
37517
37621
  passive: false
37518
37622
  } : false);
37519
37623
  }
37520
- componentWillUnmount() {
37521
- this._mounted = false;
37522
- // Event handlers should be unbound before component unmounting, but
37523
- // just in case...
37524
- if (this.isMouseMoveUpBound) {
37525
- this.unbindMouseMoveUp();
37526
- }
37527
- if (this.animationFrameRequest) {
37528
- // TODO(jeff, CP-3128): Use Wonder Blocks Timing API.
37529
- // eslint-disable-next-line no-restricted-syntax
37530
- cancelAnimationFrame(this.animationFrameRequest);
37531
- }
37532
- document.removeEventListener("touchmove", this.onMouseMove);
37533
- }
37534
- getCurrentPosition = () => {
37535
- return {
37536
- left: this.state.startPosition.left + this.state.mouse.left - this.state.startMouse.left,
37537
- top: this.state.startPosition.top + this.state.mouse.top - this.state.startMouse.top
37538
- };
37539
- };
37540
- render() {
37541
- const {
37542
- includePadding,
37543
- layout,
37544
- state: type
37545
- } = this.props;
37546
-
37547
- // We need to keep backwards compatbility with rules specified directly
37548
- // in CSS. Hence the hacky tacking on of manual classNames.
37549
- // See sortable.less for details.
37550
- let className = aphrodite.css(styles$d.card, styles$d.draggable, layout === Layout.HORIZONTAL && styles$d.horizontalCard, layout === Layout.VERTICAL && styles$d.verticalCard, type === ItemState.DRAGGING && styles$d.dragging, type === ItemState.DISABLED && styles$d.disabled, !includePadding && styles$d.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
37551
- if (!includePadding) {
37552
- className += " perseus-sortable-draggable-unpadded";
37553
- }
37554
- const style = {
37555
- position: "static"
37556
- };
37557
- if (this.props.state === ItemState.DRAGGING || this.props.state === ItemState.ANIMATING) {
37558
- ___default["default"].extend(style, {
37559
- position: "absolute"
37560
- }, this.getCurrentPosition());
37561
- }
37562
- if (this.props.width) {
37563
- style.width = this.props.width + 1; // Fix for non-integer widths
37564
- }
37565
-
37566
- if (this.props.height) {
37567
- style.height = this.props.height;
37568
- }
37569
- if (this.props.margin != null) {
37570
- style.margin = this.props.margin;
37571
- }
37572
- return /*#__PURE__*/React__namespace.createElement("li", {
37573
- className: className,
37574
- style: style,
37575
- onMouseDown: this.onMouseDown,
37576
- onTouchStart: this.onMouseDown,
37577
- onTouchMove: this.onMouseMove,
37578
- onTouchEnd: this.onMouseUp,
37579
- onTouchCancel: this.onMouseUp
37580
- }, /*#__PURE__*/React__namespace.createElement(Renderer, {
37581
- content: this.props.content,
37582
- linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "draggable"),
37583
- onRender: this.props.onRender,
37584
- strings: this.context.strings
37585
- }));
37586
- }
37587
37624
  componentDidUpdate(prevProps) {
37588
37625
  if (this.props.state === prevProps.state) {
37589
37626
  return;
@@ -37605,6 +37642,26 @@ class Draggable extends React__namespace.Component {
37605
37642
  $__default["default"](ReactDOM__default["default"].findDOMNode(this)).finish();
37606
37643
  }
37607
37644
  }
37645
+ componentWillUnmount() {
37646
+ this._mounted = false;
37647
+ // Event handlers should be unbound before component unmounting, but
37648
+ // just in case...
37649
+ if (this.isMouseMoveUpBound) {
37650
+ this.unbindMouseMoveUp();
37651
+ }
37652
+ if (this.animationFrameRequest) {
37653
+ // TODO(jeff, CP-3128): Use Wonder Blocks Timing API.
37654
+ // eslint-disable-next-line no-restricted-syntax
37655
+ cancelAnimationFrame(this.animationFrameRequest);
37656
+ }
37657
+ document.removeEventListener("touchmove", this.onMouseMove);
37658
+ }
37659
+ getCurrentPosition = () => {
37660
+ return {
37661
+ left: this.state.startPosition.left + this.state.mouse.left - this.state.startMouse.left,
37662
+ top: this.state.startPosition.top + this.state.mouse.top - this.state.startMouse.top
37663
+ };
37664
+ };
37608
37665
  bindMouseMoveUp = () => {
37609
37666
  this.isMouseMoveUpBound = true;
37610
37667
  $__default["default"](document).on("mousemove", this.onMouseMove);
@@ -37692,6 +37749,53 @@ class Draggable extends React__namespace.Component {
37692
37749
  this.props.onMouseUp();
37693
37750
  }
37694
37751
  };
37752
+ render() {
37753
+ const {
37754
+ includePadding,
37755
+ layout,
37756
+ state: type
37757
+ } = this.props;
37758
+
37759
+ // We need to keep backwards compatbility with rules specified directly
37760
+ // in CSS. Hence the hacky tacking on of manual classNames.
37761
+ // See sortable.less for details.
37762
+ let className = aphrodite.css(styles$d.card, styles$d.draggable, layout === Layout.HORIZONTAL && styles$d.horizontalCard, layout === Layout.VERTICAL && styles$d.verticalCard, type === ItemState.DRAGGING && styles$d.dragging, type === ItemState.DISABLED && styles$d.disabled, !includePadding && styles$d.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
37763
+ if (!includePadding) {
37764
+ className += " perseus-sortable-draggable-unpadded";
37765
+ }
37766
+ const style = {
37767
+ position: "static"
37768
+ };
37769
+ if (this.props.state === ItemState.DRAGGING || this.props.state === ItemState.ANIMATING) {
37770
+ ___default["default"].extend(style, {
37771
+ position: "absolute"
37772
+ }, this.getCurrentPosition());
37773
+ }
37774
+ if (this.props.width) {
37775
+ style.width = this.props.width + 1; // Fix for non-integer widths
37776
+ }
37777
+
37778
+ if (this.props.height) {
37779
+ style.height = this.props.height;
37780
+ }
37781
+ if (this.props.margin != null) {
37782
+ style.margin = this.props.margin;
37783
+ }
37784
+ return /*#__PURE__*/React__namespace.createElement("li", {
37785
+ className: className,
37786
+ style: style,
37787
+ onMouseDown: this.onMouseDown,
37788
+ onTouchStart: this.onMouseDown,
37789
+ onTouchMove: this.onMouseMove,
37790
+ onTouchEnd: this.onMouseUp,
37791
+ onTouchCancel: this.onMouseUp
37792
+ }, /*#__PURE__*/React__namespace.createElement(Renderer, {
37793
+ content: this.props.content,
37794
+ linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "draggable"),
37795
+ onRender: this.props.onRender,
37796
+ strings: this.context.strings
37797
+ }));
37798
+ }
37695
37799
  }
37696
37800
  class Sortable extends React__namespace.Component {
37697
37801
  static defaultProps = {
@@ -37705,6 +37809,33 @@ class Sortable extends React__namespace.Component {
37705
37809
  linterContext: PerseusLinter__namespace.linterContextDefault,
37706
37810
  waitForTexRendererToLoad: true
37707
37811
  };
37812
+ remeasureItems = ___default["default"].debounce(() => {
37813
+ this.setState({
37814
+ // Clear item measurements
37815
+ items: Sortable.clearItemMeasurements(this.state.items)
37816
+ });
37817
+ }, 20);
37818
+ static itemsFromProps(props) {
37819
+ const state = props.disabled ? ItemState.DISABLED : ItemState.STATIC;
37820
+ return props.options.map((option, i) => {
37821
+ return {
37822
+ option: option,
37823
+ key: i,
37824
+ state,
37825
+ width: 0,
37826
+ height: 0
37827
+ };
37828
+ });
37829
+ }
37830
+ static clearItemMeasurements(items) {
37831
+ return items.map(item => {
37832
+ return {
37833
+ ...item,
37834
+ width: 0,
37835
+ height: 0
37836
+ };
37837
+ });
37838
+ }
37708
37839
  constructor(props) {
37709
37840
  super(props);
37710
37841
  // Don't call this.setState() here!
@@ -37738,27 +37869,6 @@ class Sortable extends React__namespace.Component {
37738
37869
  }, 0);
37739
37870
  }
37740
37871
  }
37741
- static itemsFromProps(props) {
37742
- const state = props.disabled ? ItemState.DISABLED : ItemState.STATIC;
37743
- return props.options.map((option, i) => {
37744
- return {
37745
- option: option,
37746
- key: i,
37747
- state,
37748
- width: 0,
37749
- height: 0
37750
- };
37751
- });
37752
- }
37753
- static clearItemMeasurements(items) {
37754
- return items.map(item => {
37755
- return {
37756
- ...item,
37757
- width: 0,
37758
- height: 0
37759
- };
37760
- });
37761
- }
37762
37872
  measureItems() {
37763
37873
  // Measure all items and cache what their dimensions should be, taking
37764
37874
  // into account constraints and the current layout. This allows syncing
@@ -37810,129 +37920,6 @@ class Sortable extends React__namespace.Component {
37810
37920
  });
37811
37921
  });
37812
37922
  }
37813
- remeasureItems = ___default["default"].debounce(() => {
37814
- this.setState({
37815
- // Clear item measurements
37816
- items: Sortable.clearItemMeasurements(this.state.items)
37817
- });
37818
- }, 20);
37819
- render() {
37820
- // To minimize layout shift, we display a spinner until our math
37821
- // renderer is ready to render the math inside the sortable. To
37822
- // do this, we:
37823
- // - render a dummy TeX component to force the math renderer to load
37824
- // - display a spinner until the TeX component calls its onRender
37825
- // callback, signifying that the math is rendered (from which we can
37826
- // infer that the math renderer has loaded)
37827
- //
37828
- // If we didn't do this, the user might see a sortable with empty
37829
- // cells on first render, and then the math would pop in a few moments
37830
- // later once the rendering library loaded.
37831
- if (this.props.waitForTexRendererToLoad && !this.state.texRendererLoaded) {
37832
- const {
37833
- TeX
37834
- } = getDependencies();
37835
- return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksProgressSpinner.CircularSpinner, null), /*#__PURE__*/React__namespace.createElement("div", {
37836
- style: {
37837
- display: "none"
37838
- }
37839
- }, /*#__PURE__*/React__namespace.createElement(TeX, {
37840
- onRender: () => this.setState({
37841
- texRendererLoaded: true
37842
- })
37843
- }, "1")));
37844
- }
37845
- const cards = [];
37846
- const {
37847
- layout
37848
- } = this.props;
37849
- // We need to keep backwards compatbility with rules specified directly
37850
- // in CSS. See sortable.less for details.
37851
- const className = aphrodite.css(styles$d.sortable) + " perseus-sortable";
37852
- const syncWidth = this.props.constraints?.width || layout === Layout.VERTICAL;
37853
- const syncHeight = this.props.constraints?.height || layout === Layout.HORIZONTAL;
37854
- ___default["default"].each(this.state.items, function (item, i, items) {
37855
- const isLast = i === items.length - 1;
37856
- const isStatic = item.state === ItemState.STATIC || item.state === ItemState.DISABLED;
37857
- let margin;
37858
-
37859
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37860
- if (this.props.layout === Layout.HORIZONTAL) {
37861
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37862
- margin = "0 " + this.props.margin + "px 0 0"; // right
37863
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37864
- } else if (this.props.layout === Layout.VERTICAL) {
37865
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37866
- margin = "0 0 " + this.props.margin + "px 0"; // bottom
37867
- }
37868
-
37869
- cards.push( /*#__PURE__*/React__namespace.createElement(Draggable, {
37870
- content: item.option,
37871
- key: item.key,
37872
- state: item.state
37873
- // @ts-expect-error - TS2769 - No overload matches this call.
37874
- ,
37875
- ref: item.key,
37876
- width: syncWidth ? item.width : undefined,
37877
- height: syncHeight ? item.height : undefined,
37878
- layout: layout
37879
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37880
- ,
37881
- includePadding: this.props.padding,
37882
- margin: isLast && isStatic ? 0 : margin,
37883
- endPosition: item.endPosition,
37884
- linterContext: PerseusLinter__namespace.pushContextStack(
37885
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37886
- this.props.linterContext, "sortable")
37887
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37888
- ,
37889
- onRender: this.remeasureItems
37890
- // eslint-disable-next-line react/jsx-no-bind
37891
- // @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.
37892
- ,
37893
- onMouseDown: this.onMouseDown.bind(this, item.key)
37894
- // eslint-disable-next-line react/jsx-no-bind
37895
- // @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.
37896
- ,
37897
- onMouseMove: this.onMouseMove.bind(this, item.key)
37898
- // eslint-disable-next-line react/jsx-no-bind
37899
- // @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.
37900
- ,
37901
- onMouseUp: this.onMouseUp.bind(this, item.key)
37902
- // eslint-disable-next-line react/jsx-no-bind
37903
- // @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.
37904
- ,
37905
- onTouchMove: this.onMouseMove.bind(this, item.key)
37906
- // eslint-disable-next-line react/jsx-no-bind
37907
- // @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.
37908
- ,
37909
- onTouchEnd: this.onMouseUp.bind(this, item.key)
37910
- // eslint-disable-next-line react/jsx-no-bind
37911
- // @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.
37912
- ,
37913
- onTouchCancel: this.onMouseUp.bind(this, item.key)
37914
- // eslint-disable-next-line react/jsx-no-bind
37915
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37916
- ,
37917
- onAnimationEnd: this.onAnimationEnd.bind(
37918
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
37919
- this, item.key)
37920
- }));
37921
- if (item.state === ItemState.DRAGGING || item.state === ItemState.ANIMATING) {
37922
- cards.push( /*#__PURE__*/React__namespace.createElement(Placeholder, {
37923
- key: "placeholder_" + item.key,
37924
- ref: "placeholder_" + item.key,
37925
- width: item.width,
37926
- height: item.height,
37927
- layout: layout,
37928
- margin: isLast ? 0 : margin
37929
- }));
37930
- }
37931
- }, this);
37932
- return /*#__PURE__*/React__namespace.createElement("ul", {
37933
- className: className
37934
- }, cards);
37935
- }
37936
37923
  onMouseDown(key) {
37937
37924
  // Static -> Dragging
37938
37925
  const items = ___default["default"].map(this.state.items, function (item) {
@@ -38078,6 +38065,123 @@ class Sortable extends React__namespace.Component {
38078
38065
  getOptions() {
38079
38066
  return ___default["default"].pluck(this.state.items, "option");
38080
38067
  }
38068
+ render() {
38069
+ // To minimize layout shift, we display a spinner until our math
38070
+ // renderer is ready to render the math inside the sortable. To
38071
+ // do this, we:
38072
+ // - render a dummy TeX component to force the math renderer to load
38073
+ // - display a spinner until the TeX component calls its onRender
38074
+ // callback, signifying that the math is rendered (from which we can
38075
+ // infer that the math renderer has loaded)
38076
+ //
38077
+ // If we didn't do this, the user might see a sortable with empty
38078
+ // cells on first render, and then the math would pop in a few moments
38079
+ // later once the rendering library loaded.
38080
+ if (this.props.waitForTexRendererToLoad && !this.state.texRendererLoaded) {
38081
+ const {
38082
+ TeX
38083
+ } = getDependencies();
38084
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksProgressSpinner.CircularSpinner, null), /*#__PURE__*/React__namespace.createElement("div", {
38085
+ style: {
38086
+ display: "none"
38087
+ }
38088
+ }, /*#__PURE__*/React__namespace.createElement(TeX, {
38089
+ onRender: () => this.setState({
38090
+ texRendererLoaded: true
38091
+ })
38092
+ }, "1")));
38093
+ }
38094
+ const cards = [];
38095
+ const {
38096
+ layout
38097
+ } = this.props;
38098
+ // We need to keep backwards compatbility with rules specified directly
38099
+ // in CSS. See sortable.less for details.
38100
+ const className = aphrodite.css(styles$d.sortable) + " perseus-sortable";
38101
+ const syncWidth = this.props.constraints?.width || layout === Layout.VERTICAL;
38102
+ const syncHeight = this.props.constraints?.height || layout === Layout.HORIZONTAL;
38103
+ ___default["default"].each(this.state.items, function (item, i, items) {
38104
+ const isLast = i === items.length - 1;
38105
+ const isStatic = item.state === ItemState.STATIC || item.state === ItemState.DISABLED;
38106
+ let margin;
38107
+
38108
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
38109
+ if (this.props.layout === Layout.HORIZONTAL) {
38110
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
38111
+ margin = "0 " + this.props.margin + "px 0 0"; // right
38112
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
38113
+ } else if (this.props.layout === Layout.VERTICAL) {
38114
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
38115
+ margin = "0 0 " + this.props.margin + "px 0"; // bottom
38116
+ }
38117
+
38118
+ cards.push( /*#__PURE__*/React__namespace.createElement(Draggable, {
38119
+ content: item.option,
38120
+ key: item.key,
38121
+ state: item.state
38122
+ // @ts-expect-error - TS2769 - No overload matches this call.
38123
+ ,
38124
+ ref: item.key,
38125
+ width: syncWidth ? item.width : undefined,
38126
+ height: syncHeight ? item.height : undefined,
38127
+ layout: layout
38128
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
38129
+ ,
38130
+ includePadding: this.props.padding,
38131
+ margin: isLast && isStatic ? 0 : margin,
38132
+ endPosition: item.endPosition,
38133
+ linterContext: PerseusLinter__namespace.pushContextStack(
38134
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
38135
+ this.props.linterContext, "sortable")
38136
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
38137
+ ,
38138
+ onRender: this.remeasureItems
38139
+ // eslint-disable-next-line react/jsx-no-bind
38140
+ // @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.
38141
+ ,
38142
+ onMouseDown: this.onMouseDown.bind(this, item.key)
38143
+ // eslint-disable-next-line react/jsx-no-bind
38144
+ // @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.
38145
+ ,
38146
+ onMouseMove: this.onMouseMove.bind(this, item.key)
38147
+ // eslint-disable-next-line react/jsx-no-bind
38148
+ // @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.
38149
+ ,
38150
+ onMouseUp: this.onMouseUp.bind(this, item.key)
38151
+ // eslint-disable-next-line react/jsx-no-bind
38152
+ // @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.
38153
+ ,
38154
+ onTouchMove: this.onMouseMove.bind(this, item.key)
38155
+ // eslint-disable-next-line react/jsx-no-bind
38156
+ // @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.
38157
+ ,
38158
+ onTouchEnd: this.onMouseUp.bind(this, item.key)
38159
+ // eslint-disable-next-line react/jsx-no-bind
38160
+ // @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.
38161
+ ,
38162
+ onTouchCancel: this.onMouseUp.bind(this, item.key)
38163
+ // eslint-disable-next-line react/jsx-no-bind
38164
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
38165
+ ,
38166
+ onAnimationEnd: this.onAnimationEnd.bind(
38167
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
38168
+ this, item.key)
38169
+ }));
38170
+ if (item.state === ItemState.DRAGGING || item.state === ItemState.ANIMATING) {
38171
+ cards.push( /*#__PURE__*/React__namespace.createElement(Placeholder, {
38172
+ key: "placeholder_" + item.key,
38173
+ ref: "placeholder_" + item.key,
38174
+ width: item.width,
38175
+ height: item.height,
38176
+ layout: layout,
38177
+ margin: isLast ? 0 : margin
38178
+ }));
38179
+ }
38180
+ }, this);
38181
+ return /*#__PURE__*/React__namespace.createElement("ul", {
38182
+ className: className
38183
+ }, cards);
38184
+ }
38081
38185
  }
38082
38186
  const styles$d = aphrodite.StyleSheet.create({
38083
38187
  sortable: {
@@ -38163,6 +38267,61 @@ class Matcher extends React__namespace.Component {
38163
38267
  rightHeight: 0,
38164
38268
  texRendererLoaded: false
38165
38269
  };
38270
+ changeAndTrack = e => {
38271
+ this.props.onChange(e);
38272
+ this.props.trackInteraction();
38273
+ };
38274
+ onMeasureLeft = dimensions => {
38275
+ const height = ___default["default"].max(dimensions.heights);
38276
+ this.setState({
38277
+ leftHeight: height
38278
+ });
38279
+ };
38280
+ onMeasureRight = dimensions => {
38281
+ const height = ___default["default"].max(dimensions.heights);
38282
+ this.setState({
38283
+ rightHeight: height
38284
+ });
38285
+ };
38286
+ getUserInput = () => {
38287
+ // If the math renderer hasn't loaded then we won't be able to get the
38288
+ // contents of the sortables on the left and right, so we just return
38289
+ // empty arrays until we render for the first time.
38290
+ if (!this.state.texRendererLoaded) {
38291
+ return {
38292
+ left: [],
38293
+ right: []
38294
+ };
38295
+ }
38296
+ return {
38297
+ // eslint-disable-next-line react/no-string-refs
38298
+ // @ts-expect-error - TS2339 - Property 'getOptions' does not exist on type 'ReactInstance'.
38299
+ left: this.refs.left.getOptions(),
38300
+ // eslint-disable-next-line react/no-string-refs
38301
+ // @ts-expect-error - TS2339 - Property 'getOptions' does not exist on type 'ReactInstance'.
38302
+ right: this.refs.right.getOptions()
38303
+ };
38304
+ };
38305
+
38306
+ // Programatic API for moving options
38307
+ // This is used by testing
38308
+ moveLeftOptionToIndex = (option, index) => {
38309
+ // eslint-disable-next-line react/no-string-refs
38310
+ // @ts-expect-error - TS2339 - Property 'moveOptionToIndex' does not exist on type 'ReactInstance'.
38311
+ this.refs.left.moveOptionToIndex(option, index);
38312
+ };
38313
+
38314
+ // Programatic API for moving options
38315
+ // This is used by testing
38316
+ moveRightOptionToIndex = (option, index) => {
38317
+ // eslint-disable-next-line react/no-string-refs
38318
+ // @ts-expect-error - TS2339 - Property 'moveOptionToIndex' does not exist on type 'ReactInstance'.
38319
+ this.refs.right.moveOptionToIndex(option, index);
38320
+ };
38321
+ simpleValidate = rubric => {
38322
+ // @ts-expect-error - TS2339 - Property 'validate' does not exist on type 'typeof Matcher'.
38323
+ return Matcher.validate(this.getUserInput(), rubric);
38324
+ };
38166
38325
  render() {
38167
38326
  // To minimize layout shift, we display a spinner until our math
38168
38327
  // renderer is ready to render the math inside the matcher. To
@@ -38258,61 +38417,6 @@ class Matcher extends React__namespace.Component {
38258
38417
  ref: "right"
38259
38418
  })))));
38260
38419
  }
38261
- changeAndTrack = e => {
38262
- this.props.onChange(e);
38263
- this.props.trackInteraction();
38264
- };
38265
- onMeasureLeft = dimensions => {
38266
- const height = ___default["default"].max(dimensions.heights);
38267
- this.setState({
38268
- leftHeight: height
38269
- });
38270
- };
38271
- onMeasureRight = dimensions => {
38272
- const height = ___default["default"].max(dimensions.heights);
38273
- this.setState({
38274
- rightHeight: height
38275
- });
38276
- };
38277
- getUserInput = () => {
38278
- // If the math renderer hasn't loaded then we won't be able to get the
38279
- // contents of the sortables on the left and right, so we just return
38280
- // empty arrays until we render for the first time.
38281
- if (!this.state.texRendererLoaded) {
38282
- return {
38283
- left: [],
38284
- right: []
38285
- };
38286
- }
38287
- return {
38288
- // eslint-disable-next-line react/no-string-refs
38289
- // @ts-expect-error - TS2339 - Property 'getOptions' does not exist on type 'ReactInstance'.
38290
- left: this.refs.left.getOptions(),
38291
- // eslint-disable-next-line react/no-string-refs
38292
- // @ts-expect-error - TS2339 - Property 'getOptions' does not exist on type 'ReactInstance'.
38293
- right: this.refs.right.getOptions()
38294
- };
38295
- };
38296
-
38297
- // Programatic API for moving options
38298
- // This is used by testing
38299
- moveLeftOptionToIndex = (option, index) => {
38300
- // eslint-disable-next-line react/no-string-refs
38301
- // @ts-expect-error - TS2339 - Property 'moveOptionToIndex' does not exist on type 'ReactInstance'.
38302
- this.refs.left.moveOptionToIndex(option, index);
38303
- };
38304
-
38305
- // Programatic API for moving options
38306
- // This is used by testing
38307
- moveRightOptionToIndex = (option, index) => {
38308
- // eslint-disable-next-line react/no-string-refs
38309
- // @ts-expect-error - TS2339 - Property 'moveOptionToIndex' does not exist on type 'ReactInstance'.
38310
- this.refs.right.moveOptionToIndex(option, index);
38311
- };
38312
- simpleValidate = rubric => {
38313
- // @ts-expect-error - TS2339 - Property 'validate' does not exist on type 'typeof Matcher'.
38314
- return Matcher.validate(this.getUserInput(), rubric);
38315
- };
38316
38420
  }
38317
38421
  ___default["default"].extend(Matcher, {
38318
38422
  validate: function (state, rubric) {
@@ -38504,6 +38608,144 @@ class Matrix extends React__namespace.Component {
38504
38608
  // Used in the `onBlur` and `onFocus` handlers
38505
38609
  this.cursorPosition = [0, 0];
38506
38610
  }
38611
+ getInputPaths = () => {
38612
+ const inputPaths = [];
38613
+ const maxRows = this.props.matrixBoardSize[0];
38614
+ const maxCols = this.props.matrixBoardSize[1];
38615
+ ___default["default"](maxRows).times(row => {
38616
+ ___default["default"](maxCols).times(col => {
38617
+ const inputPath = getInputPath$1(row, col);
38618
+ inputPaths.push(inputPath);
38619
+ });
38620
+ });
38621
+ return inputPaths;
38622
+ };
38623
+ getGrammarTypeForPath = inputPath => {
38624
+ return "number";
38625
+ };
38626
+ _handleFocus = (row, col) => {
38627
+ this.props.onFocus(getInputPath$1(row, col));
38628
+ };
38629
+ _handleBlur = (row, col) => {
38630
+ this.props.onBlur(getInputPath$1(row, col));
38631
+ };
38632
+ focus = () => {
38633
+ this.focusInputPath(getDefaultPath$1());
38634
+ return true;
38635
+ };
38636
+ focusInputPath = path => {
38637
+ const inputID = getRefForPath$1(path);
38638
+ // eslint-disable-next-line react/no-string-refs
38639
+ // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
38640
+ this.refs[inputID].focus();
38641
+ };
38642
+ blurInputPath = path => {
38643
+ if (path.length === 0) {
38644
+ path = getDefaultPath$1();
38645
+ }
38646
+ const inputID = getRefForPath$1(path);
38647
+ // eslint-disable-next-line react/no-string-refs
38648
+ // @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
38649
+ this.refs[inputID].blur();
38650
+ };
38651
+ getDOMNodeForPath = inputPath => {
38652
+ const inputID = getRefForPath$1(inputPath);
38653
+ // eslint-disable-next-line react/no-string-refs
38654
+ return ReactDOM__default["default"].findDOMNode(this.refs[inputID]);
38655
+ };
38656
+ setInputValue = (inputPath, value, callback) => {
38657
+ const row = getRowFromPath$1(inputPath);
38658
+ const col = getColumnFromPath$1(inputPath);
38659
+ this.onValueChange(row, col, value, callback);
38660
+ };
38661
+ handleKeyDown = (row, col, e) => {
38662
+ const maxRow = this.props.matrixBoardSize[0];
38663
+ const maxCol = this.props.matrixBoardSize[1];
38664
+ let enterTheMatrix = null;
38665
+
38666
+ // eslint-disable-next-line react/no-string-refs
38667
+ const curInput = this.refs[getRefForPath$1(getInputPath$1(row, col))];
38668
+ // @ts-expect-error - TS2339 - Property 'getStringValue' does not exist on type 'ReactInstance'.
38669
+ const curValueString = curInput.getStringValue();
38670
+ // @ts-expect-error - TS2339 - Property 'getSelectionStart' does not exist on type 'ReactInstance'.
38671
+ const cursorStartPosition = curInput.getSelectionStart();
38672
+ // @ts-expect-error - TS2339 - Property 'getSelectionEnd' does not exist on type 'ReactInstance'.
38673
+ const cursorEndPosition = curInput.getSelectionEnd();
38674
+ let nextPath = null;
38675
+ if (e.key === "ArrowUp" && row > 0) {
38676
+ // @ts-expect-error - TS2322 - Type 'readonly string[]' is not assignable to type 'null'.
38677
+ nextPath = getInputPath$1(row - 1, col);
38678
+ } else if (e.key === "ArrowDown" && row + 1 < maxRow) {
38679
+ // @ts-expect-error - TS2322 - Type 'readonly string[]' is not assignable to type 'null'.
38680
+ nextPath = getInputPath$1(row + 1, col);
38681
+ } else if (e.key === "ArrowLeft" && col > 0) {
38682
+ if (cursorStartPosition === 0 && cursorEndPosition === 0) {
38683
+ // Only go to next input if we're at the *start* of the content
38684
+ // @ts-expect-error - TS2322 - Type 'readonly string[]' is not assignable to type 'null'.
38685
+ nextPath = getInputPath$1(row, col - 1);
38686
+ }
38687
+ } else if (e.key === "ArrowRight" && col + 1 < maxCol) {
38688
+ if (cursorStartPosition === curValueString.length) {
38689
+ // Only go to next input if we're at the *end* of the content
38690
+ // @ts-expect-error - TS2322 - Type 'readonly string[]' is not assignable to type 'null'.
38691
+ nextPath = getInputPath$1(row, col + 1);
38692
+ }
38693
+ } else if (e.key === "Enter") {
38694
+ // @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'null'.
38695
+ enterTheMatrix = this.state.enterTheMatrix + 1;
38696
+ } else if (e.key === "Escape") {
38697
+ // @ts-expect-error - TS2322 - Type '0' is not assignable to type 'null'.
38698
+ enterTheMatrix = 0;
38699
+ }
38700
+ if (nextPath) {
38701
+ // Prevent the cursor from jumping again inside the next input
38702
+ e.preventDefault();
38703
+
38704
+ // Focus the input and move the cursor to the end of it.
38705
+ // eslint-disable-next-line react/no-string-refs
38706
+ const input = this.refs[getRefForPath$1(nextPath)];
38707
+
38708
+ // Multiply by 2 to ensure the cursor always ends up at the end;
38709
+ // Opera sometimes sees a carriage return as 2 characters.
38710
+ // @ts-expect-error - TS2339 - Property 'getStringValue' does not exist on type 'ReactInstance'.
38711
+ const inputValString = input.getStringValue();
38712
+ const valueLength = inputValString.length * 2;
38713
+
38714
+ // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
38715
+ input.focus();
38716
+ if (e.key === "ArrowRight") {
38717
+ // @ts-expect-error - TS2339 - Property 'setSelectionRange' does not exist on type 'ReactInstance'.
38718
+ input.setSelectionRange(0, 0);
38719
+ } else {
38720
+ // @ts-expect-error - TS2339 - Property 'setSelectionRange' does not exist on type 'ReactInstance'.
38721
+ input.setSelectionRange(valueLength, valueLength);
38722
+ }
38723
+ }
38724
+ if (enterTheMatrix != null) {
38725
+ this.setState({
38726
+ enterTheMatrix: enterTheMatrix
38727
+ });
38728
+ }
38729
+ };
38730
+ onValueChange = (row, column, value, cb) => {
38731
+ const answers = this.props.answers.map(answer => [...answer]);
38732
+ if (!answers[row]) {
38733
+ answers[row] = [];
38734
+ }
38735
+ answers[row][column] = value;
38736
+ this.props.onChange({
38737
+ answers
38738
+ }, cb);
38739
+ this.props.trackInteraction();
38740
+ };
38741
+ getUserInput = () => {
38742
+ return {
38743
+ answers: this.props.answers
38744
+ };
38745
+ };
38746
+ simpleValidate = rubric => {
38747
+ return Matrix.validate(this.getUserInput(), rubric, this.context.strings);
38748
+ };
38507
38749
  render() {
38508
38750
  // Set the input sizes through JS so we can control the size of the
38509
38751
  // brackets. (If we set them in CSS we won't know values until the
@@ -38659,144 +38901,6 @@ class Matrix extends React__namespace.Component {
38659
38901
  strings: this.context.strings
38660
38902
  })));
38661
38903
  }
38662
- getInputPaths = () => {
38663
- const inputPaths = [];
38664
- const maxRows = this.props.matrixBoardSize[0];
38665
- const maxCols = this.props.matrixBoardSize[1];
38666
- ___default["default"](maxRows).times(row => {
38667
- ___default["default"](maxCols).times(col => {
38668
- const inputPath = getInputPath$1(row, col);
38669
- inputPaths.push(inputPath);
38670
- });
38671
- });
38672
- return inputPaths;
38673
- };
38674
- getGrammarTypeForPath = inputPath => {
38675
- return "number";
38676
- };
38677
- _handleFocus = (row, col) => {
38678
- this.props.onFocus(getInputPath$1(row, col));
38679
- };
38680
- _handleBlur = (row, col) => {
38681
- this.props.onBlur(getInputPath$1(row, col));
38682
- };
38683
- focus = () => {
38684
- this.focusInputPath(getDefaultPath$1());
38685
- return true;
38686
- };
38687
- focusInputPath = path => {
38688
- const inputID = getRefForPath$1(path);
38689
- // eslint-disable-next-line react/no-string-refs
38690
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
38691
- this.refs[inputID].focus();
38692
- };
38693
- blurInputPath = path => {
38694
- if (path.length === 0) {
38695
- path = getDefaultPath$1();
38696
- }
38697
- const inputID = getRefForPath$1(path);
38698
- // eslint-disable-next-line react/no-string-refs
38699
- // @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
38700
- this.refs[inputID].blur();
38701
- };
38702
- getDOMNodeForPath = inputPath => {
38703
- const inputID = getRefForPath$1(inputPath);
38704
- // eslint-disable-next-line react/no-string-refs
38705
- return ReactDOM__default["default"].findDOMNode(this.refs[inputID]);
38706
- };
38707
- setInputValue = (inputPath, value, callback) => {
38708
- const row = getRowFromPath$1(inputPath);
38709
- const col = getColumnFromPath$1(inputPath);
38710
- this.onValueChange(row, col, value, callback);
38711
- };
38712
- handleKeyDown = (row, col, e) => {
38713
- const maxRow = this.props.matrixBoardSize[0];
38714
- const maxCol = this.props.matrixBoardSize[1];
38715
- let enterTheMatrix = null;
38716
-
38717
- // eslint-disable-next-line react/no-string-refs
38718
- const curInput = this.refs[getRefForPath$1(getInputPath$1(row, col))];
38719
- // @ts-expect-error - TS2339 - Property 'getStringValue' does not exist on type 'ReactInstance'.
38720
- const curValueString = curInput.getStringValue();
38721
- // @ts-expect-error - TS2339 - Property 'getSelectionStart' does not exist on type 'ReactInstance'.
38722
- const cursorStartPosition = curInput.getSelectionStart();
38723
- // @ts-expect-error - TS2339 - Property 'getSelectionEnd' does not exist on type 'ReactInstance'.
38724
- const cursorEndPosition = curInput.getSelectionEnd();
38725
- let nextPath = null;
38726
- if (e.key === "ArrowUp" && row > 0) {
38727
- // @ts-expect-error - TS2322 - Type 'readonly string[]' is not assignable to type 'null'.
38728
- nextPath = getInputPath$1(row - 1, col);
38729
- } else if (e.key === "ArrowDown" && row + 1 < maxRow) {
38730
- // @ts-expect-error - TS2322 - Type 'readonly string[]' is not assignable to type 'null'.
38731
- nextPath = getInputPath$1(row + 1, col);
38732
- } else if (e.key === "ArrowLeft" && col > 0) {
38733
- if (cursorStartPosition === 0 && cursorEndPosition === 0) {
38734
- // Only go to next input if we're at the *start* of the content
38735
- // @ts-expect-error - TS2322 - Type 'readonly string[]' is not assignable to type 'null'.
38736
- nextPath = getInputPath$1(row, col - 1);
38737
- }
38738
- } else if (e.key === "ArrowRight" && col + 1 < maxCol) {
38739
- if (cursorStartPosition === curValueString.length) {
38740
- // Only go to next input if we're at the *end* of the content
38741
- // @ts-expect-error - TS2322 - Type 'readonly string[]' is not assignable to type 'null'.
38742
- nextPath = getInputPath$1(row, col + 1);
38743
- }
38744
- } else if (e.key === "Enter") {
38745
- // @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'null'.
38746
- enterTheMatrix = this.state.enterTheMatrix + 1;
38747
- } else if (e.key === "Escape") {
38748
- // @ts-expect-error - TS2322 - Type '0' is not assignable to type 'null'.
38749
- enterTheMatrix = 0;
38750
- }
38751
- if (nextPath) {
38752
- // Prevent the cursor from jumping again inside the next input
38753
- e.preventDefault();
38754
-
38755
- // Focus the input and move the cursor to the end of it.
38756
- // eslint-disable-next-line react/no-string-refs
38757
- const input = this.refs[getRefForPath$1(nextPath)];
38758
-
38759
- // Multiply by 2 to ensure the cursor always ends up at the end;
38760
- // Opera sometimes sees a carriage return as 2 characters.
38761
- // @ts-expect-error - TS2339 - Property 'getStringValue' does not exist on type 'ReactInstance'.
38762
- const inputValString = input.getStringValue();
38763
- const valueLength = inputValString.length * 2;
38764
-
38765
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
38766
- input.focus();
38767
- if (e.key === "ArrowRight") {
38768
- // @ts-expect-error - TS2339 - Property 'setSelectionRange' does not exist on type 'ReactInstance'.
38769
- input.setSelectionRange(0, 0);
38770
- } else {
38771
- // @ts-expect-error - TS2339 - Property 'setSelectionRange' does not exist on type 'ReactInstance'.
38772
- input.setSelectionRange(valueLength, valueLength);
38773
- }
38774
- }
38775
- if (enterTheMatrix != null) {
38776
- this.setState({
38777
- enterTheMatrix: enterTheMatrix
38778
- });
38779
- }
38780
- };
38781
- onValueChange = (row, column, value, cb) => {
38782
- const answers = this.props.answers.map(answer => [...answer]);
38783
- if (!answers[row]) {
38784
- answers[row] = [];
38785
- }
38786
- answers[row][column] = value;
38787
- this.props.onChange({
38788
- answers
38789
- }, cb);
38790
- this.props.trackInteraction();
38791
- };
38792
- getUserInput = () => {
38793
- return {
38794
- answers: this.props.answers
38795
- };
38796
- };
38797
- simpleValidate = rubric => {
38798
- return Matrix.validate(this.getUserInput(), rubric, this.context.strings);
38799
- };
38800
38904
  }
38801
38905
  const propTransform$1 = editorProps => {
38802
38906
  // Remove answers before passing to widget
@@ -38828,7 +38932,7 @@ var Matrix$1 = {
38828
38932
  isLintable: true
38829
38933
  };
38830
38934
 
38831
- /* eslint-disable @babel/no-invalid-this, react/sort-comp */
38935
+ /* eslint-disable @babel/no-invalid-this */
38832
38936
  const defaultImage = {
38833
38937
  url: null,
38834
38938
  top: 0,
@@ -38870,30 +38974,6 @@ const Measurer = createReactClass__default["default"]({
38870
38974
  getInitialState: function () {
38871
38975
  return {};
38872
38976
  },
38873
- render: function () {
38874
- const image = ___default["default"].extend({}, defaultImage, this.props.image);
38875
-
38876
- // TODO(scottgrant): This isn't a11y-friendly! We should insist on
38877
- // finding some valid alt text when this widget is used.
38878
- return /*#__PURE__*/React__namespace.createElement("div", {
38879
- className: "perseus-widget perseus-widget-measurer " + "graphie-container above-scratchpad",
38880
- style: {
38881
- width: this.props.box[0],
38882
- height: this.props.box[1]
38883
- }
38884
- }, image.url && /*#__PURE__*/React__namespace.createElement("div", {
38885
- style: {
38886
- position: "relative",
38887
- top: image.top,
38888
- left: image.left
38889
- }
38890
- }, /*#__PURE__*/React__namespace.createElement(SvgImage, {
38891
- src: image.url
38892
- })), /*#__PURE__*/React__namespace.createElement("div", {
38893
- className: "graphie",
38894
- ref: "graphieDiv"
38895
- }));
38896
- },
38897
38977
  componentDidMount: function () {
38898
38978
  this.setupGraphie();
38899
38979
  },
@@ -38951,7 +39031,31 @@ const Measurer = createReactClass__default["default"]({
38951
39031
  // TODO(joel) - I don't understand how this is useful!
38952
39032
  return Measurer.validate(this.getUserInput(), rubric);
38953
39033
  },
38954
- focus: $__default["default"].noop
39034
+ focus: $__default["default"].noop,
39035
+ render: function () {
39036
+ const image = ___default["default"].extend({}, defaultImage, this.props.image);
39037
+
39038
+ // TODO(scottgrant): This isn't a11y-friendly! We should insist on
39039
+ // finding some valid alt text when this widget is used.
39040
+ return /*#__PURE__*/React__namespace.createElement("div", {
39041
+ className: "perseus-widget perseus-widget-measurer " + "graphie-container above-scratchpad",
39042
+ style: {
39043
+ width: this.props.box[0],
39044
+ height: this.props.box[1]
39045
+ }
39046
+ }, image.url && /*#__PURE__*/React__namespace.createElement("div", {
39047
+ style: {
39048
+ position: "relative",
39049
+ top: image.top,
39050
+ left: image.left
39051
+ }
39052
+ }, /*#__PURE__*/React__namespace.createElement(SvgImage, {
39053
+ src: image.url
39054
+ })), /*#__PURE__*/React__namespace.createElement("div", {
39055
+ className: "graphie",
39056
+ ref: "graphieDiv"
39057
+ }));
39058
+ }
38955
39059
  });
38956
39060
  ___default["default"].extend(Measurer, {
38957
39061
  validate: function (state, rubric) {
@@ -40533,6 +40637,97 @@ class Card extends React__namespace.Component {
40533
40637
  state = {
40534
40638
  dragging: false
40535
40639
  };
40640
+ componentDidMount() {
40641
+ this.mouseMoveUpBound = false;
40642
+
40643
+ // On touch devices, we set up our own touchmove handler because React
40644
+ // all event subscriptions using `OnTouchMove` props are non-passive.
40645
+ // See: https://github.com/facebook/react/issues/6436
40646
+ // Also, we can't subscribe to `ontouchmove` within the `ontouchstart`
40647
+ // handler because of a WebKit bug:
40648
+ // https://github.com/atlassian/react-beautiful-dnd/issues/413 and
40649
+ // https://bugs.webkit.org/show_bug.cgi?id=184250
40650
+ document.addEventListener("touchmove", this.onMouseMove,
40651
+ // Not all browsers support passive events, and when they don't
40652
+ // this third paramter is just a boolean. If we pass the "options"
40653
+ // object, it's interpreted as `capture=true` (which we don't want!)
40654
+ Util.supportsPassiveEvents() ? {
40655
+ passive: false
40656
+ } : false);
40657
+ }
40658
+ shouldComponentUpdate(nextProps, nextState) {
40659
+ // Cards in the bank or drag list don't usually change -- they only
40660
+ // reorder themselves -- so we want to skip the update to things a
40661
+ // little faster. We also need to re-render if the content changes,
40662
+ // which happens only in the editor. (We do want to update the floating
40663
+ // card on mouse move to update its position.)
40664
+ return this.props.floating || nextProps.floating || this.props.content !== nextProps.content ||
40665
+ // TODO(alpert): Remove ref here after fixing facebook/react#1392.
40666
+ this.props.fakeRef !== nextProps.fakeRef;
40667
+ }
40668
+ componentDidUpdate(prevProps, prevState) {
40669
+ if (this.props.animating && !prevProps.animating) {
40670
+ // If we just were changed into animating, start the animation.
40671
+ // We pick the animation speed based on the distance that the card
40672
+ // needs to travel. (Why sqrt? Just because it looks nice -- with a
40673
+ // linear scale, far things take too long to come back.)
40674
+ const ms = 15 * Math.sqrt(Math.sqrt(Math.pow(this.props.animateTo.left - this.props.startOffset.left, 2) + Math.pow(this.props.animateTo.top - this.props.startOffset.top, 2)));
40675
+ // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'animate' does not exist on type 'JQueryStatic'.
40676
+ $__default["default"](ReactDOM__default["default"].findDOMNode(this)).animate(this.props.animateTo, Math.max(ms, 1), this.props.onAnimationEnd);
40677
+ }
40678
+ }
40679
+ componentWillUnmount() {
40680
+ // Event handlers should be unbound before component unmounting, but
40681
+ // just in case...
40682
+ if (this.mouseMoveUpBound) {
40683
+ Log.error("Removing an element with bound event handlers.", perseusCore.Errors.Internal);
40684
+ this.unbindMouseMoveUp();
40685
+ Util.resetTouchHandlers();
40686
+ }
40687
+ document.removeEventListener("touchmove", this.onMouseMove);
40688
+ }
40689
+ bindMouseMoveUp = () => {
40690
+ this.mouseMoveUpBound = true;
40691
+ $__default["default"](document).on("mousemove", this.onMouseMove);
40692
+ $__default["default"](document).on("mouseup", this.onMouseUp);
40693
+ };
40694
+ unbindMouseMoveUp = () => {
40695
+ this.mouseMoveUpBound = false;
40696
+ $__default["default"](document).off("mousemove", this.onMouseMove);
40697
+ $__default["default"](document).off("mouseup", this.onMouseUp);
40698
+ };
40699
+ onMouseDown = event => {
40700
+ event.preventDefault();
40701
+ const loc = Util.extractPointerLocation(event);
40702
+ if (loc) {
40703
+ this.setState({
40704
+ dragging: true
40705
+ });
40706
+ this.bindMouseMoveUp();
40707
+ this.props.onMouseDown && this.props.onMouseDown(loc, this);
40708
+ }
40709
+ };
40710
+ onMouseMove = event => {
40711
+ if (!this.state.dragging) {
40712
+ return;
40713
+ }
40714
+ event.preventDefault();
40715
+ const loc = Util.extractPointerLocation(event);
40716
+ if (loc) {
40717
+ this.props.onMouseMove && this.props.onMouseMove(loc);
40718
+ }
40719
+ };
40720
+ onMouseUp = event => {
40721
+ event.preventDefault();
40722
+ const loc = Util.extractPointerLocation(event);
40723
+ if (loc) {
40724
+ this.setState({
40725
+ dragging: false
40726
+ });
40727
+ this.unbindMouseMoveUp();
40728
+ this.props.onMouseUp && this.props.onMouseUp(loc);
40729
+ }
40730
+ };
40536
40731
  render() {
40537
40732
  let style = {};
40538
40733
  if (this.props.floating) {
@@ -40572,97 +40767,6 @@ class Card extends React__namespace.Component {
40572
40767
  strings: this.context.strings
40573
40768
  }))));
40574
40769
  }
40575
- shouldComponentUpdate(nextProps, nextState) {
40576
- // Cards in the bank or drag list don't usually change -- they only
40577
- // reorder themselves -- so we want to skip the update to things a
40578
- // little faster. We also need to re-render if the content changes,
40579
- // which happens only in the editor. (We do want to update the floating
40580
- // card on mouse move to update its position.)
40581
- return this.props.floating || nextProps.floating || this.props.content !== nextProps.content ||
40582
- // TODO(alpert): Remove ref here after fixing facebook/react#1392.
40583
- this.props.fakeRef !== nextProps.fakeRef;
40584
- }
40585
- componentDidMount() {
40586
- this.mouseMoveUpBound = false;
40587
-
40588
- // On touch devices, we set up our own touchmove handler because React
40589
- // all event subscriptions using `OnTouchMove` props are non-passive.
40590
- // See: https://github.com/facebook/react/issues/6436
40591
- // Also, we can't subscribe to `ontouchmove` within the `ontouchstart`
40592
- // handler because of a WebKit bug:
40593
- // https://github.com/atlassian/react-beautiful-dnd/issues/413 and
40594
- // https://bugs.webkit.org/show_bug.cgi?id=184250
40595
- document.addEventListener("touchmove", this.onMouseMove,
40596
- // Not all browsers support passive events, and when they don't
40597
- // this third paramter is just a boolean. If we pass the "options"
40598
- // object, it's interpreted as `capture=true` (which we don't want!)
40599
- Util.supportsPassiveEvents() ? {
40600
- passive: false
40601
- } : false);
40602
- }
40603
- componentDidUpdate(prevProps, prevState) {
40604
- if (this.props.animating && !prevProps.animating) {
40605
- // If we just were changed into animating, start the animation.
40606
- // We pick the animation speed based on the distance that the card
40607
- // needs to travel. (Why sqrt? Just because it looks nice -- with a
40608
- // linear scale, far things take too long to come back.)
40609
- const ms = 15 * Math.sqrt(Math.sqrt(Math.pow(this.props.animateTo.left - this.props.startOffset.left, 2) + Math.pow(this.props.animateTo.top - this.props.startOffset.top, 2)));
40610
- // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'animate' does not exist on type 'JQueryStatic'.
40611
- $__default["default"](ReactDOM__default["default"].findDOMNode(this)).animate(this.props.animateTo, Math.max(ms, 1), this.props.onAnimationEnd);
40612
- }
40613
- }
40614
- componentWillUnmount() {
40615
- // Event handlers should be unbound before component unmounting, but
40616
- // just in case...
40617
- if (this.mouseMoveUpBound) {
40618
- Log.error("Removing an element with bound event handlers.", perseusCore.Errors.Internal);
40619
- this.unbindMouseMoveUp();
40620
- Util.resetTouchHandlers();
40621
- }
40622
- document.removeEventListener("touchmove", this.onMouseMove);
40623
- }
40624
- bindMouseMoveUp = () => {
40625
- this.mouseMoveUpBound = true;
40626
- $__default["default"](document).on("mousemove", this.onMouseMove);
40627
- $__default["default"](document).on("mouseup", this.onMouseUp);
40628
- };
40629
- unbindMouseMoveUp = () => {
40630
- this.mouseMoveUpBound = false;
40631
- $__default["default"](document).off("mousemove", this.onMouseMove);
40632
- $__default["default"](document).off("mouseup", this.onMouseUp);
40633
- };
40634
- onMouseDown = event => {
40635
- event.preventDefault();
40636
- const loc = Util.extractPointerLocation(event);
40637
- if (loc) {
40638
- this.setState({
40639
- dragging: true
40640
- });
40641
- this.bindMouseMoveUp();
40642
- this.props.onMouseDown && this.props.onMouseDown(loc, this);
40643
- }
40644
- };
40645
- onMouseMove = event => {
40646
- if (!this.state.dragging) {
40647
- return;
40648
- }
40649
- event.preventDefault();
40650
- const loc = Util.extractPointerLocation(event);
40651
- if (loc) {
40652
- this.props.onMouseMove && this.props.onMouseMove(loc);
40653
- }
40654
- };
40655
- onMouseUp = event => {
40656
- event.preventDefault();
40657
- const loc = Util.extractPointerLocation(event);
40658
- if (loc) {
40659
- this.setState({
40660
- dragging: false
40661
- });
40662
- this.unbindMouseMoveUp();
40663
- this.props.onMouseUp && this.props.onMouseUp(loc);
40664
- }
40665
- };
40666
40770
  }
40667
40771
  const NORMAL = "normal",
40668
40772
  HORIZONTAL$1 = "horizontal";
@@ -40695,109 +40799,6 @@ class Orderer extends React__namespace.Component {
40695
40799
  });
40696
40800
  }
40697
40801
  }
40698
- render() {
40699
- // This is the card we are currently dragging
40700
- const dragging = this.state.dragging && /*#__PURE__*/React__namespace.createElement(Card
40701
- // eslint-disable-next-line react/no-string-refs
40702
- , {
40703
- ref: "dragging",
40704
- floating: true,
40705
- content: this.state.dragContent,
40706
- startOffset: this.state.offsetPos,
40707
- startMouse: this.state.grabPos,
40708
- mouse: this.state.mousePos,
40709
- width: this.state.dragWidth,
40710
- onMouseUp: this.onRelease,
40711
- onMouseMove: this.onMouseMove,
40712
- key: this.state.dragKey || "draggingCard",
40713
- linterContext: this.props.linterContext
40714
- });
40715
-
40716
- // This is the card that is currently animating
40717
- const animating = this.state.animating && /*#__PURE__*/React__namespace.createElement(Card, {
40718
- floating: true,
40719
- animating: true,
40720
- content: this.state.dragContent,
40721
- startOffset: this.state.offsetPos,
40722
- width: this.state.dragWidth,
40723
- animateTo: this.state.animateTo,
40724
- onAnimationEnd: this.state.onAnimationEnd,
40725
- key: this.state.dragKey || "draggingCard",
40726
- linterContext: this.props.linterContext
40727
- });
40728
-
40729
- // This is the list of draggable, rearrangable cards
40730
- const sortableCards = ___default["default"].map(this.state.current, function (opt, i) {
40731
- return /*#__PURE__*/React__namespace.createElement(Card, {
40732
- key: `sortableCard${i}`,
40733
- ref: "sortable" + i,
40734
- fakeRef: "sortable" + i,
40735
- floating: false,
40736
- content: opt.content,
40737
- width: opt.width
40738
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
40739
- ,
40740
- linterContext: this.props.linterContext
40741
- // eslint-disable-next-line react/jsx-no-bind
40742
- ,
40743
- onMouseDown:
40744
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
40745
- this.state.animating ? $__default["default"].noop :
40746
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
40747
- this.onClick.bind(null, "current", i)
40748
- });
40749
- }, this);
40750
- if (this.state.placeholderIndex != null) {
40751
- const placeholder = /*#__PURE__*/React__namespace.createElement(PlaceholderCard
40752
- // eslint-disable-next-line react/no-string-refs
40753
- , {
40754
- ref: "placeholder",
40755
- width: this.state.dragWidth,
40756
- height: this.state.dragHeight,
40757
- key: "placeholder"
40758
- });
40759
- sortableCards.splice(this.state.placeholderIndex, 0, placeholder);
40760
- }
40761
- const anySortableCards = sortableCards.length > 0;
40762
- // @ts-expect-error - TS2345 - Argument of type 'false | Element' is not assignable to parameter of type 'Element'.
40763
- sortableCards.push(dragging, animating);
40764
-
40765
- // If there are no cards in the list, then add a "hint" card
40766
- const sortable = /*#__PURE__*/React__namespace.createElement("div", {
40767
- className: "perseus-clearfix draggable-box"
40768
- }, !anySortableCards && /*#__PURE__*/React__namespace.createElement(DragHintCard, null), /*#__PURE__*/React__namespace.createElement("div", {
40769
- ref: "dragList"
40770
- }, sortableCards));
40771
-
40772
- // This is the bank of stacks of cards
40773
- const bank =
40774
- /*#__PURE__*/
40775
- // eslint-disable-next-line react/no-string-refs
40776
- React__namespace.createElement("div", {
40777
- ref: "bank",
40778
- className: "bank perseus-clearfix"
40779
- }, ___default["default"].map(this.props.options, (opt, i) => {
40780
- return /*#__PURE__*/React__namespace.createElement(Card, {
40781
- ref: "bank" + i,
40782
- floating: false,
40783
- content: opt.content,
40784
- stack: true,
40785
- key: i,
40786
- linterContext: this.props.linterContext
40787
- // eslint-disable-next-line react/jsx-no-bind
40788
- ,
40789
- onMouseDown: this.state.animating ? $__default["default"].noop : this.onClick.bind(null, "bank", i),
40790
- onMouseMove: this.onMouseMove,
40791
- onMouseUp: this.onRelease
40792
- });
40793
- }, this));
40794
- return /*#__PURE__*/React__namespace.createElement("div", {
40795
- className: "draggy-boxy-thing orderer " + "height-" + this.props.height + " " + "layout-" + this.props.layout + " " + "above-scratchpad blank-background " + "perseus-clearfix " + ClassNames.INTERACTIVE
40796
- // eslint-disable-next-line react/no-string-refs
40797
- ,
40798
- ref: "orderer"
40799
- }, bank, sortable);
40800
- }
40801
40802
  onClick = (type, index, loc, draggable) => {
40802
40803
  // @ts-expect-error - TS2769 - No overload matches this call.
40803
40804
  const $draggable = $__default["default"](ReactDOM__default["default"].findDOMNode(draggable));
@@ -41034,6 +41035,109 @@ class Orderer extends React__namespace.Component {
41034
41035
  // @ts-expect-error - TS2339 - Property 'validate' does not exist on type 'typeof Orderer'.
41035
41036
  return Orderer.validate(this.getUserInput(), rubric);
41036
41037
  };
41038
+ render() {
41039
+ // This is the card we are currently dragging
41040
+ const dragging = this.state.dragging && /*#__PURE__*/React__namespace.createElement(Card
41041
+ // eslint-disable-next-line react/no-string-refs
41042
+ , {
41043
+ ref: "dragging",
41044
+ floating: true,
41045
+ content: this.state.dragContent,
41046
+ startOffset: this.state.offsetPos,
41047
+ startMouse: this.state.grabPos,
41048
+ mouse: this.state.mousePos,
41049
+ width: this.state.dragWidth,
41050
+ onMouseUp: this.onRelease,
41051
+ onMouseMove: this.onMouseMove,
41052
+ key: this.state.dragKey || "draggingCard",
41053
+ linterContext: this.props.linterContext
41054
+ });
41055
+
41056
+ // This is the card that is currently animating
41057
+ const animating = this.state.animating && /*#__PURE__*/React__namespace.createElement(Card, {
41058
+ floating: true,
41059
+ animating: true,
41060
+ content: this.state.dragContent,
41061
+ startOffset: this.state.offsetPos,
41062
+ width: this.state.dragWidth,
41063
+ animateTo: this.state.animateTo,
41064
+ onAnimationEnd: this.state.onAnimationEnd,
41065
+ key: this.state.dragKey || "draggingCard",
41066
+ linterContext: this.props.linterContext
41067
+ });
41068
+
41069
+ // This is the list of draggable, rearrangable cards
41070
+ const sortableCards = ___default["default"].map(this.state.current, function (opt, i) {
41071
+ return /*#__PURE__*/React__namespace.createElement(Card, {
41072
+ key: `sortableCard${i}`,
41073
+ ref: "sortable" + i,
41074
+ fakeRef: "sortable" + i,
41075
+ floating: false,
41076
+ content: opt.content,
41077
+ width: opt.width
41078
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41079
+ ,
41080
+ linterContext: this.props.linterContext
41081
+ // eslint-disable-next-line react/jsx-no-bind
41082
+ ,
41083
+ onMouseDown:
41084
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41085
+ this.state.animating ? $__default["default"].noop :
41086
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41087
+ this.onClick.bind(null, "current", i)
41088
+ });
41089
+ }, this);
41090
+ if (this.state.placeholderIndex != null) {
41091
+ const placeholder = /*#__PURE__*/React__namespace.createElement(PlaceholderCard
41092
+ // eslint-disable-next-line react/no-string-refs
41093
+ , {
41094
+ ref: "placeholder",
41095
+ width: this.state.dragWidth,
41096
+ height: this.state.dragHeight,
41097
+ key: "placeholder"
41098
+ });
41099
+ sortableCards.splice(this.state.placeholderIndex, 0, placeholder);
41100
+ }
41101
+ const anySortableCards = sortableCards.length > 0;
41102
+ // @ts-expect-error - TS2345 - Argument of type 'false | Element' is not assignable to parameter of type 'Element'.
41103
+ sortableCards.push(dragging, animating);
41104
+
41105
+ // If there are no cards in the list, then add a "hint" card
41106
+ const sortable = /*#__PURE__*/React__namespace.createElement("div", {
41107
+ className: "perseus-clearfix draggable-box"
41108
+ }, !anySortableCards && /*#__PURE__*/React__namespace.createElement(DragHintCard, null), /*#__PURE__*/React__namespace.createElement("div", {
41109
+ ref: "dragList"
41110
+ }, sortableCards));
41111
+
41112
+ // This is the bank of stacks of cards
41113
+ const bank =
41114
+ /*#__PURE__*/
41115
+ // eslint-disable-next-line react/no-string-refs
41116
+ React__namespace.createElement("div", {
41117
+ ref: "bank",
41118
+ className: "bank perseus-clearfix"
41119
+ }, ___default["default"].map(this.props.options, (opt, i) => {
41120
+ return /*#__PURE__*/React__namespace.createElement(Card, {
41121
+ ref: "bank" + i,
41122
+ floating: false,
41123
+ content: opt.content,
41124
+ stack: true,
41125
+ key: i,
41126
+ linterContext: this.props.linterContext
41127
+ // eslint-disable-next-line react/jsx-no-bind
41128
+ ,
41129
+ onMouseDown: this.state.animating ? $__default["default"].noop : this.onClick.bind(null, "bank", i),
41130
+ onMouseMove: this.onMouseMove,
41131
+ onMouseUp: this.onRelease
41132
+ });
41133
+ }, this));
41134
+ return /*#__PURE__*/React__namespace.createElement("div", {
41135
+ className: "draggy-boxy-thing orderer " + "height-" + this.props.height + " " + "layout-" + this.props.layout + " " + "above-scratchpad blank-background " + "perseus-clearfix " + ClassNames.INTERACTIVE
41136
+ // eslint-disable-next-line react/no-string-refs
41137
+ ,
41138
+ ref: "orderer"
41139
+ }, bank, sortable);
41140
+ }
41037
41141
  }
41038
41142
  ___default["default"].extend(Orderer, {
41039
41143
  validate: function (state, rubric) {
@@ -41847,8 +41951,6 @@ class HighlightSetRenderer extends React__namespace.PureComponent {
41847
41951
  hoveredHighlightKey: null,
41848
41952
  hoveringTooltipFor: null
41849
41953
  };
41850
-
41851
- // eslint-disable-next-line react/sort-comp
41852
41954
  _highlightRenderers = {};
41853
41955
  componentDidMount() {
41854
41956
  this._updateEditListeners(false, this.props.editable);
@@ -42184,8 +42286,6 @@ class HighlightingUI extends React__namespace.PureComponent {
42184
42286
  */
42185
42287
  class WordIndexer extends React__namespace.PureComponent {
42186
42288
  _container;
42187
- /* eslint-enable react/sort-comp */
42188
-
42189
42289
  componentDidMount() {
42190
42290
  this._sendWordsUpdate();
42191
42291
  }
@@ -42447,7 +42547,6 @@ const styles$8 = aphrodite.StyleSheet.create({
42447
42547
  }
42448
42548
  });
42449
42549
 
42450
- /* eslint-disable react/sort-comp */
42451
42550
  function getInitialParseState() {
42452
42551
  return {
42453
42552
  currentRef: [],
@@ -42462,16 +42561,15 @@ function getInitialParseState() {
42462
42561
  };
42463
42562
  }
42464
42563
  class RefStart extends React__namespace.Component {
42564
+ // @ts-expect-error - TS2322 - Type '() => React.ReactNode' is not assignable to type '() => ReactElement<any, string | JSXElementConstructor<any>>'.
42565
+ getRefContent = () => {
42566
+ return this.props.refContent;
42567
+ };
42465
42568
  render() {
42466
42569
  return /*#__PURE__*/React__namespace.createElement("span", {
42467
42570
  style: REF_STYLE
42468
42571
  }, "_");
42469
42572
  }
42470
-
42471
- // @ts-expect-error - TS2322 - Type '() => React.ReactNode' is not assignable to type '() => ReactElement<any, string | JSXElementConstructor<any>>'.
42472
- getRefContent = () => {
42473
- return this.props.refContent;
42474
- };
42475
42573
  }
42476
42574
  class RefEnd extends React__namespace.Component {
42477
42575
  render() {
@@ -42870,6 +42968,14 @@ class Passage extends React__namespace.Component {
42870
42968
  startLineNumbersAfter: 0,
42871
42969
  stylesAreApplied: false
42872
42970
  };
42971
+ static validate(state, rubric) {
42972
+ return {
42973
+ type: "points",
42974
+ earned: 0,
42975
+ total: 0,
42976
+ message: null
42977
+ };
42978
+ }
42873
42979
  componentDidMount() {
42874
42980
  this._updateState();
42875
42981
 
@@ -43091,17 +43197,6 @@ class Passage extends React__namespace.Component {
43091
43197
  return Passage.validate(this.getUserInput(), rubric);
43092
43198
  }
43093
43199
 
43094
- /* eslint-disable react/sort-comp */
43095
- static validate(state, rubric) {
43096
- return {
43097
- type: "points",
43098
- earned: 0,
43099
- total: 0,
43100
- message: null
43101
- };
43102
- }
43103
- /* eslint-enable react/sort-comp */
43104
-
43105
43200
  /**
43106
43201
  * Rendering
43107
43202
  *
@@ -43308,7 +43403,10 @@ var PassageRefTarget$1 = {
43308
43403
  isLintable: true
43309
43404
  };
43310
43405
 
43311
- /* eslint-disable react/forbid-prop-types, react/sort-comp */
43406
+ /**
43407
+ * This is a PhET simulation widget. It is used for rendering simulations
43408
+ * from https://phet.colorado.edu/.
43409
+ */
43312
43410
 
43313
43411
  // For returning user input, but currently the PhET widget
43314
43412
  // does not support accessing user input
@@ -43325,9 +43423,6 @@ class PhetSimulation extends React__namespace.Component {
43325
43423
  super(props);
43326
43424
  this.locale = this.getPhetCompatibleLocale(getDependencies().kaLocale);
43327
43425
  }
43328
- getUserInput() {
43329
- return null;
43330
- }
43331
43426
  async componentDidMount() {
43332
43427
  await this.updateSimState(this.props.url);
43333
43428
  }
@@ -43337,66 +43432,9 @@ class PhetSimulation extends React__namespace.Component {
43337
43432
  await this.updateSimState(this.props.url);
43338
43433
  }
43339
43434
  }
43340
- render() {
43341
- // We sandbox the iframe so that we allowlist only the functionality
43342
- // that we need. This makes it safer to present third-party content
43343
- // from the PhET website.
43344
- // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
43345
- const sandboxProperties = "allow-same-origin allow-scripts";
43346
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
43347
- style: styles$6.container
43348
- }, this.state.banner !== null &&
43349
- /*#__PURE__*/
43350
- // TODO(anna): Make this banner focusable
43351
- React__namespace.createElement(wonderBlocksCore.View, {
43352
- style: {
43353
- marginBottom: phoneMargin
43354
- }
43355
- }, /*#__PURE__*/React__namespace.createElement(Banner__default["default"], {
43356
- layout: "floating",
43357
- kind: this.state.banner.kind,
43358
- text: this.state.banner.message
43359
- })), /*#__PURE__*/React__namespace.createElement("iframe", {
43360
- ref: this.iframeRef,
43361
- title: this.props.description,
43362
- sandbox: sandboxProperties,
43363
- style: {
43364
- minWidth: 400,
43365
- height: 360,
43366
- width: "100%",
43367
- borderWidth: 0
43368
- },
43369
- src: this.state.url?.toString(),
43370
- allow: "fullscreen"
43371
- }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
43372
- icon: cornersOutIcon__default["default"],
43373
- onClick: () => {
43374
- this.iframeRef.current?.requestFullscreen();
43375
- },
43376
- kind: "secondary",
43377
- "aria-label": "Fullscreen",
43378
- style: {
43379
- marginTop: 5,
43380
- marginBottom: 5,
43381
- alignSelf: "flex-end"
43382
- },
43383
- disabled: this.state.url === null
43384
- }));
43435
+ getUserInput() {
43436
+ return null;
43385
43437
  }
43386
- change = (() => {
43387
- var _this = this;
43388
- return function () {
43389
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
43390
- args[_key] = arguments[_key];
43391
- }
43392
- // @ts-expect-error - TS2345 - Argument of type 'readonly unknown[]' is not assignable to parameter of type 'any[]'.
43393
- return change.apply(_this, args);
43394
- };
43395
- })();
43396
- simpleValidate = rubric => {
43397
- // @ts-expect-error - TS2339 - Property 'validate' does not exist on type 'typeof PhetSimulation'.
43398
- return PhetSimulation.validate(this.getUserInput(), rubric);
43399
- };
43400
43438
 
43401
43439
  // kaLocales and PhET locales use different formats and abbreviations.
43402
43440
  // PhET accepts different formats, i.e. kaLocale's hyphens, but it does not accept
@@ -43481,6 +43519,51 @@ class PhetSimulation extends React__namespace.Component {
43481
43519
  }
43482
43520
  return true;
43483
43521
  }
43522
+ render() {
43523
+ // We sandbox the iframe so that we allowlist only the functionality
43524
+ // that we need. This makes it safer to present third-party content
43525
+ // from the PhET website.
43526
+ // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
43527
+ const sandboxProperties = "allow-same-origin allow-scripts";
43528
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
43529
+ style: styles$6.container
43530
+ }, this.state.banner !== null &&
43531
+ /*#__PURE__*/
43532
+ // TODO(anna): Make this banner focusable
43533
+ React__namespace.createElement(wonderBlocksCore.View, {
43534
+ style: {
43535
+ marginBottom: phoneMargin
43536
+ }
43537
+ }, /*#__PURE__*/React__namespace.createElement(Banner__default["default"], {
43538
+ layout: "floating",
43539
+ kind: this.state.banner.kind,
43540
+ text: this.state.banner.message
43541
+ })), /*#__PURE__*/React__namespace.createElement("iframe", {
43542
+ ref: this.iframeRef,
43543
+ title: this.props.description,
43544
+ sandbox: sandboxProperties,
43545
+ style: {
43546
+ height: 225,
43547
+ width: "100%",
43548
+ borderWidth: 0
43549
+ },
43550
+ src: this.state.url?.toString(),
43551
+ allow: "fullscreen"
43552
+ }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
43553
+ icon: cornersOutIcon__default["default"],
43554
+ onClick: () => {
43555
+ this.iframeRef.current?.requestFullscreen();
43556
+ },
43557
+ kind: "secondary",
43558
+ "aria-label": "Fullscreen",
43559
+ style: {
43560
+ marginTop: 5,
43561
+ marginBottom: 5,
43562
+ alignSelf: "flex-end"
43563
+ },
43564
+ disabled: this.state.url === null
43565
+ }));
43566
+ }
43484
43567
  }
43485
43568
 
43486
43569
  // Setting URL to null will display an error message in the iframe
@@ -43495,24 +43578,23 @@ const makeSafeUrl = (urlString, locale) => {
43495
43578
  url.searchParams.set("locale", locale);
43496
43579
  return url;
43497
43580
  };
43498
- var PhetSimulation$1 = {
43499
- name: "phet-simulation",
43500
- displayName: "PhET Simulation",
43501
- widget: PhetSimulation,
43502
- // Hides widget from content creators until full release
43503
- hidden: true,
43504
- isLintable: true
43505
- };
43506
43581
  const styles$6 = aphrodite.StyleSheet.create({
43507
43582
  container: {
43508
43583
  borderRadius: borderRadiusLarge,
43509
43584
  borderWidth: 1,
43510
43585
  borderColor: basicBorderColor,
43511
- padding: phoneMargin,
43586
+ padding: wonderBlocksTokens.spacing.medium_16,
43512
43587
  paddingBottom: 0,
43513
- width: 650
43588
+ // Include space for medium_16 padding on each side
43589
+ width: 400 + wonderBlocksTokens.spacing.xLarge_32
43514
43590
  }
43515
43591
  });
43592
+ var PhetSimulation$1 = {
43593
+ name: "phet-simulation",
43594
+ displayName: "PhET Simulation",
43595
+ widget: PhetSimulation,
43596
+ isLintable: true
43597
+ };
43516
43598
 
43517
43599
  /* eslint-disable react/no-unsafe */
43518
43600
  const {
@@ -44567,65 +44649,6 @@ class Table extends React__namespace.Component {
44567
44649
  _getColumns = () => {
44568
44650
  return this.props.answers[0].length;
44569
44651
  };
44570
- render() {
44571
- const rows = this._getRows();
44572
- const columns = this._getColumns();
44573
- const headers = this.props.headers;
44574
- let InputComponent;
44575
- let inputStyle;
44576
- const extraInputProps = {};
44577
- if (this.props.apiOptions.customKeypad) {
44578
- InputComponent = SimpleKeypadInput;
44579
- // NOTE(charlie): This is intended to match the "width: 80px" in
44580
- // input in table.less. Those values should be kept in-sync.
44581
- inputStyle = {
44582
- width: 80
44583
- };
44584
- extraInputProps.keypadElement = this.props.keypadElement;
44585
- } else {
44586
- InputComponent = "input";
44587
- inputStyle = {};
44588
- }
44589
- return /*#__PURE__*/React__namespace.createElement("table", {
44590
- className: "perseus-widget-table-of-values non-markdown"
44591
- }, /*#__PURE__*/React__namespace.createElement("thead", null, /*#__PURE__*/React__namespace.createElement("tr", null, ___default["default"].map(headers, (header, i) => {
44592
- if (this.props.editableHeaders) {
44593
- return /*#__PURE__*/React__namespace.createElement("th", {
44594
- key: i
44595
- }, /*#__PURE__*/React__namespace.createElement(this.props.Editor, {
44596
- ref: "columnHeader" + i,
44597
- apiOptions: this.props.apiOptions,
44598
- content: header,
44599
- widgetEnabled: false,
44600
- onChange: ___default["default"].partial(this.onHeaderChange, i)
44601
- }));
44602
- }
44603
- return /*#__PURE__*/React__namespace.createElement("th", {
44604
- key: i
44605
- }, /*#__PURE__*/React__namespace.createElement(Renderer, {
44606
- content: header,
44607
- linterContext: this.props.linterContext,
44608
- strings: this.context.strings
44609
- }));
44610
- }))), /*#__PURE__*/React__namespace.createElement("tbody", null, ___default["default"](rows).times(r => {
44611
- return /*#__PURE__*/React__namespace.createElement("tr", {
44612
- key: r
44613
- }, ___default["default"](columns).times(c => {
44614
- return /*#__PURE__*/React__namespace.createElement("td", {
44615
- key: c
44616
- }, /*#__PURE__*/React__namespace.createElement(InputComponent, _extends({
44617
- ref: getRefForPath(getInputPath(r, c)),
44618
- type: "text",
44619
- value: this.props.answers[r][c],
44620
- disabled: this.props.apiOptions.readOnly,
44621
- onFocus: ___default["default"].partial(this._handleFocus, getInputPath(r, c)),
44622
- onBlur: ___default["default"].partial(this._handleBlur, getInputPath(r, c)),
44623
- onChange: ___default["default"].partial(this.onValueChange, r, c),
44624
- style: inputStyle
44625
- }, extraInputProps)));
44626
- }));
44627
- })));
44628
- }
44629
44652
  getUserInput = () => {
44630
44653
  return ___default["default"].map(this.props.answers, ___default["default"].clone);
44631
44654
  };
@@ -44717,6 +44740,65 @@ class Table extends React__namespace.Component {
44717
44740
  answers: answers
44718
44741
  }, cb);
44719
44742
  };
44743
+ render() {
44744
+ const rows = this._getRows();
44745
+ const columns = this._getColumns();
44746
+ const headers = this.props.headers;
44747
+ let InputComponent;
44748
+ let inputStyle;
44749
+ const extraInputProps = {};
44750
+ if (this.props.apiOptions.customKeypad) {
44751
+ InputComponent = SimpleKeypadInput;
44752
+ // NOTE(charlie): This is intended to match the "width: 80px" in
44753
+ // input in table.less. Those values should be kept in-sync.
44754
+ inputStyle = {
44755
+ width: 80
44756
+ };
44757
+ extraInputProps.keypadElement = this.props.keypadElement;
44758
+ } else {
44759
+ InputComponent = "input";
44760
+ inputStyle = {};
44761
+ }
44762
+ return /*#__PURE__*/React__namespace.createElement("table", {
44763
+ className: "perseus-widget-table-of-values non-markdown"
44764
+ }, /*#__PURE__*/React__namespace.createElement("thead", null, /*#__PURE__*/React__namespace.createElement("tr", null, ___default["default"].map(headers, (header, i) => {
44765
+ if (this.props.editableHeaders) {
44766
+ return /*#__PURE__*/React__namespace.createElement("th", {
44767
+ key: i
44768
+ }, /*#__PURE__*/React__namespace.createElement(this.props.Editor, {
44769
+ ref: "columnHeader" + i,
44770
+ apiOptions: this.props.apiOptions,
44771
+ content: header,
44772
+ widgetEnabled: false,
44773
+ onChange: ___default["default"].partial(this.onHeaderChange, i)
44774
+ }));
44775
+ }
44776
+ return /*#__PURE__*/React__namespace.createElement("th", {
44777
+ key: i
44778
+ }, /*#__PURE__*/React__namespace.createElement(Renderer, {
44779
+ content: header,
44780
+ linterContext: this.props.linterContext,
44781
+ strings: this.context.strings
44782
+ }));
44783
+ }))), /*#__PURE__*/React__namespace.createElement("tbody", null, ___default["default"](rows).times(r => {
44784
+ return /*#__PURE__*/React__namespace.createElement("tr", {
44785
+ key: r
44786
+ }, ___default["default"](columns).times(c => {
44787
+ return /*#__PURE__*/React__namespace.createElement("td", {
44788
+ key: c
44789
+ }, /*#__PURE__*/React__namespace.createElement(InputComponent, _extends({
44790
+ ref: getRefForPath(getInputPath(r, c)),
44791
+ type: "text",
44792
+ value: this.props.answers[r][c],
44793
+ disabled: this.props.apiOptions.readOnly,
44794
+ onFocus: ___default["default"].partial(this._handleFocus, getInputPath(r, c)),
44795
+ onBlur: ___default["default"].partial(this._handleBlur, getInputPath(r, c)),
44796
+ onChange: ___default["default"].partial(this.onValueChange, r, c),
44797
+ style: inputStyle
44798
+ }, extraInputProps)));
44799
+ }));
44800
+ })));
44801
+ }
44720
44802
  }
44721
44803
  ___default["default"].extend(Table, {
44722
44804
  validate: function (state, rubric, strings) {
@@ -45015,7 +45097,7 @@ const init = function (options) {
45015
45097
 
45016
45098
  // This file is processed by a Rollup plugin (replace) to inject the production
45017
45099
  const libName = "@khanacademy/perseus";
45018
- const libVersion = "31.0.1";
45100
+ const libVersion = "32.0.0";
45019
45101
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
45020
45102
 
45021
45103
  const apiVersion = {
@@ -46827,8 +46909,6 @@ class MultiRenderer extends React__namespace.Component {
46827
46909
  // Keep state in sync with props.
46828
46910
  this.state = this._tryMakeRendererState(this.props);
46829
46911
  }
46830
- /* eslint-enable react/sort-comp */
46831
-
46832
46912
  UNSAFE_componentWillReceiveProps(nextProps) {
46833
46913
  // Keep state in sync with props.
46834
46914
  if (nextProps.item !== this.props.item) {
@@ -48710,6 +48790,7 @@ exports.itemVersion = ItemVersion;
48710
48790
  exports.libVersion = libVersion;
48711
48791
  exports.lockedFigureColors = lockedFigureColors;
48712
48792
  exports.lockedFigureFillStyles = lockedFigureFillStyles;
48793
+ exports.makeSafeUrl = makeSafeUrl;
48713
48794
  exports.mediaQueries = mediaQueries;
48714
48795
  exports.parsePerseusItem = parsePerseusItem;
48715
48796
  exports.plotterPlotTypes = plotterPlotTypes;