@khanacademy/perseus-editor 6.2.2 → 6.3.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
@@ -67,7 +67,7 @@ var Switch__default = /*#__PURE__*/_interopDefaultLegacy(Switch);
67
67
 
68
68
  // This file is processed by a Rollup plugin (replace) to inject the production
69
69
  const libName = "@khanacademy/perseus-editor";
70
- const libVersion = "6.2.2";
70
+ const libVersion = "6.3.0";
71
71
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
72
72
 
73
73
  function _extends() {
@@ -262,13 +262,13 @@ class SectionControlButton extends React__namespace.Component {
262
262
  role: "button",
263
263
  hideDefaultFocusRing: true,
264
264
  "aria-label": title,
265
- style: styles$u.button
265
+ style: styles$v.button
266
266
  }, _ref => {
267
267
  return /*#__PURE__*/React__namespace.createElement(InlineIcon$b, icon);
268
268
  });
269
269
  }
270
270
  }
271
- const styles$u = aphrodite.StyleSheet.create({
271
+ const styles$v = aphrodite.StyleSheet.create({
272
272
  button: {
273
273
  backgroundColor: wonderBlocksTokens.color.gold,
274
274
  margin: 2,
@@ -20787,19 +20787,19 @@ class TexErrorView extends React__namespace.Component {
20787
20787
  const {
20788
20788
  showErrors
20789
20789
  } = this.state;
20790
- const iconStyle = showErrors ? styles$t.iconExpanded : styles$t.iconCollapsed;
20790
+ const iconStyle = showErrors ? styles$u.iconExpanded : styles$u.iconCollapsed;
20791
20791
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20792
- style: styles$t.errorContainer
20792
+ style: styles$u.errorContainer
20793
20793
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20794
- style: styles$t.title,
20794
+ style: styles$u.title,
20795
20795
  onClick: this.handleToggleTexErrors
20796
20796
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksIcon.PhosphorIcon, {
20797
20797
  icon: caretRight__default["default"],
20798
20798
  style: iconStyle
20799
20799
  }), "\xA0 TeX Errors (", errorList.length, ")"), showErrors && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20800
- style: styles$t.errorExplanation
20800
+ style: styles$u.errorExplanation
20801
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, {
20802
- style: styles$t.error,
20802
+ style: styles$u.error,
20803
20803
  key: index
20804
20804
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20805
20805
  style: {
@@ -20808,7 +20808,7 @@ class TexErrorView extends React__namespace.Component {
20808
20808
  }, e.math), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, e.message))));
20809
20809
  }
20810
20810
  }
20811
- const styles$t = aphrodite.StyleSheet.create({
20811
+ const styles$u = aphrodite.StyleSheet.create({
20812
20812
  title: {
20813
20813
  backgroundColor: "#eee",
20814
20814
  fontSize: "1.25em",
@@ -24565,12 +24565,12 @@ class SimpleButton extends React__namespace.Component {
24565
24565
  ...otherProps
24566
24566
  } = this.props;
24567
24567
  return /*#__PURE__*/React__namespace.createElement("div", _extends({
24568
- className: aphrodite.css(styles$s.baseButton, color === "green" && styles$s.green, color === "orange" && styles$s.orange),
24568
+ className: aphrodite.css(styles$t.baseButton, color === "green" && styles$t.green, color === "orange" && styles$t.orange),
24569
24569
  onClick: onClick
24570
24570
  }, otherProps), children);
24571
24571
  }
24572
24572
  }
24573
- const styles$s = aphrodite.StyleSheet.create({
24573
+ const styles$t = aphrodite.StyleSheet.create({
24574
24574
  baseButton: {
24575
24575
  top: "0",
24576
24576
  fontSize: "11px",
@@ -24783,23 +24783,23 @@ const LeafContainer = _ref2 => {
24783
24783
  } = _ref2;
24784
24784
  const hasPreviewHeading = shape.type === "content" || shape.type === "hint";
24785
24785
  const previewHeading = hasPreviewHeading && /*#__PURE__*/React__namespace.createElement("div", {
24786
- className: aphrodite.css(styles$r.containerHeader)
24786
+ className: aphrodite.css(styles$s.containerHeader)
24787
24787
  }, /*#__PURE__*/React__namespace.createElement(Header, {
24788
24788
  depth: path.length,
24789
- className: aphrodite.css(styles$r.containerTitle)
24789
+ className: aphrodite.css(styles$s.containerTitle)
24790
24790
  }, capitalize(name)));
24791
24791
  return /*#__PURE__*/React__namespace.createElement("div", {
24792
- className: aphrodite.css(styles$r.container)
24792
+ className: aphrodite.css(styles$s.container)
24793
24793
  }, /*#__PURE__*/React__namespace.createElement("span", {
24794
- className: aphrodite.css(styles$r.row, styles$r.rowHeading)
24794
+ className: aphrodite.css(styles$s.row, styles$s.rowHeading)
24795
24795
  }, /*#__PURE__*/React__namespace.createElement("div", {
24796
- className: aphrodite.css(styles$r.columnLeft)
24796
+ className: aphrodite.css(styles$s.columnLeft)
24797
24797
  }, /*#__PURE__*/React__namespace.createElement("div", {
24798
- className: "pod-title " + aphrodite.css(styles$r.containerHeader)
24798
+ className: "pod-title " + aphrodite.css(styles$s.containerHeader)
24799
24799
  }, /*#__PURE__*/React__namespace.createElement("div", {
24800
- className: aphrodite.css(styles$r.containerTitle)
24800
+ className: aphrodite.css(styles$s.containerTitle)
24801
24801
  }, capitalize(name)), controls)), /*#__PURE__*/React__namespace.createElement("div", {
24802
- className: aphrodite.css(styles$r.columnRight)
24802
+ className: aphrodite.css(styles$s.columnRight)
24803
24803
  }, previewHeading)), children);
24804
24804
  };
24805
24805
  const ArrayContainer = props => {
@@ -24812,11 +24812,11 @@ const ArrayContainer = props => {
24812
24812
  actions
24813
24813
  } = props;
24814
24814
  return /*#__PURE__*/React__namespace.createElement("div", {
24815
- className: aphrodite.css(styles$r.container)
24815
+ className: aphrodite.css(styles$s.container)
24816
24816
  }, controls && /*#__PURE__*/React__namespace.createElement("div", {
24817
- className: aphrodite.css(styles$r.columnLeft, styles$r.containerHeader)
24817
+ className: aphrodite.css(styles$s.columnLeft, styles$s.containerHeader)
24818
24818
  }, controls), /*#__PURE__*/React__namespace.createElement("div", null, children), /*#__PURE__*/React__namespace.createElement("div", {
24819
- className: aphrodite.css(styles$r.columnLeft)
24819
+ className: aphrodite.css(styles$s.columnLeft)
24820
24820
  }, /*#__PURE__*/React__namespace.createElement("a", {
24821
24821
  href: "javascript:void 0",
24822
24822
  onClick: () => actions.addArrayElement(path, shape.elementShape)
@@ -24830,28 +24830,28 @@ const ObjectContainer = _ref3 => {
24830
24830
  path
24831
24831
  } = _ref3;
24832
24832
  const headingEditor = /*#__PURE__*/React__namespace.createElement("div", {
24833
- className: aphrodite.css(styles$r.containerHeader)
24833
+ className: aphrodite.css(styles$s.containerHeader)
24834
24834
  }, /*#__PURE__*/React__namespace.createElement(Header, {
24835
24835
  depth: path.length,
24836
- className: aphrodite.css(styles$r.containerTitle)
24836
+ className: aphrodite.css(styles$s.containerTitle)
24837
24837
  }, capitalize(name)), controls);
24838
24838
  const headingPreview = (name || controls) && /*#__PURE__*/React__namespace.createElement("div", {
24839
- className: aphrodite.css(styles$r.containerHeader, styles$r.previewCollectionHeader)
24839
+ className: aphrodite.css(styles$s.containerHeader, styles$s.previewCollectionHeader)
24840
24840
  }, /*#__PURE__*/React__namespace.createElement(Header, {
24841
24841
  depth: path.length,
24842
- className: aphrodite.css(styles$r.containerTitle)
24842
+ className: aphrodite.css(styles$s.containerTitle)
24843
24843
  }, capitalize(name)));
24844
24844
  const hasBothHeadings = headingEditor && headingPreview;
24845
24845
  return /*#__PURE__*/React__namespace.createElement("div", {
24846
- className: aphrodite.css(styles$r.container)
24846
+ className: aphrodite.css(styles$s.container)
24847
24847
  }, hasBothHeadings && /*#__PURE__*/React__namespace.createElement("span", {
24848
- className: aphrodite.css(styles$r.row)
24848
+ className: aphrodite.css(styles$s.row)
24849
24849
  }, /*#__PURE__*/React__namespace.createElement("div", {
24850
- className: aphrodite.css(styles$r.columnLeft)
24850
+ className: aphrodite.css(styles$s.columnLeft)
24851
24851
  }, headingEditor), /*#__PURE__*/React__namespace.createElement("div", {
24852
- className: aphrodite.css(styles$r.columnRight)
24852
+ className: aphrodite.css(styles$s.columnRight)
24853
24853
  }, headingPreview)), /*#__PURE__*/React__namespace.createElement("div", {
24854
- className: aphrodite.css(path.length > 0 && styles$r.contentIndent)
24854
+ className: aphrodite.css(path.length > 0 && styles$s.contentIndent)
24855
24855
  }, children));
24856
24856
  };
24857
24857
 
@@ -24971,11 +24971,11 @@ const ItemNodeContent = withStickiness(props => {
24971
24971
  className: "framework-perseus"
24972
24972
  }, lens(renderers).get(path));
24973
24973
  return /*#__PURE__*/React__namespace.createElement("span", null, /*#__PURE__*/React__namespace.createElement("div", {
24974
- className: aphrodite.css(styles$r.row)
24974
+ className: aphrodite.css(styles$s.row)
24975
24975
  }, /*#__PURE__*/React__namespace.createElement("div", {
24976
- className: aphrodite.css(styles$r.columnLeft)
24976
+ className: aphrodite.css(styles$s.columnLeft)
24977
24977
  }, /*#__PURE__*/React__namespace.createElement("div", {
24978
- className: aphrodite.css(sticky && styles$r.sticky)
24978
+ className: aphrodite.css(sticky && styles$s.sticky)
24979
24979
  },
24980
24980
  /*#__PURE__*/
24981
24981
  // @ts-expect-error - TS2769 - No overload matches this call.
@@ -24983,9 +24983,9 @@ const ItemNodeContent = withStickiness(props => {
24983
24983
  onChange: newVal => actions.mergeValueAtPath(path, newVal),
24984
24984
  apiOptions: apiOptions
24985
24985
  })))), /*#__PURE__*/React__namespace.createElement("div", {
24986
- className: aphrodite.css(styles$r.columnRight)
24986
+ className: aphrodite.css(styles$s.columnRight)
24987
24987
  }, /*#__PURE__*/React__namespace.createElement("div", {
24988
- className: aphrodite.css(sticky && styles$r.sticky)
24988
+ className: aphrodite.css(sticky && styles$s.sticky)
24989
24989
  }, preview))));
24990
24990
  });
24991
24991
  const HintNodeContent = withStickiness(props => {
@@ -25001,13 +25001,13 @@ const HintNodeContent = withStickiness(props => {
25001
25001
  className: "framework-perseus"
25002
25002
  }, lens(renderers).get(path));
25003
25003
  return /*#__PURE__*/React__namespace.createElement("div", {
25004
- className: aphrodite.css(styles$r.row)
25004
+ className: aphrodite.css(styles$s.row)
25005
25005
  }, /*#__PURE__*/React__namespace.createElement("div", {
25006
- className: aphrodite.css(styles$r.columnLeft)
25006
+ className: aphrodite.css(styles$s.columnLeft)
25007
25007
  }, /*#__PURE__*/React__namespace.createElement("div", {
25008
- className: aphrodite.css(sticky && styles$r.sticky)
25008
+ className: aphrodite.css(sticky && styles$s.sticky)
25009
25009
  }, /*#__PURE__*/React__namespace.createElement(HintEditor, _extends({}, data, {
25010
- className: aphrodite.css(styles$r.hintEditor),
25010
+ className: aphrodite.css(styles$s.hintEditor),
25011
25011
  onChange: newVal => actions.mergeValueAtPath(path, newVal),
25012
25012
  apiOptions: apiOptions,
25013
25013
  showTitle: false,
@@ -25022,9 +25022,9 @@ const HintNodeContent = withStickiness(props => {
25022
25022
  isFirst: true,
25023
25023
  isLast: true
25024
25024
  })))), /*#__PURE__*/React__namespace.createElement("div", {
25025
- className: aphrodite.css(styles$r.columnRight)
25025
+ className: aphrodite.css(styles$s.columnRight)
25026
25026
  }, /*#__PURE__*/React__namespace.createElement("div", {
25027
- className: aphrodite.css(sticky && styles$r.sticky)
25027
+ className: aphrodite.css(sticky && styles$s.sticky)
25028
25028
  }, preview)));
25029
25029
  });
25030
25030
  const TagsNodeContent = props => {
@@ -25041,9 +25041,9 @@ const TagsNodeContent = props => {
25041
25041
  return null;
25042
25042
  }
25043
25043
  return /*#__PURE__*/React__namespace.createElement("div", {
25044
- className: aphrodite.css(styles$r.columnLeft)
25044
+ className: aphrodite.css(styles$s.columnLeft)
25045
25045
  }, /*#__PURE__*/React__namespace.createElement("div", {
25046
- className: aphrodite.css(styles$r.tagsEditor)
25046
+ className: aphrodite.css(styles$s.tagsEditor)
25047
25047
  }, /*#__PURE__*/React__namespace.createElement(GroupMetadataEditor, {
25048
25048
  value: data,
25049
25049
  onChange: newVal => actions.setValueAtPath(path, newVal),
@@ -25074,23 +25074,23 @@ const ArrayNodeContent = props => {
25074
25074
  const subpath = path.concat(i);
25075
25075
  const controls = [i > 0 && /*#__PURE__*/React__namespace.createElement("div", {
25076
25076
  key: "moveArrayElementUp",
25077
- className: aphrodite.css(styles$r.control)
25077
+ className: aphrodite.css(styles$s.control)
25078
25078
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25079
25079
  color: "orange",
25080
25080
  title: "Move up",
25081
25081
  onClick: () => actions.moveArrayElementUp(subpath)
25082
25082
  }, /*#__PURE__*/React__namespace.createElement("div", {
25083
- className: aphrodite.css(styles$r.verticalFlip)
25083
+ className: aphrodite.css(styles$s.verticalFlip)
25084
25084
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconChevronDown)))), i < data.length - 1 && /*#__PURE__*/React__namespace.createElement("div", {
25085
25085
  key: "moveArrayElementDown",
25086
- className: aphrodite.css(styles$r.control)
25086
+ className: aphrodite.css(styles$s.control)
25087
25087
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25088
25088
  color: "orange",
25089
25089
  title: "Move down",
25090
25090
  onClick: () => actions.moveArrayElementDown(subpath)
25091
25091
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconChevronDown))), /*#__PURE__*/React__namespace.createElement("div", {
25092
25092
  key: "removeArrayElement",
25093
- className: aphrodite.css(styles$r.control)
25093
+ className: aphrodite.css(styles$s.control)
25094
25094
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25095
25095
  color: "orange",
25096
25096
  title: "Delete",
@@ -25098,7 +25098,7 @@ const ArrayNodeContent = props => {
25098
25098
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconTrash$4)))];
25099
25099
  return /*#__PURE__*/React__namespace.createElement("div", {
25100
25100
  key: i,
25101
- className: aphrodite.css(styles$r.arrayElement, !elementIsLeaf && styles$r.arrayElementAndNotLeaf)
25101
+ className: aphrodite.css(styles$s.arrayElement, !elementIsLeaf && styles$s.arrayElementAndNotLeaf)
25102
25102
  }, /*#__PURE__*/React__namespace.createElement(NodeContainer, _extends({}, otherProps, {
25103
25103
  key: i,
25104
25104
  shape: shape.elementShape,
@@ -25124,7 +25124,7 @@ const ObjectNodeContent = props => {
25124
25124
  // made sense to the shape's author is the order in which we'll iterate :)
25125
25125
  const children = Object.keys(shape.shape).map(subkey => /*#__PURE__*/React__namespace.createElement("div", {
25126
25126
  key: subkey,
25127
- className: aphrodite.css(styles$r.objectElement)
25127
+ className: aphrodite.css(styles$s.objectElement)
25128
25128
  }, /*#__PURE__*/React__namespace.createElement(NodeContainer, _extends({}, otherProps, {
25129
25129
  shape: shape.shape[subkey],
25130
25130
  data: data[subkey],
@@ -25294,7 +25294,7 @@ class MultiRendererEditor extends React__namespace.Component {
25294
25294
  }, this._renderContent());
25295
25295
  }
25296
25296
  }
25297
- const styles$r = aphrodite.StyleSheet.create({
25297
+ const styles$s = aphrodite.StyleSheet.create({
25298
25298
  // This is used in a number of places throughout this file.
25299
25299
  container: {},
25300
25300
  // eslint-disable-next-line react-native/no-unused-styles
@@ -25446,47 +25446,47 @@ const StatefulArticleEditor = createReactClass__default["default"]({
25446
25446
  screen
25447
25447
  } = this.state;
25448
25448
  return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", {
25449
- style: styles$q.controlBar
25449
+ style: styles$r.controlBar
25450
25450
  }, /*#__PURE__*/React__namespace.createElement("span", {
25451
- style: styles$q.controls
25451
+ style: styles$r.controls
25452
25452
  }, "Mode:", " ", /*#__PURE__*/React__namespace.createElement("span", {
25453
25453
  onClick: () => this.setState({
25454
25454
  mode: "edit"
25455
25455
  }),
25456
- style: mode === "edit" ? styles$q.controlSelected : styles$q.control
25456
+ style: mode === "edit" ? styles$r.controlSelected : styles$r.control
25457
25457
  }, "EDIT"), " | ", /*#__PURE__*/React__namespace.createElement("span", {
25458
25458
  onClick: () => this.setState({
25459
25459
  mode: "preview"
25460
25460
  }),
25461
- style: mode === "preview" ? styles$q.controlSelected : styles$q.control
25461
+ style: mode === "preview" ? styles$r.controlSelected : styles$r.control
25462
25462
  }, "PREVIEW"), " | ", /*#__PURE__*/React__namespace.createElement("span", {
25463
25463
  onClick: () => this.setState({
25464
25464
  mode: "json"
25465
25465
  }),
25466
- style: mode === "json" ? styles$q.controlSelected : styles$q.control
25466
+ style: mode === "json" ? styles$r.controlSelected : styles$r.control
25467
25467
  }, "JSON")), /*#__PURE__*/React__namespace.createElement("span", {
25468
- style: styles$q.controls
25468
+ style: styles$r.controls
25469
25469
  }, "Screen:", " ", /*#__PURE__*/React__namespace.createElement("span", {
25470
25470
  onClick: () => this.setState({
25471
25471
  screen: "phone"
25472
25472
  }),
25473
- style: screen === "phone" ? styles$q.controlSelected : styles$q.control
25473
+ style: screen === "phone" ? styles$r.controlSelected : styles$r.control
25474
25474
  }, "PHONE"), " | ", /*#__PURE__*/React__namespace.createElement("span", {
25475
25475
  onClick: () => this.setState({
25476
25476
  screen: "tablet"
25477
25477
  }),
25478
- style: screen === "tablet" ? styles$q.controlSelected : styles$q.control
25478
+ style: screen === "tablet" ? styles$r.controlSelected : styles$r.control
25479
25479
  }, "TABLET"), " | ", /*#__PURE__*/React__namespace.createElement("span", {
25480
25480
  onClick: () => this.setState({
25481
25481
  screen: "desktop"
25482
25482
  }),
25483
- style: screen === "desktop" ? styles$q.controlSelected : styles$q.control
25483
+ style: screen === "desktop" ? styles$r.controlSelected : styles$r.control
25484
25484
  }, "DESKTOP"))), /*#__PURE__*/React__namespace.createElement("div", {
25485
- style: styles$q.editor
25485
+ style: styles$r.editor
25486
25486
  }, /*#__PURE__*/React__namespace.createElement(ArticleEditor, this.state)));
25487
25487
  }
25488
25488
  });
25489
- const styles$q = {
25489
+ const styles$r = {
25490
25490
  controlBar: {
25491
25491
  marginBottom: 25,
25492
25492
  marginTop: 5
@@ -27025,10 +27025,10 @@ class GradedGroupEditor extends React__namespace.Component {
27025
27025
  }, /*#__PURE__*/React__namespace.createElement("div", {
27026
27026
  className: "perseus-widget-row"
27027
27027
  }, /*#__PURE__*/React__namespace.createElement("label", {
27028
- className: aphrodite.css(styles$p.title)
27028
+ className: aphrodite.css(styles$q.title)
27029
27029
  }, "Title:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$6, {
27030
27030
  value: this.props.title,
27031
- className: aphrodite.css(styles$p.input)
27031
+ className: aphrodite.css(styles$q.input)
27032
27032
  // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
27033
27033
  ,
27034
27034
  onChange: this.change("title")
@@ -27053,7 +27053,7 @@ class GradedGroupEditor extends React__namespace.Component {
27053
27053
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$4, iconPlus$1), " Add a hint"), this.props.hint && /*#__PURE__*/React__namespace.createElement("div", {
27054
27054
  className: "perseus-hint-editor"
27055
27055
  }, /*#__PURE__*/React__namespace.createElement("div", {
27056
- className: aphrodite.css(styles$p.hintsTitle)
27056
+ className: aphrodite.css(styles$q.hintsTitle)
27057
27057
  }, "Hint"), /*#__PURE__*/React__namespace.createElement(Editor, {
27058
27058
  ref: this.hintEditor,
27059
27059
  content: this.props.hint ? this.props.hint.content : "",
@@ -27085,7 +27085,7 @@ class GradedGroupEditor extends React__namespace.Component {
27085
27085
  };
27086
27086
  };
27087
27087
  }
27088
- const styles$p = aphrodite.StyleSheet.create({
27088
+ const styles$q = aphrodite.StyleSheet.create({
27089
27089
  title: {
27090
27090
  fontSize: 18,
27091
27091
  fontWeight: "bold"
@@ -28456,13 +28456,13 @@ function MathquillInput(props) {
28456
28456
  }
28457
28457
  });
28458
28458
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
28459
- style: styles$o.outerWrapper
28459
+ style: styles$p.outerWrapper
28460
28460
  }, /*#__PURE__*/React__namespace.createElement("span", {
28461
28461
  ref: mathFieldWrapperRef,
28462
28462
  className: "perseus-math-input mq-editable-field mq-math-mode"
28463
28463
  }));
28464
28464
  }
28465
- const styles$o = aphrodite.StyleSheet.create({
28465
+ const styles$p = aphrodite.StyleSheet.create({
28466
28466
  outerWrapper: {
28467
28467
  display: "inline-block",
28468
28468
  borderStyle: "solid",
@@ -29548,7 +29548,7 @@ const GraphPointsCountSelector = _ref => {
29548
29548
  // Never uses placeholder, always has value
29549
29549
  ,
29550
29550
  placeholder: "",
29551
- style: styles$n.singleSelectShort
29551
+ style: styles$o.singleSelectShort
29552
29552
  }, [...[...Array(7).keys()].map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29553
29553
  key: n,
29554
29554
  value: `${n}`,
@@ -29559,7 +29559,7 @@ const GraphPointsCountSelector = _ref => {
29559
29559
  label: "unlimited"
29560
29560
  })]);
29561
29561
  };
29562
- const styles$n = aphrodite.StyleSheet.create({
29562
+ const styles$o = aphrodite.StyleSheet.create({
29563
29563
  singleSelectShort: {
29564
29564
  // Non-standard spacing, but it's the smallest we can go
29565
29565
  // without running into styling issues with the dropdown.
@@ -29572,7 +29572,7 @@ const GraphTypeSelector = props => {
29572
29572
  selectedValue: props.graphType,
29573
29573
  onChange: props.onChange,
29574
29574
  placeholder: "Select a graph type",
29575
- style: styles$m.singleSelectShort
29575
+ style: styles$n.singleSelectShort
29576
29576
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29577
29577
  value: "linear",
29578
29578
  label: "Linear function"
@@ -29605,7 +29605,7 @@ const GraphTypeSelector = props => {
29605
29605
  label: "Angle"
29606
29606
  }));
29607
29607
  };
29608
- const styles$m = aphrodite.StyleSheet.create({
29608
+ const styles$n = aphrodite.StyleSheet.create({
29609
29609
  singleSelectShort: {
29610
29610
  // Non-standard spacing, but it's the smallest we can go
29611
29611
  // without running into styling issues with the dropdown.
@@ -29622,16 +29622,16 @@ const LabeledRow = props => {
29622
29622
  style
29623
29623
  } = props;
29624
29624
  return /*#__PURE__*/React__namespace.createElement("label", {
29625
- className: aphrodite.css(styles$l.label)
29625
+ className: aphrodite.css(styles$m.label)
29626
29626
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29627
- style: [styles$l.row, style]
29627
+ style: [styles$m.row, style]
29628
29628
  }, labelSide === "start" || /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29629
- style: styles$l.spaceEnd
29629
+ style: styles$m.spaceEnd
29630
29630
  }, label), children, labelSide === "end" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29631
- style: styles$l.spaceStart
29631
+ style: styles$m.spaceStart
29632
29632
  }, label)));
29633
29633
  };
29634
- const styles$l = aphrodite.StyleSheet.create({
29634
+ const styles$m = aphrodite.StyleSheet.create({
29635
29635
  label: {
29636
29636
  width: "fit-content"
29637
29637
  },
@@ -30053,10 +30053,10 @@ class InteractiveGraphSettings extends React__namespace.Component {
30053
30053
  onChange: this.change
30054
30054
  }))), /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30055
30055
  label: "Background image URL:",
30056
- style: styles$k.resetSpaceTop
30056
+ style: styles$l.resetSpaceTop
30057
30057
  }, /*#__PURE__*/React__namespace.createElement("input", {
30058
30058
  type: "text",
30059
- className: aphrodite.css(styles$k.backgroundUrlInput),
30059
+ className: aphrodite.css(styles$l.backgroundUrlInput),
30060
30060
  ref: this.bgUrlRef,
30061
30061
  value: this.state.backgroundImage.url || "",
30062
30062
  onChange: e => {
@@ -30072,28 +30072,28 @@ class InteractiveGraphSettings extends React__namespace.Component {
30072
30072
  onKeyPress: this.changeBackgroundUrl,
30073
30073
  onBlur: this.changeBackgroundUrl
30074
30074
  }), /*#__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, {
30075
- style: styles$k.rulerSection
30075
+ style: styles$l.rulerSection
30076
30076
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30077
- style: styles$k.checkboxRow
30077
+ style: styles$l.checkboxRow
30078
30078
  }, /*#__PURE__*/React__namespace.createElement(PropCheckBox$7, {
30079
30079
  label: "Show ruler",
30080
30080
  showRuler: this.props.showRuler,
30081
30081
  onChange: this.change,
30082
- style: styles$k.resetSpaceTop
30082
+ style: styles$l.resetSpaceTop
30083
30083
  }), /*#__PURE__*/React__namespace.createElement(PropCheckBox$7, {
30084
30084
  label: "Show protractor",
30085
30085
  showProtractor: this.props.showProtractor,
30086
30086
  onChange: this.change,
30087
- style: styles$k.resetSpaceTop
30087
+ style: styles$l.resetSpaceTop
30088
30088
  })), (this.props.showRuler || this.props.showProtractor) && /*#__PURE__*/React__namespace.createElement(Banner__default["default"], {
30089
30089
  layout: "floating",
30090
30090
  text: "The ruler and protractor are not accessible. Please consider an alternate approach.",
30091
30091
  kind: "warning"
30092
30092
  }), this.props.showRuler && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30093
- style: styles$k.spaceTop
30093
+ style: styles$l.spaceTop
30094
30094
  }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30095
30095
  label: "Ruler label:",
30096
- style: styles$k.resetSpaceTop
30096
+ style: styles$l.resetSpaceTop
30097
30097
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30098
30098
  id: "ruler-label-select",
30099
30099
  selectedValue: this.props.rulerLabel,
@@ -30103,7 +30103,7 @@ class InteractiveGraphSettings extends React__namespace.Component {
30103
30103
  });
30104
30104
  },
30105
30105
  placeholder: "None",
30106
- style: styles$k.singleSelectShort
30106
+ style: styles$l.singleSelectShort
30107
30107
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30108
30108
  value: "",
30109
30109
  label: "None",
@@ -30144,7 +30144,7 @@ class InteractiveGraphSettings extends React__namespace.Component {
30144
30144
  });
30145
30145
  },
30146
30146
  placeholder: "10",
30147
- style: styles$k.singleSelectShort
30147
+ style: styles$l.singleSelectShort
30148
30148
  }, [1, 2, 4, 8, 10, 16].map(value => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30149
30149
  key: value,
30150
30150
  value: `${value}`,
@@ -30152,7 +30152,7 @@ class InteractiveGraphSettings extends React__namespace.Component {
30152
30152
  })))))));
30153
30153
  }
30154
30154
  }
30155
- const styles$k = aphrodite.StyleSheet.create({
30155
+ const styles$l = aphrodite.StyleSheet.create({
30156
30156
  resetSpaceTop: {
30157
30157
  marginTop: 0
30158
30158
  },
@@ -30197,10 +30197,10 @@ const LockedFigureSelect = props => {
30197
30197
  onChange
30198
30198
  } = props;
30199
30199
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30200
- style: styles$j.container
30200
+ style: styles$k.container
30201
30201
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionMenu, {
30202
30202
  menuText: "Add locked figure",
30203
- style: styles$j.addElementSelect
30203
+ style: styles$k.addElementSelect
30204
30204
  }, [/*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
30205
30205
  key: `${id}-point`,
30206
30206
  label: "Point",
@@ -30211,7 +30211,7 @@ const LockedFigureSelect = props => {
30211
30211
  onClick: () => onChange("line")
30212
30212
  }, "Line")]));
30213
30213
  };
30214
- const styles$j = aphrodite.StyleSheet.create({
30214
+ const styles$k = aphrodite.StyleSheet.create({
30215
30215
  container: {
30216
30216
  marginTop: wonderBlocksTokens.spacing.xSmall_8
30217
30217
  },
@@ -30311,13 +30311,13 @@ const ColorSwatch = props => {
30311
30311
  "aria-label":
30312
30312
  // Don't include an aria label for decorative circles.
30313
30313
  !decorative ? `Color: ${color}, ${filled ? "filled" : "open"}` : undefined,
30314
- style: [styles$i.colorSwatch, {
30314
+ style: [styles$j.colorSwatch, {
30315
30315
  border: `4px solid ${perseus.lockedFigureColors[color]}`,
30316
30316
  backgroundColor: filled ? perseus.lockedFigureColors[color] : wonderBlocksTokens.color.white
30317
30317
  }]
30318
30318
  });
30319
30319
  };
30320
- const styles$i = aphrodite.StyleSheet.create({
30320
+ const styles$j = aphrodite.StyleSheet.create({
30321
30321
  colorSwatch: {
30322
30322
  // Add a white outline so that the color swatch is visible when
30323
30323
  // the dropdown option is highlighted with its blue background.
@@ -30337,10 +30337,10 @@ const ColorSelect = props => {
30337
30337
  onChange
30338
30338
  } = props;
30339
30339
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30340
- style: [styles$h.row, style]
30340
+ style: [styles$i.row, style]
30341
30341
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30342
30342
  htmlFor: id,
30343
- style: styles$h.label,
30343
+ style: styles$i.label,
30344
30344
  tag: "label"
30345
30345
  }, "color"), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30346
30346
  id: id,
@@ -30359,7 +30359,7 @@ const ColorSelect = props => {
30359
30359
  })
30360
30360
  }, colorName))));
30361
30361
  };
30362
- const styles$h = aphrodite.StyleSheet.create({
30362
+ const styles$i = aphrodite.StyleSheet.create({
30363
30363
  row: {
30364
30364
  flexDirection: "row",
30365
30365
  alignItems: "center"
@@ -30369,6 +30369,34 @@ const styles$h = aphrodite.StyleSheet.create({
30369
30369
  }
30370
30370
  });
30371
30371
 
30372
+ const LineSwatch = props => {
30373
+ const {
30374
+ color,
30375
+ lineStyle
30376
+ } = props;
30377
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30378
+ style: styles$h.container
30379
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30380
+ "aria-label": `${color}, ${lineStyle}`,
30381
+ style: [styles$h.lineSwatch, {
30382
+ border: `5px ${lineStyle} ${perseus.lockedFigureColors[color]}`
30383
+ }]
30384
+ }));
30385
+ };
30386
+ const styles$h = aphrodite.StyleSheet.create({
30387
+ container: {
30388
+ backgroundColor: wonderBlocksTokens.color.white,
30389
+ justifyContent: "center",
30390
+ padding: wonderBlocksTokens.spacing.xSmall_8,
30391
+ borderRadius: wonderBlocksTokens.spacing.xxxSmall_4
30392
+ },
30393
+ lineSwatch: {
30394
+ // Add a white outline so that the color swatch is visible when
30395
+ // the dropdown option is highlighted with its blue background.
30396
+ width: 40
30397
+ }
30398
+ });
30399
+
30372
30400
  const LockedFigureSettingsAccordion = props => {
30373
30401
  const {
30374
30402
  children,
@@ -30473,79 +30501,6 @@ const styles$e = aphrodite.StyleSheet.create({
30473
30501
  }
30474
30502
  });
30475
30503
 
30476
- function focusWithChromeStickyFocusBugWorkaround(element) {
30477
- // NOTE(marksandstrom) Chrome sticky focus bug.
30478
- //
30479
- // There is a bug in Chrome related to sticky positioning and
30480
- // focus: When a child of an element with sticky positioning is
30481
- // focused with the focus() method, the scrollable area
30482
- // containing that element will scroll to the top (even though
30483
- // the element is already visble on the page). For a dropdown
30484
- // this means that the area will be scrolled to the top when
30485
- // the user interacts with the dropdown (since we actively
30486
- // manage dropdown header and option focus for keyboard users).
30487
- //
30488
- // To work around this bug the `preventScroll` focus option is
30489
- // used.
30490
- //
30491
- // Using `focusOptions` is an experimental browser feature
30492
- // "that should not be used in production code". However, since
30493
- // Chrome is the only browser we support that exhibits this
30494
- // buggy behavior and using `focusOptions` works around the
30495
- // bug, it is perfectly reasonable to use the feature in this
30496
- // case. We are not relying on the effect of the
30497
- // `preventScroll` option otherwise.
30498
- //
30499
- // focusOptions documentation:
30500
- //
30501
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
30502
- //
30503
- // Note that there could be cases where we want default focus() behavior.
30504
- // One that comes to mind is a dropdown with a long list of options that
30505
- // might be rendered off screen when opened. With this workaround the
30506
- // selected option would not be scrolled into view if the option is near
30507
- // the end of the list. We're not aware of any uses of the dropdown where
30508
- // this is an issue, however, so there isn't currently a way to out of the
30509
- // `preventScroll` behavior.
30510
-
30511
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element'.
30512
- element.focus({
30513
- preventScroll: true
30514
- });
30515
- }
30516
- function getValidNumberFromString(value) {
30517
- const parsed = parseFloat(value);
30518
- // If the value is not a number, return 0.
30519
- return isNaN(parsed) ? 0 : parsed;
30520
- }
30521
- const DEFAULT_COLOR = "grayH";
30522
- function getDefaultFigureForType(type) {
30523
- switch (type) {
30524
- case "point":
30525
- return {
30526
- type: "point",
30527
- coord: [0, 0],
30528
- color: DEFAULT_COLOR,
30529
- filled: true
30530
- };
30531
- case "line":
30532
- return {
30533
- type: "line",
30534
- kind: "line",
30535
- points: [getDefaultFigureForType("point"), {
30536
- ...getDefaultFigureForType("point"),
30537
- coord: [2, 2]
30538
- }],
30539
- color: DEFAULT_COLOR,
30540
- lineStyle: "solid",
30541
- showStartPoint: false,
30542
- showEndPoint: false
30543
- };
30544
- default:
30545
- throw new wonderStuffCore.UnreachableCaseError(type);
30546
- }
30547
- }
30548
-
30549
30504
  /**
30550
30505
  * LockedPointSettings is a component that allows the user to edit the
30551
30506
  * settings of specifically a locked point on the graph.
@@ -30566,7 +30521,7 @@ const LockedPointSettings = props => {
30566
30521
  } = props;
30567
30522
 
30568
30523
  // Keep track of the coordinates via state as the user is editing them,
30569
- // before they are updated in the props on blur.
30524
+ // before they are updated in the props as a valid number.
30570
30525
  const [coordState, setCoordState] = React__namespace.useState([
30571
30526
  // Using strings to make it easier to work with the text fields.
30572
30527
  coord[0].toString(), coord[1].toString()]);
@@ -30577,21 +30532,25 @@ const LockedPointSettings = props => {
30577
30532
  const xCoordId = ids.get("x-coord");
30578
30533
  const yCoordId = ids.get("y-coord");
30579
30534
  const colorSelectId = ids.get("point-color-select");
30580
- function handleBlur() {
30581
- const validCoord = [getValidNumberFromString(coordState[0]), getValidNumberFromString(coordState[1])];
30535
+ function handleCoordChange(newValue, coordIndex) {
30536
+ // Update the local state (update the input field value).
30537
+ const newCoordState = [...coordState];
30538
+ newCoordState[coordIndex] = newValue;
30539
+ setCoordState(newCoordState);
30540
+
30541
+ // If the new value is not a number, don't update the props.
30542
+ // If it's empty, keep the props the same value instead of setting to 0.
30543
+ if (isNaN(+newValue) || newValue === "") {
30544
+ return;
30545
+ }
30582
30546
 
30583
- // Make the text field only show valid numbers after blur.
30584
- setCoordState([validCoord[0].toString(), validCoord[1].toString()]);
30585
- // Update the graph with the new coordinates.
30547
+ // Update the props (update the graph).
30548
+ const newCoords = [...coord];
30549
+ newCoords[coordIndex] = +newValue;
30586
30550
  onChangeProps({
30587
- coord: validCoord
30551
+ coord: newCoords
30588
30552
  });
30589
30553
  }
30590
- function handleCoordChange(newValue, coordIndex) {
30591
- const newCoord = [...coordState];
30592
- newCoord[coordIndex] = newValue;
30593
- setCoordState(newCoord);
30594
- }
30595
30554
  function handleColorChange(newValue) {
30596
30555
  onChangeProps({
30597
30556
  color: newValue
@@ -30622,7 +30581,6 @@ const LockedPointSettings = props => {
30622
30581
  type: "number",
30623
30582
  value: coordState[0],
30624
30583
  onChange: newValue => handleCoordChange(newValue, 0),
30625
- onBlur: handleBlur,
30626
30584
  style: styles$d.textField
30627
30585
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
30628
30586
  size: wonderBlocksTokens.spacing.medium_16
@@ -30635,7 +30593,6 @@ const LockedPointSettings = props => {
30635
30593
  type: "number",
30636
30594
  value: coordState[1],
30637
30595
  onChange: newValue => handleCoordChange(newValue, 1),
30638
- onBlur: handleBlur,
30639
30596
  style: styles$d.textField
30640
30597
  })), onToggle && /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
30641
30598
  label: "show point on graph",
@@ -30657,7 +30614,7 @@ const LockedPointSettings = props => {
30657
30614
  }
30658
30615
  })), onRemove && /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
30659
30616
  onRemove: onRemove,
30660
- figureAriaLabel: `locked point at ${coordState[0]}, ${coordState[1]}`
30617
+ figureAriaLabel: `locked point at ${coord[0]}, ${coord[1]}`
30661
30618
  }));
30662
30619
  };
30663
30620
  const styles$d = aphrodite.StyleSheet.create({
@@ -30686,12 +30643,12 @@ const LockedLineSettings = props => {
30686
30643
  points,
30687
30644
  color: lineColor,
30688
30645
  lineStyle = "solid",
30689
- showStartPoint,
30690
- showEndPoint,
30646
+ showPoint1,
30647
+ showPoint2,
30691
30648
  onChangeProps,
30692
30649
  onRemove
30693
30650
  } = props;
30694
- const [startPoint, endPoint] = points;
30651
+ const [point1, point2] = points;
30695
30652
 
30696
30653
  // Generate unique IDs so that the programmatic labels can be associated
30697
30654
  // with their respective text fields.
@@ -30699,8 +30656,9 @@ const LockedLineSettings = props => {
30699
30656
  const kindSelectId = ids.get("line-kind-select");
30700
30657
  const colorSelectId = ids.get("line-color-select");
30701
30658
  const styleSelectId = ids.get("line-style-select");
30702
- const lineLabel = `Line (${startPoint.coord[0]}, ${startPoint.coord[1]}),
30703
- (${endPoint.coord[0]}, ${endPoint.coord[1]})`;
30659
+ const capitalizeKind = kind.charAt(0).toUpperCase() + kind.slice(1);
30660
+ const lineLabel = `${capitalizeKind} (${point1.coord[0]},
30661
+ ${point1.coord[1]}), (${point2.coord[0]}, ${point2.coord[1]})`;
30704
30662
  function handleChangePoint(newPointProps, index) {
30705
30663
  const newPoints = [...points];
30706
30664
  newPoints[index] = {
@@ -30716,10 +30674,10 @@ const LockedLineSettings = props => {
30716
30674
  color: newColor,
30717
30675
  // Keep the line's points' colors in sync with the line color.
30718
30676
  points: [{
30719
- ...startPoint,
30677
+ ...point1,
30720
30678
  color: newColor
30721
30679
  }, {
30722
- ...endPoint,
30680
+ ...point2,
30723
30681
  color: newColor
30724
30682
  }]
30725
30683
  });
@@ -30729,8 +30687,9 @@ const LockedLineSettings = props => {
30729
30687
  style: styles$c.row
30730
30688
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
30731
30689
  size: wonderBlocksTokens.spacing.xSmall_8
30732
- }), /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
30733
- color: lineColor
30690
+ }), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
30691
+ color: lineColor,
30692
+ lineStyle: lineStyle
30734
30693
  }))
30735
30694
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30736
30695
  style: [styles$c.row, styles$c.spaceUnder]
@@ -30787,28 +30746,28 @@ const LockedLineSettings = props => {
30787
30746
  value: "dashed",
30788
30747
  label: "dashed"
30789
30748
  })))), /*#__PURE__*/React__namespace.createElement(LockedPointSettings, _extends({
30790
- label: "Start point",
30791
- toggled: showStartPoint
30792
- }, startPoint, {
30749
+ label: "Point 1",
30750
+ toggled: showPoint1
30751
+ }, point1, {
30793
30752
  onToggle: newValue => onChangeProps({
30794
- showStartPoint: newValue
30753
+ showPoint1: newValue
30795
30754
  }),
30796
30755
  onChangeProps: newProps => handleChangePoint(newProps, 0),
30797
30756
  style: styles$c.lockedPointSettingsContainer
30798
30757
  })), /*#__PURE__*/React__namespace.createElement(LockedPointSettings, _extends({
30799
- label: "End point",
30800
- toggled: showEndPoint
30801
- }, endPoint, {
30758
+ label: "Point 2",
30759
+ toggled: showPoint2
30760
+ }, point2, {
30802
30761
  onToggle: newValue => onChangeProps({
30803
- showEndPoint: newValue
30762
+ showPoint2: newValue
30804
30763
  }),
30805
30764
  onChangeProps: newProps => handleChangePoint(newProps, 1),
30806
30765
  style: styles$c.lockedPointSettingsContainer
30807
30766
  })), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
30808
30767
  onRemove: onRemove,
30809
30768
  figureAriaLabel: `locked line defined by
30810
- ${startPoint.coord[0]}, ${startPoint.coord[1]} and
30811
- ${endPoint.coord[0]}, ${endPoint.coord[1]}.`
30769
+ ${point1.coord[0]}, ${point1.coord[1]} and
30770
+ ${point2.coord[0]}, ${point2.coord[1]}.`
30812
30771
  }));
30813
30772
  };
30814
30773
  const styles$c = aphrodite.StyleSheet.create({
@@ -30854,6 +30813,74 @@ const LockedFigureSettings = props => {
30854
30813
  return null;
30855
30814
  };
30856
30815
 
30816
+ function focusWithChromeStickyFocusBugWorkaround(element) {
30817
+ // NOTE(marksandstrom) Chrome sticky focus bug.
30818
+ //
30819
+ // There is a bug in Chrome related to sticky positioning and
30820
+ // focus: When a child of an element with sticky positioning is
30821
+ // focused with the focus() method, the scrollable area
30822
+ // containing that element will scroll to the top (even though
30823
+ // the element is already visble on the page). For a dropdown
30824
+ // this means that the area will be scrolled to the top when
30825
+ // the user interacts with the dropdown (since we actively
30826
+ // manage dropdown header and option focus for keyboard users).
30827
+ //
30828
+ // To work around this bug the `preventScroll` focus option is
30829
+ // used.
30830
+ //
30831
+ // Using `focusOptions` is an experimental browser feature
30832
+ // "that should not be used in production code". However, since
30833
+ // Chrome is the only browser we support that exhibits this
30834
+ // buggy behavior and using `focusOptions` works around the
30835
+ // bug, it is perfectly reasonable to use the feature in this
30836
+ // case. We are not relying on the effect of the
30837
+ // `preventScroll` option otherwise.
30838
+ //
30839
+ // focusOptions documentation:
30840
+ //
30841
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
30842
+ //
30843
+ // Note that there could be cases where we want default focus() behavior.
30844
+ // One that comes to mind is a dropdown with a long list of options that
30845
+ // might be rendered off screen when opened. With this workaround the
30846
+ // selected option would not be scrolled into view if the option is near
30847
+ // the end of the list. We're not aware of any uses of the dropdown where
30848
+ // this is an issue, however, so there isn't currently a way to out of the
30849
+ // `preventScroll` behavior.
30850
+
30851
+ // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element'.
30852
+ element.focus({
30853
+ preventScroll: true
30854
+ });
30855
+ }
30856
+ const DEFAULT_COLOR = "grayH";
30857
+ function getDefaultFigureForType(type) {
30858
+ switch (type) {
30859
+ case "point":
30860
+ return {
30861
+ type: "point",
30862
+ coord: [0, 0],
30863
+ color: DEFAULT_COLOR,
30864
+ filled: true
30865
+ };
30866
+ case "line":
30867
+ return {
30868
+ type: "line",
30869
+ kind: "line",
30870
+ points: [getDefaultFigureForType("point"), {
30871
+ ...getDefaultFigureForType("point"),
30872
+ coord: [2, 2]
30873
+ }],
30874
+ color: DEFAULT_COLOR,
30875
+ lineStyle: "solid",
30876
+ showPoint1: false,
30877
+ showPoint2: false
30878
+ };
30879
+ default:
30880
+ throw new wonderStuffCore.UnreachableCaseError(type);
30881
+ }
30882
+ }
30883
+
30857
30884
  const LockedFiguresSection = props => {
30858
30885
  const uniqueId = wonderBlocksCore.useUniqueIdWithMock().get("locked-figures-section");
30859
30886
  const {