@khanacademy/perseus-editor 6.2.3 → 6.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -25,10 +25,10 @@ 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
27
  var Banner = require('@khanacademy/wonder-blocks-banner');
28
- var wonderBlocksAccordion = require('@khanacademy/wonder-blocks-accordion');
29
28
  var Button = require('@khanacademy/wonder-blocks-button');
30
- var trashIcon = require('@phosphor-icons/core/bold/trash-bold.svg');
31
29
  var Switch = require('@khanacademy/wonder-blocks-switch');
30
+ var wonderBlocksAccordion = require('@khanacademy/wonder-blocks-accordion');
31
+ var trashIcon = require('@phosphor-icons/core/bold/trash-bold.svg');
32
32
 
33
33
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
34
34
 
@@ -62,12 +62,12 @@ var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
62
62
  var KAS__namespace = /*#__PURE__*/_interopNamespace(KAS);
63
63
  var Banner__default = /*#__PURE__*/_interopDefaultLegacy(Banner);
64
64
  var Button__default = /*#__PURE__*/_interopDefaultLegacy(Button);
65
- var trashIcon__default = /*#__PURE__*/_interopDefaultLegacy(trashIcon);
66
65
  var Switch__default = /*#__PURE__*/_interopDefaultLegacy(Switch);
66
+ var trashIcon__default = /*#__PURE__*/_interopDefaultLegacy(trashIcon);
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.3";
70
+ const libVersion = "6.4.1";
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$y.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$y = 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$x.iconExpanded : styles$x.iconCollapsed;
20791
20791
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20792
- style: styles$t.errorContainer
20792
+ style: styles$x.errorContainer
20793
20793
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20794
- style: styles$t.title,
20794
+ style: styles$x.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$x.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$x.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$x = 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$w.baseButton, color === "green" && styles$w.green, color === "orange" && styles$w.orange),
24569
24569
  onClick: onClick
24570
24570
  }, otherProps), children);
24571
24571
  }
24572
24572
  }
24573
- const styles$s = aphrodite.StyleSheet.create({
24573
+ const styles$w = 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$v.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$v.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$v.container)
24793
24793
  }, /*#__PURE__*/React__namespace.createElement("span", {
24794
- className: aphrodite.css(styles$r.row, styles$r.rowHeading)
24794
+ className: aphrodite.css(styles$v.row, styles$v.rowHeading)
24795
24795
  }, /*#__PURE__*/React__namespace.createElement("div", {
24796
- className: aphrodite.css(styles$r.columnLeft)
24796
+ className: aphrodite.css(styles$v.columnLeft)
24797
24797
  }, /*#__PURE__*/React__namespace.createElement("div", {
24798
- className: "pod-title " + aphrodite.css(styles$r.containerHeader)
24798
+ className: "pod-title " + aphrodite.css(styles$v.containerHeader)
24799
24799
  }, /*#__PURE__*/React__namespace.createElement("div", {
24800
- className: aphrodite.css(styles$r.containerTitle)
24800
+ className: aphrodite.css(styles$v.containerTitle)
24801
24801
  }, capitalize(name)), controls)), /*#__PURE__*/React__namespace.createElement("div", {
24802
- className: aphrodite.css(styles$r.columnRight)
24802
+ className: aphrodite.css(styles$v.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$v.container)
24816
24816
  }, controls && /*#__PURE__*/React__namespace.createElement("div", {
24817
- className: aphrodite.css(styles$r.columnLeft, styles$r.containerHeader)
24817
+ className: aphrodite.css(styles$v.columnLeft, styles$v.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$v.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$v.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$v.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$v.containerHeader, styles$v.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$v.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$v.container)
24847
24847
  }, hasBothHeadings && /*#__PURE__*/React__namespace.createElement("span", {
24848
- className: aphrodite.css(styles$r.row)
24848
+ className: aphrodite.css(styles$v.row)
24849
24849
  }, /*#__PURE__*/React__namespace.createElement("div", {
24850
- className: aphrodite.css(styles$r.columnLeft)
24850
+ className: aphrodite.css(styles$v.columnLeft)
24851
24851
  }, headingEditor), /*#__PURE__*/React__namespace.createElement("div", {
24852
- className: aphrodite.css(styles$r.columnRight)
24852
+ className: aphrodite.css(styles$v.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$v.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$v.row)
24975
24975
  }, /*#__PURE__*/React__namespace.createElement("div", {
24976
- className: aphrodite.css(styles$r.columnLeft)
24976
+ className: aphrodite.css(styles$v.columnLeft)
24977
24977
  }, /*#__PURE__*/React__namespace.createElement("div", {
24978
- className: aphrodite.css(sticky && styles$r.sticky)
24978
+ className: aphrodite.css(sticky && styles$v.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$v.columnRight)
24987
24987
  }, /*#__PURE__*/React__namespace.createElement("div", {
24988
- className: aphrodite.css(sticky && styles$r.sticky)
24988
+ className: aphrodite.css(sticky && styles$v.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$v.row)
25005
25005
  }, /*#__PURE__*/React__namespace.createElement("div", {
25006
- className: aphrodite.css(styles$r.columnLeft)
25006
+ className: aphrodite.css(styles$v.columnLeft)
25007
25007
  }, /*#__PURE__*/React__namespace.createElement("div", {
25008
- className: aphrodite.css(sticky && styles$r.sticky)
25008
+ className: aphrodite.css(sticky && styles$v.sticky)
25009
25009
  }, /*#__PURE__*/React__namespace.createElement(HintEditor, _extends({}, data, {
25010
- className: aphrodite.css(styles$r.hintEditor),
25010
+ className: aphrodite.css(styles$v.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$v.columnRight)
25026
25026
  }, /*#__PURE__*/React__namespace.createElement("div", {
25027
- className: aphrodite.css(sticky && styles$r.sticky)
25027
+ className: aphrodite.css(sticky && styles$v.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$v.columnLeft)
25045
25045
  }, /*#__PURE__*/React__namespace.createElement("div", {
25046
- className: aphrodite.css(styles$r.tagsEditor)
25046
+ className: aphrodite.css(styles$v.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$v.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$v.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$v.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$v.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$v.arrayElement, !elementIsLeaf && styles$v.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$v.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$v = 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$u.controlBar
25450
25450
  }, /*#__PURE__*/React__namespace.createElement("span", {
25451
- style: styles$q.controls
25451
+ style: styles$u.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$u.controlSelected : styles$u.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$u.controlSelected : styles$u.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$u.controlSelected : styles$u.control
25467
25467
  }, "JSON")), /*#__PURE__*/React__namespace.createElement("span", {
25468
- style: styles$q.controls
25468
+ style: styles$u.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$u.controlSelected : styles$u.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$u.controlSelected : styles$u.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$u.controlSelected : styles$u.control
25484
25484
  }, "DESKTOP"))), /*#__PURE__*/React__namespace.createElement("div", {
25485
- style: styles$q.editor
25485
+ style: styles$u.editor
25486
25486
  }, /*#__PURE__*/React__namespace.createElement(ArticleEditor, this.state)));
25487
25487
  }
25488
25488
  });
25489
- const styles$q = {
25489
+ const styles$u = {
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$t.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$t.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$t.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$t = 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$s.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$s = 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$r.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$r = 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$q.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$q = 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$p.label)
29626
29626
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29627
- style: [styles$l.row, style]
29627
+ style: [styles$p.row, style]
29628
29628
  }, labelSide === "start" || /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29629
- style: styles$l.spaceEnd
29629
+ style: styles$p.spaceEnd
29630
29630
  }, label), children, labelSide === "end" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29631
- style: styles$l.spaceStart
29631
+ style: styles$p.spaceStart
29632
29632
  }, label)));
29633
29633
  };
29634
- const styles$l = aphrodite.StyleSheet.create({
29634
+ const styles$p = 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$o.resetSpaceTop
30057
30057
  }, /*#__PURE__*/React__namespace.createElement("input", {
30058
30058
  type: "text",
30059
- className: aphrodite.css(styles$k.backgroundUrlInput),
30059
+ className: aphrodite.css(styles$o.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$o.rulerSection
30076
30076
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30077
- style: styles$k.checkboxRow
30077
+ style: styles$o.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$o.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$o.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$o.spaceTop
30094
30094
  }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30095
30095
  label: "Ruler label:",
30096
- style: styles$k.resetSpaceTop
30096
+ style: styles$o.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$o.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$o.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$o = aphrodite.StyleSheet.create({
30156
30156
  resetSpaceTop: {
30157
30157
  marginTop: 0
30158
30158
  },
@@ -30184,43 +30184,6 @@ const styles$k = aphrodite.StyleSheet.create({
30184
30184
  }
30185
30185
  });
30186
30186
 
30187
- /**
30188
- * Dropdown for selecting a locked figure to add to an interactive graph.
30189
- * Locked figures are elements (points, segmeents, etc.) that are not
30190
- * interactive, just present in the graph's background.
30191
- *
30192
- * Used in the interactive graph editor's locked figures section.
30193
- */
30194
- const LockedFigureSelect = props => {
30195
- const {
30196
- id,
30197
- onChange
30198
- } = props;
30199
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30200
- style: styles$j.container
30201
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionMenu, {
30202
- menuText: "Add locked figure",
30203
- style: styles$j.addElementSelect
30204
- }, [/*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
30205
- key: `${id}-point`,
30206
- label: "Point",
30207
- onClick: () => onChange("point")
30208
- }, "Point"), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
30209
- key: `${id}-line`,
30210
- label: "Line",
30211
- onClick: () => onChange("line")
30212
- }, "Line")]));
30213
- };
30214
- const styles$j = aphrodite.StyleSheet.create({
30215
- container: {
30216
- marginTop: wonderBlocksTokens.spacing.xSmall_8
30217
- },
30218
- addElementSelect: {
30219
- backgroundColor: wonderBlocksTokens.color.fadedBlue8,
30220
- borderRadius: wonderBlocksTokens.spacing.xxxSmall_4
30221
- }
30222
- });
30223
-
30224
30187
  const mediaDefaultSpecLargeMarginWidth = wonderBlocksTokens.spacing.large_24;
30225
30188
  const MEDIA_DEFAULT_SPEC = {
30226
30189
  small: {
@@ -30301,6 +30264,43 @@ const strutStyle = size => {
30301
30264
  };
30302
30265
  };
30303
30266
 
30267
+ /**
30268
+ * Dropdown for selecting a locked figure to add to an interactive graph.
30269
+ * Locked figures are elements (points, segmeents, etc.) that are not
30270
+ * interactive, just present in the graph's background.
30271
+ *
30272
+ * Used in the interactive graph editor's locked figures section.
30273
+ */
30274
+ const LockedFigureSelect = props => {
30275
+ const {
30276
+ id,
30277
+ onChange
30278
+ } = props;
30279
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30280
+ style: styles$n.container
30281
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionMenu, {
30282
+ menuText: "Add locked figure",
30283
+ style: styles$n.addElementSelect
30284
+ }, [/*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
30285
+ key: `${id}-point`,
30286
+ label: "Point",
30287
+ onClick: () => onChange("point")
30288
+ }, "Point"), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
30289
+ key: `${id}-line`,
30290
+ label: "Line",
30291
+ onClick: () => onChange("line")
30292
+ }, "Line")]));
30293
+ };
30294
+ const styles$n = aphrodite.StyleSheet.create({
30295
+ container: {
30296
+ marginTop: wonderBlocksTokens.spacing.xSmall_8
30297
+ },
30298
+ addElementSelect: {
30299
+ backgroundColor: wonderBlocksTokens.color.fadedBlue8,
30300
+ borderRadius: wonderBlocksTokens.spacing.xxxSmall_4
30301
+ }
30302
+ });
30303
+
30304
30304
  const ColorSwatch = props => {
30305
30305
  const {
30306
30306
  color,
@@ -30310,14 +30310,14 @@ const ColorSwatch = props => {
30310
30310
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30311
30311
  "aria-label":
30312
30312
  // Don't include an aria label for decorative circles.
30313
- !decorative ? `Color: ${color}, ${filled ? "filled" : "open"}` : undefined,
30314
- style: [styles$i.colorSwatch, {
30313
+ !decorative ? `${color}, ${filled ? "filled" : "open"}` : undefined,
30314
+ style: [styles$m.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$m = 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.
@@ -30331,16 +30331,17 @@ const styles$i = aphrodite.StyleSheet.create({
30331
30331
  const possibleColors = Object.keys(perseus.lockedFigureColors);
30332
30332
  const ColorSelect = props => {
30333
30333
  const {
30334
- id,
30335
30334
  selectedValue,
30336
30335
  style,
30337
30336
  onChange
30338
30337
  } = props;
30338
+ const ids = wonderBlocksCore.useUniqueIdWithMock();
30339
+ const id = ids.get("color-select");
30339
30340
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30340
- style: [styles$h.row, style]
30341
+ style: [styles$l.row, style]
30341
30342
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30342
30343
  htmlFor: id,
30343
- style: styles$h.label,
30344
+ style: styles$l.label,
30344
30345
  tag: "label"
30345
30346
  }, "color"), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30346
30347
  id: id,
@@ -30359,7 +30360,7 @@ const ColorSelect = props => {
30359
30360
  })
30360
30361
  }, colorName))));
30361
30362
  };
30362
- const styles$h = aphrodite.StyleSheet.create({
30363
+ const styles$l = aphrodite.StyleSheet.create({
30363
30364
  row: {
30364
30365
  flexDirection: "row",
30365
30366
  alignItems: "center"
@@ -30369,12 +30370,121 @@ const styles$h = aphrodite.StyleSheet.create({
30369
30370
  }
30370
30371
  });
30371
30372
 
30373
+ const CoordinatePairInput = props => {
30374
+ const {
30375
+ coord,
30376
+ onChangeProps
30377
+ } = props;
30378
+
30379
+ // Keep track of the coordinates via state as the user is editing them,
30380
+ // before they are updated in the props as a valid number.
30381
+ const [coordState, setCoordState] = React__namespace.useState([
30382
+ // Using strings to make it easier to work with the text fields.
30383
+ coord[0].toString(), coord[1].toString()]);
30384
+
30385
+ // Generate unique IDs so that the programmatic labels can be associated
30386
+ // with their respective text fields.
30387
+ const ids = wonderBlocksCore.useUniqueIdWithMock();
30388
+ const xCoordId = ids.get("x-coord");
30389
+ const yCoordId = ids.get("y-coord");
30390
+ function handleCoordChange(newValue, coordIndex) {
30391
+ // Update the local state (update the input field value).
30392
+ const newCoordState = [...coordState];
30393
+ newCoordState[coordIndex] = newValue;
30394
+ setCoordState(newCoordState);
30395
+
30396
+ // If the new value is not a number, don't update the props.
30397
+ // If it's empty, keep the props the same value instead of setting to 0.
30398
+ if (isNaN(+newValue) || newValue === "") {
30399
+ return;
30400
+ }
30401
+
30402
+ // Update the props (update the graph).
30403
+ const newCoords = [...coord];
30404
+ newCoords[coordIndex] = +newValue;
30405
+ onChangeProps({
30406
+ coord: newCoords
30407
+ });
30408
+ }
30409
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30410
+ style: [styles$k.row, styles$k.spaceUnder]
30411
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30412
+ htmlFor: xCoordId,
30413
+ style: styles$k.label,
30414
+ tag: "label"
30415
+ }, "x coord"), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30416
+ id: xCoordId,
30417
+ type: "number",
30418
+ value: coordState[0],
30419
+ onChange: newValue => handleCoordChange(newValue, 0),
30420
+ style: styles$k.textField
30421
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
30422
+ size: wonderBlocksTokens.spacing.medium_16
30423
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30424
+ htmlFor: yCoordId,
30425
+ style: styles$k.label,
30426
+ tag: "label"
30427
+ }, "y coord"), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30428
+ id: yCoordId,
30429
+ type: "number",
30430
+ value: coordState[1],
30431
+ onChange: newValue => handleCoordChange(newValue, 1),
30432
+ style: styles$k.textField
30433
+ }));
30434
+ };
30435
+ const styles$k = aphrodite.StyleSheet.create({
30436
+ row: {
30437
+ flexDirection: "row",
30438
+ alignItems: "center"
30439
+ },
30440
+ spaceUnder: {
30441
+ marginBottom: wonderBlocksTokens.spacing.xSmall_8
30442
+ },
30443
+ label: {
30444
+ marginInlineEnd: wonderBlocksTokens.spacing.xxSmall_6
30445
+ },
30446
+ textField: {
30447
+ width: wonderBlocksTokens.spacing.xxxLarge_64
30448
+ }
30449
+ });
30450
+
30451
+ const LabeledSwitch = props => {
30452
+ const {
30453
+ checked,
30454
+ label,
30455
+ style,
30456
+ onChange
30457
+ } = props;
30458
+ const ids = wonderBlocksCore.useUniqueIdWithMock();
30459
+ const switchId = ids.get("switch");
30460
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30461
+ style: [styles$j.row, style]
30462
+ }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
30463
+ id: switchId,
30464
+ checked: checked,
30465
+ onChange: onChange
30466
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
30467
+ size: wonderBlocksTokens.spacing.xSmall_8
30468
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30469
+ tag: "label",
30470
+ htmlFor: switchId
30471
+ }, label));
30472
+ };
30473
+ const styles$j = aphrodite.StyleSheet.create({
30474
+ row: {
30475
+ flexDirection: "row",
30476
+ alignItems: "center"
30477
+ }
30478
+ });
30479
+
30372
30480
  const LockedFigureSettingsAccordion = props => {
30373
30481
  const {
30374
30482
  children,
30375
30483
  header,
30484
+ expanded,
30376
30485
  containerStyle,
30377
- panelStyle
30486
+ panelStyle,
30487
+ onToggle
30378
30488
  } = props;
30379
30489
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View
30380
30490
  // More specificity so that we can override the default
@@ -30383,14 +30493,16 @@ const LockedFigureSettingsAccordion = props => {
30383
30493
  , {
30384
30494
  className: "locked-figure-accordion"
30385
30495
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksAccordion.AccordionSection, {
30386
- style: [styles$g.container, containerStyle],
30387
- headerStyle: styles$g.accordionHeader,
30496
+ expanded: expanded,
30497
+ onToggle: onToggle,
30498
+ style: [styles$i.container, containerStyle],
30499
+ headerStyle: styles$i.accordionHeader,
30388
30500
  header: header
30389
30501
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30390
- style: [styles$g.accordionPanel, panelStyle]
30502
+ style: [styles$i.accordionPanel, panelStyle]
30391
30503
  }, children)));
30392
30504
  };
30393
- const styles$g = aphrodite.StyleSheet.create({
30505
+ const styles$i = aphrodite.StyleSheet.create({
30394
30506
  container: {
30395
30507
  backgroundColor: wonderBlocksTokens.color.fadedBlue8,
30396
30508
  marginTop: wonderBlocksTokens.spacing.xSmall_8
@@ -30412,271 +30524,141 @@ const styles$g = aphrodite.StyleSheet.create({
30412
30524
  });
30413
30525
 
30414
30526
  /**
30415
- * The part of a locked figure settings panel that contains actions
30416
- * for this panel and its associated locked figure, including
30417
- * the delete button.
30527
+ * DefiningPointSettings is a component that allows the user to edit the
30528
+ * settings of a point that defines a locked figure (ex. line) on the graph.
30529
+ *
30530
+ * Used in the interactive graph editor's locked figures section.
30418
30531
  */
30419
- const LockedFigureSettingsActions = props => {
30532
+ const DefiningPointSettings = props => {
30420
30533
  const {
30421
- onRemove,
30422
- figureAriaLabel
30534
+ coord,
30535
+ color: pointColor,
30536
+ filled = true,
30537
+ label,
30538
+ showPoint = "false",
30539
+ onChangeProps,
30540
+ onTogglePoint
30423
30541
  } = props;
30424
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30425
- style: styles$f.container
30426
- }, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
30427
- startIcon: trashIcon__default["default"],
30428
- "aria-label": `Delete ${figureAriaLabel}`,
30429
- onClick: onRemove,
30430
- kind: "tertiary",
30431
- style: styles$f.deleteButton
30432
- }, "Delete"));
30542
+ function handleColorChange(newValue) {
30543
+ onChangeProps({
30544
+ color: newValue
30545
+ });
30546
+ }
30547
+ return /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsAccordion, {
30548
+ expanded: props.expanded,
30549
+ onToggle: props.onToggle,
30550
+ containerStyle: styles$h.container,
30551
+ panelStyle: styles$h.accordionPanel,
30552
+ header:
30553
+ /*#__PURE__*/
30554
+ // Summary: Point, coords, color (filled/open)
30555
+ React__namespace.createElement(wonderBlocksCore.View, {
30556
+ style: styles$h.row
30557
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `${label || "Point"} (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React__namespace.createElement(Strut, {
30558
+ size: wonderBlocksTokens.spacing.xSmall_8
30559
+ }), showPoint && /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
30560
+ color: pointColor,
30561
+ filled: filled
30562
+ }))
30563
+ }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
30564
+ coord: coord,
30565
+ onChangeProps: onChangeProps
30566
+ }), onTogglePoint && /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
30567
+ label: "show point on graph",
30568
+ checked: !!showPoint,
30569
+ style: showPoint && styles$h.spaceUnder,
30570
+ onChange: onTogglePoint
30571
+ }), showPoint && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30572
+ selectedValue: pointColor,
30573
+ onChange: handleColorChange,
30574
+ style: styles$h.spaceUnder
30575
+ }), /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
30576
+ label: "open point",
30577
+ checked: !filled,
30578
+ onChange: newValue => {
30579
+ onChangeProps({
30580
+ filled: !newValue
30581
+ });
30582
+ }
30583
+ })));
30433
30584
  };
30434
- const styles$f = aphrodite.StyleSheet.create({
30585
+ const styles$h = aphrodite.StyleSheet.create({
30435
30586
  container: {
30436
- width: "100%",
30587
+ marginTop: wonderBlocksTokens.spacing.xSmall_8,
30588
+ marginBottom: 0,
30589
+ marginLeft: -wonderBlocksTokens.spacing.xxxSmall_4,
30590
+ marginRight: -wonderBlocksTokens.spacing.xxxSmall_4,
30591
+ backgroundColor: wonderBlocksTokens.color.white
30592
+ },
30593
+ accordionPanel: {
30594
+ // Need more space since we don't have the actions' margins.
30595
+ paddingBottom: wonderBlocksTokens.spacing.medium_16
30596
+ },
30597
+ row: {
30437
30598
  flexDirection: "row",
30438
- alignItems: "center",
30439
- marginTop: wonderBlocksTokens.spacing.xxxSmall_4
30599
+ alignItems: "center"
30440
30600
  },
30441
- deleteButton: {
30442
- // Line up the delete icon with the rest of the content.
30443
- marginInlineStart: -wonderBlocksTokens.spacing.xxxSmall_4
30444
- }
30601
+ spaceUnder: {
30602
+ marginBottom: wonderBlocksTokens.spacing.xSmall_8
30603
+ }
30445
30604
  });
30446
30605
 
30447
- const LabeledSwitch = props => {
30606
+ const LineSwatch = props => {
30448
30607
  const {
30449
- checked,
30450
- label,
30451
- style,
30452
- onChange
30608
+ color,
30609
+ lineStyle
30453
30610
  } = props;
30454
- const ids = wonderBlocksCore.useUniqueIdWithMock();
30455
- const switchId = ids.get("switch");
30456
30611
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30457
- style: [styles$e.row, style]
30458
- }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
30459
- id: switchId,
30460
- checked: checked,
30461
- onChange: onChange
30462
- }), /*#__PURE__*/React__namespace.createElement(Strut, {
30463
- size: wonderBlocksTokens.spacing.xSmall_8
30464
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30465
- tag: "label",
30466
- htmlFor: switchId
30467
- }, label));
30612
+ style: styles$g.container
30613
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30614
+ "aria-label": `${color}, ${lineStyle}`,
30615
+ style: [styles$g.lineSwatch, {
30616
+ border: `5px ${lineStyle} ${perseus.lockedFigureColors[color]}`
30617
+ }]
30618
+ }));
30468
30619
  };
30469
- const styles$e = aphrodite.StyleSheet.create({
30470
- row: {
30471
- flexDirection: "row",
30472
- alignItems: "center"
30620
+ const styles$g = aphrodite.StyleSheet.create({
30621
+ container: {
30622
+ backgroundColor: wonderBlocksTokens.color.white,
30623
+ justifyContent: "center",
30624
+ padding: wonderBlocksTokens.spacing.xSmall_8,
30625
+ borderRadius: wonderBlocksTokens.spacing.xxxSmall_4
30626
+ },
30627
+ lineSwatch: {
30628
+ width: 40
30473
30629
  }
30474
30630
  });
30475
30631
 
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
30632
  /**
30550
- * LockedPointSettings is a component that allows the user to edit the
30551
- * settings of specifically a locked point on the graph.
30552
- *
30553
- * Used in the interactive graph editor's locked figures section.
30633
+ * The part of a locked figure settings panel that contains actions
30634
+ * for this panel and its associated locked figure, including
30635
+ * the delete button.
30554
30636
  */
30555
- const LockedPointSettings = props => {
30637
+ const LockedFigureSettingsActions = props => {
30556
30638
  const {
30557
- coord,
30558
- color: pointColor,
30559
- filled = true,
30560
- label,
30561
- toggled = "true",
30562
- style,
30563
- onChangeProps,
30564
- onToggle,
30565
- onRemove
30639
+ onRemove,
30640
+ figureAriaLabel
30566
30641
  } = props;
30567
-
30568
- // Keep track of the coordinates via state as the user is editing them,
30569
- // before they are updated in the props on blur.
30570
- const [coordState, setCoordState] = React__namespace.useState([
30571
- // Using strings to make it easier to work with the text fields.
30572
- coord[0].toString(), coord[1].toString()]);
30573
-
30574
- // Generate unique IDs so that the programmatic labels can be associated
30575
- // with their respective text fields.
30576
- const ids = wonderBlocksCore.useUniqueIdWithMock();
30577
- const xCoordId = ids.get("x-coord");
30578
- const yCoordId = ids.get("y-coord");
30579
- const colorSelectId = ids.get("point-color-select");
30580
- function handleBlur() {
30581
- const validCoord = [getValidNumberFromString(coordState[0]), getValidNumberFromString(coordState[1])];
30582
-
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.
30586
- onChangeProps({
30587
- coord: validCoord
30588
- });
30589
- }
30590
- function handleCoordChange(newValue, coordIndex) {
30591
- const newCoord = [...coordState];
30592
- newCoord[coordIndex] = newValue;
30593
- setCoordState(newCoord);
30594
- }
30595
- function handleColorChange(newValue) {
30596
- onChangeProps({
30597
- color: newValue
30598
- });
30599
- }
30600
- return /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsAccordion, {
30601
- containerStyle: style,
30602
- panelStyle: !onRemove && styles$d.accordionPanelWithoutActions,
30603
- header:
30604
- /*#__PURE__*/
30605
- // Summary: Point, coords, color (filled/open)
30606
- React__namespace.createElement(wonderBlocksCore.View, {
30607
- style: styles$d.row
30608
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `${label || "Point"} (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React__namespace.createElement(Strut, {
30609
- size: wonderBlocksTokens.spacing.xSmall_8
30610
- }), toggled && /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
30611
- color: pointColor,
30612
- filled: filled
30613
- }))
30614
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30615
- style: [styles$d.row, styles$d.spaceUnder]
30616
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30617
- htmlFor: xCoordId,
30618
- style: styles$d.label,
30619
- tag: "label"
30620
- }, "x coord"), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30621
- id: xCoordId,
30622
- type: "number",
30623
- value: coordState[0],
30624
- onChange: newValue => handleCoordChange(newValue, 0),
30625
- onBlur: handleBlur,
30626
- style: styles$d.textField
30627
- }), /*#__PURE__*/React__namespace.createElement(Strut, {
30628
- size: wonderBlocksTokens.spacing.medium_16
30629
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30630
- htmlFor: yCoordId,
30631
- style: styles$d.label,
30632
- tag: "label"
30633
- }, "y coord"), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30634
- id: yCoordId,
30635
- type: "number",
30636
- value: coordState[1],
30637
- onChange: newValue => handleCoordChange(newValue, 1),
30638
- onBlur: handleBlur,
30639
- style: styles$d.textField
30640
- })), onToggle && /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
30641
- label: "show point on graph",
30642
- checked: !!toggled,
30643
- style: toggled && styles$d.spaceUnder,
30644
- onChange: onToggle
30645
- }), toggled && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30646
- id: colorSelectId,
30647
- selectedValue: pointColor,
30648
- onChange: handleColorChange,
30649
- style: styles$d.spaceUnder
30650
- }), /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
30651
- label: "open point",
30652
- checked: !filled,
30653
- onChange: newValue => {
30654
- onChangeProps({
30655
- filled: !newValue
30656
- });
30657
- }
30658
- })), onRemove && /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
30659
- onRemove: onRemove,
30660
- figureAriaLabel: `locked point at ${coordState[0]}, ${coordState[1]}`
30661
- }));
30642
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30643
+ style: styles$f.container
30644
+ }, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
30645
+ startIcon: trashIcon__default["default"],
30646
+ "aria-label": `Delete ${figureAriaLabel}`,
30647
+ onClick: onRemove,
30648
+ kind: "tertiary",
30649
+ style: styles$f.deleteButton
30650
+ }, "Delete"));
30662
30651
  };
30663
- const styles$d = aphrodite.StyleSheet.create({
30664
- accordionPanelWithoutActions: {
30665
- // Need more space since we don't have the actions' margins.
30666
- paddingBottom: wonderBlocksTokens.spacing.medium_16
30667
- },
30668
- row: {
30652
+ const styles$f = aphrodite.StyleSheet.create({
30653
+ container: {
30654
+ width: "100%",
30669
30655
  flexDirection: "row",
30670
- alignItems: "center"
30671
- },
30672
- spaceUnder: {
30673
- marginBottom: wonderBlocksTokens.spacing.xSmall_8
30674
- },
30675
- label: {
30676
- marginInlineEnd: wonderBlocksTokens.spacing.xxSmall_6
30656
+ alignItems: "center",
30657
+ marginTop: wonderBlocksTokens.spacing.xxxSmall_4
30677
30658
  },
30678
- textField: {
30679
- width: wonderBlocksTokens.spacing.xxxLarge_64
30659
+ deleteButton: {
30660
+ // Line up the delete icon with the rest of the content.
30661
+ marginInlineStart: -wonderBlocksTokens.spacing.xxxSmall_4
30680
30662
  }
30681
30663
  });
30682
30664
 
@@ -30686,21 +30668,21 @@ const LockedLineSettings = props => {
30686
30668
  points,
30687
30669
  color: lineColor,
30688
30670
  lineStyle = "solid",
30689
- showStartPoint,
30690
- showEndPoint,
30671
+ showPoint1,
30672
+ showPoint2,
30691
30673
  onChangeProps,
30692
30674
  onRemove
30693
30675
  } = props;
30694
- const [startPoint, endPoint] = points;
30676
+ const [point1, point2] = points;
30695
30677
 
30696
30678
  // Generate unique IDs so that the programmatic labels can be associated
30697
30679
  // with their respective text fields.
30698
30680
  const ids = wonderBlocksCore.useUniqueIdWithMock();
30699
30681
  const kindSelectId = ids.get("line-kind-select");
30700
- const colorSelectId = ids.get("line-color-select");
30701
30682
  const styleSelectId = ids.get("line-style-select");
30702
- const lineLabel = `Line (${startPoint.coord[0]}, ${startPoint.coord[1]}),
30703
- (${endPoint.coord[0]}, ${endPoint.coord[1]})`;
30683
+ const capitalizeKind = kind.charAt(0).toUpperCase() + kind.slice(1);
30684
+ const lineLabel = `${capitalizeKind} (${point1.coord[0]},
30685
+ ${point1.coord[1]}), (${point2.coord[0]}, ${point2.coord[1]})`;
30704
30686
  function handleChangePoint(newPointProps, index) {
30705
30687
  const newPoints = [...points];
30706
30688
  newPoints[index] = {
@@ -30716,27 +30698,30 @@ const LockedLineSettings = props => {
30716
30698
  color: newColor,
30717
30699
  // Keep the line's points' colors in sync with the line color.
30718
30700
  points: [{
30719
- ...startPoint,
30701
+ ...point1,
30720
30702
  color: newColor
30721
30703
  }, {
30722
- ...endPoint,
30704
+ ...point2,
30723
30705
  color: newColor
30724
30706
  }]
30725
30707
  });
30726
30708
  }
30727
30709
  return /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsAccordion, {
30710
+ expanded: props.expanded,
30711
+ onToggle: props.onToggle,
30728
30712
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30729
- style: styles$c.row
30713
+ style: styles$e.row
30730
30714
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
30731
30715
  size: wonderBlocksTokens.spacing.xSmall_8
30732
- }), /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
30733
- color: lineColor
30716
+ }), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
30717
+ color: lineColor,
30718
+ lineStyle: lineStyle
30734
30719
  }))
30735
30720
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30736
- style: [styles$c.row, styles$c.spaceUnder]
30721
+ style: [styles$e.row, styles$e.spaceUnder]
30737
30722
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30738
30723
  htmlFor: kindSelectId,
30739
- style: styles$c.label,
30724
+ style: styles$e.label,
30740
30725
  tag: "label"
30741
30726
  }, "kind"), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30742
30727
  id: kindSelectId,
@@ -30757,18 +30742,17 @@ const LockedLineSettings = props => {
30757
30742
  value: "ray",
30758
30743
  label: "ray"
30759
30744
  }))), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30760
- style: [styles$c.row, styles$c.spaceUnder]
30745
+ style: [styles$e.row, styles$e.spaceUnder]
30761
30746
  }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30762
- id: colorSelectId,
30763
30747
  selectedValue: lineColor,
30764
30748
  onChange: handleColorChange
30765
30749
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
30766
30750
  size: wonderBlocksTokens.spacing.small_12
30767
30751
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30768
- style: styles$c.row
30752
+ style: styles$e.row
30769
30753
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30770
30754
  htmlFor: styleSelectId,
30771
- style: styles$c.label,
30755
+ style: styles$e.label,
30772
30756
  tag: "label"
30773
30757
  }, "style"), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30774
30758
  id: styleSelectId,
@@ -30779,46 +30763,37 @@ const LockedLineSettings = props => {
30779
30763
  // Placeholder is required, but never gets used.
30780
30764
  ,
30781
30765
  placeholder: "",
30782
- style: styles$c.selectMarginOffset
30766
+ style: styles$e.selectMarginOffset
30783
30767
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30784
30768
  value: "solid",
30785
30769
  label: "solid"
30786
30770
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30787
30771
  value: "dashed",
30788
30772
  label: "dashed"
30789
- })))), /*#__PURE__*/React__namespace.createElement(LockedPointSettings, _extends({
30790
- label: "Start point",
30791
- toggled: showStartPoint
30792
- }, startPoint, {
30793
- onToggle: newValue => onChangeProps({
30794
- showStartPoint: newValue
30773
+ })))), /*#__PURE__*/React__namespace.createElement(DefiningPointSettings, _extends({
30774
+ label: "Point 1",
30775
+ showPoint: showPoint1
30776
+ }, point1, {
30777
+ onTogglePoint: newValue => onChangeProps({
30778
+ showPoint1: newValue
30795
30779
  }),
30796
- onChangeProps: newProps => handleChangePoint(newProps, 0),
30797
- style: styles$c.lockedPointSettingsContainer
30798
- })), /*#__PURE__*/React__namespace.createElement(LockedPointSettings, _extends({
30799
- label: "End point",
30800
- toggled: showEndPoint
30801
- }, endPoint, {
30802
- onToggle: newValue => onChangeProps({
30803
- showEndPoint: newValue
30780
+ onChangeProps: newProps => handleChangePoint(newProps, 0)
30781
+ })), /*#__PURE__*/React__namespace.createElement(DefiningPointSettings, _extends({
30782
+ label: "Point 2",
30783
+ showPoint: showPoint2
30784
+ }, point2, {
30785
+ onTogglePoint: newValue => onChangeProps({
30786
+ showPoint2: newValue
30804
30787
  }),
30805
- onChangeProps: newProps => handleChangePoint(newProps, 1),
30806
- style: styles$c.lockedPointSettingsContainer
30788
+ onChangeProps: newProps => handleChangePoint(newProps, 1)
30807
30789
  })), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
30808
30790
  onRemove: onRemove,
30809
30791
  figureAriaLabel: `locked line defined by
30810
- ${startPoint.coord[0]}, ${startPoint.coord[1]} and
30811
- ${endPoint.coord[0]}, ${endPoint.coord[1]}.`
30792
+ ${point1.coord[0]}, ${point1.coord[1]} and
30793
+ ${point2.coord[0]}, ${point2.coord[1]}.`
30812
30794
  }));
30813
30795
  };
30814
- const styles$c = aphrodite.StyleSheet.create({
30815
- lockedPointSettingsContainer: {
30816
- marginTop: wonderBlocksTokens.spacing.xSmall_8,
30817
- marginBottom: 0,
30818
- marginLeft: -wonderBlocksTokens.spacing.xxxSmall_4,
30819
- marginRight: -wonderBlocksTokens.spacing.xxxSmall_4,
30820
- backgroundColor: wonderBlocksTokens.color.white
30821
- },
30796
+ const styles$e = aphrodite.StyleSheet.create({
30822
30797
  row: {
30823
30798
  flexDirection: "row",
30824
30799
  alignItems: "center"
@@ -30835,6 +30810,69 @@ const styles$c = aphrodite.StyleSheet.create({
30835
30810
  }
30836
30811
  });
30837
30812
 
30813
+ /**
30814
+ * LockedPointSettings is a component that allows the user to edit the
30815
+ * settings of specifically a locked point on the graph.
30816
+ *
30817
+ * Used in the interactive graph editor's locked figures section.
30818
+ */
30819
+ const LockedPointSettings = props => {
30820
+ const {
30821
+ coord,
30822
+ color: pointColor,
30823
+ filled = true,
30824
+ onChangeProps,
30825
+ onRemove
30826
+ } = props;
30827
+ function handleColorChange(newValue) {
30828
+ onChangeProps({
30829
+ color: newValue
30830
+ });
30831
+ }
30832
+ return /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsAccordion, {
30833
+ expanded: props.expanded,
30834
+ onToggle: props.onToggle,
30835
+ header:
30836
+ /*#__PURE__*/
30837
+ // Summary: Point, coords, color (filled/open)
30838
+ React__namespace.createElement(wonderBlocksCore.View, {
30839
+ style: styles$d.row
30840
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Point (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React__namespace.createElement(Strut, {
30841
+ size: wonderBlocksTokens.spacing.xSmall_8
30842
+ }), /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
30843
+ color: pointColor,
30844
+ filled: filled
30845
+ }))
30846
+ }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
30847
+ coord: coord,
30848
+ onChangeProps: onChangeProps
30849
+ }), /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30850
+ selectedValue: pointColor,
30851
+ onChange: handleColorChange,
30852
+ style: styles$d.spaceUnder
30853
+ }), /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
30854
+ label: "open point",
30855
+ checked: !filled,
30856
+ onChange: newValue => {
30857
+ onChangeProps({
30858
+ filled: !newValue
30859
+ });
30860
+ }
30861
+ }), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
30862
+ onRemove: onRemove,
30863
+ figureAriaLabel: `locked point at ${coord[0]}, ${coord[1]}`
30864
+ }));
30865
+ };
30866
+ const styles$d = aphrodite.StyleSheet.create({
30867
+ row: {
30868
+ flexDirection: "row",
30869
+ alignItems: "center"
30870
+ },
30871
+ spaceUnder: {
30872
+ marginBottom: wonderBlocksTokens.spacing.xSmall_8
30873
+ }
30874
+ });
30875
+
30838
30876
  /**
30839
30877
  * LockedFigureSettings takes in a figure and renders the
30840
30878
  * respective settings for that figure type.
@@ -30854,7 +30892,78 @@ const LockedFigureSettings = props => {
30854
30892
  return null;
30855
30893
  };
30856
30894
 
30895
+ function focusWithChromeStickyFocusBugWorkaround(element) {
30896
+ // NOTE(marksandstrom) Chrome sticky focus bug.
30897
+ //
30898
+ // There is a bug in Chrome related to sticky positioning and
30899
+ // focus: When a child of an element with sticky positioning is
30900
+ // focused with the focus() method, the scrollable area
30901
+ // containing that element will scroll to the top (even though
30902
+ // the element is already visble on the page). For a dropdown
30903
+ // this means that the area will be scrolled to the top when
30904
+ // the user interacts with the dropdown (since we actively
30905
+ // manage dropdown header and option focus for keyboard users).
30906
+ //
30907
+ // To work around this bug the `preventScroll` focus option is
30908
+ // used.
30909
+ //
30910
+ // Using `focusOptions` is an experimental browser feature
30911
+ // "that should not be used in production code". However, since
30912
+ // Chrome is the only browser we support that exhibits this
30913
+ // buggy behavior and using `focusOptions` works around the
30914
+ // bug, it is perfectly reasonable to use the feature in this
30915
+ // case. We are not relying on the effect of the
30916
+ // `preventScroll` option otherwise.
30917
+ //
30918
+ // focusOptions documentation:
30919
+ //
30920
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
30921
+ //
30922
+ // Note that there could be cases where we want default focus() behavior.
30923
+ // One that comes to mind is a dropdown with a long list of options that
30924
+ // might be rendered off screen when opened. With this workaround the
30925
+ // selected option would not be scrolled into view if the option is near
30926
+ // the end of the list. We're not aware of any uses of the dropdown where
30927
+ // this is an issue, however, so there isn't currently a way to out of the
30928
+ // `preventScroll` behavior.
30929
+
30930
+ // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element'.
30931
+ element.focus({
30932
+ preventScroll: true
30933
+ });
30934
+ }
30935
+ const DEFAULT_COLOR = "grayH";
30936
+ function getDefaultFigureForType(type) {
30937
+ switch (type) {
30938
+ case "point":
30939
+ return {
30940
+ type: "point",
30941
+ coord: [0, 0],
30942
+ color: DEFAULT_COLOR,
30943
+ filled: true
30944
+ };
30945
+ case "line":
30946
+ return {
30947
+ type: "line",
30948
+ kind: "line",
30949
+ points: [getDefaultFigureForType("point"), {
30950
+ ...getDefaultFigureForType("point"),
30951
+ coord: [2, 2]
30952
+ }],
30953
+ color: DEFAULT_COLOR,
30954
+ lineStyle: "solid",
30955
+ showPoint1: false,
30956
+ showPoint2: false
30957
+ };
30958
+ default:
30959
+ throw new wonderStuffCore.UnreachableCaseError(type);
30960
+ }
30961
+ }
30962
+
30857
30963
  const LockedFiguresSection = props => {
30964
+ // Keep track of all figures' accordions' expanded states for the
30965
+ // expand/collapse all button. Set the whole array to false initially.
30966
+ const [expandedStates, setExpandedStates] = React__namespace.useState(Array(props.figures?.length).fill(false));
30858
30967
  const uniqueId = wonderBlocksCore.useUniqueIdWithMock().get("locked-figures-section");
30859
30968
  const {
30860
30969
  figures,
@@ -30866,6 +30975,7 @@ const LockedFiguresSection = props => {
30866
30975
  lockedFigures: [...lockedFigures, getDefaultFigureForType(newFigure)]
30867
30976
  };
30868
30977
  onChange(newProps);
30978
+ setExpandedStates([...expandedStates, true]);
30869
30979
  }
30870
30980
  function removeLockedFigure(index) {
30871
30981
  // eslint-disable-next-line no-alert
@@ -30874,6 +30984,11 @@ const LockedFiguresSection = props => {
30874
30984
  onChange({
30875
30985
  lockedFigures: [...lockedFigures.slice(0, index), ...lockedFigures.slice(index + 1)]
30876
30986
  });
30987
+
30988
+ // Update expanded states
30989
+ const newExpandedStates = [...expandedStates];
30990
+ newExpandedStates.splice(index, 1);
30991
+ setExpandedStates(newExpandedStates);
30877
30992
  }
30878
30993
  }
30879
30994
  function changeProps(index,
@@ -30889,16 +31004,46 @@ const LockedFiguresSection = props => {
30889
31004
  };
30890
31005
  onChange(newFigures);
30891
31006
  }
31007
+ function toggleExpanded(newValue) {
31008
+ setExpandedStates(Array(figures?.length).fill(newValue));
31009
+ }
31010
+ const allCollapsed = expandedStates.every(value => !value);
31011
+ const buttonLabel = allCollapsed ? "Expand all" : "Collapse all";
31012
+ const showExpandButton = !!figures?.length;
30892
31013
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, figures?.map((figure, index) => /*#__PURE__*/React__namespace.createElement(LockedFigureSettings, _extends({
31014
+ expanded: expandedStates[index],
31015
+ onToggle: newValue => {
31016
+ const newExpanded = [...expandedStates];
31017
+ newExpanded[index] = newValue;
31018
+ setExpandedStates(newExpanded);
31019
+ },
30893
31020
  key: `${uniqueId}-locked-${figure}-${index}`
30894
31021
  }, figure, {
30895
31022
  onChangeProps: newProps => changeProps(index, newProps),
30896
31023
  onRemove: () => removeLockedFigure(index)
30897
- }))), /*#__PURE__*/React__namespace.createElement(LockedFigureSelect, {
31024
+ }))), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31025
+ style: styles$c.buttonContainer
31026
+ }, /*#__PURE__*/React__namespace.createElement(LockedFigureSelect, {
30898
31027
  id: `${uniqueId}-select`,
30899
31028
  onChange: addLockedFigure
30900
- }));
31029
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
31030
+ size: wonderBlocksTokens.spacing.small_12
31031
+ }), showExpandButton && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
31032
+ kind: "secondary",
31033
+ onClick: () => toggleExpanded(allCollapsed),
31034
+ style: styles$c.button
31035
+ }, buttonLabel)));
30901
31036
  };
31037
+ const styles$c = aphrodite.StyleSheet.create({
31038
+ buttonContainer: {
31039
+ flexDirection: "row",
31040
+ alignItems: "center"
31041
+ },
31042
+ button: {
31043
+ marginTop: wonderBlocksTokens.spacing.xSmall_8,
31044
+ flexGrow: 1
31045
+ }
31046
+ });
30902
31047
 
30903
31048
  const SegmentCountSelector = _ref => {
30904
31049
  let {