@khanacademy/perseus-editor 13.1.0 → 14.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/all-editors.d.ts +1 -4
  2. package/dist/components/hover-behavior.d.ts +2 -2
  3. package/dist/components/widget-editor.d.ts +1 -1
  4. package/dist/es/index.js +187 -624
  5. package/dist/es/index.js.map +1 -1
  6. package/dist/index.d.ts +2 -2
  7. package/dist/index.js +745 -1210
  8. package/dist/index.js.map +1 -1
  9. package/dist/widgets/expression-editor.d.ts +1 -1
  10. package/dist/widgets/graded-group-editor.d.ts +1 -1
  11. package/dist/widgets/grapher-editor.d.ts +1 -1
  12. package/dist/widgets/group-editor.d.ts +1 -1
  13. package/dist/widgets/iframe-editor.d.ts +1 -1
  14. package/dist/widgets/image-editor.d.ts +2 -2
  15. package/dist/widgets/input-number-editor.d.ts +1 -1
  16. package/dist/widgets/interactive-graph-editor.d.ts +30 -38
  17. package/dist/widgets/matcher-editor.d.ts +1 -1
  18. package/dist/widgets/matrix-editor.d.ts +1 -1
  19. package/dist/widgets/measurer-editor.d.ts +1 -1
  20. package/dist/widgets/numeric-input-editor.d.ts +1 -1
  21. package/dist/widgets/orderer-editor.d.ts +1 -1
  22. package/dist/widgets/phet-simulation-editor.d.ts +2 -1
  23. package/dist/widgets/radio/editor.d.ts +1 -1
  24. package/dist/widgets/table-editor.d.ts +1 -1
  25. package/package.json +2 -2
  26. package/dist/all-widgets.d.ts +0 -22
  27. package/dist/testing-widgets.d.ts +0 -22
  28. package/dist/widgets/example-graphie-widget-editor.d.ts +0 -18
  29. package/dist/widgets/example-graphie-widget.d.ts +0 -61
  30. package/dist/widgets/example-widget-editor.d.ts +0 -20
  31. package/dist/widgets/example-widget.d.ts +0 -89
  32. package/dist/widgets/simple-markdown-tester-editor.d.ts +0 -21
  33. package/dist/widgets/simple-markdown-tester.d.ts +0 -54
package/dist/index.js CHANGED
@@ -19,12 +19,12 @@ var caretRight = require('@phosphor-icons/core/bold/caret-right-bold.svg');
19
19
  var classNames = require('classnames');
20
20
  var wonderBlocksForm = require('@khanacademy/wonder-blocks-form');
21
21
  var ReactDOM = require('react-dom');
22
- var kmath = require('@khanacademy/kmath');
23
22
  var KAS = require('@khanacademy/kas');
24
23
  var Button = require('@khanacademy/wonder-blocks-button');
25
24
  var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
26
25
  var wonderStuffCore = require('@khanacademy/wonder-stuff-core');
27
26
  var mathInput = require('@khanacademy/math-input');
27
+ var kmath = require('@khanacademy/kmath');
28
28
  var wonderBlocksDropdown = require('@khanacademy/wonder-blocks-dropdown');
29
29
  var wonderBlocksAccordion = require('@khanacademy/wonder-blocks-accordion');
30
30
  var IconButton = require('@khanacademy/wonder-blocks-icon-button');
@@ -91,7 +91,7 @@ var arrowCounterClockwise__default = /*#__PURE__*/_interopDefaultLegacy(arrowCou
91
91
 
92
92
  // This file is processed by a Rollup plugin (replace) to inject the production
93
93
  const libName = "@khanacademy/perseus-editor";
94
- const libVersion = "13.1.0";
94
+ const libVersion = "14.0.1";
95
95
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
96
96
 
97
97
  function _extends() {
@@ -188,16 +188,6 @@ const JsonEditor = createReactClass__default["default"]({
188
188
  this.setState(this.getInitialState());
189
189
  }
190
190
  },
191
- render: function () {
192
- const classes = "perseus-json-editor " + (this.state.valid ? "valid" : "invalid");
193
- return /*#__PURE__*/React__namespace.createElement("textarea", {
194
- className: classes,
195
- value: this.state.currentValue,
196
- onChange: this.handleChange,
197
- onKeyDown: this.handleKeyDown,
198
- onBlur: this.handleBlur
199
- });
200
- },
201
191
  handleKeyDown: function (e) {
202
192
  // This handler allows the tab character to be entered by pressing
203
193
  // tab, instead of jumping to the next (non-existant) field
@@ -264,6 +254,16 @@ const JsonEditor = createReactClass__default["default"]({
264
254
  valid: true
265
255
  });
266
256
  }
257
+ },
258
+ render: function () {
259
+ const classes = "perseus-json-editor " + (this.state.valid ? "valid" : "invalid");
260
+ return /*#__PURE__*/React__namespace.createElement("textarea", {
261
+ className: classes,
262
+ value: this.state.currentValue,
263
+ onChange: this.handleChange,
264
+ onKeyDown: this.handleKeyDown,
265
+ onBlur: this.handleBlur
266
+ });
267
267
  }
268
268
  });
269
269
 
@@ -25549,7 +25549,7 @@ const styles$N = aphrodite.StyleSheet.create({
25549
25549
  }
25550
25550
  });
25551
25551
 
25552
- /* eslint-disable react/no-unsafe, react/sort-comp */
25552
+ /* eslint-disable react/no-unsafe */
25553
25553
 
25554
25554
  /* Renders an EditorPage (or an ArticleEditor) as a non-controlled component.
25555
25555
  *
@@ -25568,10 +25568,6 @@ const StatefulEditorPage = createReactClass__default["default"]({
25568
25568
  componentClass: EditorPage
25569
25569
  };
25570
25570
  },
25571
- render: function () {
25572
- const Component = this.props.componentClass;
25573
- return /*#__PURE__*/React__namespace.createElement(Component, this.state);
25574
- },
25575
25571
  getInitialState: function () {
25576
25572
  return ___default["default"]({}).extend(___default["default"].omit(this.props, "componentClass"), {
25577
25573
  onChange: this.handleChange,
@@ -25581,9 +25577,6 @@ const StatefulEditorPage = createReactClass__default["default"]({
25581
25577
  componentDidMount: function () {
25582
25578
  this._isMounted = true;
25583
25579
  },
25584
- componentWillUnmount: function () {
25585
- this._isMounted = false;
25586
- },
25587
25580
  // getInitialState isn't called if the react component is re-rendered
25588
25581
  // in-place on the dom, in which case this is called instead, so we
25589
25582
  // need to update the state here.
@@ -25591,6 +25584,9 @@ const StatefulEditorPage = createReactClass__default["default"]({
25591
25584
  UNSAFE_componentWillReceiveProps: function (nextProps) {
25592
25585
  this.setState(___default["default"](nextProps).pick("apiOptions", "imageUploader", "developerMode", "problemNum", "previewDevice", "frameSource"));
25593
25586
  },
25587
+ componentWillUnmount: function () {
25588
+ this._isMounted = false;
25589
+ },
25594
25590
  getSaveWarnings: function () {
25595
25591
  // eslint-disable-next-line react/no-string-refs
25596
25592
  return this.refs.editor.getSaveWarnings();
@@ -25607,6 +25603,10 @@ const StatefulEditorPage = createReactClass__default["default"]({
25607
25603
  scorePreview: function () {
25608
25604
  // eslint-disable-next-line react/no-string-refs
25609
25605
  return this.refs.editor.scorePreview();
25606
+ },
25607
+ render: function () {
25608
+ const Component = this.props.componentClass;
25609
+ return /*#__PURE__*/React__namespace.createElement(Component, this.state);
25610
25610
  }
25611
25611
  });
25612
25612
 
@@ -25955,7 +25955,7 @@ class CSProgramEditor extends React__namespace.Component {
25955
25955
 
25956
25956
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
25957
25957
  const {
25958
- TextInput: TextInput$8
25958
+ TextInput: TextInput$7
25959
25959
  } = perseus.components;
25960
25960
  class DefinitionEditor extends React__namespace.Component {
25961
25961
  static propTypes = {
@@ -25989,7 +25989,7 @@ class DefinitionEditor extends React__namespace.Component {
25989
25989
  target: "_blank"
25990
25990
  }, "Definition style guide"), /*#__PURE__*/React__namespace.createElement("div", {
25991
25991
  className: "perseus-widget-row"
25992
- }, /*#__PURE__*/React__namespace.createElement("label", null, "Word to be defined:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$8, {
25992
+ }, /*#__PURE__*/React__namespace.createElement("label", null, "Word to be defined:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$7, {
25993
25993
  value: this.props.togglePrompt
25994
25994
  // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
25995
25995
  ,
@@ -26170,236 +26170,9 @@ class DropdownEditor extends React__namespace.Component {
26170
26170
  }
26171
26171
  }
26172
26172
 
26173
- /* eslint-disable @typescript-eslint/no-unused-vars, react/forbid-prop-types, react/sort-comp */
26174
- const {
26175
- Graphie
26176
- } = perseus.components;
26177
-
26178
- // @ts-expect-error - TS2339 - Property 'MovablePoint' does not exist on type 'typeof Graphie'.
26179
- const MovablePoint = Graphie.MovablePoint;
26180
- /**
26181
- * This is the widget's renderer. It shows up in the right column
26182
- * in the demo, and is what is visible to users, and where
26183
- * users enter their answers.
26184
- */
26185
- class ExampleGraphieWidget$1 extends React__namespace.Component {
26186
- static defaultProps = {
26187
- // We want to allow our coord to be null to test if the
26188
- // user has interacted with this widget yet when grading it
26189
- coord: null,
26190
- graph: {
26191
- box: [400, 400],
26192
- labels: ["x", "y"],
26193
- range: [[-10, 10], [-10, 10]],
26194
- step: [1, 1],
26195
- gridStep: [1, 1],
26196
- valid: true,
26197
- backgroundImage: null,
26198
- markings: "grid",
26199
- showProtractor: false
26200
- }
26201
- };
26202
-
26203
- /**
26204
- * This is the widget's grading function
26205
- */
26206
- static validate(state, rubric) {
26207
- if (state.coord == null) {
26208
- return {
26209
- type: "invalid",
26210
- message: null
26211
- };
26212
- }
26213
- if (kmath.point.equal(state.coord, rubric.correct)) {
26214
- return {
26215
- type: "points",
26216
- earned: 1,
26217
- total: 1,
26218
- message: null
26219
- };
26220
- }
26221
- return {
26222
- type: "points",
26223
- earned: 0,
26224
- total: 1,
26225
- message: null
26226
- };
26227
- }
26228
- getUserInput = () => {
26229
- return perseus.WidgetJsonifyDeprecated.getUserInput.call(this);
26230
- };
26231
- render() {
26232
- return /*#__PURE__*/React__namespace.createElement(Graphie
26233
- // eslint-disable-next-line react/no-string-refs
26234
- , {
26235
- ref: "graphie",
26236
- box: this.props.graph.box,
26237
- range: this.props.graph.range,
26238
- options: this.props.graph,
26239
- setup: this.setupGraphie,
26240
- setDrawingAreaAvailable: this.props.apiOptions?.setDrawingAreaAvailable
26241
- }, /*#__PURE__*/React__namespace.createElement(MovablePoint, {
26242
- pointSize: 5,
26243
- coord: this.props.coord || [0, 0],
26244
- constraints: [MovablePoint.constraints.snap(), MovablePoint.constraints.bound()],
26245
- onMove: this.movePoint
26246
- }));
26247
- }
26248
- change = (() => {
26249
- var _this = this;
26250
- return function () {
26251
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
26252
- args[_key] = arguments[_key];
26253
- }
26254
- return perseus.Changeable.change.apply(_this, args);
26255
- };
26256
- })();
26257
- movePoint = newCoord => {
26258
- // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
26259
- this.change({
26260
- coord: newCoord
26261
- });
26262
- };
26263
- _getGridConfig = options => {
26264
- return ___default["default"].map(options.step, function (step, i) {
26265
- return perseus.Util.gridDimensionConfig(step, options.range[i], options.box[i], options.gridStep[i]);
26266
- });
26267
- };
26268
- setupGraphie = (graphie, options) => {
26269
- const gridConfig = this._getGridConfig(options);
26270
- graphie.graphInit({
26271
- range: options.range,
26272
- scale: ___default["default"].pluck(gridConfig, "scale"),
26273
- axisArrows: "<->",
26274
- labelFormat: function (s) {
26275
- return "\\small{" + s + "}";
26276
- },
26277
- gridStep: options.gridStep,
26278
- tickStep: ___default["default"].pluck(gridConfig, "tickStep"),
26279
- labelStep: 1,
26280
- unityLabels: ___default["default"].pluck(gridConfig, "unityLabel")
26281
- });
26282
- graphie.label([0, options.range[1][1]], options.labels[1], "above");
26283
- };
26284
- simpleValidate = rubric => {
26285
- return ExampleGraphieWidget$1.validate(this.getUserInput(), rubric);
26286
- };
26287
- }
26288
-
26289
- /**
26290
- * For this widget to work, we must export it.
26291
- * We also must import this file in src/all-widgets.js
26292
- */
26293
- var ExampleGraphieWidget$2 = {
26294
- name: "example-graphie-widget",
26295
- displayName: "Example Graphie Widget",
26296
- hidden: true,
26297
- // Hides this widget from the Perseus.Editor widget select
26298
- widget: ExampleGraphieWidget$1
26299
- };
26300
-
26301
- const ExampleGraphieWidget = ExampleGraphieWidget$2.widget;
26302
- /**
26303
- * This is the widget's editor. This is what shows up on the left side
26304
- * of the screen in the demo page. Only the question writer sees this.
26305
- */
26306
- class ExampleGraphieWidgetEditor extends React__namespace.Component {
26307
- static propTypes = {
26308
- ...perseus.Changeable.propTypes
26309
- };
26310
- static widgetName = "example-graphie-widget";
26311
- static defaultProps = {
26312
- correct: [4, 4],
26313
- graph: {
26314
- box: [340, 340],
26315
- labels: ["x", "y"],
26316
- range: [[-10, 10], [-10, 10]],
26317
- step: [1, 1],
26318
- gridStep: [1, 1],
26319
- valid: true,
26320
- backgroundImage: null,
26321
- markings: "grid",
26322
- showProtractor: false
26323
- }
26324
- };
26325
- change = (() => {
26326
- var _this = this;
26327
- return function () {
26328
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
26329
- args[_key] = arguments[_key];
26330
- }
26331
- return perseus.Changeable.change.apply(_this, args);
26332
- };
26333
- })();
26334
- handleChange = newProps => {
26335
- if (newProps.coord) {
26336
- // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
26337
- this.change({
26338
- correct: newProps.coord
26339
- });
26340
- }
26341
- };
26342
- serialize = () => {
26343
- return perseus.EditorJsonify.serialize.call(this);
26344
- };
26345
- render() {
26346
- return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(ExampleGraphieWidget, {
26347
- graph: this.props.graph,
26348
- coord: this.props.correct,
26349
- onChange: this.handleChange,
26350
- apiOptions: this.props.apiOptions
26351
- }));
26352
- }
26353
- }
26354
-
26355
- /* eslint-disable react/sort-comp */
26356
- /**
26357
- * This is the widget's editor. This is what shows up on the left side
26358
- * of the screen in the demo. Only the question writer sees this.
26359
- */
26360
- class ExampleWidgetEditor extends React__namespace.Component {
26361
- static propTypes = {
26362
- ...perseus.Changeable.propTypes
26363
- };
26364
- static widgetName = "example-widget";
26365
- static defaultProps = {
26366
- correct: ""
26367
- };
26368
- input = /*#__PURE__*/React__namespace.createRef();
26369
- handleAnswerChange = event => {
26370
- // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
26371
- this.change({
26372
- correct: event.target.value
26373
- });
26374
- };
26375
- render() {
26376
- return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, "Correct answer:", /*#__PURE__*/React__namespace.createElement("input", {
26377
- value: this.props.correct,
26378
- onChange: this.handleAnswerChange,
26379
- ref: this.input
26380
- })));
26381
- }
26382
- change = (() => {
26383
- var _this = this;
26384
- return function () {
26385
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
26386
- args[_key] = arguments[_key];
26387
- }
26388
- return perseus.Changeable.change.apply(_this, args);
26389
- };
26390
- })();
26391
- focus = () => {
26392
- this.input.current?.focus();
26393
- return true;
26394
- };
26395
- serialize = () => {
26396
- return perseus.EditorJsonify.serialize.call(this);
26397
- };
26398
- }
26399
-
26400
26173
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
26401
26174
  const {
26402
- TextInput: TextInput$7
26175
+ TextInput: TextInput$6
26403
26176
  } = perseus.components;
26404
26177
  const defaultExplanationProps = {
26405
26178
  showPrompt: "Explain",
@@ -26436,14 +26209,14 @@ class ExplanationEditor extends React__namespace.Component {
26436
26209
  className: "perseus-widget-explanation-editor"
26437
26210
  }, /*#__PURE__*/React__namespace.createElement("div", {
26438
26211
  className: "perseus-widget-row"
26439
- }, /*#__PURE__*/React__namespace.createElement("label", null, "Prompt to show explanation:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$7, {
26212
+ }, /*#__PURE__*/React__namespace.createElement("label", null, "Prompt to show explanation:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$6, {
26440
26213
  value: this.props.showPrompt
26441
26214
  // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
26442
26215
  ,
26443
26216
  onChange: this.change("showPrompt")
26444
26217
  }))), /*#__PURE__*/React__namespace.createElement("div", {
26445
26218
  className: "perseus-widget-row"
26446
- }, /*#__PURE__*/React__namespace.createElement("label", null, "Prompt to hide explanation:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$7, {
26219
+ }, /*#__PURE__*/React__namespace.createElement("label", null, "Prompt to hide explanation:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$6, {
26447
26220
  value: this.props.hidePrompt
26448
26221
  // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
26449
26222
  ,
@@ -26718,101 +26491,6 @@ class ExpressionEditor extends React__namespace.Component {
26718
26491
  }
26719
26492
  return perseus.Changeable.change.apply(this, args);
26720
26493
  }
26721
- render() {
26722
- const answerOptions = this.props.answerForms.map(ans => {
26723
- const key = parseAnswerKey(ans);
26724
- const expressionProps = {
26725
- // note we're using
26726
- // *this.props*.{times,functions,buttonSets} since each
26727
- // answer area has the same settings for those
26728
- times: this.props.times,
26729
- functions: this.props.functions,
26730
- buttonSets: this.props.buttonSets,
26731
- buttonsVisible: "focused",
26732
- form: ans.form,
26733
- simplify: ans.simplify,
26734
- value: ans.value,
26735
- onChange: props => this.updateForm(key, props),
26736
- trackInteraction: () => {},
26737
- widgetId: this.props.widgetId + "-" + ans.key
26738
- };
26739
- return lens(ans).merge([], {
26740
- key,
26741
- draggable: true,
26742
- onChange: props => this.updateForm(Number.parseInt(ans.key ?? ""), props),
26743
- onDelete: () => this.handleRemoveForm(key),
26744
- expressionProps: expressionProps
26745
- }).freeze();
26746
- }).map(obj => /*#__PURE__*/React__namespace.createElement(AnswerOption, _extends({
26747
- key: obj.key
26748
- }, obj)));
26749
- const sortable = /*#__PURE__*/React__namespace.createElement(SortableArea, {
26750
- components: answerOptions,
26751
- onReorder: this.handleReorder
26752
- });
26753
-
26754
- // checkboxes to choose which sets of input buttons are shown
26755
- const buttonSetChoices = buttonSetsList.map(name => {
26756
- // The first one gets special cased to always be checked, disabled,
26757
- // and float left.
26758
- const isBasic = name === "basic";
26759
- const checked = this.props.buttonSets.includes(name) || isBasic;
26760
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26761
- key: name,
26762
- label: name,
26763
- checked: checked,
26764
- disabled: isBasic,
26765
- onChange: () => this.handleButtonSet(name)
26766
- });
26767
- });
26768
- buttonSetChoices.unshift( /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26769
- key: "show \xF7 button",
26770
- label: "show \xF7 button",
26771
- checked: this.props.buttonSets.includes("basic+div"),
26772
- onChange: this.handleToggleDiv
26773
- }));
26774
- return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingSmall, null, "Global Options"), /*#__PURE__*/React__namespace.createElement("div", {
26775
- className: aphrodite.css(styles$L.paddedY)
26776
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26777
- label: "Visible label",
26778
- value: this.props.visibleLabel || "",
26779
- onChange: this.change("visibleLabel")
26780
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "Optional visible text; strongly encouraged to help learners using dictation software, but can be omitted if the surrounding content provides enough context."))), /*#__PURE__*/React__namespace.createElement("div", {
26781
- className: aphrodite.css(styles$L.paddedY)
26782
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26783
- label: "Aria label",
26784
- value: this.props.ariaLabel || "",
26785
- onChange: this.change("ariaLabel")
26786
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writting accessible labels, please see", " ", /*#__PURE__*/React__namespace.createElement("a", {
26787
- href: "https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",
26788
- target: "_blank"
26789
- }, "this article.")))), /*#__PURE__*/React__namespace.createElement("div", {
26790
- className: aphrodite.css(styles$L.paddedY)
26791
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26792
- label: "Function variables",
26793
- value: this.state.functionsInternal,
26794
- onChange: this.handleFunctions
26795
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "Single-letter variables listed here will be interpreted as functions. This let us know that f(x) means \"f of x\" and not \"f times x\"."))), /*#__PURE__*/React__namespace.createElement("div", {
26796
- className: aphrodite.css(styles$L.paddedY)
26797
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26798
- label: "Use \xD7 instead of \u22C5 for multiplication",
26799
- checked: this.props.times,
26800
- onChange: value => {
26801
- this.props.onChange({
26802
- times: value
26803
- });
26804
- }
26805
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "For pre-algebra problems this option displays multiplication as \\times instead of \\cdot in both the rendered output and the acceptable formats examples."))), /*#__PURE__*/React__namespace.createElement("div", {
26806
- className: aphrodite.css(styles$L.paddedY)
26807
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingXSmall, null, "Button Sets"), buttonSetChoices), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingSmall, null, "Answers"), /*#__PURE__*/React__namespace.createElement("p", {
26808
- style: {
26809
- margin: "4px 0"
26810
- }
26811
- }, "student responses area matched against these from top to bottom"), sortable, /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
26812
- size: "small",
26813
- onClick: this.newAnswer
26814
- }, "Add new answer")));
26815
- }
26816
26494
  serialize = () => {
26817
26495
  const formSerializables = ["value", "form", "simplify", "considered",
26818
26496
  // it's a little weird to serialize the react key, but saves some
@@ -26953,6 +26631,101 @@ class ExpressionEditor extends React__namespace.Component {
26953
26631
  newProps.functions = value.split(/[ ,]+/).filter(wonderStuffCore.isTruthy);
26954
26632
  this.props.onChange(newProps);
26955
26633
  };
26634
+ render() {
26635
+ const answerOptions = this.props.answerForms.map(ans => {
26636
+ const key = parseAnswerKey(ans);
26637
+ const expressionProps = {
26638
+ // note we're using
26639
+ // *this.props*.{times,functions,buttonSets} since each
26640
+ // answer area has the same settings for those
26641
+ times: this.props.times,
26642
+ functions: this.props.functions,
26643
+ buttonSets: this.props.buttonSets,
26644
+ buttonsVisible: "focused",
26645
+ form: ans.form,
26646
+ simplify: ans.simplify,
26647
+ value: ans.value,
26648
+ onChange: props => this.updateForm(key, props),
26649
+ trackInteraction: () => {},
26650
+ widgetId: this.props.widgetId + "-" + ans.key
26651
+ };
26652
+ return lens(ans).merge([], {
26653
+ key,
26654
+ draggable: true,
26655
+ onChange: props => this.updateForm(Number.parseInt(ans.key ?? ""), props),
26656
+ onDelete: () => this.handleRemoveForm(key),
26657
+ expressionProps: expressionProps
26658
+ }).freeze();
26659
+ }).map(obj => /*#__PURE__*/React__namespace.createElement(AnswerOption, _extends({
26660
+ key: obj.key
26661
+ }, obj)));
26662
+ const sortable = /*#__PURE__*/React__namespace.createElement(SortableArea, {
26663
+ components: answerOptions,
26664
+ onReorder: this.handleReorder
26665
+ });
26666
+
26667
+ // checkboxes to choose which sets of input buttons are shown
26668
+ const buttonSetChoices = buttonSetsList.map(name => {
26669
+ // The first one gets special cased to always be checked, disabled,
26670
+ // and float left.
26671
+ const isBasic = name === "basic";
26672
+ const checked = this.props.buttonSets.includes(name) || isBasic;
26673
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26674
+ key: name,
26675
+ label: name,
26676
+ checked: checked,
26677
+ disabled: isBasic,
26678
+ onChange: () => this.handleButtonSet(name)
26679
+ });
26680
+ });
26681
+ buttonSetChoices.unshift( /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26682
+ key: "show \xF7 button",
26683
+ label: "show \xF7 button",
26684
+ checked: this.props.buttonSets.includes("basic+div"),
26685
+ onChange: this.handleToggleDiv
26686
+ }));
26687
+ return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingSmall, null, "Global Options"), /*#__PURE__*/React__namespace.createElement("div", {
26688
+ className: aphrodite.css(styles$L.paddedY)
26689
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26690
+ label: "Visible label",
26691
+ value: this.props.visibleLabel || "",
26692
+ onChange: this.change("visibleLabel")
26693
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "Optional visible text; strongly encouraged to help learners using dictation software, but can be omitted if the surrounding content provides enough context."))), /*#__PURE__*/React__namespace.createElement("div", {
26694
+ className: aphrodite.css(styles$L.paddedY)
26695
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26696
+ label: "Aria label",
26697
+ value: this.props.ariaLabel || "",
26698
+ onChange: this.change("ariaLabel")
26699
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writting accessible labels, please see", " ", /*#__PURE__*/React__namespace.createElement("a", {
26700
+ href: "https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",
26701
+ target: "_blank"
26702
+ }, "this article.")))), /*#__PURE__*/React__namespace.createElement("div", {
26703
+ className: aphrodite.css(styles$L.paddedY)
26704
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26705
+ label: "Function variables",
26706
+ value: this.state.functionsInternal,
26707
+ onChange: this.handleFunctions
26708
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "Single-letter variables listed here will be interpreted as functions. This let us know that f(x) means \"f of x\" and not \"f times x\"."))), /*#__PURE__*/React__namespace.createElement("div", {
26709
+ className: aphrodite.css(styles$L.paddedY)
26710
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26711
+ label: "Use \xD7 instead of \u22C5 for multiplication",
26712
+ checked: this.props.times,
26713
+ onChange: value => {
26714
+ this.props.onChange({
26715
+ times: value
26716
+ });
26717
+ }
26718
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "For pre-algebra problems this option displays multiplication as \\times instead of \\cdot in both the rendered output and the acceptable formats examples."))), /*#__PURE__*/React__namespace.createElement("div", {
26719
+ className: aphrodite.css(styles$L.paddedY)
26720
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingXSmall, null, "Button Sets"), buttonSetChoices), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingSmall, null, "Answers"), /*#__PURE__*/React__namespace.createElement("p", {
26721
+ style: {
26722
+ margin: "4px 0"
26723
+ }
26724
+ }, "student responses area matched against these from top to bottom"), sortable, /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
26725
+ size: "small",
26726
+ onClick: this.newAnswer
26727
+ }, "Add new answer")));
26728
+ }
26956
26729
  }
26957
26730
 
26958
26731
  // Find the next element in arr after val, wrapping around to the first.
@@ -26974,6 +26747,25 @@ class AnswerOption extends React__namespace.Component {
26974
26747
  return perseus.Changeable.change.apply(_this, args);
26975
26748
  };
26976
26749
  })();
26750
+ handleImSure = () => {
26751
+ this.props.onDelete();
26752
+ };
26753
+ handleCancelDelete = () => {
26754
+ this.setState({
26755
+ deleteFocused: false
26756
+ });
26757
+ };
26758
+ handleDelete = () => {
26759
+ this.setState({
26760
+ deleteFocused: true
26761
+ });
26762
+ };
26763
+ toggleConsidered = () => {
26764
+ const newVal = findNextIn(perseus.PerseusExpressionAnswerFormConsidered, this.props.considered);
26765
+ this.change({
26766
+ considered: newVal
26767
+ });
26768
+ };
26977
26769
  render() {
26978
26770
  const removeButton = this.state.deleteFocused ? /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
26979
26771
  size: "small",
@@ -27025,25 +26817,6 @@ class AnswerOption extends React__namespace.Component {
27025
26817
  className: aphrodite.css(styles$L.buttonRow, styles$L.paddedY)
27026
26818
  }, removeButton)));
27027
26819
  }
27028
- handleImSure = () => {
27029
- this.props.onDelete();
27030
- };
27031
- handleCancelDelete = () => {
27032
- this.setState({
27033
- deleteFocused: false
27034
- });
27035
- };
27036
- handleDelete = () => {
27037
- this.setState({
27038
- deleteFocused: true
27039
- });
27040
- };
27041
- toggleConsidered = () => {
27042
- const newVal = findNextIn(perseus.PerseusExpressionAnswerFormConsidered, this.props.considered);
27043
- this.change({
27044
- considered: newVal
27045
- });
27046
- };
27047
26820
  }
27048
26821
  const styles$L = aphrodite.StyleSheet.create({
27049
26822
  paddedX: {
@@ -27092,7 +26865,7 @@ const styles$L = aphrodite.StyleSheet.create({
27092
26865
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
27093
26866
  const {
27094
26867
  InlineIcon: InlineIcon$3,
27095
- TextInput: TextInput$6
26868
+ TextInput: TextInput$5
27096
26869
  } = perseus.components;
27097
26870
  const {
27098
26871
  iconPlus: iconPlus$1,
@@ -27141,6 +26914,16 @@ class GradedGroupEditor extends React__namespace.Component {
27141
26914
  hint: null
27142
26915
  });
27143
26916
  };
26917
+ getSaveWarnings = () => {
26918
+ return this.editor.current?.getSaveWarnings();
26919
+ };
26920
+ serialize = () => {
26921
+ return {
26922
+ title: this.props.title,
26923
+ ...this.editor.current?.serialize(),
26924
+ hint: this.hintEditor.current?.serialize()
26925
+ };
26926
+ };
27144
26927
  render() {
27145
26928
  return /*#__PURE__*/React__namespace.createElement("div", {
27146
26929
  className: "perseus-group-editor"
@@ -27148,7 +26931,7 @@ class GradedGroupEditor extends React__namespace.Component {
27148
26931
  className: "perseus-widget-row"
27149
26932
  }, /*#__PURE__*/React__namespace.createElement("label", {
27150
26933
  className: aphrodite.css(styles$K.title)
27151
- }, "Title:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$6, {
26934
+ }, "Title:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$5, {
27152
26935
  value: this.props.title,
27153
26936
  className: aphrodite.css(styles$K.input)
27154
26937
  // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
@@ -27196,16 +26979,6 @@ class GradedGroupEditor extends React__namespace.Component {
27196
26979
  onClick: this.handleRemoveHint
27197
26980
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$3, iconTrash$2), " Remove this hint")));
27198
26981
  }
27199
- getSaveWarnings = () => {
27200
- return this.editor.current?.getSaveWarnings();
27201
- };
27202
- serialize = () => {
27203
- return {
27204
- title: this.props.title,
27205
- ...this.editor.current?.serialize(),
27206
- hint: this.hintEditor.current?.serialize()
27207
- };
27208
- };
27209
26982
  }
27210
26983
  const styles$K = aphrodite.StyleSheet.create({
27211
26984
  title: {
@@ -27839,6 +27612,26 @@ class GrapherEditor extends React__namespace.Component {
27839
27612
  return perseus.Changeable.change.apply(_this, args);
27840
27613
  };
27841
27614
  })();
27615
+ handleAvailableTypesChange = newAvailableTypes => {
27616
+ let correct = this.props.correct;
27617
+
27618
+ // If the currently 'correct' type is removed from the list of types,
27619
+ // we need to change it to avoid impossible questions.
27620
+ if (!___default["default"].contains(newAvailableTypes, this.props.correct.type)) {
27621
+ const graph = this.props.graph;
27622
+ const newType = chooseType(newAvailableTypes);
27623
+ correct = defaultPlotProps(newType, graph);
27624
+ }
27625
+ this.props.onChange({
27626
+ availableTypes: newAvailableTypes,
27627
+ correct: correct
27628
+ });
27629
+ };
27630
+ serialize = () => {
27631
+ return ___default["default"].chain(this.props).pick("correct", "availableTypes").extend({
27632
+ graph: ___default["default"].omit(this.props.graph, "box")
27633
+ }).value();
27634
+ };
27842
27635
  render() {
27843
27636
  const sizeClass = containerSizeClass$1.SMALL;
27844
27637
  let equationString;
@@ -27904,26 +27697,6 @@ class GrapherEditor extends React__namespace.Component {
27904
27697
  onChange: this.handleAvailableTypesChange
27905
27698
  })), graph);
27906
27699
  }
27907
- handleAvailableTypesChange = newAvailableTypes => {
27908
- let correct = this.props.correct;
27909
-
27910
- // If the currently 'correct' type is removed from the list of types,
27911
- // we need to change it to avoid impossible questions.
27912
- if (!___default["default"].contains(newAvailableTypes, this.props.correct.type)) {
27913
- const graph = this.props.graph;
27914
- const newType = chooseType(newAvailableTypes);
27915
- correct = defaultPlotProps(newType, graph);
27916
- }
27917
- this.props.onChange({
27918
- availableTypes: newAvailableTypes,
27919
- correct: correct
27920
- });
27921
- };
27922
- serialize = () => {
27923
- return ___default["default"].chain(this.props).pick("correct", "availableTypes").extend({
27924
- graph: ___default["default"].omit(this.props.graph, "box")
27925
- }).value();
27926
- };
27927
27700
  }
27928
27701
 
27929
27702
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
@@ -27946,20 +27719,6 @@ class GroupEditor extends React__namespace.Component {
27946
27719
  metadata: undefined
27947
27720
  };
27948
27721
  editor = /*#__PURE__*/React__namespace.createRef();
27949
- render() {
27950
- return /*#__PURE__*/React__namespace.createElement("div", {
27951
- className: "perseus-group-editor"
27952
- }, /*#__PURE__*/React__namespace.createElement("div", null, this._renderMetadataEditor()), /*#__PURE__*/React__namespace.createElement(Editor, {
27953
- ref: this.editor,
27954
- content: this.props.content,
27955
- widgets: this.props.widgets,
27956
- apiOptions: this.props.apiOptions,
27957
- images: this.props.images,
27958
- widgetEnabled: true,
27959
- immutableWidgets: false,
27960
- onChange: this.props.onChange
27961
- }));
27962
- }
27963
27722
  _renderMetadataEditor = () => {
27964
27723
  const GroupMetadataEditor = this.props.apiOptions.GroupMetadataEditor;
27965
27724
  return /*#__PURE__*/React__namespace.createElement(GroupMetadataEditor, {
@@ -27986,6 +27745,20 @@ class GroupEditor extends React__namespace.Component {
27986
27745
  metadata: this.props.metadata
27987
27746
  });
27988
27747
  };
27748
+ render() {
27749
+ return /*#__PURE__*/React__namespace.createElement("div", {
27750
+ className: "perseus-group-editor"
27751
+ }, /*#__PURE__*/React__namespace.createElement("div", null, this._renderMetadataEditor()), /*#__PURE__*/React__namespace.createElement(Editor, {
27752
+ ref: this.editor,
27753
+ content: this.props.content,
27754
+ widgets: this.props.widgets,
27755
+ apiOptions: this.props.apiOptions,
27756
+ images: this.props.images,
27757
+ widgetEnabled: true,
27758
+ immutableWidgets: false,
27759
+ onChange: this.props.onChange
27760
+ }));
27761
+ }
27989
27762
  }
27990
27763
 
27991
27764
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
@@ -28011,6 +27784,9 @@ class PairEditor extends React__namespace.Component {
28011
27784
  return perseus.Changeable.change.apply(_this, args);
28012
27785
  };
28013
27786
  })();
27787
+ serialize = () => {
27788
+ return perseus.EditorJsonify.serialize.call(this);
27789
+ };
28014
27790
  render() {
28015
27791
  return /*#__PURE__*/React__namespace.createElement("fieldset", null, /*#__PURE__*/React__namespace.createElement("label", null, "Name:", /*#__PURE__*/React__namespace.createElement(BlurInput, {
28016
27792
  value: this.props.name,
@@ -28020,9 +27796,6 @@ class PairEditor extends React__namespace.Component {
28020
27796
  onChange: this.change("value")
28021
27797
  })));
28022
27798
  }
28023
- serialize = () => {
28024
- return perseus.EditorJsonify.serialize.call(this);
28025
- };
28026
27799
  }
28027
27800
  /**
28028
27801
  * This is used for editing a set of name/value pairs.
@@ -28035,19 +27808,6 @@ class PairsEditor extends React__namespace.Component {
28035
27808
  value: PropTypes__default["default"].string
28036
27809
  })).isRequired
28037
27810
  };
28038
- render() {
28039
- const editors = ___default["default"].map(this.props.pairs, (pair, i) => {
28040
- return /*#__PURE__*/React__namespace.createElement(PairEditor, {
28041
- key: i,
28042
- name: pair.name,
28043
- value: pair.value
28044
- // eslint-disable-next-line react/jsx-no-bind
28045
- ,
28046
- onChange: this.handlePairChange.bind(this, i)
28047
- });
28048
- });
28049
- return /*#__PURE__*/React__namespace.createElement("div", null, editors);
28050
- }
28051
27811
  change = (() => {
28052
27812
  var _this2 = this;
28053
27813
  return function () {
@@ -28073,6 +27833,19 @@ class PairsEditor extends React__namespace.Component {
28073
27833
  serialize = () => {
28074
27834
  return perseus.EditorJsonify.serialize.call(this);
28075
27835
  };
27836
+ render() {
27837
+ const editors = ___default["default"].map(this.props.pairs, (pair, i) => {
27838
+ return /*#__PURE__*/React__namespace.createElement(PairEditor, {
27839
+ key: i,
27840
+ name: pair.name,
27841
+ value: pair.value
27842
+ // eslint-disable-next-line react/jsx-no-bind
27843
+ ,
27844
+ onChange: this.handlePairChange.bind(this, i)
27845
+ });
27846
+ });
27847
+ return /*#__PURE__*/React__namespace.createElement("div", null, editors);
27848
+ }
28076
27849
  }
28077
27850
  /**
28078
27851
  * This is the main editor for this widget, to specify all the options.
@@ -28102,6 +27875,15 @@ class IframeEditor extends React__namespace.Component {
28102
27875
  return perseus.Changeable.change.apply(_this3, args);
28103
27876
  };
28104
27877
  })();
27878
+ handleSettingsChange = settings => {
27879
+ // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
27880
+ this.change({
27881
+ settings: settings.pairs
27882
+ });
27883
+ };
27884
+ serialize = () => {
27885
+ return perseus.EditorJsonify.serialize.call(this);
27886
+ };
28105
27887
  render() {
28106
27888
  return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", {
28107
27889
  style: {
@@ -28145,18 +27927,9 @@ class IframeEditor extends React__namespace.Component {
28145
27927
  }
28146
27928
  }));
28147
27929
  }
28148
- handleSettingsChange = settings => {
28149
- // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
28150
- this.change({
28151
- settings: settings.pairs
28152
- });
28153
- };
28154
- serialize = () => {
28155
- return perseus.EditorJsonify.serialize.call(this);
28156
- };
28157
27930
  }
28158
27931
 
28159
- /* eslint-disable jsx-a11y/anchor-is-valid, react/sort-comp */
27932
+ /* eslint-disable jsx-a11y/anchor-is-valid */
28160
27933
  const {
28161
27934
  InfoTip: InfoTip$f,
28162
27935
  InlineIcon: InlineIcon$2,
@@ -28182,9 +27955,9 @@ const INTERNALLY_HOSTED_URL_RE = new RegExp("^(https?|web\\+graphie)://[^/]*" +
28182
27955
  */
28183
27956
  const captionAlignments = ["center", "above", "above right", "right", "below right", "below", "below left", "left", "above left"];
28184
27957
  class ImageEditor extends React__namespace.Component {
28185
- _isMounted = false;
28186
27958
  static displayName = "ImageEditor";
28187
27959
  static widgetName = "image";
27960
+ _isMounted = false;
28188
27961
  static defaultProps = {
28189
27962
  title: "",
28190
27963
  range: [defaultRange, defaultRange],
@@ -28205,48 +27978,6 @@ class ImageEditor extends React__namespace.Component {
28205
27978
  componentWillUnmount() {
28206
27979
  this._isMounted = false;
28207
27980
  }
28208
- render() {
28209
- const backgroundImage = this.props.backgroundImage;
28210
- const imageSettings = /*#__PURE__*/React__namespace.createElement("div", {
28211
- className: "image-settings"
28212
- }, !perseus.Util.isLabeledSVG(backgroundImage.url) && /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Preview:"), /*#__PURE__*/React__namespace.createElement("img", {
28213
- alt: "Editor preview of image",
28214
- src: backgroundImage.url,
28215
- style: {
28216
- width: "100%"
28217
- }
28218
- }))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Dimensions:"), /*#__PURE__*/React__namespace.createElement("p", null, backgroundImage.width, "x", backgroundImage.height))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Alt text:", /*#__PURE__*/React__namespace.createElement(InfoTip$f, null, "This is important for screenreaders. The content of this alt text will be formatted as markdown (tables, emphasis, etc. are supported).")), /*#__PURE__*/React__namespace.createElement(Editor, {
28219
- apiOptions: this.props.apiOptions,
28220
- content: this.props.alt,
28221
- onChange: props => {
28222
- if (props.content != null) {
28223
- this.change("alt", props.content);
28224
- }
28225
- },
28226
- widgetEnabled: false
28227
- }))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Caption:"), /*#__PURE__*/React__namespace.createElement(Editor, {
28228
- apiOptions: this.props.apiOptions,
28229
- content: this.props.caption,
28230
- onChange: props => {
28231
- if (props.content != null) {
28232
- this.change("caption", props.content);
28233
- }
28234
- },
28235
- widgetEnabled: false
28236
- }))));
28237
- const backgroundImageErrorText = /*#__PURE__*/React__namespace.createElement("div", {
28238
- className: "renderer-widget-error"
28239
- }, this.state.backgroundImageError);
28240
- return /*#__PURE__*/React__namespace.createElement("div", {
28241
- className: "perseus-image-editor"
28242
- }, /*#__PURE__*/React__namespace.createElement("label", null, "Image url:", /*#__PURE__*/React__namespace.createElement(InfoTip$f, null, "Paste an image or graphie image URL."), this.state.backgroundImageError && backgroundImageErrorText, /*#__PURE__*/React__namespace.createElement(BlurInput, {
28243
- value: backgroundImage.url || "",
28244
- style: {
28245
- width: 332
28246
- },
28247
- onChange: url => this.onUrlChange(url, false)
28248
- })), backgroundImage.url && imageSettings);
28249
- }
28250
27981
  _renderRowForLabel(label, i) {
28251
27982
  return /*#__PURE__*/React__namespace.createElement("tr", {
28252
27983
  key: i
@@ -28391,9 +28122,50 @@ class ImageEditor extends React__namespace.Component {
28391
28122
  serialize() {
28392
28123
  return perseus.EditorJsonify.serialize.call(this);
28393
28124
  }
28125
+ render() {
28126
+ const backgroundImage = this.props.backgroundImage;
28127
+ const imageSettings = /*#__PURE__*/React__namespace.createElement("div", {
28128
+ className: "image-settings"
28129
+ }, !perseus.Util.isLabeledSVG(backgroundImage.url) && /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Preview:"), /*#__PURE__*/React__namespace.createElement("img", {
28130
+ alt: "Editor preview of image",
28131
+ src: backgroundImage.url,
28132
+ style: {
28133
+ width: "100%"
28134
+ }
28135
+ }))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Dimensions:"), /*#__PURE__*/React__namespace.createElement("p", null, backgroundImage.width, "x", backgroundImage.height))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Alt text:", /*#__PURE__*/React__namespace.createElement(InfoTip$f, null, "This is important for screenreaders. The content of this alt text will be formatted as markdown (tables, emphasis, etc. are supported).")), /*#__PURE__*/React__namespace.createElement(Editor, {
28136
+ apiOptions: this.props.apiOptions,
28137
+ content: this.props.alt,
28138
+ onChange: props => {
28139
+ if (props.content != null) {
28140
+ this.change("alt", props.content);
28141
+ }
28142
+ },
28143
+ widgetEnabled: false
28144
+ }))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Caption:"), /*#__PURE__*/React__namespace.createElement(Editor, {
28145
+ apiOptions: this.props.apiOptions,
28146
+ content: this.props.caption,
28147
+ onChange: props => {
28148
+ if (props.content != null) {
28149
+ this.change("caption", props.content);
28150
+ }
28151
+ },
28152
+ widgetEnabled: false
28153
+ }))));
28154
+ const backgroundImageErrorText = /*#__PURE__*/React__namespace.createElement("div", {
28155
+ className: "renderer-widget-error"
28156
+ }, this.state.backgroundImageError);
28157
+ return /*#__PURE__*/React__namespace.createElement("div", {
28158
+ className: "perseus-image-editor"
28159
+ }, /*#__PURE__*/React__namespace.createElement("label", null, "Image url:", /*#__PURE__*/React__namespace.createElement(InfoTip$f, null, "Paste an image or graphie image URL."), this.state.backgroundImageError && backgroundImageErrorText, /*#__PURE__*/React__namespace.createElement(BlurInput, {
28160
+ value: backgroundImage.url || "",
28161
+ style: {
28162
+ width: 332
28163
+ },
28164
+ onChange: url => this.onUrlChange(url, false)
28165
+ })), backgroundImage.url && imageSettings);
28166
+ }
28394
28167
  }
28395
28168
 
28396
- /* eslint-disable react/sort-comp */
28397
28169
  const {
28398
28170
  InfoTip: InfoTip$e
28399
28171
  } = perseus.components;
@@ -28450,6 +28222,19 @@ class InputNumberEditor extends React__namespace.Component {
28450
28222
  value: value
28451
28223
  });
28452
28224
  };
28225
+ focus = () => {
28226
+ this.input.current?.focus();
28227
+ return true;
28228
+ };
28229
+ serialize = () => ({
28230
+ value: this.props.value,
28231
+ simplify: this.props.simplify,
28232
+ size: this.props.size,
28233
+ inexact: this.props.inexact,
28234
+ maxError: this.props.maxError,
28235
+ answerType: this.props.answerType,
28236
+ rightAlign: this.props.rightAlign
28237
+ });
28453
28238
  render() {
28454
28239
  const answerTypeOptions = ___default["default"].map(answerTypes, function (v, k) {
28455
28240
  return /*#__PURE__*/React__namespace.createElement("option", {
@@ -28533,19 +28318,6 @@ class InputNumberEditor extends React__namespace.Component {
28533
28318
  }
28534
28319
  }), " ", "Right alignment")));
28535
28320
  }
28536
- focus = () => {
28537
- this.input.current?.focus();
28538
- return true;
28539
- };
28540
- serialize = () => ({
28541
- value: this.props.value,
28542
- simplify: this.props.simplify,
28543
- size: this.props.size,
28544
- inexact: this.props.inexact,
28545
- maxError: this.props.maxError,
28546
- answerType: this.props.answerType,
28547
- rightAlign: this.props.rightAlign
28548
- });
28549
28321
  }
28550
28322
 
28551
28323
  /**
@@ -28681,7 +28453,7 @@ class FunctionEditor extends React__namespace.Component {
28681
28453
  }
28682
28454
 
28683
28455
  const {
28684
- TextInput: TextInput$5
28456
+ TextInput: TextInput$4
28685
28457
  } = perseus.components;
28686
28458
  const {
28687
28459
  getDependencies: getDependencies$7
@@ -28715,7 +28487,7 @@ class LabelEditor extends React__namespace.Component {
28715
28487
  className: "graph-settings"
28716
28488
  }, /*#__PURE__*/React__namespace.createElement("div", {
28717
28489
  className: "perseus-widget-row"
28718
- }, /*#__PURE__*/React__namespace.createElement(TextInput$5, {
28490
+ }, /*#__PURE__*/React__namespace.createElement(TextInput$4, {
28719
28491
  value: this.props.label,
28720
28492
  onChange: this.change("label"),
28721
28493
  style: {
@@ -32805,18 +32577,10 @@ const {
32805
32577
  containerSizeClass,
32806
32578
  getInteractiveBoxFromSizeClass
32807
32579
  } = perseus.SizingUtils;
32808
- const DeprecationMixin = perseus.Util.DeprecationMixin;
32809
32580
  const InteractiveGraph = perseus.InteractiveGraphWidget.widget;
32810
32581
  const defaultBackgroundImage = {
32811
32582
  url: null
32812
32583
  };
32813
- const deprecatedProps = {
32814
- showGraph: function (props) {
32815
- return {
32816
- markings: props.showGraph ? "graph" : "none"
32817
- };
32818
- }
32819
- };
32820
32584
  const POLYGON_SIDES = ___default["default"].map(___default["default"].range(3, 13), function (value) {
32821
32585
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
32822
32586
  key: `polygon-sides-${value}`,
@@ -32831,9 +32595,9 @@ const POLYGON_SIDES = ___default["default"].map(___default["default"].range(3, 1
32831
32595
  * Used in the exercise editor.
32832
32596
  */
32833
32597
  class InteractiveGraphEditor extends React__namespace.Component {
32598
+ static widgetName = "interactive-graph";
32834
32599
  displayName = "InteractiveGraphEditor";
32835
32600
  className = "perseus-widget-interactive-graph";
32836
- static widgetName = "interactive-graph";
32837
32601
  static defaultProps = {
32838
32602
  ...InteractiveGraph.defaultProps,
32839
32603
  valid: true,
@@ -32844,14 +32608,68 @@ class InteractiveGraphEditor extends React__namespace.Component {
32844
32608
  coords: null
32845
32609
  }
32846
32610
  };
32611
+ changeMatchType = newValue => {
32612
+ const correct = {
32613
+ ...this.props.correct,
32614
+ match: newValue
32615
+ };
32616
+ this.props.onChange({
32617
+ correct: correct
32618
+ });
32619
+ };
32620
+ changeStartCoords = coords => {
32621
+ if (!this.props.graph?.type) {
32622
+ return;
32623
+ }
32624
+ const graph = {
32625
+ ...this.props.graph,
32626
+ startCoords: coords
32627
+ };
32628
+ this.props.onChange({
32629
+ graph: graph
32630
+ });
32631
+ };
32847
32632
 
32848
- // TODO(jack): Use versioning instead of DeprecationMixin
32849
- deprecatedProps = deprecatedProps;
32633
+ // serialize() is what makes copy/paste work. All the properties included
32634
+ // in the serialization json are included when, for example, a graph
32635
+ // is copied from the question editor and pasted into the hint editor
32636
+ // (double brackets in the markdown).
32637
+ serialize() {
32638
+ const json = ___default["default"].pick(this.props, "step", "backgroundImage", "markings", "labels", "showProtractor", "showTooltips", "range", "gridStep", "snapStep", "lockedFigures");
32850
32639
 
32851
- // TODO(jangmi, CP-3288): Remove usage of `UNSAFE_componentWillMount`
32852
- UNSAFE_componentWillMount() {
32853
- DeprecationMixin.UNSAFE_componentWillMount.call(this);
32640
+ // eslint-disable-next-line react/no-string-refs
32641
+ const graph = this.refs.graph;
32642
+ if (graph) {
32643
+ // @ts-expect-error TS2339 Property 'getUserInput' does not exist on type 'ReactInstance'. Property 'getUserInput' does not exist on type 'Component<any, {}, any>'.
32644
+ const correct = graph && graph.getUserInput();
32645
+ ___default["default"].extend(json, {
32646
+ graph: {
32647
+ type: correct.type,
32648
+ startCoords: this.props.graph?.startCoords
32649
+ },
32650
+ correct: correct
32651
+ });
32652
+ ___default["default"].each(["allowReflexAngles", "angleOffsetDeg", "numPoints", "numSides", "numSegments", "showAngles", "showSides", "snapTo", "snapDegrees"], function (key) {
32653
+ if (___default["default"].has(correct, key)) {
32654
+ // @ts-expect-error - TS2339 - Property 'graph' does not exist on type 'Pick<any, "step" | "range" | "backgroundImage" | "snapStep" | "labels" | "showTooltips" | "markings" | "gridStep" | "showProtractor">'.
32655
+ json.graph[key] = correct[key];
32656
+ }
32657
+ });
32658
+ }
32659
+ // @ts-expect-error TS2739 Type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "step" | "gridStep" | "snapStep" | "backgroundImage" | "markings" | "labels" | ... 5 more ... | "range">' is missing the following properties from type 'PerseusInteractiveGraphWidgetOptions': graph, correct
32660
+ return json;
32854
32661
  }
32662
+ getSaveWarnings = () => {
32663
+ const issues = [];
32664
+
32665
+ // A locked line on the graph cannot have length 0.
32666
+ for (const figure of this.props.lockedFigures ?? []) {
32667
+ if (figure.type === "line" && kmath.vector.equal(figure.points[0].coord, figure.points[1].coord)) {
32668
+ issues.push("The line cannot have length 0.");
32669
+ }
32670
+ }
32671
+ return issues;
32672
+ };
32855
32673
  render() {
32856
32674
  let graph;
32857
32675
  let equationString;
@@ -33127,68 +32945,6 @@ class InteractiveGraphEditor extends React__namespace.Component {
33127
32945
  onChange: this.props.onChange
33128
32946
  }));
33129
32947
  }
33130
- changeMatchType = newValue => {
33131
- const correct = {
33132
- ...this.props.correct,
33133
- match: newValue
33134
- };
33135
- this.props.onChange({
33136
- correct: correct
33137
- });
33138
- };
33139
- changeStartCoords = coords => {
33140
- if (!this.props.graph?.type) {
33141
- return;
33142
- }
33143
- const graph = {
33144
- ...this.props.graph,
33145
- startCoords: coords
33146
- };
33147
- this.props.onChange({
33148
- graph: graph
33149
- });
33150
- };
33151
-
33152
- // serialize() is what makes copy/paste work. All the properties included
33153
- // in the serialization json are included when, for example, a graph
33154
- // is copied from the question editor and pasted into the hint editor
33155
- // (double brackets in the markdown).
33156
- serialize() {
33157
- const json = ___default["default"].pick(this.props, "step", "backgroundImage", "markings", "labels", "showProtractor", "showTooltips", "range", "gridStep", "snapStep", "lockedFigures");
33158
-
33159
- // eslint-disable-next-line react/no-string-refs
33160
- const graph = this.refs.graph;
33161
- if (graph) {
33162
- // @ts-expect-error TS2339 Property 'getUserInput' does not exist on type 'ReactInstance'. Property 'getUserInput' does not exist on type 'Component<any, {}, any>'.
33163
- const correct = graph && graph.getUserInput();
33164
- ___default["default"].extend(json, {
33165
- graph: {
33166
- type: correct.type,
33167
- startCoords: this.props.graph?.startCoords
33168
- },
33169
- correct: correct
33170
- });
33171
- ___default["default"].each(["allowReflexAngles", "angleOffsetDeg", "numPoints", "numSides", "numSegments", "showAngles", "showSides", "snapTo", "snapDegrees"], function (key) {
33172
- if (___default["default"].has(correct, key)) {
33173
- // @ts-expect-error - TS2339 - Property 'graph' does not exist on type 'Pick<any, "step" | "range" | "backgroundImage" | "snapStep" | "labels" | "showTooltips" | "markings" | "gridStep" | "showProtractor">'.
33174
- json.graph[key] = correct[key];
33175
- }
33176
- });
33177
- }
33178
- // @ts-expect-error TS2739 Type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "step" | "gridStep" | "snapStep" | "backgroundImage" | "markings" | "labels" | ... 5 more ... | "range">' is missing the following properties from type 'PerseusInteractiveGraphWidgetOptions': graph, correct
33179
- return json;
33180
- }
33181
- getSaveWarnings = () => {
33182
- const issues = [];
33183
-
33184
- // A locked line on the graph cannot have length 0.
33185
- for (const figure of this.props.lockedFigures ?? []) {
33186
- if (figure.type === "line" && kmath.vector.equal(figure.points[0].coord, figure.points[1].coord)) {
33187
- issues.push("The line cannot have length 0.");
33188
- }
33189
- }
33190
- return issues;
33191
- };
33192
32948
  }
33193
32949
  const styles$a = aphrodite.StyleSheet.create({
33194
32950
  singleSelectShort: {
@@ -33637,8 +33393,55 @@ const editorStyles = aphrodite.StyleSheet.create({
33637
33393
  }
33638
33394
  });
33639
33395
 
33640
- /* eslint-disable react/sort-comp */
33396
+ /**
33397
+ * Add hover behavior to another component.
33398
+ *
33399
+ * This component provides hover and focus status updates in a consistent way
33400
+ * across desktop and mobile.
33401
+ *
33402
+ * For advice on when to use this component instead of Button, see README.md.
33403
+ *
33404
+ * Many mobile browsers treat :hover as sticky which results in buttons looking
33405
+ * pressed even when the user has lifted their finger. This component ensures
33406
+ * that when user lifts their finger the hover state is removed.
33407
+ *
33408
+ * We also chnage how the focus state works. Browsers immediately set the
33409
+ * focus state as soon as you click on a button. This component only sets the
33410
+ * focus state when a user starts navigating between elements via keybaord.
33411
+ *
33412
+ * HoverBehavior accepts a function as 'children' which is passed state and
33413
+ * an object containing event handlers. The 'children' function should return
33414
+ * an React Element of some sort.
33415
+ *
33416
+ * Example:
33417
+ *
33418
+ * class MyButtonLikeComponent extends React.Component {
33419
+ * render(): React.Node {
33420
+ * return <HoverBehavior
33421
+ * disabled={this.props.disabled}
33422
+ * onClick={this.handleClick}
33423
+ * >
33424
+ * {({hovered}, handlers) =>
33425
+ * <RoundRect
33426
+ * textcolor='white'
33427
+ * backgroundColor={hovered ? 'red' : 'blue'}/>}
33428
+ * {...handlers}
33429
+ * >
33430
+ * {this.props.children}
33431
+ * </RoundRect>
33432
+ * }
33433
+ * </HoverBehavior>
33434
+ * }
33435
+ * }
33436
+ *
33437
+ * This follows a pattern call 'Function as Child Components':
33438
+ * https://medium.com/merrickchristensen/function-as-child-components-5f3920a9ace9#.sw0jiio8b
33439
+ */
33641
33440
  class HoverBehavior extends React__namespace.Component {
33441
+ // @ts-expect-error - TS2564 - Property 'focusFlag' has no initializer and is not definitely assigned in the constructor.
33442
+ focusFlag;
33443
+ // @ts-expect-error - TS2564 - Property 'waitingForClick' has no initializer and is not definitely assigned in the constructor.
33444
+ waitingForClick;
33642
33445
  static defaultProps = {
33643
33446
  startHovered: false,
33644
33447
  shouldUpdate: () => true
@@ -33650,11 +33453,6 @@ class HoverBehavior extends React__namespace.Component {
33650
33453
  hovered: props.startHovered
33651
33454
  };
33652
33455
  }
33653
-
33654
- // @ts-expect-error - TS2564 - Property 'focusFlag' has no initializer and is not definitely assigned in the constructor.
33655
- focusFlag;
33656
- // @ts-expect-error - TS2564 - Property 'waitingForClick' has no initializer and is not definitely assigned in the constructor.
33657
- waitingForClick;
33658
33456
  handleClick = e => {
33659
33457
  if (!this.props.disabled) {
33660
33458
  if (this.props.shouldUpdate()) {
@@ -34688,7 +34486,7 @@ const styles = aphrodite.StyleSheet.create({
34688
34486
  }
34689
34487
  });
34690
34488
 
34691
- /* eslint-disable react/forbid-prop-types, react/sort-comp */
34489
+ /* eslint-disable react/forbid-prop-types */
34692
34490
  const {
34693
34491
  InfoTip: InfoTip$a,
34694
34492
  TextListEditor: TextListEditor$3
@@ -34709,6 +34507,22 @@ class MatcherEditor extends React__namespace.Component {
34709
34507
  orderMatters: false,
34710
34508
  padding: true
34711
34509
  };
34510
+ onLabelChange = (index, e) => {
34511
+ const labels = ___default["default"].clone(this.props.labels);
34512
+ labels[index] = e.target.value;
34513
+ this.props.onChange({
34514
+ labels: labels
34515
+ });
34516
+ };
34517
+ getSaveWarnings = () => {
34518
+ if (this.props.left.length !== this.props.right.length) {
34519
+ return ["The two halves of the matcher have different numbers" + " of cards."];
34520
+ }
34521
+ return [];
34522
+ };
34523
+ serialize = () => {
34524
+ return ___default["default"].pick(this.props, "left", "right", "labels", "orderMatters", "padding");
34525
+ };
34712
34526
  render() {
34713
34527
  return /*#__PURE__*/React__namespace.createElement("div", {
34714
34528
  className: "perseus-matcher-editor"
@@ -34760,25 +34574,8 @@ class MatcherEditor extends React__namespace.Component {
34760
34574
  }
34761
34575
  }), /*#__PURE__*/React__namespace.createElement(InfoTip$a, null, /*#__PURE__*/React__namespace.createElement("p", null, "Padding is good for text, but not needed for images."))));
34762
34576
  }
34763
- onLabelChange = (index, e) => {
34764
- const labels = ___default["default"].clone(this.props.labels);
34765
- labels[index] = e.target.value;
34766
- this.props.onChange({
34767
- labels: labels
34768
- });
34769
- };
34770
- getSaveWarnings = () => {
34771
- if (this.props.left.length !== this.props.right.length) {
34772
- return ["The two halves of the matcher have different numbers" + " of cards."];
34773
- }
34774
- return [];
34775
- };
34776
- serialize = () => {
34777
- return ___default["default"].pick(this.props, "left", "right", "labels", "orderMatters", "padding");
34778
- };
34779
34577
  }
34780
34578
 
34781
- /* eslint-disable react/sort-comp */
34782
34579
  const {
34783
34580
  RangeInput: RangeInput$3
34784
34581
  } = perseus.components;
@@ -34827,6 +34624,33 @@ class MatrixEditor extends React__namespace.Component {
34827
34624
  suffix: "",
34828
34625
  cursorPosition: [0, 0]
34829
34626
  };
34627
+ change = (() => {
34628
+ var _this = this;
34629
+ return function () {
34630
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
34631
+ args[_key] = arguments[_key];
34632
+ }
34633
+ return perseus.Changeable.change.apply(_this, args);
34634
+ };
34635
+ })();
34636
+ onMatrixBoardSizeChange = range => {
34637
+ const matrixSize = getMatrixSize(this.props.answers);
34638
+ if (range[0] !== null && range[1] !== null) {
34639
+ range = [Math.round(Math.min(Math.max(range[0], 1), MAX_BOARD_SIZE)), Math.round(Math.min(Math.max(range[1], 1), MAX_BOARD_SIZE))];
34640
+ const answers = ___default["default"](Math.min(range[0], matrixSize[0])).times(row => {
34641
+ return ___default["default"](Math.min(range[1], matrixSize[1])).times(col => {
34642
+ return this.props.answers[row][col];
34643
+ });
34644
+ });
34645
+ this.props.onChange({
34646
+ matrixBoardSize: range,
34647
+ answers: answers
34648
+ });
34649
+ }
34650
+ };
34651
+ serialize = () => {
34652
+ return perseus.EditorJsonify.serialize.call(this);
34653
+ };
34830
34654
  render() {
34831
34655
  const matrixProps = ___default["default"].extend({
34832
34656
  numericInput: true,
@@ -34877,33 +34701,6 @@ class MatrixEditor extends React__namespace.Component {
34877
34701
  }
34878
34702
  })));
34879
34703
  }
34880
- change = (() => {
34881
- var _this = this;
34882
- return function () {
34883
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
34884
- args[_key] = arguments[_key];
34885
- }
34886
- return perseus.Changeable.change.apply(_this, args);
34887
- };
34888
- })();
34889
- onMatrixBoardSizeChange = range => {
34890
- const matrixSize = getMatrixSize(this.props.answers);
34891
- if (range[0] !== null && range[1] !== null) {
34892
- range = [Math.round(Math.min(Math.max(range[0], 1), MAX_BOARD_SIZE)), Math.round(Math.min(Math.max(range[1], 1), MAX_BOARD_SIZE))];
34893
- const answers = ___default["default"](Math.min(range[0], matrixSize[0])).times(row => {
34894
- return ___default["default"](Math.min(range[1], matrixSize[1])).times(col => {
34895
- return this.props.answers[row][col];
34896
- });
34897
- });
34898
- this.props.onChange({
34899
- matrixBoardSize: range,
34900
- answers: answers
34901
- });
34902
- }
34903
- };
34904
- serialize = () => {
34905
- return perseus.EditorJsonify.serialize.call(this);
34906
- };
34907
34704
  }
34908
34705
 
34909
34706
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
@@ -34945,6 +34742,42 @@ class MeasurerEditor extends React__namespace.Component {
34945
34742
  rulerLength: 10
34946
34743
  };
34947
34744
  className = "perseus-widget-measurer";
34745
+ change = (() => {
34746
+ var _this = this;
34747
+ return function () {
34748
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
34749
+ args[_key] = arguments[_key];
34750
+ }
34751
+ return perseus.Changeable.change.apply(_this, args);
34752
+ };
34753
+ })();
34754
+ _changeUrl = e => {
34755
+ this._changeImage("url", e.target.value);
34756
+ };
34757
+ _changeTop = newTop => {
34758
+ this._changeImage("top", newTop);
34759
+ };
34760
+ _changeLeft = newLeft => {
34761
+ this._changeImage("left", newLeft);
34762
+ };
34763
+ _changeImage = (subProp, newValue) => {
34764
+ const image = ___default["default"].clone(this.props.image);
34765
+ image[subProp] = newValue;
34766
+ // @ts-expect-error - TS2554 - Expected 3 arguments, but got 2.
34767
+ this.change("image", image);
34768
+ };
34769
+ renderLabelChoices = choices => {
34770
+ return ___default["default"].map(choices, function (nameAndValue) {
34771
+ const [name, value] = nameAndValue;
34772
+ return /*#__PURE__*/React__namespace.createElement("option", {
34773
+ key: value,
34774
+ value: value
34775
+ }, name);
34776
+ });
34777
+ };
34778
+ serialize = () => {
34779
+ return perseus.EditorJsonify.serialize.call(this);
34780
+ };
34948
34781
  render() {
34949
34782
  const image = ___default["default"].extend({}, defaultImage, this.props.image);
34950
34783
  return /*#__PURE__*/React__namespace.createElement("div", {
@@ -35038,47 +34871,11 @@ class MeasurerEditor extends React__namespace.Component {
35038
34871
  useArrowKeys: true
35039
34872
  })))));
35040
34873
  }
35041
- change = (() => {
35042
- var _this = this;
35043
- return function () {
35044
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
35045
- args[_key] = arguments[_key];
35046
- }
35047
- return perseus.Changeable.change.apply(_this, args);
35048
- };
35049
- })();
35050
- _changeUrl = e => {
35051
- this._changeImage("url", e.target.value);
35052
- };
35053
- _changeTop = newTop => {
35054
- this._changeImage("top", newTop);
35055
- };
35056
- _changeLeft = newLeft => {
35057
- this._changeImage("left", newLeft);
35058
- };
35059
- _changeImage = (subProp, newValue) => {
35060
- const image = ___default["default"].clone(this.props.image);
35061
- image[subProp] = newValue;
35062
- // @ts-expect-error - TS2554 - Expected 3 arguments, but got 2.
35063
- this.change("image", image);
35064
- };
35065
- renderLabelChoices = choices => {
35066
- return ___default["default"].map(choices, function (nameAndValue) {
35067
- const [name, value] = nameAndValue;
35068
- return /*#__PURE__*/React__namespace.createElement("option", {
35069
- key: value,
35070
- value: value
35071
- }, name);
35072
- });
35073
- };
35074
- serialize = () => {
35075
- return perseus.EditorJsonify.serialize.call(this);
35076
- };
35077
34874
  }
35078
34875
 
35079
34876
  const {
35080
34877
  NumberInput: NumberInput$6,
35081
- TextInput: TextInput$4
34878
+ TextInput: TextInput$3
35082
34879
  } = perseus.components;
35083
34880
  class MoleculeWidgetEditor extends React__namespace.Component {
35084
34881
  static propTypes = {
@@ -35112,7 +34909,7 @@ class MoleculeWidgetEditor extends React__namespace.Component {
35112
34909
  return perseus.EditorJsonify.serialize.call(this);
35113
34910
  };
35114
34911
  render() {
35115
- return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, "SMILES:\xA0", /*#__PURE__*/React__namespace.createElement(TextInput$4, {
34912
+ return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, "SMILES:\xA0", /*#__PURE__*/React__namespace.createElement(TextInput$3, {
35116
34913
  onChange: this.updateMolecule,
35117
34914
  value: this.props.smiles
35118
34915
  }))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, "Rotation (deg):\xA0", /*#__PURE__*/React__namespace.createElement(NumberInput$6, {
@@ -35437,14 +35234,14 @@ class NumberLineEditor extends React__namespace.Component {
35437
35234
  }
35438
35235
  }
35439
35236
 
35440
- /* eslint-disable jsx-a11y/anchor-is-valid, react/sort-comp */
35237
+ /* eslint-disable jsx-a11y/anchor-is-valid */
35441
35238
  const {
35442
35239
  ButtonGroup,
35443
35240
  InfoTip: InfoTip$7,
35444
35241
  InlineIcon: InlineIcon$1,
35445
35242
  MultiButtonGroup,
35446
35243
  NumberInput: NumberInput$4,
35447
- TextInput: TextInput$3
35244
+ TextInput: TextInput$2
35448
35245
  } = perseus.components;
35449
35246
  const {
35450
35247
  iconGear,
@@ -35510,6 +35307,106 @@ class NumericInputEditor extends React__namespace.Component {
35510
35307
  showOptions: ___default["default"].map(this.props.answers, () => false)
35511
35308
  };
35512
35309
  }
35310
+ change = (() => {
35311
+ var _this = this;
35312
+ return function () {
35313
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
35314
+ args[_key] = arguments[_key];
35315
+ }
35316
+ return perseus.Changeable.change.apply(_this, args);
35317
+ };
35318
+ })();
35319
+ onToggleOptions = choiceIndex => {
35320
+ const showOptions = this.state.showOptions.slice();
35321
+ showOptions[choiceIndex] = !showOptions[choiceIndex];
35322
+ this.setState({
35323
+ showOptions: showOptions
35324
+ });
35325
+ };
35326
+ onTrashAnswer = choiceIndex => {
35327
+ if (choiceIndex >= 0 && choiceIndex < this.props.answers.length) {
35328
+ const answers = this.props.answers.slice(0);
35329
+ answers.splice(choiceIndex, 1);
35330
+ this.props.onChange({
35331
+ answers: answers
35332
+ });
35333
+ }
35334
+ };
35335
+ onSpace = (() => {
35336
+ var _this2 = this;
35337
+ return function (e, callback) {
35338
+ if (e.key === " ") {
35339
+ e.preventDefault(); // prevent page shifting
35340
+ for (var _len2 = arguments.length, args = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
35341
+ args[_key2 - 2] = arguments[_key2];
35342
+ }
35343
+ callback.apply(_this2, args);
35344
+ }
35345
+ };
35346
+ })();
35347
+ onStatusChange = choiceIndex => {
35348
+ const statuses = ["wrong", "ungraded", "correct"];
35349
+ const answers = this.props.answers;
35350
+ const i = ___default["default"].indexOf(statuses, answers[choiceIndex].status);
35351
+ const newStatus = statuses[(i + 1) % statuses.length];
35352
+ this.updateAnswer(choiceIndex, {
35353
+ status: newStatus,
35354
+ simplify: newStatus === "correct" ? "required" : "accepted"
35355
+ });
35356
+ };
35357
+ updateAnswer = (choiceIndex, update) => {
35358
+ if (!___default["default"].isObject(update)) {
35359
+ return ___default["default"].partial((choiceIndex, key, value) => {
35360
+ const update = {};
35361
+ update[key] = value;
35362
+ this.updateAnswer(choiceIndex, update);
35363
+ }, choiceIndex, update);
35364
+ }
35365
+ let answers = [
35366
+ // Have to do this to remove the `readonly` state from the prop
35367
+ ...this.props.answers];
35368
+
35369
+ // Don't bother to make a new answer box unless we are editing the last
35370
+ // one.
35371
+ // TODO(oliver): This might not be necessary anymore.
35372
+ if (choiceIndex === answers.length) {
35373
+ const lastAnswer = initAnswer(this.state.lastStatus);
35374
+ answers = answers.concat(lastAnswer);
35375
+ }
35376
+ answers[choiceIndex] = ___default["default"].extend({}, answers[choiceIndex], update);
35377
+ this.props.onChange({
35378
+ answers: answers
35379
+ });
35380
+ };
35381
+ addAnswer = () => {
35382
+ const lastAnswer = initAnswer(this.state.lastStatus);
35383
+ const answers = this.props.answers.concat(lastAnswer);
35384
+ this.props.onChange({
35385
+ answers: answers
35386
+ });
35387
+ };
35388
+ getSaveWarnings = () => {
35389
+ // Filter out all the empty answers
35390
+ const warnings = [];
35391
+ // TODO(emily): This doesn't actually work, because the value is either
35392
+ // null or undefined when undefined, probably.
35393
+ if (___default["default"].contains(___default["default"].pluck(this.props.answers, "value"), "")) {
35394
+ // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'never'.
35395
+ warnings.push("One or more answers is empty");
35396
+ }
35397
+ this.props.answers.forEach((answer, i) => {
35398
+ const formatError = answer.strict && (!answer.answerForms || answer.answerForms.length === 0);
35399
+ if (formatError) {
35400
+ warnings.push(
35401
+ // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'never'.
35402
+ `Answer ${i + 1} is set to string format ` + "matching, but no format was selected");
35403
+ }
35404
+ });
35405
+ return warnings;
35406
+ };
35407
+ serialize = () => {
35408
+ return perseus.EditorJsonify.serialize.call(this);
35409
+ };
35513
35410
  render() {
35514
35411
  const answers = this.props.answers;
35515
35412
  const unsimplifiedAnswers = i => /*#__PURE__*/React__namespace.createElement("div", {
@@ -35581,7 +35478,7 @@ class NumericInputEditor extends React__namespace.Component {
35581
35478
  }));
35582
35479
  const labelText = /*#__PURE__*/React__namespace.createElement("div", {
35583
35480
  className: "perseus-widget-row"
35584
- }, /*#__PURE__*/React__namespace.createElement("label", null, "Aria label", /*#__PURE__*/React__namespace.createElement(TextInput$3, {
35481
+ }, /*#__PURE__*/React__namespace.createElement("label", null, "Aria label", /*#__PURE__*/React__namespace.createElement(TextInput$2, {
35585
35482
  value: this.props.labelText,
35586
35483
  onChange: this.change("labelText")
35587
35484
  })), /*#__PURE__*/React__namespace.createElement(InfoTip$7, null, /*#__PURE__*/React__namespace.createElement("p", null, "Text to describe this input. This will be shown to users using screenreaders.")));
@@ -35731,106 +35628,6 @@ class NumericInputEditor extends React__namespace.Component {
35731
35628
  className: "msg-title"
35732
35629
  }, "Message shown to user on attempt"), generateInputAnswerEditors(), addAnswerButton, inputSize, rightAlign, coefficientCheck, labelText);
35733
35630
  }
35734
- change = (() => {
35735
- var _this = this;
35736
- return function () {
35737
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
35738
- args[_key] = arguments[_key];
35739
- }
35740
- return perseus.Changeable.change.apply(_this, args);
35741
- };
35742
- })();
35743
- onToggleOptions = choiceIndex => {
35744
- const showOptions = this.state.showOptions.slice();
35745
- showOptions[choiceIndex] = !showOptions[choiceIndex];
35746
- this.setState({
35747
- showOptions: showOptions
35748
- });
35749
- };
35750
- onTrashAnswer = choiceIndex => {
35751
- if (choiceIndex >= 0 && choiceIndex < this.props.answers.length) {
35752
- const answers = this.props.answers.slice(0);
35753
- answers.splice(choiceIndex, 1);
35754
- this.props.onChange({
35755
- answers: answers
35756
- });
35757
- }
35758
- };
35759
- onSpace = (() => {
35760
- var _this2 = this;
35761
- return function (e, callback) {
35762
- if (e.key === " ") {
35763
- e.preventDefault(); // prevent page shifting
35764
- for (var _len2 = arguments.length, args = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
35765
- args[_key2 - 2] = arguments[_key2];
35766
- }
35767
- callback.apply(_this2, args);
35768
- }
35769
- };
35770
- })();
35771
- onStatusChange = choiceIndex => {
35772
- const statuses = ["wrong", "ungraded", "correct"];
35773
- const answers = this.props.answers;
35774
- const i = ___default["default"].indexOf(statuses, answers[choiceIndex].status);
35775
- const newStatus = statuses[(i + 1) % statuses.length];
35776
- this.updateAnswer(choiceIndex, {
35777
- status: newStatus,
35778
- simplify: newStatus === "correct" ? "required" : "accepted"
35779
- });
35780
- };
35781
- updateAnswer = (choiceIndex, update) => {
35782
- if (!___default["default"].isObject(update)) {
35783
- return ___default["default"].partial((choiceIndex, key, value) => {
35784
- const update = {};
35785
- update[key] = value;
35786
- this.updateAnswer(choiceIndex, update);
35787
- }, choiceIndex, update);
35788
- }
35789
- let answers = [
35790
- // Have to do this to remove the `readonly` state from the prop
35791
- ...this.props.answers];
35792
-
35793
- // Don't bother to make a new answer box unless we are editing the last
35794
- // one.
35795
- // TODO(oliver): This might not be necessary anymore.
35796
- if (choiceIndex === answers.length) {
35797
- const lastAnswer = initAnswer(this.state.lastStatus);
35798
- answers = answers.concat(lastAnswer);
35799
- }
35800
- answers[choiceIndex] = ___default["default"].extend({}, answers[choiceIndex], update);
35801
- this.props.onChange({
35802
- answers: answers
35803
- });
35804
- };
35805
- addAnswer = () => {
35806
- const lastAnswer = initAnswer(this.state.lastStatus);
35807
- const answers = this.props.answers.concat(lastAnswer);
35808
- this.props.onChange({
35809
- answers: answers
35810
- });
35811
- };
35812
- getSaveWarnings = () => {
35813
- // Filter out all the empty answers
35814
- const warnings = [];
35815
- // TODO(emily): This doesn't actually work, because the value is either
35816
- // null or undefined when undefined, probably.
35817
- if (___default["default"].contains(___default["default"].pluck(this.props.answers, "value"), "")) {
35818
- // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'never'.
35819
- warnings.push("One or more answers is empty");
35820
- }
35821
- this.props.answers.forEach((answer, i) => {
35822
- const formatError = answer.strict && (!answer.answerForms || answer.answerForms.length === 0);
35823
- if (formatError) {
35824
- warnings.push(
35825
- // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'never'.
35826
- `Answer ${i + 1} is set to string format ` + "matching, but no format was selected");
35827
- }
35828
- });
35829
- return warnings;
35830
- };
35831
- serialize = () => {
35832
- return perseus.EditorJsonify.serialize.call(this);
35833
- };
35834
35631
  }
35835
35632
 
35836
35633
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
@@ -35861,41 +35658,6 @@ class OrdererEditor extends React__namespace.Component {
35861
35658
  height: NORMAL,
35862
35659
  layout: HORIZONTAL$1
35863
35660
  };
35864
- render() {
35865
- return /*#__PURE__*/React__namespace.createElement("div", {
35866
- className: "perseus-widget-orderer"
35867
- }, /*#__PURE__*/React__namespace.createElement("div", null, " ", "Correct answer:", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$6, null, /*#__PURE__*/React__namespace.createElement("p", null, "Place the cards in the correct order. The same card can be used more than once in the answer but will only be displayed once at the top of a stack of identical cards."))), /*#__PURE__*/React__namespace.createElement(TextListEditor$2, {
35868
- options: ___default["default"].pluck(this.props.correctOptions, "content")
35869
- // eslint-disable-next-line react/jsx-no-bind
35870
- ,
35871
- onChange: this.onOptionsChange.bind(this, "correctOptions"),
35872
- layout: this.props.layout
35873
- }), /*#__PURE__*/React__namespace.createElement("div", null, " ", "Other cards:", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$6, null, /*#__PURE__*/React__namespace.createElement("p", null, "Create cards that are not part of the answer."))), /*#__PURE__*/React__namespace.createElement(TextListEditor$2, {
35874
- options: ___default["default"].pluck(this.props.otherOptions, "content")
35875
- // eslint-disable-next-line react/jsx-no-bind
35876
- ,
35877
- onChange: this.onOptionsChange.bind(this, "otherOptions"),
35878
- layout: this.props.layout
35879
- }), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, " ", "Layout:", " ", /*#__PURE__*/React__namespace.createElement("select", {
35880
- value: this.props.layout
35881
- // @ts-expect-error - TS2322 - Type '(arg1: ChangeEvent<HTMLInputElement>) => void' is not assignable to type 'ChangeEventHandler<HTMLSelectElement>'.
35882
- ,
35883
- onChange: this.onLayoutChange
35884
- }, /*#__PURE__*/React__namespace.createElement("option", {
35885
- value: HORIZONTAL$1
35886
- }, "Horizontal"), /*#__PURE__*/React__namespace.createElement("option", {
35887
- value: VERTICAL$1
35888
- }, "Vertical"))), /*#__PURE__*/React__namespace.createElement(InfoTip$6, null, /*#__PURE__*/React__namespace.createElement("p", null, "Use the horizontal layout for short text and small images. The vertical layout is best for longer text (e.g. proofs)."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, " ", "Height:", " ", /*#__PURE__*/React__namespace.createElement("select", {
35889
- value: this.props.height
35890
- // @ts-expect-error - TS2322 - Type '(arg1: ChangeEvent<HTMLInputElement>) => void' is not assignable to type 'ChangeEventHandler<HTMLSelectElement>'.
35891
- ,
35892
- onChange: this.onHeightChange
35893
- }, /*#__PURE__*/React__namespace.createElement("option", {
35894
- value: NORMAL
35895
- }, "Normal"), /*#__PURE__*/React__namespace.createElement("option", {
35896
- value: AUTO
35897
- }, "Automatic"))), /*#__PURE__*/React__namespace.createElement(InfoTip$6, null, /*#__PURE__*/React__namespace.createElement("p", null, "Use \"Normal\" for text, \"Automatic\" for images."))));
35898
- }
35899
35661
  onOptionsChange = (whichOptions, options, cb) => {
35900
35662
  const props = {};
35901
35663
  props[whichOptions] = ___default["default"].map(options, function (option) {
@@ -35942,6 +35704,41 @@ class OrdererEditor extends React__namespace.Component {
35942
35704
  layout: this.props.layout
35943
35705
  };
35944
35706
  };
35707
+ render() {
35708
+ return /*#__PURE__*/React__namespace.createElement("div", {
35709
+ className: "perseus-widget-orderer"
35710
+ }, /*#__PURE__*/React__namespace.createElement("div", null, " ", "Correct answer:", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$6, null, /*#__PURE__*/React__namespace.createElement("p", null, "Place the cards in the correct order. The same card can be used more than once in the answer but will only be displayed once at the top of a stack of identical cards."))), /*#__PURE__*/React__namespace.createElement(TextListEditor$2, {
35711
+ options: ___default["default"].pluck(this.props.correctOptions, "content")
35712
+ // eslint-disable-next-line react/jsx-no-bind
35713
+ ,
35714
+ onChange: this.onOptionsChange.bind(this, "correctOptions"),
35715
+ layout: this.props.layout
35716
+ }), /*#__PURE__*/React__namespace.createElement("div", null, " ", "Other cards:", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$6, null, /*#__PURE__*/React__namespace.createElement("p", null, "Create cards that are not part of the answer."))), /*#__PURE__*/React__namespace.createElement(TextListEditor$2, {
35717
+ options: ___default["default"].pluck(this.props.otherOptions, "content")
35718
+ // eslint-disable-next-line react/jsx-no-bind
35719
+ ,
35720
+ onChange: this.onOptionsChange.bind(this, "otherOptions"),
35721
+ layout: this.props.layout
35722
+ }), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, " ", "Layout:", " ", /*#__PURE__*/React__namespace.createElement("select", {
35723
+ value: this.props.layout
35724
+ // @ts-expect-error - TS2322 - Type '(arg1: ChangeEvent<HTMLInputElement>) => void' is not assignable to type 'ChangeEventHandler<HTMLSelectElement>'.
35725
+ ,
35726
+ onChange: this.onLayoutChange
35727
+ }, /*#__PURE__*/React__namespace.createElement("option", {
35728
+ value: HORIZONTAL$1
35729
+ }, "Horizontal"), /*#__PURE__*/React__namespace.createElement("option", {
35730
+ value: VERTICAL$1
35731
+ }, "Vertical"))), /*#__PURE__*/React__namespace.createElement(InfoTip$6, null, /*#__PURE__*/React__namespace.createElement("p", null, "Use the horizontal layout for short text and small images. The vertical layout is best for longer text (e.g. proofs)."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, " ", "Height:", " ", /*#__PURE__*/React__namespace.createElement("select", {
35732
+ value: this.props.height
35733
+ // @ts-expect-error - TS2322 - Type '(arg1: ChangeEvent<HTMLInputElement>) => void' is not assignable to type 'ChangeEventHandler<HTMLSelectElement>'.
35734
+ ,
35735
+ onChange: this.onHeightChange
35736
+ }, /*#__PURE__*/React__namespace.createElement("option", {
35737
+ value: NORMAL
35738
+ }, "Normal"), /*#__PURE__*/React__namespace.createElement("option", {
35739
+ value: AUTO
35740
+ }, "Automatic"))), /*#__PURE__*/React__namespace.createElement(InfoTip$6, null, /*#__PURE__*/React__namespace.createElement("p", null, "Use \"Normal\" for text, \"Automatic\" for images."))));
35741
+ }
35945
35742
  }
35946
35743
 
35947
35744
  const {
@@ -36035,7 +35832,7 @@ class PassageEditor extends React__namespace.Component {
36035
35832
  const {
36036
35833
  InfoTip: InfoTip$4,
36037
35834
  NumberInput: NumberInput$3,
36038
- TextInput: TextInput$2
35835
+ TextInput: TextInput$1
36039
35836
  } = perseus.components;
36040
35837
  class PassageRefEditor extends React__namespace.Component {
36041
35838
  static propTypes = {
@@ -36073,7 +35870,7 @@ class PassageRefEditor extends React__namespace.Component {
36073
35870
  // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
36074
35871
  ,
36075
35872
  onChange: this.change("referenceNumber")
36076
- }))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, "Summary Text: ", /*#__PURE__*/React__namespace.createElement(TextInput$2, {
35873
+ }))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, "Summary Text: ", /*#__PURE__*/React__namespace.createElement(TextInput$1, {
36077
35874
  value: this.props.summaryText
36078
35875
  // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
36079
35876
  ,
@@ -36125,14 +35922,29 @@ class PhetSimulationEditor extends React__namespace.Component {
36125
35922
  description: ""
36126
35923
  };
36127
35924
  static widgetName = "phet-simulation";
35925
+ serialize() {
35926
+ return {
35927
+ url: this.props.url,
35928
+ description: this.props.description
35929
+ };
35930
+ }
35931
+ getSaveWarnings = () => {
35932
+ if (perseus.makeSafeUrl(this.props.url, "en") === null) {
35933
+ return ["Please enter a URL from the PhET domain."];
35934
+ }
35935
+ return [];
35936
+ };
36128
35937
  render() {
36129
35938
  return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
36130
35939
  label: "URL",
36131
35940
  value: this.props.url,
36132
35941
  onChange: url => this.props.onChange({
36133
35942
  url
36134
- })
36135
- }), /*#__PURE__*/React__namespace.createElement("br", null), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
35943
+ }),
35944
+ style: {
35945
+ marginBottom: wonderBlocksTokens.spacing.large_24
35946
+ }
35947
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
36136
35948
  label: "Description",
36137
35949
  value: this.props.description,
36138
35950
  onChange: description => this.props.onChange({
@@ -36140,12 +35952,6 @@ class PhetSimulationEditor extends React__namespace.Component {
36140
35952
  })
36141
35953
  }));
36142
35954
  }
36143
- serialize() {
36144
- return {
36145
- url: this.props.url,
36146
- description: this.props.description
36147
- };
36148
- }
36149
35955
  }
36150
35956
 
36151
35957
  const {
@@ -36463,7 +36269,7 @@ class PlotterEditor extends React__namespace.Component {
36463
36269
  */
36464
36270
  const {
36465
36271
  NumberInput: NumberInput$1,
36466
- TextInput: TextInput$1
36272
+ TextInput
36467
36273
  } = perseus.components;
36468
36274
  function validateOptions(height, programID) {
36469
36275
  const errors = [];
@@ -36505,7 +36311,7 @@ class PythonProgramEditor extends React__namespace.Component {
36505
36311
  return validateOptions(this.props.height, this.props.programID);
36506
36312
  };
36507
36313
  render() {
36508
- return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, "User Program ID:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$1, {
36314
+ return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, "User Program ID:", " ", /*#__PURE__*/React__namespace.createElement(TextInput, {
36509
36315
  value: this.props.programID,
36510
36316
  onChange: this.change("programID"),
36511
36317
  placeholder: "123"
@@ -36517,7 +36323,7 @@ class PythonProgramEditor extends React__namespace.Component {
36517
36323
  }
36518
36324
  }
36519
36325
 
36520
- /* eslint-disable jsx-a11y/anchor-is-valid, react/forbid-prop-types, react/sort-comp */
36326
+ /* eslint-disable jsx-a11y/anchor-is-valid, react/forbid-prop-types */
36521
36327
  const {
36522
36328
  InlineIcon
36523
36329
  } = perseus.components;
@@ -36610,94 +36416,6 @@ class RadioEditor extends React__namespace.Component {
36610
36416
  countChoices: false,
36611
36417
  deselectEnabled: false
36612
36418
  };
36613
- render() {
36614
- const numCorrect = ___default["default"].reduce(this.props.choices, function (memo, choice) {
36615
- return choice.correct ? memo + 1 : memo;
36616
- }, 0);
36617
- return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", {
36618
- className: "perseus-widget-row"
36619
- }, /*#__PURE__*/React__namespace.createElement("a", {
36620
- href:
36621
- // This is an editor component, not user-facing.
36622
- "https://docs.google.com/document/d/1frZf7yrWVWb1n4tVjqlzqVUiv1pn4cZXbxgP62-JDBY/edit#heading=h.8ng1isya19nu",
36623
- target: "_blank"
36624
- }, "Multiple choice style guide"), /*#__PURE__*/React__namespace.createElement("br", null), /*#__PURE__*/React__namespace.createElement("div", {
36625
- className: "perseus-widget-left-col"
36626
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
36627
- label: "Multiple selections",
36628
- checked: this.props.multipleSelect,
36629
- onChange: value => {
36630
- this.onMultipleSelectChange({
36631
- multipleSelect: value
36632
- });
36633
- }
36634
- })), /*#__PURE__*/React__namespace.createElement("div", {
36635
- className: "perseus-widget-right-col"
36636
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
36637
- label: "Randomize order",
36638
- checked: this.props.randomize,
36639
- onChange: value => {
36640
- this.props.onChange({
36641
- randomize: value
36642
- });
36643
- }
36644
- })), this.props.multipleSelect && /*#__PURE__*/React__namespace.createElement("div", {
36645
- className: "perseus-widget-left-col"
36646
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
36647
- label: "Specify number correct",
36648
- checked: this.props.countChoices,
36649
- onChange: value => {
36650
- this.onCountChoicesChange({
36651
- countChoices: value
36652
- });
36653
- }
36654
- }))), /*#__PURE__*/React__namespace.createElement(perseus.BaseRadio, {
36655
- multipleSelect: this.props.multipleSelect,
36656
- countChoices: this.props.countChoices,
36657
- numCorrect: numCorrect,
36658
- editMode: true,
36659
- labelWrap: false,
36660
- apiOptions: this.props.apiOptions,
36661
- choices: this.props.choices.map((choice, i) => {
36662
- return {
36663
- content: /*#__PURE__*/React__namespace.createElement(ChoiceEditor, {
36664
- ref: `choice-editor${i}`,
36665
- apiOptions: this.props.apiOptions,
36666
- choice: choice,
36667
- onContentChange: newProps => {
36668
- if ("content" in newProps) {
36669
- this.onContentChange(i, newProps.content);
36670
- }
36671
- },
36672
- onClueChange: newProps => {
36673
- if ("content" in newProps) {
36674
- this.onClueChange(i, newProps.content);
36675
- }
36676
- },
36677
- onDelete: () => this.onDelete(i),
36678
- showDelete: this.props.choices.length >= 2
36679
- }),
36680
- isNoneOfTheAbove: choice.isNoneOfTheAbove,
36681
- checked: choice.correct
36682
- };
36683
- }, this),
36684
- onChange: this.onChange
36685
- }), /*#__PURE__*/React__namespace.createElement("div", {
36686
- className: "add-choice-container"
36687
- }, /*#__PURE__*/React__namespace.createElement("a", {
36688
- className: "simple-button orange",
36689
- href: "#"
36690
- // eslint-disable-next-line react/jsx-no-bind
36691
- ,
36692
- onClick: this.addChoice.bind(this, false)
36693
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconPlus), " Add a choice", " "), !this.props.hasNoneOfTheAbove && /*#__PURE__*/React__namespace.createElement("a", {
36694
- className: "simple-button",
36695
- href: "#"
36696
- // eslint-disable-next-line react/jsx-no-bind
36697
- ,
36698
- onClick: this.addChoice.bind(this, true)
36699
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconPlus), " None of the above", " ")));
36700
- }
36701
36419
  change = (() => {
36702
36420
  var _this = this;
36703
36421
  return function () {
@@ -36816,64 +36534,94 @@ class RadioEditor extends React__namespace.Component {
36816
36534
  serialize = () => {
36817
36535
  return ___default["default"].pick(this.props, "choices", "randomize", "multipleSelect", "countChoices", "displayCount", "hasNoneOfTheAbove", "deselectEnabled");
36818
36536
  };
36819
- }
36820
-
36821
- /* eslint-disable @khanacademy/ts-no-error-suppressions */
36822
- class TextArea extends React__namespace.Component {
36823
- render() {
36824
- return /*#__PURE__*/React__namespace.createElement("textarea", {
36825
- // eslint-disable-next-line react/no-string-refs
36826
- ref: "input",
36827
- value: this.props.value || "",
36828
- onChange: this.changeValue
36829
- });
36830
- }
36831
- focus = () => {
36832
- // eslint-disable-next-line react/no-string-refs
36833
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
36834
- this.refs.input.focus();
36835
- return true;
36836
- };
36837
- changeValue = e => {
36838
- // Translating from the js event e to the value
36839
- // of the textbox to send to onChange
36840
- this.props.onChange(e.target.value);
36841
- };
36842
- }
36843
- class SimpleMarkdownTesterEditor extends React__namespace.Component {
36844
- static propTypes = {
36845
- ...perseus.Changeable.propTypes
36846
- };
36847
- static widgetName = "simple-markdown-tester";
36848
- static defaultProps = {
36849
- value: ""
36850
- };
36851
- input = /*#__PURE__*/React__namespace.createRef();
36852
36537
  render() {
36853
- return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Simple markdown contents:"), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(TextArea, {
36854
- value: this.props.value
36855
- // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
36538
+ const numCorrect = ___default["default"].reduce(this.props.choices, function (memo, choice) {
36539
+ return choice.correct ? memo + 1 : memo;
36540
+ }, 0);
36541
+ return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", {
36542
+ className: "perseus-widget-row"
36543
+ }, /*#__PURE__*/React__namespace.createElement("a", {
36544
+ href:
36545
+ // This is an editor component, not user-facing.
36546
+ "https://docs.google.com/document/d/1frZf7yrWVWb1n4tVjqlzqVUiv1pn4cZXbxgP62-JDBY/edit#heading=h.8ng1isya19nu",
36547
+ target: "_blank"
36548
+ }, "Multiple choice style guide"), /*#__PURE__*/React__namespace.createElement("br", null), /*#__PURE__*/React__namespace.createElement("div", {
36549
+ className: "perseus-widget-left-col"
36550
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
36551
+ label: "Multiple selections",
36552
+ checked: this.props.multipleSelect,
36553
+ onChange: value => {
36554
+ this.onMultipleSelectChange({
36555
+ multipleSelect: value
36556
+ });
36557
+ }
36558
+ })), /*#__PURE__*/React__namespace.createElement("div", {
36559
+ className: "perseus-widget-right-col"
36560
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
36561
+ label: "Randomize order",
36562
+ checked: this.props.randomize,
36563
+ onChange: value => {
36564
+ this.props.onChange({
36565
+ randomize: value
36566
+ });
36567
+ }
36568
+ })), this.props.multipleSelect && /*#__PURE__*/React__namespace.createElement("div", {
36569
+ className: "perseus-widget-left-col"
36570
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
36571
+ label: "Specify number correct",
36572
+ checked: this.props.countChoices,
36573
+ onChange: value => {
36574
+ this.onCountChoicesChange({
36575
+ countChoices: value
36576
+ });
36577
+ }
36578
+ }))), /*#__PURE__*/React__namespace.createElement(perseus.BaseRadio, {
36579
+ multipleSelect: this.props.multipleSelect,
36580
+ countChoices: this.props.countChoices,
36581
+ numCorrect: numCorrect,
36582
+ editMode: true,
36583
+ labelWrap: false,
36584
+ apiOptions: this.props.apiOptions,
36585
+ choices: this.props.choices.map((choice, i) => {
36586
+ return {
36587
+ content: /*#__PURE__*/React__namespace.createElement(ChoiceEditor, {
36588
+ ref: `choice-editor${i}`,
36589
+ apiOptions: this.props.apiOptions,
36590
+ choice: choice,
36591
+ onContentChange: newProps => {
36592
+ if ("content" in newProps) {
36593
+ this.onContentChange(i, newProps.content);
36594
+ }
36595
+ },
36596
+ onClueChange: newProps => {
36597
+ if ("content" in newProps) {
36598
+ this.onClueChange(i, newProps.content);
36599
+ }
36600
+ },
36601
+ onDelete: () => this.onDelete(i),
36602
+ showDelete: this.props.choices.length >= 2
36603
+ }),
36604
+ isNoneOfTheAbove: choice.isNoneOfTheAbove,
36605
+ checked: choice.correct
36606
+ };
36607
+ }, this),
36608
+ onChange: this.onChange
36609
+ }), /*#__PURE__*/React__namespace.createElement("div", {
36610
+ className: "add-choice-container"
36611
+ }, /*#__PURE__*/React__namespace.createElement("a", {
36612
+ className: "simple-button orange",
36613
+ href: "#"
36614
+ // eslint-disable-next-line react/jsx-no-bind
36856
36615
  ,
36857
- onChange: this.change("value"),
36858
- ref: this.input
36859
- }))));
36616
+ onClick: this.addChoice.bind(this, false)
36617
+ }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconPlus), " Add a choice", " "), !this.props.hasNoneOfTheAbove && /*#__PURE__*/React__namespace.createElement("a", {
36618
+ className: "simple-button",
36619
+ href: "#"
36620
+ // eslint-disable-next-line react/jsx-no-bind
36621
+ ,
36622
+ onClick: this.addChoice.bind(this, true)
36623
+ }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconPlus), " None of the above", " ")));
36860
36624
  }
36861
- change = (() => {
36862
- var _this = this;
36863
- return function () {
36864
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
36865
- args[_key] = arguments[_key];
36866
- }
36867
- return perseus.Changeable.change.apply(_this, args);
36868
- };
36869
- })();
36870
- focus = () => {
36871
- this.input.current?.focus();
36872
- return true;
36873
- };
36874
- serialize = () => {
36875
- return perseus.EditorJsonify.serialize.call(this);
36876
- };
36877
36625
  }
36878
36626
 
36879
36627
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
@@ -36936,7 +36684,6 @@ class SorterEditor extends React__namespace.Component {
36936
36684
  }
36937
36685
  }
36938
36686
 
36939
- /* eslint-disable react/sort-comp */
36940
36687
  const {
36941
36688
  InfoTip: InfoTip$1,
36942
36689
  NumberInput
@@ -36967,41 +36714,6 @@ class TableEditor extends React__namespace.Component {
36967
36714
  focus = () => {
36968
36715
  this.numberOfColumns.current?.focus();
36969
36716
  };
36970
- render() {
36971
- const tableProps = ___default["default"].pick(this.props, "headers", "answers", "onChange", "apiOptions");
36972
- ___default["default"].extend(tableProps, {
36973
- editableHeaders: true,
36974
- Editor,
36975
- onFocus: () => {},
36976
- onBlur: () => {},
36977
- trackInteraction: () => {}
36978
- });
36979
- return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", {
36980
- className: "perseus-widget-row"
36981
- }, /*#__PURE__*/React__namespace.createElement("label", null, "Number of columns:", " ", /*#__PURE__*/React__namespace.createElement(NumberInput, {
36982
- ref: this.numberOfColumns,
36983
- value: this.props.columns,
36984
- onChange: val => {
36985
- if (val) {
36986
- this.onSizeInput(this.props.rows, val);
36987
- }
36988
- },
36989
- useArrowKeys: true
36990
- }))), /*#__PURE__*/React__namespace.createElement("div", {
36991
- className: "perseus-widget-row"
36992
- }, /*#__PURE__*/React__namespace.createElement("label", null, "Number of rows:", " ", /*#__PURE__*/React__namespace.createElement(NumberInput
36993
- // eslint-disable-next-line react/no-string-refs
36994
- , {
36995
- ref: "numberOfRows",
36996
- value: this.props.rows,
36997
- onChange: val => {
36998
- if (val) {
36999
- this.onSizeInput(val, this.props.columns);
37000
- }
37001
- },
37002
- useArrowKeys: true
37003
- }))), /*#__PURE__*/React__namespace.createElement("div", null, " ", "Table of answers:", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$1, null, /*#__PURE__*/React__namespace.createElement("p", null, "The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(Table, tableProps)));
37004
- }
37005
36717
  onSizeInput = (numRawRows, numRawColumns) => {
37006
36718
  let rows = +numRawRows || 0;
37007
36719
  let columns = +numRawColumns || 0;
@@ -37044,6 +36756,41 @@ class TableEditor extends React__namespace.Component {
37044
36756
  answers: ___default["default"].map(this.props.answers, ___default["default"].clone)
37045
36757
  });
37046
36758
  };
36759
+ render() {
36760
+ const tableProps = ___default["default"].pick(this.props, "headers", "answers", "onChange", "apiOptions");
36761
+ ___default["default"].extend(tableProps, {
36762
+ editableHeaders: true,
36763
+ Editor,
36764
+ onFocus: () => {},
36765
+ onBlur: () => {},
36766
+ trackInteraction: () => {}
36767
+ });
36768
+ return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", {
36769
+ className: "perseus-widget-row"
36770
+ }, /*#__PURE__*/React__namespace.createElement("label", null, "Number of columns:", " ", /*#__PURE__*/React__namespace.createElement(NumberInput, {
36771
+ ref: this.numberOfColumns,
36772
+ value: this.props.columns,
36773
+ onChange: val => {
36774
+ if (val) {
36775
+ this.onSizeInput(this.props.rows, val);
36776
+ }
36777
+ },
36778
+ useArrowKeys: true
36779
+ }))), /*#__PURE__*/React__namespace.createElement("div", {
36780
+ className: "perseus-widget-row"
36781
+ }, /*#__PURE__*/React__namespace.createElement("label", null, "Number of rows:", " ", /*#__PURE__*/React__namespace.createElement(NumberInput
36782
+ // eslint-disable-next-line react/no-string-refs
36783
+ , {
36784
+ ref: "numberOfRows",
36785
+ value: this.props.rows,
36786
+ onChange: val => {
36787
+ if (val) {
36788
+ this.onSizeInput(val, this.props.columns);
36789
+ }
36790
+ },
36791
+ useArrowKeys: true
36792
+ }))), /*#__PURE__*/React__namespace.createElement("div", null, " ", "Table of answers:", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$1, null, /*#__PURE__*/React__namespace.createElement("p", null, "The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(Table, tableProps)));
36793
+ }
37047
36794
  }
37048
36795
 
37049
36796
  const {
@@ -37103,230 +36850,18 @@ class VideoEditor extends React__namespace.Component {
37103
36850
  }
37104
36851
  }
37105
36852
 
37106
- var AllEditors = [CategorizerEditor, CSProgramEditor, DefinitionEditor, DropdownEditor, ExampleGraphieWidgetEditor, ExampleWidgetEditor, ExplanationEditor, ExpressionEditor, GradedGroupEditor, GradedGroupSetEditor, GrapherEditor, GroupEditor, IframeEditor, ImageEditor, InputNumberEditor, InteractionEditor, InteractiveGraphEditor, LabelImageEditor, MatcherEditor, MatrixEditor, MeasurerEditor, MoleculeWidgetEditor, NumberLineEditor, NumericInputEditor, OrdererEditor, PassageEditor, PassageRefEditor, PassageRefTargetEditor, PhetSimulationEditor, PlotterEditor, PythonProgramEditor, SimpleMarkdownTesterEditor, SorterEditor, TableEditor, VideoEditor, RadioEditor, DeprecatedStandinEditor];
37107
-
37108
- /* eslint-disable @khanacademy/ts-no-error-suppressions */
37109
- class TextInput extends React__namespace.Component {
37110
- input = /*#__PURE__*/React__namespace.createRef();
37111
- render() {
37112
- return /*#__PURE__*/React__namespace.createElement("input", {
37113
- ref: this.input,
37114
- value: this.props.value || "",
37115
- onChange: this.changeValue
37116
- });
37117
- }
37118
- focus = () => {
37119
- this.input.current?.focus();
37120
- return true;
37121
- };
37122
- changeValue = e => {
37123
- // Translating from the js event e to the value
37124
- // of the textbox to send to onChange
37125
- this.props.onChange(e.target.value);
37126
- };
37127
- }
37128
- /**
37129
- * This is the widget's renderer. It shows up in the right column
37130
- * in the demo, and is what is visible to users, and where
37131
- * users enter their answers.
37132
- */
37133
- class ExampleWidget extends React__namespace.Component {
37134
- static defaultProps = {
37135
- value: ""
37136
- };
37137
- input = /*#__PURE__*/React__namespace.createRef();
37138
-
37139
- /**
37140
- * This is the widget's grading function. simpleValidate generally
37141
- * defers to this function.
37142
- *
37143
- * value is usually the result of getUserInput on the widget
37144
- * rubric is the result of calling serialize() on the editor
37145
- */
37146
- static validate(value, rubric) {
37147
- if (value === "") {
37148
- return {
37149
- type: "invalid",
37150
- message: "It looks like you haven't answered all of the " + "question yet."
37151
- };
37152
- }
37153
- if (value === rubric.correct) {
37154
- return {
37155
- type: "points",
37156
- earned: 1,
37157
- total: 1,
37158
- message: null
37159
- };
37160
- }
37161
- return {
37162
- type: "points",
37163
- earned: 0,
37164
- total: 1,
37165
- message: null
37166
- };
37167
- }
37168
-
37169
- /**
37170
- * Tell our parent to update our props.
37171
- */
37172
- change = (() => {
37173
- var _this = this;
37174
- return function () {
37175
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
37176
- args[_key] = arguments[_key];
37177
- }
37178
- return perseus.Changeable.change.apply(_this, args);
37179
- };
37180
- })();
37181
- render() {
37182
- return /*#__PURE__*/React__namespace.createElement(TextInput, {
37183
- ref: this.input,
37184
- value: this.props.value
37185
- // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
37186
- ,
37187
- onChange: this.change("value")
37188
- });
37189
- }
37190
- getUserInput = () => {
37191
- return this.props.value;
37192
- };
37193
-
37194
- /**
37195
- * Widgets that are focusable should add a focus method that returns
37196
- * true if focusing succeeded. The first such widget found will be
37197
- * focused on page load.
37198
- */
37199
- focus = () => {
37200
- this.input.current?.focus();
37201
- return true;
37202
- };
37203
-
37204
- /**
37205
- * simpleValidate is called for grading. Rubric is the result of calling
37206
- * getUserInput() on the editor that created this widget.
37207
- *
37208
- * Should return an object representing the grading result, such as
37209
- * {
37210
- * type: "points",
37211
- * earned: 1,
37212
- * total: 1,
37213
- * message: null
37214
- * }
37215
- */
37216
- simpleValidate = rubric => {
37217
- return ExampleWidget.validate(this.getUserInput(), rubric);
37218
- };
37219
- }
37220
-
37221
- /**
37222
- * For this widget to work, we must import this file in src/all-widgets.js
37223
- */
37224
- var ExampleWidget$1 = {
37225
- name: "example-widget",
37226
- displayName: "Example Widget",
37227
- // Tell the renderer what type of `display:` style we would like
37228
- // for the component wrapping this one.
37229
- defaultAlignment: "inline-block",
37230
- hidden: true,
37231
- // Hides this widget from the Perseus.Editor widget select
37232
- widget: ExampleWidget
37233
- };
37234
-
37235
- /* eslint-disable react/sort-comp */
37236
- const mdParse = perseus.PerseusMarkdown.parse;
37237
- const mdOutput = perseus.PerseusMarkdown.basicOutput;
37238
- class SimpleMarkdownTester extends React__namespace.Component {
37239
- static defaultProps = {
37240
- value: ""
37241
- };
37242
-
37243
- /**
37244
- * This is the widget's grading function.
37245
- *
37246
- * simpleValidate generally defers to this function
37247
- *
37248
- * state is usually the result of toJSON on the widget
37249
- * rubric is the result of calling toJSON() on the editor
37250
- */
37251
- static validate(state, rubric) {
37252
- return {
37253
- type: "points",
37254
- earned: 0,
37255
- total: 0,
37256
- message: null
37257
- };
37258
- }
37259
- change = (() => {
37260
- var _this = this;
37261
- return function () {
37262
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
37263
- args[_key] = arguments[_key];
37264
- }
37265
- return perseus.Changeable.change.apply(_this, args);
37266
- };
37267
- })();
37268
- toJSON = () => {
37269
- return {};
37270
- };
37271
- render() {
37272
- // @ts-expect-error - TS2554 - Expected 2 arguments, but got 1.
37273
- const parsed = mdParse(this.props.value);
37274
- const output = mdOutput(parsed);
37275
- return /*#__PURE__*/React__namespace.createElement("div", null, output);
37276
- }
37277
-
37278
- /**
37279
- * Widgets that are focusable should add a focus method that returns
37280
- * true if focusing succeeded. The first such widget found will be
37281
- * focused on page load.
37282
- */
37283
- focus = () => {
37284
- // eslint-disable-next-line react/no-string-refs
37285
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
37286
- this.refs.input.focus();
37287
- return true;
37288
- };
37289
-
37290
- /**
37291
- * simpleValidate is called for grading. Rubric is the result of calling
37292
- * toJSON() on the editor that created this widget.
37293
- *
37294
- * Should return an object representing the grading result, such as
37295
- * {
37296
- * type: "points",
37297
- * earned: 1,
37298
- * total: 1,
37299
- * message: null
37300
- * }
37301
- */
37302
- simpleValidate = rubric => {
37303
- return SimpleMarkdownTester.validate(this.toJSON(), rubric);
37304
- };
37305
- }
37306
-
37307
- /**
37308
- * For this widget to work, we must import this file in src/all-widgets.js
37309
- */
37310
- var SimpleMarkdownTester$1 = {
37311
- name: "simple-markdown-tester",
37312
- displayName: "Simple Markdown Tester",
37313
- hidden: true,
37314
- // Hides this widget from the Perseus.Editor widget select
37315
- widget: SimpleMarkdownTester,
37316
- transform: ___default["default"].identity
37317
- };
37318
-
37319
- var testingWidgets = [ExampleGraphieWidget$2, ExampleWidget$1, SimpleMarkdownTester$1];
37320
-
37321
- var AllWidgets = [...perseus.widgets, ...testingWidgets];
36853
+ var AllEditors = [CategorizerEditor, CSProgramEditor, DefinitionEditor, DropdownEditor, ExplanationEditor, ExpressionEditor, GradedGroupEditor, GradedGroupSetEditor, GrapherEditor, GroupEditor, IframeEditor, ImageEditor, InputNumberEditor, InteractionEditor, InteractiveGraphEditor, LabelImageEditor, MatcherEditor, MatrixEditor, MeasurerEditor, MoleculeWidgetEditor, NumberLineEditor, NumericInputEditor, OrdererEditor, PassageEditor, PassageRefEditor, PassageRefTargetEditor, PhetSimulationEditor, PlotterEditor, PythonProgramEditor, SorterEditor, TableEditor, VideoEditor, RadioEditor, DeprecatedStandinEditor];
37322
36854
 
37323
36855
  perseus.Widgets.registerEditors(AllEditors);
37324
- perseus.Widgets.registerWidgets(AllWidgets);
36856
+ perseus.Widgets.registerWidgets(perseus.widgets);
37325
36857
  perseus.Widgets.replaceDeprecatedWidgets();
37326
36858
  perseus.Widgets.replaceDeprecatedEditors();
37327
36859
 
36860
+ Object.defineProperty(exports, 'widgets', {
36861
+ enumerable: true,
36862
+ get: function () { return perseus.widgets; }
36863
+ });
37328
36864
  exports.AllEditors = AllEditors;
37329
- exports.AllWidgets = AllWidgets;
37330
36865
  exports.ArticleDiff = ArticleDiff;
37331
36866
  exports.ArticleEditor = ArticleEditor;
37332
36867
  exports.DeviceFramer = DeviceFramer;