@khanacademy/perseus-editor 5.2.14 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -24,10 +24,11 @@ var mathInput = require('@khanacademy/math-input');
24
24
  var wonderBlocksDropdown = require('@khanacademy/wonder-blocks-dropdown');
25
25
  var wonderBlocksForm = require('@khanacademy/wonder-blocks-form');
26
26
  var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
27
+ var wonderBlocksAccordion = require('@khanacademy/wonder-blocks-accordion');
27
28
  var IconButton = require('@khanacademy/wonder-blocks-icon-button');
28
29
  var trashIcon = require('@phosphor-icons/core/bold/trash-bold.svg');
30
+ var Switch = require('@khanacademy/wonder-blocks-switch');
29
31
  var Button = require('@khanacademy/wonder-blocks-button');
30
- var i18n$1 = require('@khanacademy/wonder-blocks-i18n');
31
32
 
32
33
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
33
34
 
@@ -61,12 +62,12 @@ var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
61
62
  var KAS__namespace = /*#__PURE__*/_interopNamespace(KAS);
62
63
  var IconButton__default = /*#__PURE__*/_interopDefaultLegacy(IconButton);
63
64
  var trashIcon__default = /*#__PURE__*/_interopDefaultLegacy(trashIcon);
65
+ var Switch__default = /*#__PURE__*/_interopDefaultLegacy(Switch);
64
66
  var Button__default = /*#__PURE__*/_interopDefaultLegacy(Button);
65
- var i18n__namespace = /*#__PURE__*/_interopNamespace(i18n$1);
66
67
 
67
68
  // This file is processed by a Rollup plugin (replace) to inject the production
68
69
  const libName = "@khanacademy/perseus-editor";
69
- const libVersion = "5.2.14";
70
+ const libVersion = "6.0.0";
70
71
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
71
72
 
72
73
  function _extends() {
@@ -261,13 +262,13 @@ class SectionControlButton extends React__namespace.Component {
261
262
  role: "button",
262
263
  hideDefaultFocusRing: true,
263
264
  "aria-label": title,
264
- style: styles$q.button
265
+ style: styles$s.button
265
266
  }, _ref => {
266
267
  return /*#__PURE__*/React__namespace.createElement(InlineIcon$b, icon);
267
268
  });
268
269
  }
269
270
  }
270
- const styles$q = aphrodite.StyleSheet.create({
271
+ const styles$s = aphrodite.StyleSheet.create({
271
272
  button: {
272
273
  backgroundColor: wonderBlocksTokens.color.gold,
273
274
  margin: 2,
@@ -20611,6 +20612,7 @@ const _upgradeWidgetInfo = props => {
20611
20612
  // transforms will not be propogated upwards until serialization.
20612
20613
  // eslint-disable-next-line react/no-unsafe
20613
20614
  class WidgetEditor extends React__namespace.Component {
20615
+ widget;
20614
20616
  constructor(props) {
20615
20617
  super(props);
20616
20618
  this.state = {
@@ -20785,19 +20787,19 @@ class TexErrorView extends React__namespace.Component {
20785
20787
  const {
20786
20788
  showErrors
20787
20789
  } = this.state;
20788
- const iconStyle = showErrors ? styles$p.iconExpanded : styles$p.iconCollapsed;
20790
+ const iconStyle = showErrors ? styles$r.iconExpanded : styles$r.iconCollapsed;
20789
20791
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20790
- style: styles$p.errorContainer
20792
+ style: styles$r.errorContainer
20791
20793
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20792
- style: styles$p.title,
20794
+ style: styles$r.title,
20793
20795
  onClick: this.handleToggleTexErrors
20794
20796
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksIcon.PhosphorIcon, {
20795
20797
  icon: caretRight__default["default"],
20796
20798
  style: iconStyle
20797
20799
  }), "\xA0 TeX Errors (", errorList.length, ")"), showErrors && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20798
- style: styles$p.errorExplanation
20800
+ style: styles$r.errorExplanation
20799
20801
  }, "If your math doesn't display correctly, these errors might help you troubleshoot. Message #content-kitchen for help."), showErrors && errorList.map((e, index) => /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20800
- style: styles$p.error,
20802
+ style: styles$r.error,
20801
20803
  key: index
20802
20804
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20803
20805
  style: {
@@ -20806,7 +20808,7 @@ class TexErrorView extends React__namespace.Component {
20806
20808
  }, e.math), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, e.message))));
20807
20809
  }
20808
20810
  }
20809
- const styles$p = aphrodite.StyleSheet.create({
20811
+ const styles$r = aphrodite.StyleSheet.create({
20810
20812
  title: {
20811
20813
  backgroundColor: "#eee",
20812
20814
  fontSize: "1.25em",
@@ -20912,6 +20914,9 @@ const imageUrlsFromContent = function (content) {
20912
20914
  };
20913
20915
  // eslint-disable-next-line react/no-unsafe
20914
20916
  class Editor extends React__namespace.Component {
20917
+ lastUserValue;
20918
+ deferredChange;
20919
+ widgetIds;
20915
20920
  underlay = /*#__PURE__*/React__namespace.createRef();
20916
20921
  textarea = /*#__PURE__*/React__namespace.createRef();
20917
20922
  static defaultProps = {
@@ -21691,14 +21696,16 @@ window.addEventListener("message", event => {
21691
21696
  }
21692
21697
  });
21693
21698
  class IframeContentRenderer extends React__namespace.Component {
21699
+ _frame;
21694
21700
  container = /*#__PURE__*/React__namespace.createRef();
21695
21701
 
21696
21702
  // @ts-expect-error - TS2564 - Property '_isMounted' has no initializer and is not definitely assigned in the constructor.
21697
-
21703
+ _isMounted;
21704
+ _lastData;
21698
21705
  // @ts-expect-error - TS2564 - Property '_lastHeight' has no initializer and is not definitely assigned in the constructor.
21699
-
21706
+ _lastHeight;
21700
21707
  // @ts-expect-error - TS2564 - Property 'iframeID' has no initializer and is not definitely assigned in the constructor.
21701
-
21708
+ iframeID;
21702
21709
  componentDidMount() {
21703
21710
  // TODO(scottgrant): This is a hack to remove the deprecated call to
21704
21711
  // this.isMounted() but is still considered an anti-pattern.
@@ -24007,6 +24014,8 @@ const {
24007
24014
  HUD
24008
24015
  } = perseus.components;
24009
24016
  class EditorPage extends React__namespace.Component {
24017
+ _isMounted;
24018
+ renderer;
24010
24019
  itemEditor = /*#__PURE__*/React__namespace.createRef();
24011
24020
  hintsEditor = /*#__PURE__*/React__namespace.createRef();
24012
24021
  static defaultProps = {
@@ -24556,12 +24565,12 @@ class SimpleButton extends React__namespace.Component {
24556
24565
  ...otherProps
24557
24566
  } = this.props;
24558
24567
  return /*#__PURE__*/React__namespace.createElement("div", _extends({
24559
- className: aphrodite.css(styles$o.baseButton, color === "green" && styles$o.green, color === "orange" && styles$o.orange),
24568
+ className: aphrodite.css(styles$q.baseButton, color === "green" && styles$q.green, color === "orange" && styles$q.orange),
24560
24569
  onClick: onClick
24561
24570
  }, otherProps), children);
24562
24571
  }
24563
24572
  }
24564
- const styles$o = aphrodite.StyleSheet.create({
24573
+ const styles$q = aphrodite.StyleSheet.create({
24565
24574
  baseButton: {
24566
24575
  top: "0",
24567
24576
  fontSize: "11px",
@@ -24774,23 +24783,23 @@ const LeafContainer = _ref2 => {
24774
24783
  } = _ref2;
24775
24784
  const hasPreviewHeading = shape.type === "content" || shape.type === "hint";
24776
24785
  const previewHeading = hasPreviewHeading && /*#__PURE__*/React__namespace.createElement("div", {
24777
- className: aphrodite.css(styles$n.containerHeader)
24786
+ className: aphrodite.css(styles$p.containerHeader)
24778
24787
  }, /*#__PURE__*/React__namespace.createElement(Header, {
24779
24788
  depth: path.length,
24780
- className: aphrodite.css(styles$n.containerTitle)
24789
+ className: aphrodite.css(styles$p.containerTitle)
24781
24790
  }, capitalize(name)));
24782
24791
  return /*#__PURE__*/React__namespace.createElement("div", {
24783
- className: aphrodite.css(styles$n.container)
24792
+ className: aphrodite.css(styles$p.container)
24784
24793
  }, /*#__PURE__*/React__namespace.createElement("span", {
24785
- className: aphrodite.css(styles$n.row, styles$n.rowHeading)
24794
+ className: aphrodite.css(styles$p.row, styles$p.rowHeading)
24786
24795
  }, /*#__PURE__*/React__namespace.createElement("div", {
24787
- className: aphrodite.css(styles$n.columnLeft)
24796
+ className: aphrodite.css(styles$p.columnLeft)
24788
24797
  }, /*#__PURE__*/React__namespace.createElement("div", {
24789
- className: "pod-title " + aphrodite.css(styles$n.containerHeader)
24798
+ className: "pod-title " + aphrodite.css(styles$p.containerHeader)
24790
24799
  }, /*#__PURE__*/React__namespace.createElement("div", {
24791
- className: aphrodite.css(styles$n.containerTitle)
24800
+ className: aphrodite.css(styles$p.containerTitle)
24792
24801
  }, capitalize(name)), controls)), /*#__PURE__*/React__namespace.createElement("div", {
24793
- className: aphrodite.css(styles$n.columnRight)
24802
+ className: aphrodite.css(styles$p.columnRight)
24794
24803
  }, previewHeading)), children);
24795
24804
  };
24796
24805
  const ArrayContainer = props => {
@@ -24803,11 +24812,11 @@ const ArrayContainer = props => {
24803
24812
  actions
24804
24813
  } = props;
24805
24814
  return /*#__PURE__*/React__namespace.createElement("div", {
24806
- className: aphrodite.css(styles$n.container)
24815
+ className: aphrodite.css(styles$p.container)
24807
24816
  }, controls && /*#__PURE__*/React__namespace.createElement("div", {
24808
- className: aphrodite.css(styles$n.columnLeft, styles$n.containerHeader)
24817
+ className: aphrodite.css(styles$p.columnLeft, styles$p.containerHeader)
24809
24818
  }, controls), /*#__PURE__*/React__namespace.createElement("div", null, children), /*#__PURE__*/React__namespace.createElement("div", {
24810
- className: aphrodite.css(styles$n.columnLeft)
24819
+ className: aphrodite.css(styles$p.columnLeft)
24811
24820
  }, /*#__PURE__*/React__namespace.createElement("a", {
24812
24821
  href: "javascript:void 0",
24813
24822
  onClick: () => actions.addArrayElement(path, shape.elementShape)
@@ -24821,28 +24830,28 @@ const ObjectContainer = _ref3 => {
24821
24830
  path
24822
24831
  } = _ref3;
24823
24832
  const headingEditor = /*#__PURE__*/React__namespace.createElement("div", {
24824
- className: aphrodite.css(styles$n.containerHeader)
24833
+ className: aphrodite.css(styles$p.containerHeader)
24825
24834
  }, /*#__PURE__*/React__namespace.createElement(Header, {
24826
24835
  depth: path.length,
24827
- className: aphrodite.css(styles$n.containerTitle)
24836
+ className: aphrodite.css(styles$p.containerTitle)
24828
24837
  }, capitalize(name)), controls);
24829
24838
  const headingPreview = (name || controls) && /*#__PURE__*/React__namespace.createElement("div", {
24830
- className: aphrodite.css(styles$n.containerHeader, styles$n.previewCollectionHeader)
24839
+ className: aphrodite.css(styles$p.containerHeader, styles$p.previewCollectionHeader)
24831
24840
  }, /*#__PURE__*/React__namespace.createElement(Header, {
24832
24841
  depth: path.length,
24833
- className: aphrodite.css(styles$n.containerTitle)
24842
+ className: aphrodite.css(styles$p.containerTitle)
24834
24843
  }, capitalize(name)));
24835
24844
  const hasBothHeadings = headingEditor && headingPreview;
24836
24845
  return /*#__PURE__*/React__namespace.createElement("div", {
24837
- className: aphrodite.css(styles$n.container)
24846
+ className: aphrodite.css(styles$p.container)
24838
24847
  }, hasBothHeadings && /*#__PURE__*/React__namespace.createElement("span", {
24839
- className: aphrodite.css(styles$n.row)
24848
+ className: aphrodite.css(styles$p.row)
24840
24849
  }, /*#__PURE__*/React__namespace.createElement("div", {
24841
- className: aphrodite.css(styles$n.columnLeft)
24850
+ className: aphrodite.css(styles$p.columnLeft)
24842
24851
  }, headingEditor), /*#__PURE__*/React__namespace.createElement("div", {
24843
- className: aphrodite.css(styles$n.columnRight)
24852
+ className: aphrodite.css(styles$p.columnRight)
24844
24853
  }, headingPreview)), /*#__PURE__*/React__namespace.createElement("div", {
24845
- className: aphrodite.css(path.length > 0 && styles$n.contentIndent)
24854
+ className: aphrodite.css(path.length > 0 && styles$p.contentIndent)
24846
24855
  }, children));
24847
24856
  };
24848
24857
 
@@ -24910,7 +24919,7 @@ const NodeContent = props => {
24910
24919
  const withStickiness = WrappedComponent => {
24911
24920
  return class StickyComponent extends React__namespace.Component {
24912
24921
  // @ts-expect-error - TS2564 - Property 'stickynessTimer' has no initializer and is not definitely assigned in the constructor.
24913
-
24922
+ stickynessTimer;
24914
24923
  state = {
24915
24924
  sticky: false
24916
24925
  };
@@ -24962,11 +24971,11 @@ const ItemNodeContent = withStickiness(props => {
24962
24971
  className: "framework-perseus"
24963
24972
  }, lens(renderers).get(path));
24964
24973
  return /*#__PURE__*/React__namespace.createElement("span", null, /*#__PURE__*/React__namespace.createElement("div", {
24965
- className: aphrodite.css(styles$n.row)
24974
+ className: aphrodite.css(styles$p.row)
24966
24975
  }, /*#__PURE__*/React__namespace.createElement("div", {
24967
- className: aphrodite.css(styles$n.columnLeft)
24976
+ className: aphrodite.css(styles$p.columnLeft)
24968
24977
  }, /*#__PURE__*/React__namespace.createElement("div", {
24969
- className: aphrodite.css(sticky && styles$n.sticky)
24978
+ className: aphrodite.css(sticky && styles$p.sticky)
24970
24979
  },
24971
24980
  /*#__PURE__*/
24972
24981
  // @ts-expect-error - TS2769 - No overload matches this call.
@@ -24974,9 +24983,9 @@ const ItemNodeContent = withStickiness(props => {
24974
24983
  onChange: newVal => actions.mergeValueAtPath(path, newVal),
24975
24984
  apiOptions: apiOptions
24976
24985
  })))), /*#__PURE__*/React__namespace.createElement("div", {
24977
- className: aphrodite.css(styles$n.columnRight)
24986
+ className: aphrodite.css(styles$p.columnRight)
24978
24987
  }, /*#__PURE__*/React__namespace.createElement("div", {
24979
- className: aphrodite.css(sticky && styles$n.sticky)
24988
+ className: aphrodite.css(sticky && styles$p.sticky)
24980
24989
  }, preview))));
24981
24990
  });
24982
24991
  const HintNodeContent = withStickiness(props => {
@@ -24992,13 +25001,13 @@ const HintNodeContent = withStickiness(props => {
24992
25001
  className: "framework-perseus"
24993
25002
  }, lens(renderers).get(path));
24994
25003
  return /*#__PURE__*/React__namespace.createElement("div", {
24995
- className: aphrodite.css(styles$n.row)
25004
+ className: aphrodite.css(styles$p.row)
24996
25005
  }, /*#__PURE__*/React__namespace.createElement("div", {
24997
- className: aphrodite.css(styles$n.columnLeft)
25006
+ className: aphrodite.css(styles$p.columnLeft)
24998
25007
  }, /*#__PURE__*/React__namespace.createElement("div", {
24999
- className: aphrodite.css(sticky && styles$n.sticky)
25008
+ className: aphrodite.css(sticky && styles$p.sticky)
25000
25009
  }, /*#__PURE__*/React__namespace.createElement(HintEditor, _extends({}, data, {
25001
- className: aphrodite.css(styles$n.hintEditor),
25010
+ className: aphrodite.css(styles$p.hintEditor),
25002
25011
  onChange: newVal => actions.mergeValueAtPath(path, newVal),
25003
25012
  apiOptions: apiOptions,
25004
25013
  showTitle: false,
@@ -25013,9 +25022,9 @@ const HintNodeContent = withStickiness(props => {
25013
25022
  isFirst: true,
25014
25023
  isLast: true
25015
25024
  })))), /*#__PURE__*/React__namespace.createElement("div", {
25016
- className: aphrodite.css(styles$n.columnRight)
25025
+ className: aphrodite.css(styles$p.columnRight)
25017
25026
  }, /*#__PURE__*/React__namespace.createElement("div", {
25018
- className: aphrodite.css(sticky && styles$n.sticky)
25027
+ className: aphrodite.css(sticky && styles$p.sticky)
25019
25028
  }, preview)));
25020
25029
  });
25021
25030
  const TagsNodeContent = props => {
@@ -25032,9 +25041,9 @@ const TagsNodeContent = props => {
25032
25041
  return null;
25033
25042
  }
25034
25043
  return /*#__PURE__*/React__namespace.createElement("div", {
25035
- className: aphrodite.css(styles$n.columnLeft)
25044
+ className: aphrodite.css(styles$p.columnLeft)
25036
25045
  }, /*#__PURE__*/React__namespace.createElement("div", {
25037
- className: aphrodite.css(styles$n.tagsEditor)
25046
+ className: aphrodite.css(styles$p.tagsEditor)
25038
25047
  }, /*#__PURE__*/React__namespace.createElement(GroupMetadataEditor, {
25039
25048
  value: data,
25040
25049
  onChange: newVal => actions.setValueAtPath(path, newVal),
@@ -25065,23 +25074,23 @@ const ArrayNodeContent = props => {
25065
25074
  const subpath = path.concat(i);
25066
25075
  const controls = [i > 0 && /*#__PURE__*/React__namespace.createElement("div", {
25067
25076
  key: "moveArrayElementUp",
25068
- className: aphrodite.css(styles$n.control)
25077
+ className: aphrodite.css(styles$p.control)
25069
25078
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25070
25079
  color: "orange",
25071
25080
  title: "Move up",
25072
25081
  onClick: () => actions.moveArrayElementUp(subpath)
25073
25082
  }, /*#__PURE__*/React__namespace.createElement("div", {
25074
- className: aphrodite.css(styles$n.verticalFlip)
25083
+ className: aphrodite.css(styles$p.verticalFlip)
25075
25084
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconChevronDown)))), i < data.length - 1 && /*#__PURE__*/React__namespace.createElement("div", {
25076
25085
  key: "moveArrayElementDown",
25077
- className: aphrodite.css(styles$n.control)
25086
+ className: aphrodite.css(styles$p.control)
25078
25087
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25079
25088
  color: "orange",
25080
25089
  title: "Move down",
25081
25090
  onClick: () => actions.moveArrayElementDown(subpath)
25082
25091
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconChevronDown))), /*#__PURE__*/React__namespace.createElement("div", {
25083
25092
  key: "removeArrayElement",
25084
- className: aphrodite.css(styles$n.control)
25093
+ className: aphrodite.css(styles$p.control)
25085
25094
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25086
25095
  color: "orange",
25087
25096
  title: "Delete",
@@ -25089,7 +25098,7 @@ const ArrayNodeContent = props => {
25089
25098
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconTrash$4)))];
25090
25099
  return /*#__PURE__*/React__namespace.createElement("div", {
25091
25100
  key: i,
25092
- className: aphrodite.css(styles$n.arrayElement, !elementIsLeaf && styles$n.arrayElementAndNotLeaf)
25101
+ className: aphrodite.css(styles$p.arrayElement, !elementIsLeaf && styles$p.arrayElementAndNotLeaf)
25093
25102
  }, /*#__PURE__*/React__namespace.createElement(NodeContainer, _extends({}, otherProps, {
25094
25103
  key: i,
25095
25104
  shape: shape.elementShape,
@@ -25115,7 +25124,7 @@ const ObjectNodeContent = props => {
25115
25124
  // made sense to the shape's author is the order in which we'll iterate :)
25116
25125
  const children = Object.keys(shape.shape).map(subkey => /*#__PURE__*/React__namespace.createElement("div", {
25117
25126
  key: subkey,
25118
- className: aphrodite.css(styles$n.objectElement)
25127
+ className: aphrodite.css(styles$p.objectElement)
25119
25128
  }, /*#__PURE__*/React__namespace.createElement(NodeContainer, _extends({}, otherProps, {
25120
25129
  shape: shape.shape[subkey],
25121
25130
  data: data[subkey],
@@ -25124,6 +25133,7 @@ const ObjectNodeContent = props => {
25124
25133
  return /*#__PURE__*/React__namespace.createElement("div", null, children);
25125
25134
  };
25126
25135
  class MultiRendererEditor extends React__namespace.Component {
25136
+ layout;
25127
25137
  _renderLayout = () => {
25128
25138
  const {
25129
25139
  Layout,
@@ -25284,7 +25294,7 @@ class MultiRendererEditor extends React__namespace.Component {
25284
25294
  }, this._renderContent());
25285
25295
  }
25286
25296
  }
25287
- const styles$n = aphrodite.StyleSheet.create({
25297
+ const styles$p = aphrodite.StyleSheet.create({
25288
25298
  // This is used in a number of places throughout this file.
25289
25299
  container: {},
25290
25300
  // eslint-disable-next-line react-native/no-unused-styles
@@ -25436,47 +25446,47 @@ const StatefulArticleEditor = createReactClass__default["default"]({
25436
25446
  screen
25437
25447
  } = this.state;
25438
25448
  return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", {
25439
- style: styles$m.controlBar
25449
+ style: styles$o.controlBar
25440
25450
  }, /*#__PURE__*/React__namespace.createElement("span", {
25441
- style: styles$m.controls
25451
+ style: styles$o.controls
25442
25452
  }, "Mode:", " ", /*#__PURE__*/React__namespace.createElement("span", {
25443
25453
  onClick: () => this.setState({
25444
25454
  mode: "edit"
25445
25455
  }),
25446
- style: mode === "edit" ? styles$m.controlSelected : styles$m.control
25456
+ style: mode === "edit" ? styles$o.controlSelected : styles$o.control
25447
25457
  }, "EDIT"), " | ", /*#__PURE__*/React__namespace.createElement("span", {
25448
25458
  onClick: () => this.setState({
25449
25459
  mode: "preview"
25450
25460
  }),
25451
- style: mode === "preview" ? styles$m.controlSelected : styles$m.control
25461
+ style: mode === "preview" ? styles$o.controlSelected : styles$o.control
25452
25462
  }, "PREVIEW"), " | ", /*#__PURE__*/React__namespace.createElement("span", {
25453
25463
  onClick: () => this.setState({
25454
25464
  mode: "json"
25455
25465
  }),
25456
- style: mode === "json" ? styles$m.controlSelected : styles$m.control
25466
+ style: mode === "json" ? styles$o.controlSelected : styles$o.control
25457
25467
  }, "JSON")), /*#__PURE__*/React__namespace.createElement("span", {
25458
- style: styles$m.controls
25468
+ style: styles$o.controls
25459
25469
  }, "Screen:", " ", /*#__PURE__*/React__namespace.createElement("span", {
25460
25470
  onClick: () => this.setState({
25461
25471
  screen: "phone"
25462
25472
  }),
25463
- style: screen === "phone" ? styles$m.controlSelected : styles$m.control
25473
+ style: screen === "phone" ? styles$o.controlSelected : styles$o.control
25464
25474
  }, "PHONE"), " | ", /*#__PURE__*/React__namespace.createElement("span", {
25465
25475
  onClick: () => this.setState({
25466
25476
  screen: "tablet"
25467
25477
  }),
25468
- style: screen === "tablet" ? styles$m.controlSelected : styles$m.control
25478
+ style: screen === "tablet" ? styles$o.controlSelected : styles$o.control
25469
25479
  }, "TABLET"), " | ", /*#__PURE__*/React__namespace.createElement("span", {
25470
25480
  onClick: () => this.setState({
25471
25481
  screen: "desktop"
25472
25482
  }),
25473
- style: screen === "desktop" ? styles$m.controlSelected : styles$m.control
25483
+ style: screen === "desktop" ? styles$o.controlSelected : styles$o.control
25474
25484
  }, "DESKTOP"))), /*#__PURE__*/React__namespace.createElement("div", {
25475
- style: styles$m.editor
25485
+ style: styles$o.editor
25476
25486
  }, /*#__PURE__*/React__namespace.createElement(ArticleEditor, this.state)));
25477
25487
  }
25478
25488
  });
25479
- const styles$m = {
25489
+ const styles$o = {
25480
25490
  controlBar: {
25481
25491
  marginBottom: 25,
25482
25492
  marginTop: 5
@@ -27015,10 +27025,10 @@ class GradedGroupEditor extends React__namespace.Component {
27015
27025
  }, /*#__PURE__*/React__namespace.createElement("div", {
27016
27026
  className: "perseus-widget-row"
27017
27027
  }, /*#__PURE__*/React__namespace.createElement("label", {
27018
- className: aphrodite.css(styles$l.title)
27028
+ className: aphrodite.css(styles$n.title)
27019
27029
  }, "Title:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$6, {
27020
27030
  value: this.props.title,
27021
- className: aphrodite.css(styles$l.input)
27031
+ className: aphrodite.css(styles$n.input)
27022
27032
  // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
27023
27033
  ,
27024
27034
  onChange: this.change("title")
@@ -27043,7 +27053,7 @@ class GradedGroupEditor extends React__namespace.Component {
27043
27053
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$4, iconPlus$1), " Add a hint"), this.props.hint && /*#__PURE__*/React__namespace.createElement("div", {
27044
27054
  className: "perseus-hint-editor"
27045
27055
  }, /*#__PURE__*/React__namespace.createElement("div", {
27046
- className: aphrodite.css(styles$l.hintsTitle)
27056
+ className: aphrodite.css(styles$n.hintsTitle)
27047
27057
  }, "Hint"), /*#__PURE__*/React__namespace.createElement(Editor, {
27048
27058
  ref: this.hintEditor,
27049
27059
  content: this.props.hint ? this.props.hint.content : "",
@@ -27075,7 +27085,7 @@ class GradedGroupEditor extends React__namespace.Component {
27075
27085
  };
27076
27086
  };
27077
27087
  }
27078
- const styles$l = aphrodite.StyleSheet.create({
27088
+ const styles$n = aphrodite.StyleSheet.create({
27079
27089
  title: {
27080
27090
  fontSize: 18,
27081
27091
  fontWeight: "bold"
@@ -27092,7 +27102,7 @@ const styles$l = aphrodite.StyleSheet.create({
27092
27102
 
27093
27103
  class GradedGroupSetEditor extends React__namespace.Component {
27094
27104
  // @ts-expect-error - TS2564 - Property '_editors' has no initializer and is not definitely assigned in the constructor.
27095
-
27105
+ _editors;
27096
27106
  static propTypes = {
27097
27107
  ...perseus.Changeable.propTypes,
27098
27108
  apiOptions: perseus.ApiOptions.propTypes,
@@ -28284,6 +28294,7 @@ const answerTypes = {
28284
28294
  }
28285
28295
  };
28286
28296
  class InputNumberEditor extends React__namespace.Component {
28297
+ static contextType = perseus.PerseusI18nContext;
28287
28298
  static widgetName = "input-number";
28288
28299
  static defaultProps = {
28289
28300
  value: 0,
@@ -28296,7 +28307,7 @@ class InputNumberEditor extends React__namespace.Component {
28296
28307
  };
28297
28308
  input = /*#__PURE__*/React__namespace.createRef();
28298
28309
  handleAnswerChange = str => {
28299
- const value = perseus.Util.firstNumericalParse(str) || 0;
28310
+ const value = perseus.Util.firstNumericalParse(str, this.context.strings) || 0;
28300
28311
  this.props.onChange({
28301
28312
  value: value
28302
28313
  });
@@ -28347,7 +28358,7 @@ class InputNumberEditor extends React__namespace.Component {
28347
28358
  defaultValue: this.props.maxError,
28348
28359
  "aria-label": "Max error",
28349
28360
  onBlur: e => {
28350
- const ans = "" + (perseus.Util.firstNumericalParse(e.target.value) || 0);
28361
+ const ans = "" + (perseus.Util.firstNumericalParse(e.target.value, this.context.strings) || 0);
28351
28362
  e.target.value = ans;
28352
28363
  this.props.onChange({
28353
28364
  maxError: ans
@@ -28407,12 +28418,15 @@ class InputNumberEditor extends React__namespace.Component {
28407
28418
  function MathquillInput(props) {
28408
28419
  const mathFieldWrapperRef = React.useRef(null);
28409
28420
  const mathFieldInstance = React.useRef();
28421
+ const {
28422
+ strings
28423
+ } = mathInput.useMathInputI18n();
28410
28424
  React.useEffect(() => {
28411
28425
  // If we have the mount for the input, but not the input
28412
28426
  // make a new Mathquill input
28413
28427
  if (mathFieldWrapperRef.current && !mathFieldInstance.current) {
28414
28428
  // Initialize MathQuill.MathField instance
28415
- mathFieldInstance.current = mathInput.createMathField(mathFieldWrapperRef.current, baseConfig => ({
28429
+ mathFieldInstance.current = mathInput.createMathField(mathFieldWrapperRef.current, strings, baseConfig => ({
28416
28430
  ...baseConfig,
28417
28431
  handlers: {
28418
28432
  edit: mathField => {
@@ -28441,13 +28455,13 @@ function MathquillInput(props) {
28441
28455
  }
28442
28456
  });
28443
28457
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
28444
- style: styles$k.outerWrapper
28458
+ style: styles$m.outerWrapper
28445
28459
  }, /*#__PURE__*/React__namespace.createElement("span", {
28446
28460
  ref: mathFieldWrapperRef,
28447
28461
  className: "perseus-math-input mq-editable-field mq-math-mode"
28448
28462
  }));
28449
28463
  }
28450
- const styles$k = aphrodite.StyleSheet.create({
28464
+ const styles$m = aphrodite.StyleSheet.create({
28451
28465
  outerWrapper: {
28452
28466
  display: "inline-block",
28453
28467
  borderStyle: "solid",
@@ -29533,7 +29547,7 @@ const GraphPointsCountSelector = _ref => {
29533
29547
  // Never uses placeholder, always has value
29534
29548
  ,
29535
29549
  placeholder: "",
29536
- style: styles$j.singleSelectShort
29550
+ style: styles$l.singleSelectShort
29537
29551
  }, [...[...Array(7).keys()].map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29538
29552
  key: n,
29539
29553
  value: `${n}`,
@@ -29544,7 +29558,7 @@ const GraphPointsCountSelector = _ref => {
29544
29558
  label: "unlimited"
29545
29559
  })]);
29546
29560
  };
29547
- const styles$j = aphrodite.StyleSheet.create({
29561
+ const styles$l = aphrodite.StyleSheet.create({
29548
29562
  singleSelectShort: {
29549
29563
  // Non-standard spacing, but it's the smallest we can go
29550
29564
  // without running into styling issues with the dropdown.
@@ -29557,7 +29571,7 @@ const GraphTypeSelector = props => {
29557
29571
  selectedValue: props.graphType,
29558
29572
  onChange: props.onChange,
29559
29573
  placeholder: "Select a graph type",
29560
- style: styles$i.singleSelectShort
29574
+ style: styles$k.singleSelectShort
29561
29575
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29562
29576
  value: "linear",
29563
29577
  label: "Linear function"
@@ -29590,7 +29604,7 @@ const GraphTypeSelector = props => {
29590
29604
  label: "Angle"
29591
29605
  }));
29592
29606
  };
29593
- const styles$i = aphrodite.StyleSheet.create({
29607
+ const styles$k = aphrodite.StyleSheet.create({
29594
29608
  singleSelectShort: {
29595
29609
  // Non-standard spacing, but it's the smallest we can go
29596
29610
  // without running into styling issues with the dropdown.
@@ -29607,16 +29621,16 @@ const LabeledRow = props => {
29607
29621
  style
29608
29622
  } = props;
29609
29623
  return /*#__PURE__*/React__namespace.createElement("label", {
29610
- className: aphrodite.css(styles$h.label)
29624
+ className: aphrodite.css(styles$j.label)
29611
29625
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29612
- style: [styles$h.row, style]
29626
+ style: [styles$j.row, style]
29613
29627
  }, labelSide === "start" || /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29614
- style: styles$h.spaceEnd
29628
+ style: styles$j.spaceEnd
29615
29629
  }, label), children, labelSide === "end" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29616
- style: styles$h.spaceStart
29630
+ style: styles$j.spaceStart
29617
29631
  }, label)));
29618
29632
  };
29619
- const styles$h = aphrodite.StyleSheet.create({
29633
+ const styles$j = aphrodite.StyleSheet.create({
29620
29634
  label: {
29621
29635
  width: "fit-content"
29622
29636
  },
@@ -30038,10 +30052,10 @@ class InteractiveGraphSettings extends React__namespace.Component {
30038
30052
  onChange: this.change
30039
30053
  }))), /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30040
30054
  label: "Background image URL:",
30041
- style: styles$g.resetSpaceTop
30055
+ style: styles$i.resetSpaceTop
30042
30056
  }, /*#__PURE__*/React__namespace.createElement("input", {
30043
30057
  type: "text",
30044
- className: aphrodite.css(styles$g.backgroundUrlInput),
30058
+ className: aphrodite.css(styles$i.backgroundUrlInput),
30045
30059
  ref: this.bgUrlRef,
30046
30060
  value: this.state.backgroundImage.url || "",
30047
30061
  onChange: e => {
@@ -30057,24 +30071,24 @@ class InteractiveGraphSettings extends React__namespace.Component {
30057
30071
  onKeyPress: this.changeBackgroundUrl,
30058
30072
  onBlur: this.changeBackgroundUrl
30059
30073
  }), /*#__PURE__*/React__namespace.createElement(InfoTip$c, null, /*#__PURE__*/React__namespace.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background."))), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30060
- style: styles$g.rulerSection
30074
+ style: styles$i.rulerSection
30061
30075
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30062
- style: styles$g.checkboxRow
30076
+ style: styles$i.checkboxRow
30063
30077
  }, /*#__PURE__*/React__namespace.createElement(PropCheckBox$7, {
30064
30078
  label: "Show ruler",
30065
30079
  showRuler: this.props.showRuler,
30066
30080
  onChange: this.change,
30067
- style: styles$g.resetSpaceTop
30081
+ style: styles$i.resetSpaceTop
30068
30082
  }), /*#__PURE__*/React__namespace.createElement(PropCheckBox$7, {
30069
30083
  label: "Show protractor",
30070
30084
  showProtractor: this.props.showProtractor,
30071
30085
  onChange: this.change,
30072
- style: styles$g.resetSpaceTop
30086
+ style: styles$i.resetSpaceTop
30073
30087
  })), this.props.showRuler && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30074
- style: styles$g.spaceTop
30088
+ style: styles$i.spaceTop
30075
30089
  }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30076
30090
  label: "Ruler label:",
30077
- style: styles$g.resetSpaceTop
30091
+ style: styles$i.resetSpaceTop
30078
30092
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30079
30093
  id: "ruler-label-select",
30080
30094
  selectedValue: this.props.rulerLabel,
@@ -30084,7 +30098,7 @@ class InteractiveGraphSettings extends React__namespace.Component {
30084
30098
  });
30085
30099
  },
30086
30100
  placeholder: "None",
30087
- style: styles$g.singleSelectShort
30101
+ style: styles$i.singleSelectShort
30088
30102
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30089
30103
  value: "",
30090
30104
  label: "None",
@@ -30125,7 +30139,7 @@ class InteractiveGraphSettings extends React__namespace.Component {
30125
30139
  });
30126
30140
  },
30127
30141
  placeholder: "10",
30128
- style: styles$g.singleSelectShort
30142
+ style: styles$i.singleSelectShort
30129
30143
  }, [1, 2, 4, 8, 10, 16].map(value => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30130
30144
  key: value,
30131
30145
  value: `${value}`,
@@ -30133,7 +30147,7 @@ class InteractiveGraphSettings extends React__namespace.Component {
30133
30147
  })))))));
30134
30148
  }
30135
30149
  }
30136
- const styles$g = aphrodite.StyleSheet.create({
30150
+ const styles$i = aphrodite.StyleSheet.create({
30137
30151
  resetSpaceTop: {
30138
30152
  marginTop: 0
30139
30153
  },
@@ -30177,22 +30191,26 @@ const LockedFigureSelect = props => {
30177
30191
  onChange
30178
30192
  } = props;
30179
30193
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30180
- style: styles$f.container
30194
+ style: styles$h.container
30181
30195
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionMenu, {
30182
- menuText: "Add element",
30183
- style: styles$f.addElementSelect
30196
+ menuText: "Add locked figure",
30197
+ style: styles$h.addElementSelect
30184
30198
  }, [/*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
30185
30199
  key: `${id}-point`,
30186
30200
  label: "Point",
30187
30201
  onClick: () => onChange("point")
30188
- }, "Point")]));
30202
+ }, "Point"), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
30203
+ key: `${id}-line`,
30204
+ label: "Line",
30205
+ onClick: () => onChange("line")
30206
+ }, "Line")]));
30189
30207
  };
30190
- const styles$f = aphrodite.StyleSheet.create({
30208
+ const styles$h = aphrodite.StyleSheet.create({
30191
30209
  container: {
30192
- marginTop: wonderBlocksTokens.spacing.medium_16
30210
+ marginTop: wonderBlocksTokens.spacing.xxxSmall_4
30193
30211
  },
30194
30212
  addElementSelect: {
30195
- backgroundColor: wonderBlocksTokens.color.fadedBlue16,
30213
+ backgroundColor: wonderBlocksTokens.color.fadedBlue8,
30196
30214
  borderRadius: wonderBlocksTokens.spacing.xxxSmall_4
30197
30215
  }
30198
30216
  });
@@ -30248,21 +30266,99 @@ const defaultContext = {
30248
30266
  };
30249
30267
  const MediaLayoutContext = React__namespace.createContext(defaultContext);
30250
30268
  MediaLayoutContext.displayName = "MediaLayoutContext";
30269
+ aphrodite.StyleSheet.create({
30270
+ grow: {
30271
+ flexGrow: 1
30272
+ }
30273
+ });
30251
30274
 
30252
- class Spring extends React__namespace.Component {
30275
+ class Strut extends React__namespace.Component {
30253
30276
  render() {
30254
30277
  const {
30278
+ size,
30255
30279
  style
30256
30280
  } = this.props;
30257
30281
  return React__namespace.createElement(wonderBlocksCore.View, {
30258
30282
  "aria-hidden": "true",
30259
- style: [styles$e.grow, style]
30283
+ style: [strutStyle(size), style]
30260
30284
  });
30261
30285
  }
30262
30286
  }
30263
- const styles$e = aphrodite.StyleSheet.create({
30264
- grow: {
30265
- flexGrow: 1
30287
+ const strutStyle = size => {
30288
+ return {
30289
+ width: size,
30290
+ MsFlexBasis: size,
30291
+ MsFlexPreferredSize: size,
30292
+ WebkitFlexBasis: size,
30293
+ flexBasis: size,
30294
+ flexShrink: 0
30295
+ };
30296
+ };
30297
+
30298
+ const ColorSwatch = props => {
30299
+ const {
30300
+ color,
30301
+ filled = true,
30302
+ decorative = false
30303
+ } = props;
30304
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30305
+ "aria-label":
30306
+ // Don't include an aria label for decorative circles.
30307
+ !decorative ? `Color: ${color}, ${filled ? "filled" : "open"}` : undefined,
30308
+ style: [styles$g.colorSwatch, {
30309
+ border: `4px solid ${perseus.lockedFigureColors[color]}`,
30310
+ backgroundColor: filled ? perseus.lockedFigureColors[color] : wonderBlocksTokens.color.white
30311
+ }]
30312
+ });
30313
+ };
30314
+ const styles$g = aphrodite.StyleSheet.create({
30315
+ colorSwatch: {
30316
+ // Add a white outline so that the color swatch is visible when
30317
+ // the dropdown option is highlighted with its blue background.
30318
+ outline: `2px solid ${wonderBlocksTokens.color.offWhite}`,
30319
+ borderRadius: "50%",
30320
+ width: wonderBlocksTokens.spacing.large_24,
30321
+ height: wonderBlocksTokens.spacing.large_24
30322
+ }
30323
+ });
30324
+
30325
+ const possibleColors = Object.keys(perseus.lockedFigureColors);
30326
+ const ColorSelect = props => {
30327
+ const {
30328
+ id,
30329
+ selectedValue,
30330
+ onChange
30331
+ } = props;
30332
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30333
+ style: styles$f.row
30334
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30335
+ htmlFor: id,
30336
+ style: styles$f.label,
30337
+ tag: "label"
30338
+ }, "Color"), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30339
+ id: id,
30340
+ selectedValue: selectedValue,
30341
+ onChange: onChange
30342
+ // Placeholder is required, but never gets used.
30343
+ ,
30344
+ placeholder: ""
30345
+ }, possibleColors.map(colorName => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30346
+ key: colorName,
30347
+ value: colorName,
30348
+ label: colorName,
30349
+ leftAccessory: /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
30350
+ color: colorName,
30351
+ decorative: true
30352
+ })
30353
+ }, colorName))));
30354
+ };
30355
+ const styles$f = aphrodite.StyleSheet.create({
30356
+ row: {
30357
+ flexDirection: "row",
30358
+ alignItems: "center"
30359
+ },
30360
+ label: {
30361
+ marginInlineEnd: wonderBlocksTokens.spacing.xSmall_8
30266
30362
  }
30267
30363
  });
30268
30364
 
@@ -30307,17 +30403,35 @@ function focusWithChromeStickyFocusBugWorkaround(element) {
30307
30403
  });
30308
30404
  }
30309
30405
  function getValidNumberFromString(value) {
30310
- const parsed = parseInt(value);
30406
+ const parsed = parseFloat(value);
30311
30407
  // If the value is not a number, return 0.
30312
30408
  return isNaN(parsed) ? 0 : parsed;
30313
30409
  }
30314
- function getDefaultFigureForFigureType(type) {
30410
+ function getDefaultFigureForType(type) {
30315
30411
  switch (type) {
30316
30412
  case "point":
30317
30413
  return {
30318
30414
  type: "point",
30319
- coord: [0, 0]
30415
+ coord: [0, 0],
30416
+ color: "blue",
30417
+ filled: true
30320
30418
  };
30419
+ case "line":
30420
+ return {
30421
+ type: "line",
30422
+ kind: "line",
30423
+ points: [getDefaultFigureForType("point"), {
30424
+ ...getDefaultFigureForType("point"),
30425
+ coord: [2, 2]
30426
+ }],
30427
+ color: "blue",
30428
+ lineStyle: "solid",
30429
+ showArrows: false,
30430
+ showStartPoint: false,
30431
+ showEndPoint: false
30432
+ };
30433
+ default:
30434
+ throw new wonderStuffCore.UnreachableCaseError(type);
30321
30435
  }
30322
30436
  }
30323
30437
 
@@ -30327,15 +30441,21 @@ function getDefaultFigureForFigureType(type) {
30327
30441
  *
30328
30442
  * Used in the interactive graph editor's locked figures section.
30329
30443
  */
30330
- const possibleColors = ["purple", "blue", "teal", "green", "gold", "red", "pink"];
30331
30444
  const LockedPointSettings = props => {
30332
30445
  const {
30333
30446
  coord,
30447
+ color: pointColor,
30448
+ filled = true,
30449
+ label,
30450
+ toggled = "true",
30334
30451
  style,
30335
- onChangeColor,
30336
- onChangeCoord,
30452
+ onChangeProps,
30453
+ onToggle,
30337
30454
  onRemove
30338
30455
  } = props;
30456
+
30457
+ // Keep track of the coordinates via state as the user is editing them,
30458
+ // before they are updated in the props on blur.
30339
30459
  const [coordState, setCoordState] = React__namespace.useState([
30340
30460
  // Using strings to make it easier to work with the text fields.
30341
30461
  coord[0].toString(), coord[1].toString()]);
@@ -30345,101 +30465,335 @@ const LockedPointSettings = props => {
30345
30465
  const ids = wonderBlocksCore.useUniqueIdWithMock();
30346
30466
  const xCoordId = ids.get("x-coord");
30347
30467
  const yCoordId = ids.get("y-coord");
30348
- const colorSelectId = ids.get("color-select");
30468
+ const colorSelectId = ids.get("point-color-select");
30469
+ const showPointToggleId = ids.get("show-point-toggle");
30349
30470
  function handleBlur() {
30350
30471
  const validCoord = [getValidNumberFromString(coordState[0]), getValidNumberFromString(coordState[1])];
30351
30472
 
30352
30473
  // Make the text field only show valid numbers after blur.
30353
30474
  setCoordState([validCoord[0].toString(), validCoord[1].toString()]);
30354
30475
  // Update the graph with the new coordinates.
30355
- onChangeCoord(validCoord);
30476
+ onChangeProps({
30477
+ coord: validCoord
30478
+ });
30356
30479
  }
30357
30480
  function handleCoordChange(newValue, coordIndex) {
30358
30481
  const newCoord = [...coordState];
30359
30482
  newCoord[coordIndex] = newValue;
30360
30483
  setCoordState(newCoord);
30361
30484
  }
30362
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30363
- style: styles$d.container
30485
+ function handleColorChange(newValue) {
30486
+ onChangeProps({
30487
+ color: newValue
30488
+ });
30489
+ }
30490
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View
30491
+ // More specificity so that we can override the default
30492
+ // .heading > h2 > .header styles from the articles.less
30493
+ // file (which is imported in perseus-renderer.less).
30494
+ , {
30495
+ className: "locked-figure-accordion"
30496
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksAccordion.AccordionSection, {
30497
+ style: [styles$e.container, style],
30498
+ headerStyle: styles$e.accordionHeader,
30499
+ header:
30500
+ /*#__PURE__*/
30501
+ // Summary: Point, coords, color (filled/open)
30502
+ React__namespace.createElement(wonderBlocksCore.View, {
30503
+ style: styles$e.row
30504
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `${label || "Point"} (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React__namespace.createElement(Strut, {
30505
+ size: wonderBlocksTokens.spacing.xSmall_8
30506
+ }), toggled && /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
30507
+ color: pointColor,
30508
+ filled: filled
30509
+ }))
30364
30510
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30365
- style: styles$d.row
30366
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Point"), /*#__PURE__*/React__namespace.createElement(Spring, null), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30367
- icon: trashIcon__default["default"],
30368
- "aria-label": `Delete locked point at ${coordState[0]}, ${coordState[1]}`,
30369
- onClick: onRemove
30370
- })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30371
- style: styles$d.row
30511
+ style: styles$e.accordionPanel
30512
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30513
+ style: styles$e.row
30514
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30515
+ style: [styles$e.row, styles$e.spaceUnder]
30372
30516
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30373
30517
  htmlFor: xCoordId,
30374
- style: styles$d.label,
30518
+ style: styles$e.label,
30375
30519
  tag: "label"
30376
- }, "x Coordinate"), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30520
+ }, "x Coord"), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30377
30521
  id: xCoordId,
30522
+ type: "number",
30378
30523
  value: coordState[0],
30379
30524
  onChange: newValue => handleCoordChange(newValue, 0),
30380
30525
  onBlur: handleBlur,
30381
- style: styles$d.textField
30382
- })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30383
- style: styles$d.row
30526
+ style: styles$e.textField
30527
+ })), /*#__PURE__*/React__namespace.createElement(Strut, {
30528
+ size: wonderBlocksTokens.spacing.medium_16
30529
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30530
+ style: [styles$e.row, styles$e.spaceUnder]
30384
30531
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30385
30532
  htmlFor: yCoordId,
30386
- style: styles$d.label,
30533
+ style: styles$e.label,
30387
30534
  tag: "label"
30388
- }, "y Coordinate"), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30535
+ }, "y Coord"), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30389
30536
  id: yCoordId,
30537
+ type: "number",
30390
30538
  value: coordState[1],
30391
30539
  onChange: newValue => handleCoordChange(newValue, 1),
30392
30540
  onBlur: handleBlur,
30393
- style: styles$d.textField
30541
+ style: styles$e.textField
30542
+ }))), onToggle && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30543
+ style: [styles$e.row, styles$e.spaceUnder]
30544
+ }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
30545
+ id: showPointToggleId,
30546
+ checked: !!toggled,
30547
+ onChange: onToggle
30548
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
30549
+ size: wonderBlocksTokens.spacing.small_12
30550
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30551
+ tag: "label",
30552
+ htmlFor: showPointToggleId
30553
+ }, "Show point on graph")), toggled && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30554
+ id: colorSelectId,
30555
+ selectedValue: pointColor || "blue",
30556
+ onChange: handleColorChange
30557
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
30558
+ size: wonderBlocksTokens.spacing.xSmall_8
30559
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
30560
+ label: "Open point",
30561
+ checked: !filled,
30562
+ onChange: newValue => {
30563
+ onChangeProps({
30564
+ filled: !newValue
30565
+ });
30566
+ },
30567
+ style: styles$e.spaceUnder
30568
+ })), onRemove && /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30569
+ icon: trashIcon__default["default"],
30570
+ "aria-label": `Delete locked point at ${coordState[0]}, ${coordState[1]}`,
30571
+ onClick: onRemove,
30572
+ style: styles$e.deleteButton
30573
+ }))));
30574
+ };
30575
+ const styles$e = aphrodite.StyleSheet.create({
30576
+ container: {
30577
+ backgroundColor: wonderBlocksTokens.color.fadedBlue8,
30578
+ marginBottom: wonderBlocksTokens.spacing.small_12
30579
+ },
30580
+ accordionHeader: {
30581
+ paddingTop: wonderBlocksTokens.spacing.small_12,
30582
+ paddingBottom: wonderBlocksTokens.spacing.small_12,
30583
+ paddingInlineStart: wonderBlocksTokens.spacing.medium_16,
30584
+ // Fixed height so the addition of the color swatch doesn't
30585
+ // change the height of the header when toggling.
30586
+ height: wonderBlocksTokens.spacing.xxLarge_48
30587
+ },
30588
+ accordionPanel: {
30589
+ padding: wonderBlocksTokens.spacing.medium_16,
30590
+ paddingBottom: wonderBlocksTokens.spacing.xSmall_8
30591
+ },
30592
+ row: {
30593
+ flexDirection: "row",
30594
+ alignItems: "center"
30595
+ },
30596
+ spaceUnder: {
30597
+ marginBottom: wonderBlocksTokens.spacing.xSmall_8
30598
+ },
30599
+ label: {
30600
+ marginInlineEnd: wonderBlocksTokens.spacing.xSmall_8
30601
+ },
30602
+ textField: {
30603
+ width: wonderBlocksTokens.spacing.xxxLarge_64
30604
+ },
30605
+ deleteButton: {
30606
+ position: "absolute",
30607
+ top: wonderBlocksTokens.spacing.small_12,
30608
+ right: wonderBlocksTokens.spacing.small_12
30609
+ }
30610
+ });
30611
+
30612
+ const LockedLineSettings = props => {
30613
+ const {
30614
+ kind,
30615
+ points,
30616
+ color: lineColor = "blue",
30617
+ lineStyle = "solid",
30618
+ showArrows,
30619
+ showStartPoint,
30620
+ showEndPoint,
30621
+ onChangeProps,
30622
+ onRemove
30623
+ } = props;
30624
+ const [startPoint, endPoint] = points;
30625
+
30626
+ // Generate unique IDs so that the programmatic labels can be associated
30627
+ // with their respective text fields.
30628
+ const ids = wonderBlocksCore.useUniqueIdWithMock();
30629
+ const kindSelectId = ids.get("line-kind-select");
30630
+ const colorSelectId = ids.get("line-color-select");
30631
+ const styleSelectId = ids.get("line-style-select");
30632
+ const lineLabel = `Line (${startPoint.coord[0]}, ${startPoint.coord[1]}),
30633
+ (${endPoint.coord[0]}, ${endPoint.coord[1]})`;
30634
+ function handleChangePoint(newPointProps, index) {
30635
+ const newPoints = [...points];
30636
+ newPoints[index] = {
30637
+ ...points[index],
30638
+ ...newPointProps
30639
+ };
30640
+ onChangeProps({
30641
+ points: newPoints
30642
+ });
30643
+ }
30644
+ function handleColorChange(newColor) {
30645
+ onChangeProps({
30646
+ color: newColor,
30647
+ // Keep the line's points' colors in sync with the line color.
30648
+ points: [{
30649
+ ...startPoint,
30650
+ color: newColor
30651
+ }, {
30652
+ ...endPoint,
30653
+ color: newColor
30654
+ }]
30655
+ });
30656
+ }
30657
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View
30658
+ // More specificity so that we can override the default
30659
+ // .heading > h2 > .header styles from the articles.less
30660
+ // file (which is imported in perseus-renderer.less).
30661
+ , {
30662
+ className: "locked-figure-accordion"
30663
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksAccordion.AccordionSection, {
30664
+ style: styles$d.container,
30665
+ headerStyle: styles$d.accordionHeader,
30666
+ header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30667
+ style: styles$d.row
30668
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
30669
+ size: wonderBlocksTokens.spacing.xSmall_8
30670
+ }), /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
30671
+ color: lineColor
30672
+ }))
30673
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30674
+ style: styles$d.accordionPanel
30675
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30676
+ style: [styles$d.row, styles$d.spaceUnder]
30677
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30678
+ htmlFor: kindSelectId,
30679
+ style: styles$d.label,
30680
+ tag: "label"
30681
+ }, "Kind"), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30682
+ id: kindSelectId,
30683
+ selectedValue: kind,
30684
+ onChange: value => onChangeProps({
30685
+ kind: value
30686
+ })
30687
+ // Placeholder is required, but never gets used.
30688
+ ,
30689
+ placeholder: ""
30690
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30691
+ value: "line",
30692
+ label: "line"
30693
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30694
+ value: "segment",
30695
+ label: "segment"
30696
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30697
+ value: "ray",
30698
+ label: "ray"
30394
30699
  }))), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30700
+ style: [styles$d.row, styles$d.spaceUnder]
30701
+ }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30702
+ id: colorSelectId,
30703
+ selectedValue: lineColor || "blue",
30704
+ onChange: handleColorChange
30705
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
30706
+ size: wonderBlocksTokens.spacing.medium_16
30707
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30395
30708
  style: styles$d.row
30396
30709
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30397
- htmlFor: colorSelectId,
30710
+ htmlFor: styleSelectId,
30398
30711
  style: styles$d.label,
30399
30712
  tag: "label"
30400
- }, "Color"), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30401
- id: colorSelectId,
30402
- selectedValue: style?.fill || "blue",
30403
- onChange: onChangeColor
30713
+ }, "Style"), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30714
+ id: styleSelectId,
30715
+ selectedValue: lineStyle,
30716
+ onChange: value => onChangeProps({
30717
+ lineStyle: value
30718
+ })
30404
30719
  // Placeholder is required, but never gets used.
30405
30720
  ,
30406
30721
  placeholder: ""
30407
- }, possibleColors.map(colorName => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30408
- key: colorName,
30409
- value: colorName,
30410
- label: colorName,
30411
- leftAccessory: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30412
- style: [styles$d.colorCircle, {
30413
- backgroundColor: wonderBlocksTokens.color[colorName]
30414
- }]
30415
- })
30416
- }, colorName)))));
30722
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30723
+ value: "solid",
30724
+ label: "solid"
30725
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30726
+ value: "dashed",
30727
+ label: "dashed"
30728
+ })))), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
30729
+ label: "Show arrows",
30730
+ checked: showArrows,
30731
+ onChange: newValue => onChangeProps({
30732
+ showArrows: newValue
30733
+ }),
30734
+ style: styles$d.spaceUnder
30735
+ }), /*#__PURE__*/React__namespace.createElement(LockedPointSettings, _extends({
30736
+ label: "Start point",
30737
+ toggled: showStartPoint
30738
+ }, startPoint, {
30739
+ onToggle: newValue => onChangeProps({
30740
+ showStartPoint: newValue
30741
+ }),
30742
+ onChangeProps: newProps => handleChangePoint(newProps, 0),
30743
+ style: styles$d.lockedPointSettingsContainer
30744
+ })), /*#__PURE__*/React__namespace.createElement(LockedPointSettings, _extends({
30745
+ label: "End point",
30746
+ toggled: showEndPoint
30747
+ }, endPoint, {
30748
+ onToggle: newValue => onChangeProps({
30749
+ showEndPoint: newValue
30750
+ }),
30751
+ onChangeProps: newProps => handleChangePoint(newProps, 1),
30752
+ style: styles$d.lockedPointSettingsContainer
30753
+ })), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30754
+ icon: trashIcon__default["default"],
30755
+ "aria-label": `Delete locked line defined by
30756
+ ${startPoint.coord[0]}, ${startPoint.coord[1]} and
30757
+ ${endPoint.coord[0]}, ${endPoint.coord[1]}.`,
30758
+ onClick: onRemove,
30759
+ style: styles$d.deleteButton
30760
+ }))));
30417
30761
  };
30418
30762
  const styles$d = aphrodite.StyleSheet.create({
30419
30763
  container: {
30420
30764
  backgroundColor: wonderBlocksTokens.color.fadedBlue8,
30421
- marginBottom: wonderBlocksTokens.spacing.xSmall_8,
30765
+ marginBottom: wonderBlocksTokens.spacing.xSmall_8
30766
+ },
30767
+ accordionHeader: {
30768
+ paddingTop: wonderBlocksTokens.spacing.small_12,
30769
+ paddingBottom: wonderBlocksTokens.spacing.small_12,
30770
+ paddingInlineStart: wonderBlocksTokens.spacing.medium_16
30771
+ },
30772
+ accordionPanel: {
30422
30773
  padding: wonderBlocksTokens.spacing.medium_16,
30423
- borderRadius: wonderBlocksTokens.spacing.xSmall_8
30774
+ paddingBottom: wonderBlocksTokens.spacing.xSmall_8
30775
+ },
30776
+ lockedPointSettingsContainer: {
30777
+ marginTop: wonderBlocksTokens.spacing.xSmall_8,
30778
+ marginBottom: wonderBlocksTokens.spacing.xSmall_8,
30779
+ marginLeft: -wonderBlocksTokens.spacing.xxxSmall_4,
30780
+ marginRight: -wonderBlocksTokens.spacing.xxxSmall_4,
30781
+ backgroundColor: wonderBlocksTokens.color.white
30424
30782
  },
30425
30783
  row: {
30426
30784
  flexDirection: "row",
30427
- alignItems: "center",
30785
+ alignItems: "center"
30786
+ },
30787
+ spaceUnder: {
30428
30788
  marginBottom: wonderBlocksTokens.spacing.xSmall_8
30429
30789
  },
30430
30790
  label: {
30431
30791
  marginInlineEnd: wonderBlocksTokens.spacing.xSmall_8
30432
30792
  },
30433
- textField: {
30434
- width: wonderBlocksTokens.spacing.xxxLarge_64
30435
- },
30436
- colorCircle: {
30437
- // Add a white border so that the color circle is visible when
30438
- // the dropdown option is highlighted with its blue background.
30439
- border: `2px solid ${wonderBlocksTokens.color.offWhite}`,
30440
- borderRadius: "50%",
30441
- width: wonderBlocksTokens.spacing.large_24,
30442
- height: wonderBlocksTokens.spacing.large_24
30793
+ deleteButton: {
30794
+ position: "absolute",
30795
+ top: wonderBlocksTokens.spacing.small_12,
30796
+ right: wonderBlocksTokens.spacing.small_12
30443
30797
  }
30444
30798
  });
30445
30799
 
@@ -30456,6 +30810,8 @@ const LockedFigureSettings = props => {
30456
30810
  switch (props.type) {
30457
30811
  case "point":
30458
30812
  return /*#__PURE__*/React__namespace.createElement(LockedPointSettings, props);
30813
+ case "line":
30814
+ return /*#__PURE__*/React__namespace.createElement(LockedLineSettings, props);
30459
30815
  }
30460
30816
  return null;
30461
30817
  };
@@ -30469,7 +30825,7 @@ const LockedFiguresSection = props => {
30469
30825
  function addLockedFigure(newFigure) {
30470
30826
  const lockedFigures = figures || [];
30471
30827
  const newProps = {
30472
- lockedFigures: [...lockedFigures, getDefaultFigureForFigureType(newFigure)]
30828
+ lockedFigures: [...lockedFigures, getDefaultFigureForType(newFigure)]
30473
30829
  };
30474
30830
  onChange(newProps);
30475
30831
  }
@@ -30479,37 +30835,25 @@ const LockedFiguresSection = props => {
30479
30835
  lockedFigures: [...lockedFigures.slice(0, index), ...lockedFigures.slice(index + 1)]
30480
30836
  });
30481
30837
  }
30482
- function changeCoord(index, coord) {
30838
+ function changeProps(index,
30839
+ // Omit the type from the figure props so it doesn't think
30840
+ // we're trying to pass in the props for the wrong type.
30841
+ figureProps) {
30483
30842
  const lockedFigures = figures || [];
30484
- const newProps = {
30843
+ const newFigures = {
30485
30844
  lockedFigures: [...lockedFigures.slice(0, index), {
30486
30845
  ...lockedFigures[index],
30487
- coord
30846
+ ...figureProps
30488
30847
  }, ...lockedFigures.slice(index + 1)]
30489
30848
  };
30490
- onChange(newProps);
30491
- }
30492
- function changeColor(index, colorName) {
30493
- const lockedFigures = figures || [];
30494
- const newProps = {
30495
- lockedFigures: [...lockedFigures.slice(0, index), {
30496
- ...lockedFigures[index],
30497
- style: {
30498
- ...lockedFigures[index].style,
30499
- fill: colorName,
30500
- stroke: colorName
30501
- }
30502
- }, ...lockedFigures.slice(index + 1)]
30503
- };
30504
- onChange(newProps);
30849
+ onChange(newFigures);
30505
30850
  }
30506
30851
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30507
30852
  style: styles$c.container
30508
30853
  }, figures?.map((figure, index) => /*#__PURE__*/React__namespace.createElement(LockedFigureSettings, _extends({
30509
30854
  key: `${uniqueId}-locked-${figure}-${index}`
30510
30855
  }, figure, {
30511
- onChangeColor: color => changeColor(index, color),
30512
- onChangeCoord: coord => changeCoord(index, coord),
30856
+ onChangeProps: newProps => changeProps(index, newProps),
30513
30857
  onRemove: () => removeLockedFigure(index)
30514
30858
  }))), /*#__PURE__*/React__namespace.createElement(LockedFigureSelect, {
30515
30859
  id: `${uniqueId}-select`,
@@ -30613,6 +30957,8 @@ class InteractiveGraphEditor extends React__namespace.Component {
30613
30957
  const snapStep = this.props.snapStep || perseus.Util.snapStepFromGridStep(gridStep);
30614
30958
  const sizeClass = containerSizeClass.SMALL;
30615
30959
  if (this.props.valid === true) {
30960
+ const correct = this.props.correct;
30961
+
30616
30962
  // TODO(aria): send these down all at once
30617
30963
  const graphProps = {
30618
30964
  ref: "graph",
@@ -30622,7 +30968,7 @@ class InteractiveGraphEditor extends React__namespace.Component {
30622
30968
  step: this.props.step,
30623
30969
  gridStep: gridStep,
30624
30970
  snapStep: snapStep,
30625
- graph: this.props.correct,
30971
+ graph: correct,
30626
30972
  backgroundImage: this.props.backgroundImage,
30627
30973
  markings: this.props.markings,
30628
30974
  showProtractor: this.props.showProtractor,
@@ -30646,6 +30992,10 @@ class InteractiveGraphEditor extends React__namespace.Component {
30646
30992
  });
30647
30993
  }
30648
30994
  };
30995
+
30996
+ // This is used to force a remount of the graph component
30997
+ // when there's a significant change
30998
+ const graphKey = `${correct.type}:${correct.numSegments || 0}`;
30649
30999
  graph =
30650
31000
  /*#__PURE__*/
30651
31001
  // There are a bunch of props that renderer.jsx passes to widgets via
@@ -30653,6 +31003,7 @@ class InteractiveGraphEditor extends React__namespace.Component {
30653
31003
  // bother passing.
30654
31004
  // @ts-expect-error - TS2769 - No overload matches this call.
30655
31005
  React__namespace.createElement(InteractiveGraph, _extends({}, graphProps, {
31006
+ key: graphKey,
30656
31007
  containerSizeClass: sizeClass,
30657
31008
  apiOptions: {
30658
31009
  ...this.props.apiOptions,
@@ -30853,9 +31204,9 @@ class InteractiveGraphEditor extends React__namespace.Component {
30853
31204
  borderWidth: 1
30854
31205
  }
30855
31206
  }, equationString), /*#__PURE__*/React__namespace.createElement(InfoTip$b, null, /*#__PURE__*/React__namespace.createElement("p", null, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."))), graph,
30856
- // Only show the "Add element" dropdown if the graph is
30857
- // using Mafs.
30858
- this.props.graph && this.props.apiOptions?.flags?.["mafs"]?.[this.props.graph.type] && /*#__PURE__*/React__namespace.createElement(LockedFiguresSection, {
31207
+ // Only show the "Add locked figure" dropdown if the graph
31208
+ // is using Mafs.
31209
+ this.props.graph && this.props.apiOptions?.flags?.mafs?.["interactive-graph-locked-features-m1"] && this.props.apiOptions?.flags?.mafs?.[this.props.graph.type] && /*#__PURE__*/React__namespace.createElement(LockedFiguresSection, {
30859
31210
  figures: this.props.lockedFigures,
30860
31211
  onChange: this.props.onChange
30861
31212
  }));
@@ -30997,7 +31348,7 @@ class FormWrappedTextField extends React__namespace.Component {
30997
31348
  className: aphrodite.css(inputBase),
30998
31349
  ref: forwardedRef,
30999
31350
  id: id,
31000
- "data-test-id": testId
31351
+ "data-testid": testId
31001
31352
  })), !leftSideIcon && wrappedIcon);
31002
31353
  }
31003
31354
  }
@@ -31139,7 +31490,7 @@ class Link extends React__namespace.Component {
31139
31490
  rel = "noopener noreferrer";
31140
31491
  }
31141
31492
  return /*#__PURE__*/React__namespace.createElement(element, {
31142
- "data-test-id": testId,
31493
+ "data-testid": testId,
31143
31494
  ...otherProps,
31144
31495
  ...urlProp,
31145
31496
  className: aphrodite.css(...delegatedStyles) + delegatedClassName,
@@ -31356,9 +31707,9 @@ class HoverBehavior extends React__namespace.Component {
31356
31707
  }
31357
31708
 
31358
31709
  // @ts-expect-error - TS2564 - Property 'focusFlag' has no initializer and is not definitely assigned in the constructor.
31359
-
31710
+ focusFlag;
31360
31711
  // @ts-expect-error - TS2564 - Property 'waitingForClick' has no initializer and is not definitely assigned in the constructor.
31361
-
31712
+ waitingForClick;
31362
31713
  handleClick = e => {
31363
31714
  if (!this.props.disabled) {
31364
31715
  if (this.props.shouldUpdate()) {
@@ -31474,7 +31825,7 @@ class Checkbox extends React__namespace.Component {
31474
31825
  return /*#__PURE__*/React__namespace.createElement("div", _extends({}, handlers, {
31475
31826
  className: aphrodite.css(styles$6.container, focused && styles$6.focused),
31476
31827
  style: style,
31477
- "data-test-id": dataTestId,
31828
+ "data-testid": dataTestId,
31478
31829
  "data-checked": checked
31479
31830
  }), /*#__PURE__*/React__namespace.createElement("svg", {
31480
31831
  className: aphrodite.css(styles$6.svg, (disabled || appearDisabled) && styles$6.disabled),
@@ -31669,7 +32020,7 @@ const check = `M10,3.8C10,4,9.9,4.2,9.8,4.3L5.1,8.9L4.3,9.8C4.2,9.9,4,10,3.8,10
31669
32020
  const optionHeight = 30;
31670
32021
  class Option extends React__namespace.Component {
31671
32022
  // @ts-expect-error - TS2564 - Property 'node' has no initializer and is not definitely assigned in the constructor.
31672
-
32023
+ node;
31673
32024
  handleKeyDown(event) {
31674
32025
  const {
31675
32026
  onDropdownClose
@@ -31724,7 +32075,7 @@ class Option extends React__namespace.Component {
31724
32075
  onKeyDown: event => this.handleKeyDown(event),
31725
32076
  "aria-disabled": disabled,
31726
32077
  "aria-label": ariaLabel,
31727
- "data-test-id": testId
32078
+ "data-testid": testId
31728
32079
  }, optionRenderer && optionRenderer(
31729
32080
  /*#__PURE__*/
31730
32081
  /**
@@ -31748,7 +32099,7 @@ class Option extends React__namespace.Component {
31748
32099
  // - how does the drop down interact with tooltips? what's the z-index order?
31749
32100
  class OptionGroup extends React__namespace.Component {
31750
32101
  // @ts-expect-error - TS2564 - Property 'focusedElement' has no initializer and is not definitely assigned in the constructor.
31751
-
32102
+ focusedElement;
31752
32103
  componentDidMount() {
31753
32104
  if (this.focusedElement) {
31754
32105
  findAndFocusElement(this.focusedElement);
@@ -31853,6 +32204,7 @@ const {
31853
32204
  borderRadius
31854
32205
  } = perseus.globalStyles;
31855
32206
  class Marker extends React__namespace.Component {
32207
+ _marker;
31856
32208
  constructor(props) {
31857
32209
  super(props);
31858
32210
  this.state = {
@@ -32077,8 +32429,7 @@ class QuestionMarkers extends React__namespace.Component {
32077
32429
  // Open answer selection dropdown for each of the specified markers.
32078
32430
  indices.forEach(index => {
32079
32431
  if (this._markers[index]) {
32080
- // @ts-expect-error - TS2533 - Object is possibly 'null' or 'undefined'.
32081
- this._markers[index].openDropdown();
32432
+ this._markers[index]?.openDropdown();
32082
32433
  }
32083
32434
  });
32084
32435
  }
@@ -32233,6 +32584,7 @@ const styles$1 = aphrodite.StyleSheet.create({
32233
32584
  * knowledge by directly interacting with the image.
32234
32585
  */
32235
32586
  class LabelImageEditor extends React__namespace.Component {
32587
+ _questionMarkers;
32236
32588
  static defaultProps = {
32237
32589
  choices: [],
32238
32590
  imageAlt: "",
@@ -33132,6 +33484,9 @@ const {
33132
33484
  const {
33133
33485
  firstNumericalParse
33134
33486
  } = perseus.Util;
33487
+
33488
+ // NOTE(john): Copied from perseus-types.d.ts in the Perseus package.
33489
+ // I'm unable to find a good way of importing these types into this project.
33135
33490
  const answerFormButtons = [{
33136
33491
  title: "Integers",
33137
33492
  value: "integer",
@@ -33168,30 +33523,25 @@ const initAnswer = status => {
33168
33523
  maxError: null
33169
33524
  };
33170
33525
  };
33171
- const NumericInputEditor = createReactClass__default["default"]({
33172
- displayName: "NumericInputEditor",
33173
- propTypes: {
33174
- ...perseus.Changeable.propTypes
33175
- },
33176
- statics: {
33177
- widgetName: "numeric-input"
33178
- },
33179
- getDefaultProps: function () {
33180
- return {
33181
- answers: [initAnswer("correct")],
33182
- size: "normal",
33183
- coefficient: false,
33184
- labelText: "",
33185
- rightAlign: false
33186
- };
33187
- },
33188
- getInitialState: function () {
33189
- return {
33526
+ class NumericInputEditor extends React__namespace.Component {
33527
+ static contextType = perseus.PerseusI18nContext;
33528
+ static widgetName = "numeric-input";
33529
+ static displayName = "NumericInputEditor";
33530
+ static defaultProps = {
33531
+ answers: [initAnswer("correct")],
33532
+ size: "normal",
33533
+ coefficient: false,
33534
+ labelText: "",
33535
+ rightAlign: false
33536
+ };
33537
+ constructor(props) {
33538
+ super(props);
33539
+ this.state = {
33190
33540
  lastStatus: "wrong",
33191
33541
  showOptions: ___default["default"].map(this.props.answers, () => false)
33192
33542
  };
33193
- },
33194
- render: function () {
33543
+ }
33544
+ render() {
33195
33545
  const answers = this.props.answers;
33196
33546
  const unsimplifiedAnswers = i => /*#__PURE__*/React__namespace.createElement("div", {
33197
33547
  className: "perseus-widget-row"
@@ -33208,14 +33558,14 @@ const NumericInputEditor = createReactClass__default["default"]({
33208
33558
  value: "enforced",
33209
33559
  content: "wrong"
33210
33560
  }],
33211
- onChange: this.updateAnswer(i, "simplify")
33561
+ onChange: this.updateAnswer(i, "simplify") || (() => {})
33212
33562
  }), /*#__PURE__*/React__namespace.createElement(InfoTip$7, null, /*#__PURE__*/React__namespace.createElement("p", null, "Normally select \"ungraded\". This will give the user a message saying the answer is correct but not simplified. The user will then have to simplify it and re-enter, but will not be penalized. (5th grade and after)"), /*#__PURE__*/React__namespace.createElement("p", null, "Select \"accepted\" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)"), /*#__PURE__*/React__namespace.createElement("p", null, "Select \"wrong\" ", /*#__PURE__*/React__namespace.createElement("em", null, "only"), " if we are specifically assessing the ability to simplify.")));
33213
33563
  const suggestedAnswerTypes = i => /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", {
33214
33564
  className: "perseus-widget-row"
33215
33565
  }, /*#__PURE__*/React__namespace.createElement("label", null, "Choose the suggested answer formats"), /*#__PURE__*/React__namespace.createElement(MultiButtonGroup, {
33216
33566
  buttons: answerFormButtons,
33217
33567
  values: answers[i]["answerForms"],
33218
- onChange: this.updateAnswer(i, "answerForms")
33568
+ onChange: this.updateAnswer(i, "answerForms") || (() => {})
33219
33569
  }), /*#__PURE__*/React__namespace.createElement(InfoTip$7, null, /*#__PURE__*/React__namespace.createElement("p", null, "Formats will be autoselected for you based on the given answer; to show no suggested formats and accept all types, simply have a decimal/integer be the answer. Values with \u03C0 will have format \"pi\", and values that are fractions will have some subset (mixed will be \"mixed\" and \"proper\"; improper/proper will both be \"improper\" and \"proper\"). If you would like to specify that it is only a proper fraction (or only a mixed/improper fraction), deselect the other format. Except for specific cases, you should not need to change the autoselected formats."), /*#__PURE__*/React__namespace.createElement("p", null, "To restrict the answer to ", /*#__PURE__*/React__namespace.createElement("em", null, "only"), " an improper fraction (i.e. 7/4), select the improper fraction and toggle \"strict\" to true. This ", /*#__PURE__*/React__namespace.createElement("b", null, "will not"), " ", "accept 1.75 as an answer.", " "), /*#__PURE__*/React__namespace.createElement("p", null, "Unless you are testing that specific skill, please do not restrict the answer format."))), /*#__PURE__*/React__namespace.createElement("div", {
33220
33570
  className: "perseus-widget-row"
33221
33571
  }, /*#__PURE__*/React__namespace.createElement(PropCheckBox$3, {
@@ -33301,7 +33651,7 @@ const NumericInputEditor = createReactClass__default["default"]({
33301
33651
  value: answer.value,
33302
33652
  className: "numeric-input-value",
33303
33653
  placeholder: "answer",
33304
- format: ___default["default"].last(answer.answerForms),
33654
+ format: ___default["default"].last(answer.answerForms || []),
33305
33655
  onFormatChange: (newValue, format) => {
33306
33656
  // NOTE(charlie): The mobile web expression
33307
33657
  // editor relies on this automatic answer
@@ -33325,13 +33675,13 @@ const NumericInputEditor = createReactClass__default["default"]({
33325
33675
  forms = ["proper", "improper"];
33326
33676
  }
33327
33677
  this.updateAnswer(i, {
33328
- value: firstNumericalParse(newValue),
33678
+ value: firstNumericalParse(newValue, this.context.strings),
33329
33679
  answerForms: forms
33330
33680
  });
33331
33681
  },
33332
33682
  onChange: newValue => {
33333
33683
  this.updateAnswer(i, {
33334
- value: firstNumericalParse(newValue)
33684
+ value: firstNumericalParse(newValue, this.context.strings)
33335
33685
  });
33336
33686
  }
33337
33687
  }), answer.strict && /*#__PURE__*/React__namespace.createElement("div", {
@@ -33347,7 +33697,7 @@ const NumericInputEditor = createReactClass__default["default"]({
33347
33697
  }, "\xB1"), /*#__PURE__*/React__namespace.createElement(NumberInput$5, {
33348
33698
  placeholder: 0,
33349
33699
  value: answers[i]["maxError"],
33350
- format: ___default["default"].last(answer.answerForms),
33700
+ format: ___default["default"].last(answer.answerForms || []),
33351
33701
  onChange: this.updateAnswer(i, "maxError")
33352
33702
  })) : null, /*#__PURE__*/React__namespace.createElement("div", {
33353
33703
  className: "value-divider"
@@ -33355,19 +33705,19 @@ const NumericInputEditor = createReactClass__default["default"]({
33355
33705
  href: "javascript:void(0)",
33356
33706
  className: "answer-status " + answer.status,
33357
33707
  onClick: () => this.onStatusChange(i),
33358
- onKeyDown: e => this.onSpace(e, this.onStatusChange, i)
33708
+ onKeyDown: e => this.onSpace(e, this.onStatusChange)
33359
33709
  }, answer.status), /*#__PURE__*/React__namespace.createElement("a", {
33360
33710
  href: "javascript:void(0)",
33361
33711
  className: "answer-trash",
33362
33712
  "aria-label": "Delete answer",
33363
33713
  onClick: () => this.onTrashAnswer(i),
33364
- onKeyDown: e => this.onSpace(e, this.onTrashAnswer, i)
33714
+ onKeyDown: e => this.onSpace(e, this.onTrashAnswer)
33365
33715
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$2, iconTrash$1)), /*#__PURE__*/React__namespace.createElement("a", {
33366
33716
  href: "javascript:void(0)",
33367
33717
  className: "options-toggle",
33368
33718
  "aria-label": "Toggle options",
33369
33719
  onClick: () => this.onToggleOptions(i),
33370
- onKeyDown: e => this.onSpace(e, this.onToggleOptions, i)
33720
+ onKeyDown: e => this.onSpace(e, this.onToggleOptions)
33371
33721
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$2, iconGear))), /*#__PURE__*/React__namespace.createElement("div", {
33372
33722
  className: "input-answer-editor-message"
33373
33723
  }, editor), this.state.showOptions[i] && /*#__PURE__*/React__namespace.createElement("div", {
@@ -33381,21 +33731,21 @@ const NumericInputEditor = createReactClass__default["default"]({
33381
33731
  }, "User input"), /*#__PURE__*/React__namespace.createElement("div", {
33382
33732
  className: "msg-title"
33383
33733
  }, "Message shown to user on attempt"), generateInputAnswerEditors(), addAnswerButton, inputSize, rightAlign, coefficientCheck, labelText);
33384
- },
33734
+ }
33385
33735
  change() {
33386
33736
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
33387
33737
  args[_key] = arguments[_key];
33388
33738
  }
33389
33739
  return perseus.Changeable.change.apply(this, args);
33390
- },
33391
- onToggleOptions: function (choiceIndex) {
33740
+ }
33741
+ onToggleOptions(choiceIndex) {
33392
33742
  const showOptions = this.state.showOptions.slice();
33393
33743
  showOptions[choiceIndex] = !showOptions[choiceIndex];
33394
33744
  this.setState({
33395
33745
  showOptions: showOptions
33396
33746
  });
33397
- },
33398
- onTrashAnswer: function (choiceIndex) {
33747
+ }
33748
+ onTrashAnswer(choiceIndex) {
33399
33749
  if (choiceIndex >= 0 && choiceIndex < this.props.answers.length) {
33400
33750
  const answers = this.props.answers.slice(0);
33401
33751
  answers.splice(choiceIndex, 1);
@@ -33403,16 +33753,16 @@ const NumericInputEditor = createReactClass__default["default"]({
33403
33753
  answers: answers
33404
33754
  });
33405
33755
  }
33406
- },
33407
- onSpace: function (e, callback) {
33756
+ }
33757
+ onSpace(e, callback) {
33408
33758
  if (e.key === " ") {
33409
33759
  e.preventDefault(); // prevent page shifting
33410
33760
  // eslint-disable-next-line prefer-rest-params
33411
33761
  const args = ___default["default"].toArray(arguments).slice(2);
33412
33762
  callback.apply(this, args);
33413
33763
  }
33414
- },
33415
- onStatusChange: function (choiceIndex) {
33764
+ }
33765
+ onStatusChange(choiceIndex) {
33416
33766
  const statuses = ["wrong", "ungraded", "correct"];
33417
33767
  const answers = this.props.answers;
33418
33768
  const i = ___default["default"].indexOf(statuses, answers[choiceIndex].status);
@@ -33421,8 +33771,8 @@ const NumericInputEditor = createReactClass__default["default"]({
33421
33771
  status: newStatus,
33422
33772
  simplify: newStatus === "correct" ? "required" : "accepted"
33423
33773
  });
33424
- },
33425
- updateAnswer: function (choiceIndex, update) {
33774
+ }
33775
+ updateAnswer(choiceIndex, update) {
33426
33776
  if (!___default["default"].isObject(update)) {
33427
33777
  return ___default["default"].partial((choiceIndex, key, value) => {
33428
33778
  const update = {};
@@ -33430,7 +33780,9 @@ const NumericInputEditor = createReactClass__default["default"]({
33430
33780
  this.updateAnswer(choiceIndex, update);
33431
33781
  }, choiceIndex, update);
33432
33782
  }
33433
- let answers = ___default["default"].clone(this.props.answers);
33783
+ let answers = [
33784
+ // Have to do this to remove the `readonly` state from the prop
33785
+ ...this.props.answers];
33434
33786
 
33435
33787
  // Don't bother to make a new answer box unless we are editing the last
33436
33788
  // one.
@@ -33443,15 +33795,15 @@ const NumericInputEditor = createReactClass__default["default"]({
33443
33795
  this.props.onChange({
33444
33796
  answers: answers
33445
33797
  });
33446
- },
33447
- addAnswer: function () {
33798
+ }
33799
+ addAnswer() {
33448
33800
  const lastAnswer = initAnswer(this.state.lastStatus);
33449
33801
  const answers = this.props.answers.concat(lastAnswer);
33450
33802
  this.props.onChange({
33451
33803
  answers: answers
33452
33804
  });
33453
- },
33454
- getSaveWarnings: function () {
33805
+ }
33806
+ getSaveWarnings() {
33455
33807
  // Filter out all the empty answers
33456
33808
  const warnings = [];
33457
33809
  // TODO(emily): This doesn't actually work, because the value is either
@@ -33469,11 +33821,11 @@ const NumericInputEditor = createReactClass__default["default"]({
33469
33821
  }
33470
33822
  });
33471
33823
  return warnings;
33472
- },
33824
+ }
33473
33825
  serialize() {
33474
33826
  return perseus.EditorJsonify.serialize.call(this);
33475
33827
  }
33476
- });
33828
+ }
33477
33829
 
33478
33830
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
33479
33831
  const {
@@ -34169,9 +34521,7 @@ class ChoiceEditor extends React__namespace.Component {
34169
34521
  apiOptions: this.props.apiOptions,
34170
34522
  content: this.props.choice.clue || "",
34171
34523
  widgetEnabled: false,
34172
- placeholder: i18n__namespace._("Why is this choice %(correctOrIncorrect)s?", {
34173
- correctOrIncorrect: checkedClass
34174
- }),
34524
+ placeholder: `Why is this choice ${checkedClass}?`,
34175
34525
  onChange: this.props.onClueChange
34176
34526
  });
34177
34527
  const deleteLink = /*#__PURE__*/React__namespace.createElement("a", {
@@ -34215,7 +34565,7 @@ class RadioEditor extends React__namespace.Component {
34215
34565
  };
34216
34566
  static widgetName = "radio";
34217
34567
  static defaultProps = {
34218
- choices: [{}, {}],
34568
+ choices: [{}, {}, {}, {}],
34219
34569
  displayCount: null,
34220
34570
  randomize: false,
34221
34571
  hasNoneOfTheAbove: false,
@@ -34740,6 +35090,9 @@ class UnitExample extends React__namespace.Component {
34740
35090
  }
34741
35091
  }
34742
35092
  class UnitInputEditor extends React__namespace.Component {
35093
+ parsed;
35094
+ groupId;
35095
+ original;
34743
35096
  static propTypes = {
34744
35097
  ...perseus.Changeable.propTypes,
34745
35098
  value: PropTypes__default["default"].string,