@khanacademy/perseus-editor 14.4.0 → 14.6.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
@@ -27,7 +27,9 @@ var mathInput = require('@khanacademy/math-input');
27
27
  var kmath = require('@khanacademy/kmath');
28
28
  var wonderBlocksDropdown = require('@khanacademy/wonder-blocks-dropdown');
29
29
  var Banner = require('@khanacademy/wonder-blocks-banner');
30
+ var plusCircle = require('@phosphor-icons/core/regular/plus-circle.svg');
30
31
  var wonderBlocksAccordion = require('@khanacademy/wonder-blocks-accordion');
32
+ var pencilCircle = require('@phosphor-icons/core/regular/pencil-circle.svg');
31
33
  var IconButton = require('@khanacademy/wonder-blocks-icon-button');
32
34
  var caretDoubleDownIcon = require('@phosphor-icons/core/bold/caret-double-down-bold.svg');
33
35
  var caretDoubleUpIcon = require('@phosphor-icons/core/bold/caret-double-up-bold.svg');
@@ -36,7 +38,6 @@ var caretUpIcon = require('@phosphor-icons/core/bold/caret-up-bold.svg');
36
38
  var trashIcon = require('@phosphor-icons/core/bold/trash-bold.svg');
37
39
  var copyIcon = require('@phosphor-icons/core/assets/regular/copy.svg');
38
40
  var autoPasteIcon = require('@phosphor-icons/core/assets/regular/note-pencil.svg');
39
- var plusCircle = require('@phosphor-icons/core/regular/plus-circle.svg');
40
41
  var mafs = require('mafs');
41
42
  var arrowFatDown = require('@phosphor-icons/core/regular/arrow-fat-down.svg');
42
43
  var arrowFatLeft = require('@phosphor-icons/core/regular/arrow-fat-left.svg');
@@ -78,6 +79,8 @@ var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
78
79
  var KAS__namespace = /*#__PURE__*/_interopNamespace(KAS);
79
80
  var Button__default = /*#__PURE__*/_interopDefaultLegacy(Button);
80
81
  var Banner__default = /*#__PURE__*/_interopDefaultLegacy(Banner);
82
+ var plusCircle__default = /*#__PURE__*/_interopDefaultLegacy(plusCircle);
83
+ var pencilCircle__default = /*#__PURE__*/_interopDefaultLegacy(pencilCircle);
81
84
  var IconButton__default = /*#__PURE__*/_interopDefaultLegacy(IconButton);
82
85
  var caretDoubleDownIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretDoubleDownIcon);
83
86
  var caretDoubleUpIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretDoubleUpIcon);
@@ -86,7 +89,6 @@ var caretUpIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretUpIcon);
86
89
  var trashIcon__default = /*#__PURE__*/_interopDefaultLegacy(trashIcon);
87
90
  var copyIcon__default = /*#__PURE__*/_interopDefaultLegacy(copyIcon);
88
91
  var autoPasteIcon__default = /*#__PURE__*/_interopDefaultLegacy(autoPasteIcon);
89
- var plusCircle__default = /*#__PURE__*/_interopDefaultLegacy(plusCircle);
90
92
  var arrowFatDown__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatDown);
91
93
  var arrowFatLeft__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatLeft);
92
94
  var arrowFatRight__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatRight);
@@ -96,7 +98,7 @@ var arrowCounterClockwise__default = /*#__PURE__*/_interopDefaultLegacy(arrowCou
96
98
 
97
99
  // This file is processed by a Rollup plugin (replace) to inject the production
98
100
  const libName = "@khanacademy/perseus-editor";
99
- const libVersion = "14.4.0";
101
+ const libVersion = "14.6.1";
100
102
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
101
103
 
102
104
  function _extends() {
@@ -291,13 +293,13 @@ class SectionControlButton extends React__namespace.Component {
291
293
  role: "button",
292
294
  hideDefaultFocusRing: true,
293
295
  "aria-label": title,
294
- style: styles$T.button
296
+ style: styles$U.button
295
297
  }, _ref => {
296
298
  return /*#__PURE__*/React__namespace.createElement(InlineIcon$b, icon);
297
299
  });
298
300
  }
299
301
  }
300
- const styles$T = aphrodite.StyleSheet.create({
302
+ const styles$U = aphrodite.StyleSheet.create({
301
303
  button: {
302
304
  backgroundColor: wonderBlocksTokens.color.gold,
303
305
  margin: 2,
@@ -20678,11 +20680,11 @@ class Spring extends React__namespace.Component {
20678
20680
  } = this.props;
20679
20681
  return React__namespace.createElement(wonderBlocksCore.View, {
20680
20682
  "aria-hidden": "true",
20681
- style: [styles$S.grow, style]
20683
+ style: [styles$T.grow, style]
20682
20684
  });
20683
20685
  }
20684
20686
  }
20685
- const styles$S = aphrodite.StyleSheet.create({
20687
+ const styles$T = aphrodite.StyleSheet.create({
20686
20688
  grow: {
20687
20689
  flexGrow: 1
20688
20690
  }
@@ -20925,13 +20927,13 @@ class WidgetSelect extends React__namespace.Component {
20925
20927
  * that collapse a region.
20926
20928
  */
20927
20929
  function ToggleableCaret(props) {
20928
- const iconStyle = props.isExpanded ? styles$R.expanded : styles$R.collapsed;
20930
+ const iconStyle = props.isExpanded ? styles$S.expanded : styles$S.collapsed;
20929
20931
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksIcon.PhosphorIcon, {
20930
20932
  icon: caretRight__default["default"],
20931
20933
  style: iconStyle
20932
20934
  });
20933
20935
  }
20934
- const styles$R = aphrodite.StyleSheet.create({
20936
+ const styles$S = aphrodite.StyleSheet.create({
20935
20937
  collapsed: {
20936
20938
  transition: ".15s"
20937
20939
  },
@@ -20961,16 +20963,16 @@ class TexErrorView extends React__namespace.Component {
20961
20963
  showErrors
20962
20964
  } = this.state;
20963
20965
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20964
- style: styles$Q.errorContainer
20966
+ style: styles$R.errorContainer
20965
20967
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20966
- style: styles$Q.title,
20968
+ style: styles$R.title,
20967
20969
  onClick: this.handleToggleTexErrors
20968
20970
  }, /*#__PURE__*/React__namespace.createElement(ToggleableCaret, {
20969
20971
  isExpanded: showErrors
20970
20972
  }), "\xA0 TeX Errors (", errorList.length, ")"), showErrors && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20971
- style: styles$Q.errorExplanation
20973
+ style: styles$R.errorExplanation
20972
20974
  }, "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, {
20973
- style: styles$Q.error,
20975
+ style: styles$R.error,
20974
20976
  key: index
20975
20977
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20976
20978
  style: {
@@ -20979,7 +20981,7 @@ class TexErrorView extends React__namespace.Component {
20979
20981
  }, e.math), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, e.message))));
20980
20982
  }
20981
20983
  }
20982
- const styles$Q = aphrodite.StyleSheet.create({
20984
+ const styles$R = aphrodite.StyleSheet.create({
20983
20985
  title: {
20984
20986
  backgroundColor: "#eee",
20985
20987
  fontSize: "1.25em",
@@ -21943,8 +21945,7 @@ class IframeContentRenderer extends React__namespace.Component {
21943
21945
  this._lastData = data;
21944
21946
 
21945
21947
  // We can't use JSON.stringify/parse for this because the apiOptions
21946
- // includes the functions GroupMetadataEditor, groupAnnotator,
21947
- // onFocusChange, and onInputError.
21948
+ // includes the functions GroupMetadataEditor, groupAnnotator, and onFocusChange.
21948
21949
  // @ts-expect-error - TS2339 - Property 'iframeDataStore' does not exist on type 'Window & typeof globalThis'.
21949
21950
  window.iframeDataStore[this.iframeID] = data;
21950
21951
  frame.contentWindow.postMessage(this.iframeID, "*");
@@ -23617,7 +23618,7 @@ class StructuredItemDiff extends React__namespace.Component {
23617
23618
 
23618
23619
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
23619
23620
  const {
23620
- InfoTip: InfoTip$m,
23621
+ InfoTip: InfoTip$n,
23621
23622
  InlineIcon: InlineIcon$7
23622
23623
  } = perseus.components;
23623
23624
  const {
@@ -23691,7 +23692,7 @@ class HintEditor extends React__namespace.Component {
23691
23692
  type: "button",
23692
23693
  className: this.props.isFirst ? "hidden" : "",
23693
23694
  onClick: ___default["default"].partial(this.props.onMove, -1)
23694
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon$7, iconCircleArrowUp)), " ", this.props.isLast && /*#__PURE__*/React__namespace.createElement(InfoTip$m, null, /*#__PURE__*/React__namespace.createElement("p", null, "The last hint is automatically bolded."))), /*#__PURE__*/React__namespace.createElement("input", {
23695
+ }, /*#__PURE__*/React__namespace.createElement(InlineIcon$7, iconCircleArrowUp)), " ", this.props.isLast && /*#__PURE__*/React__namespace.createElement(InfoTip$n, null, /*#__PURE__*/React__namespace.createElement("p", null, "The last hint is automatically bolded."))), /*#__PURE__*/React__namespace.createElement("input", {
23695
23696
  type: "checkbox"
23696
23697
  // @ts-expect-error - TS2322 - Type 'boolean | null | undefined' is not assignable to type 'boolean | undefined'.
23697
23698
  ,
@@ -23919,7 +23920,7 @@ class CombinedHintsEditor extends React__namespace.Component {
23919
23920
  }
23920
23921
 
23921
23922
  const {
23922
- InfoTip: InfoTip$l
23923
+ InfoTip: InfoTip$m
23923
23924
  } = perseus.components;
23924
23925
  class ItemExtrasEditor extends React__namespace.Component {
23925
23926
  static defaultProps = {
@@ -24057,17 +24058,17 @@ class ItemExtrasEditor extends React__namespace.Component {
24057
24058
  }
24058
24059
  }
24059
24060
  const ItemExtraCheckbox = props => /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
24060
- style: [styles$P.checkbox, props.indent ? styles$P.indented : undefined]
24061
+ style: [styles$Q.checkbox, props.indent ? styles$Q.indented : undefined]
24061
24062
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
24062
24063
  label: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
24063
24064
  style: {
24064
24065
  flexDirection: "row"
24065
24066
  }
24066
- }, props.label, " ", /*#__PURE__*/React__namespace.createElement(InfoTip$l, null, props.infoTip)),
24067
+ }, props.label, " ", /*#__PURE__*/React__namespace.createElement(InfoTip$m, null, props.infoTip)),
24067
24068
  checked: props.checked,
24068
24069
  onChange: newCheckedState => props.onChange(newCheckedState)
24069
24070
  }));
24070
- const styles$P = aphrodite.StyleSheet.create({
24071
+ const styles$Q = aphrodite.StyleSheet.create({
24071
24072
  indented: {
24072
24073
  marginInlineStart: wonderBlocksTokens.spacing.large_24
24073
24074
  }
@@ -24733,12 +24734,12 @@ class SimpleButton extends React__namespace.Component {
24733
24734
  ...otherProps
24734
24735
  } = this.props;
24735
24736
  return /*#__PURE__*/React__namespace.createElement("div", _extends({
24736
- className: aphrodite.css(styles$O.baseButton, color === "green" && styles$O.green, color === "orange" && styles$O.orange),
24737
+ className: aphrodite.css(styles$P.baseButton, color === "green" && styles$P.green, color === "orange" && styles$P.orange),
24737
24738
  onClick: onClick
24738
24739
  }, otherProps), children);
24739
24740
  }
24740
24741
  }
24741
- const styles$O = aphrodite.StyleSheet.create({
24742
+ const styles$P = aphrodite.StyleSheet.create({
24742
24743
  baseButton: {
24743
24744
  top: "0",
24744
24745
  fontSize: "11px",
@@ -24951,23 +24952,23 @@ const LeafContainer = _ref2 => {
24951
24952
  } = _ref2;
24952
24953
  const hasPreviewHeading = shape.type === "content" || shape.type === "hint";
24953
24954
  const previewHeading = hasPreviewHeading && /*#__PURE__*/React__namespace.createElement("div", {
24954
- className: aphrodite.css(styles$N.containerHeader)
24955
+ className: aphrodite.css(styles$O.containerHeader)
24955
24956
  }, /*#__PURE__*/React__namespace.createElement(Header, {
24956
24957
  depth: path.length,
24957
- className: aphrodite.css(styles$N.containerTitle)
24958
+ className: aphrodite.css(styles$O.containerTitle)
24958
24959
  }, capitalize(name)));
24959
24960
  return /*#__PURE__*/React__namespace.createElement("div", {
24960
- className: aphrodite.css(styles$N.container)
24961
+ className: aphrodite.css(styles$O.container)
24961
24962
  }, /*#__PURE__*/React__namespace.createElement("span", {
24962
- className: aphrodite.css(styles$N.row, styles$N.rowHeading)
24963
+ className: aphrodite.css(styles$O.row, styles$O.rowHeading)
24963
24964
  }, /*#__PURE__*/React__namespace.createElement("div", {
24964
- className: aphrodite.css(styles$N.columnLeft)
24965
+ className: aphrodite.css(styles$O.columnLeft)
24965
24966
  }, /*#__PURE__*/React__namespace.createElement("div", {
24966
- className: "pod-title " + aphrodite.css(styles$N.containerHeader)
24967
+ className: "pod-title " + aphrodite.css(styles$O.containerHeader)
24967
24968
  }, /*#__PURE__*/React__namespace.createElement("div", {
24968
- className: aphrodite.css(styles$N.containerTitle)
24969
+ className: aphrodite.css(styles$O.containerTitle)
24969
24970
  }, capitalize(name)), controls)), /*#__PURE__*/React__namespace.createElement("div", {
24970
- className: aphrodite.css(styles$N.columnRight)
24971
+ className: aphrodite.css(styles$O.columnRight)
24971
24972
  }, previewHeading)), children);
24972
24973
  };
24973
24974
  const ArrayContainer = props => {
@@ -24980,11 +24981,11 @@ const ArrayContainer = props => {
24980
24981
  actions
24981
24982
  } = props;
24982
24983
  return /*#__PURE__*/React__namespace.createElement("div", {
24983
- className: aphrodite.css(styles$N.container)
24984
+ className: aphrodite.css(styles$O.container)
24984
24985
  }, controls && /*#__PURE__*/React__namespace.createElement("div", {
24985
- className: aphrodite.css(styles$N.columnLeft, styles$N.containerHeader)
24986
+ className: aphrodite.css(styles$O.columnLeft, styles$O.containerHeader)
24986
24987
  }, controls), /*#__PURE__*/React__namespace.createElement("div", null, children), /*#__PURE__*/React__namespace.createElement("div", {
24987
- className: aphrodite.css(styles$N.columnLeft)
24988
+ className: aphrodite.css(styles$O.columnLeft)
24988
24989
  }, /*#__PURE__*/React__namespace.createElement("a", {
24989
24990
  href: "javascript:void 0",
24990
24991
  onClick: () => actions.addArrayElement(path, shape.elementShape)
@@ -24998,28 +24999,28 @@ const ObjectContainer = _ref3 => {
24998
24999
  path
24999
25000
  } = _ref3;
25000
25001
  const headingEditor = /*#__PURE__*/React__namespace.createElement("div", {
25001
- className: aphrodite.css(styles$N.containerHeader)
25002
+ className: aphrodite.css(styles$O.containerHeader)
25002
25003
  }, /*#__PURE__*/React__namespace.createElement(Header, {
25003
25004
  depth: path.length,
25004
- className: aphrodite.css(styles$N.containerTitle)
25005
+ className: aphrodite.css(styles$O.containerTitle)
25005
25006
  }, capitalize(name)), controls);
25006
25007
  const headingPreview = (name || controls) && /*#__PURE__*/React__namespace.createElement("div", {
25007
- className: aphrodite.css(styles$N.containerHeader, styles$N.previewCollectionHeader)
25008
+ className: aphrodite.css(styles$O.containerHeader, styles$O.previewCollectionHeader)
25008
25009
  }, /*#__PURE__*/React__namespace.createElement(Header, {
25009
25010
  depth: path.length,
25010
- className: aphrodite.css(styles$N.containerTitle)
25011
+ className: aphrodite.css(styles$O.containerTitle)
25011
25012
  }, capitalize(name)));
25012
25013
  const hasBothHeadings = headingEditor && headingPreview;
25013
25014
  return /*#__PURE__*/React__namespace.createElement("div", {
25014
- className: aphrodite.css(styles$N.container)
25015
+ className: aphrodite.css(styles$O.container)
25015
25016
  }, hasBothHeadings && /*#__PURE__*/React__namespace.createElement("span", {
25016
- className: aphrodite.css(styles$N.row)
25017
+ className: aphrodite.css(styles$O.row)
25017
25018
  }, /*#__PURE__*/React__namespace.createElement("div", {
25018
- className: aphrodite.css(styles$N.columnLeft)
25019
+ className: aphrodite.css(styles$O.columnLeft)
25019
25020
  }, headingEditor), /*#__PURE__*/React__namespace.createElement("div", {
25020
- className: aphrodite.css(styles$N.columnRight)
25021
+ className: aphrodite.css(styles$O.columnRight)
25021
25022
  }, headingPreview)), /*#__PURE__*/React__namespace.createElement("div", {
25022
- className: aphrodite.css(path.length > 0 && styles$N.contentIndent)
25023
+ className: aphrodite.css(path.length > 0 && styles$O.contentIndent)
25023
25024
  }, children));
25024
25025
  };
25025
25026
 
@@ -25139,11 +25140,11 @@ const ItemNodeContent = withStickiness(props => {
25139
25140
  className: "framework-perseus"
25140
25141
  }, lens(renderers).get(path));
25141
25142
  return /*#__PURE__*/React__namespace.createElement("span", null, /*#__PURE__*/React__namespace.createElement("div", {
25142
- className: aphrodite.css(styles$N.row)
25143
+ className: aphrodite.css(styles$O.row)
25143
25144
  }, /*#__PURE__*/React__namespace.createElement("div", {
25144
- className: aphrodite.css(styles$N.columnLeft)
25145
+ className: aphrodite.css(styles$O.columnLeft)
25145
25146
  }, /*#__PURE__*/React__namespace.createElement("div", {
25146
- className: aphrodite.css(sticky && styles$N.sticky)
25147
+ className: aphrodite.css(sticky && styles$O.sticky)
25147
25148
  },
25148
25149
  /*#__PURE__*/
25149
25150
  // @ts-expect-error - TS2769 - No overload matches this call.
@@ -25151,9 +25152,9 @@ const ItemNodeContent = withStickiness(props => {
25151
25152
  onChange: newVal => actions.mergeValueAtPath(path, newVal),
25152
25153
  apiOptions: apiOptions
25153
25154
  })))), /*#__PURE__*/React__namespace.createElement("div", {
25154
- className: aphrodite.css(styles$N.columnRight)
25155
+ className: aphrodite.css(styles$O.columnRight)
25155
25156
  }, /*#__PURE__*/React__namespace.createElement("div", {
25156
- className: aphrodite.css(sticky && styles$N.sticky)
25157
+ className: aphrodite.css(sticky && styles$O.sticky)
25157
25158
  }, preview))));
25158
25159
  });
25159
25160
  const HintNodeContent = withStickiness(props => {
@@ -25169,13 +25170,13 @@ const HintNodeContent = withStickiness(props => {
25169
25170
  className: "framework-perseus"
25170
25171
  }, lens(renderers).get(path));
25171
25172
  return /*#__PURE__*/React__namespace.createElement("div", {
25172
- className: aphrodite.css(styles$N.row)
25173
+ className: aphrodite.css(styles$O.row)
25173
25174
  }, /*#__PURE__*/React__namespace.createElement("div", {
25174
- className: aphrodite.css(styles$N.columnLeft)
25175
+ className: aphrodite.css(styles$O.columnLeft)
25175
25176
  }, /*#__PURE__*/React__namespace.createElement("div", {
25176
- className: aphrodite.css(sticky && styles$N.sticky)
25177
+ className: aphrodite.css(sticky && styles$O.sticky)
25177
25178
  }, /*#__PURE__*/React__namespace.createElement(HintEditor, _extends({}, data, {
25178
- className: aphrodite.css(styles$N.hintEditor),
25179
+ className: aphrodite.css(styles$O.hintEditor),
25179
25180
  onChange: newVal => actions.mergeValueAtPath(path, newVal),
25180
25181
  apiOptions: apiOptions,
25181
25182
  showTitle: false,
@@ -25190,9 +25191,9 @@ const HintNodeContent = withStickiness(props => {
25190
25191
  isFirst: true,
25191
25192
  isLast: true
25192
25193
  })))), /*#__PURE__*/React__namespace.createElement("div", {
25193
- className: aphrodite.css(styles$N.columnRight)
25194
+ className: aphrodite.css(styles$O.columnRight)
25194
25195
  }, /*#__PURE__*/React__namespace.createElement("div", {
25195
- className: aphrodite.css(sticky && styles$N.sticky)
25196
+ className: aphrodite.css(sticky && styles$O.sticky)
25196
25197
  }, preview)));
25197
25198
  });
25198
25199
  const TagsNodeContent = props => {
@@ -25209,9 +25210,9 @@ const TagsNodeContent = props => {
25209
25210
  return null;
25210
25211
  }
25211
25212
  return /*#__PURE__*/React__namespace.createElement("div", {
25212
- className: aphrodite.css(styles$N.columnLeft)
25213
+ className: aphrodite.css(styles$O.columnLeft)
25213
25214
  }, /*#__PURE__*/React__namespace.createElement("div", {
25214
- className: aphrodite.css(styles$N.tagsEditor)
25215
+ className: aphrodite.css(styles$O.tagsEditor)
25215
25216
  }, /*#__PURE__*/React__namespace.createElement(GroupMetadataEditor, {
25216
25217
  value: data,
25217
25218
  onChange: newVal => actions.setValueAtPath(path, newVal),
@@ -25242,23 +25243,23 @@ const ArrayNodeContent = props => {
25242
25243
  const subpath = path.concat(i);
25243
25244
  const controls = [i > 0 && /*#__PURE__*/React__namespace.createElement("div", {
25244
25245
  key: "moveArrayElementUp",
25245
- className: aphrodite.css(styles$N.control)
25246
+ className: aphrodite.css(styles$O.control)
25246
25247
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25247
25248
  color: "orange",
25248
25249
  title: "Move up",
25249
25250
  onClick: () => actions.moveArrayElementUp(subpath)
25250
25251
  }, /*#__PURE__*/React__namespace.createElement("div", {
25251
- className: aphrodite.css(styles$N.verticalFlip)
25252
+ className: aphrodite.css(styles$O.verticalFlip)
25252
25253
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconChevronDown)))), i < data.length - 1 && /*#__PURE__*/React__namespace.createElement("div", {
25253
25254
  key: "moveArrayElementDown",
25254
- className: aphrodite.css(styles$N.control)
25255
+ className: aphrodite.css(styles$O.control)
25255
25256
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25256
25257
  color: "orange",
25257
25258
  title: "Move down",
25258
25259
  onClick: () => actions.moveArrayElementDown(subpath)
25259
25260
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconChevronDown))), /*#__PURE__*/React__namespace.createElement("div", {
25260
25261
  key: "removeArrayElement",
25261
- className: aphrodite.css(styles$N.control)
25262
+ className: aphrodite.css(styles$O.control)
25262
25263
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25263
25264
  color: "orange",
25264
25265
  title: "Delete",
@@ -25266,7 +25267,7 @@ const ArrayNodeContent = props => {
25266
25267
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconTrash$4)))];
25267
25268
  return /*#__PURE__*/React__namespace.createElement("div", {
25268
25269
  key: i,
25269
- className: aphrodite.css(styles$N.arrayElement, !elementIsLeaf && styles$N.arrayElementAndNotLeaf)
25270
+ className: aphrodite.css(styles$O.arrayElement, !elementIsLeaf && styles$O.arrayElementAndNotLeaf)
25270
25271
  }, /*#__PURE__*/React__namespace.createElement(NodeContainer, _extends({}, otherProps, {
25271
25272
  key: i,
25272
25273
  shape: shape.elementShape,
@@ -25292,7 +25293,7 @@ const ObjectNodeContent = props => {
25292
25293
  // made sense to the shape's author is the order in which we'll iterate :)
25293
25294
  const children = Object.keys(shape.shape).map(subkey => /*#__PURE__*/React__namespace.createElement("div", {
25294
25295
  key: subkey,
25295
- className: aphrodite.css(styles$N.objectElement)
25296
+ className: aphrodite.css(styles$O.objectElement)
25296
25297
  }, /*#__PURE__*/React__namespace.createElement(NodeContainer, _extends({}, otherProps, {
25297
25298
  shape: shape.shape[subkey],
25298
25299
  data: data[subkey],
@@ -25462,7 +25463,7 @@ class MultiRendererEditor extends React__namespace.Component {
25462
25463
  }, this._renderContent());
25463
25464
  }
25464
25465
  }
25465
- const styles$N = aphrodite.StyleSheet.create({
25466
+ const styles$O = aphrodite.StyleSheet.create({
25466
25467
  // This is used in a number of places throughout this file.
25467
25468
  container: {},
25468
25469
  // eslint-disable-next-line react-native/no-unused-styles
@@ -25761,7 +25762,7 @@ class BlurInput extends React__namespace.Component {
25761
25762
 
25762
25763
  /* eslint-disable no-useless-escape */
25763
25764
  const {
25764
- InfoTip: InfoTip$k
25765
+ InfoTip: InfoTip$l
25765
25766
  } = perseus.components;
25766
25767
  const DEFAULT_WIDTH = 400;
25767
25768
  const DEFAULT_HEIGHT = 400;
@@ -25952,7 +25953,7 @@ class CSProgramEditor extends React__namespace.Component {
25952
25953
  showEditor: value
25953
25954
  });
25954
25955
  }
25955
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$k, null, "If you show the editor, you should use the \"full-width\" alignment to make room for the width of the editor."), /*#__PURE__*/React__namespace.createElement("br", null), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
25956
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$l, null, "If you show the editor, you should use the \"full-width\" alignment to make room for the width of the editor."), /*#__PURE__*/React__namespace.createElement("br", null), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
25956
25957
  label: "Show Buttons",
25957
25958
  checked: this.props.showButtons,
25958
25959
  onChange: value => {
@@ -25964,7 +25965,7 @@ class CSProgramEditor extends React__namespace.Component {
25964
25965
  name: "settings",
25965
25966
  pairs: this.props.settings,
25966
25967
  onChange: this._handleSettingsChange
25967
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$k, null, "Settings that you add here are available to the program as an object returned by ", /*#__PURE__*/React__namespace.createElement("code", null, "Program.settings()"))));
25968
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$l, null, "Settings that you add here are available to the program as an object returned by ", /*#__PURE__*/React__namespace.createElement("code", null, "Program.settings()"))));
25968
25969
  }
25969
25970
  }
25970
25971
 
@@ -26041,7 +26042,7 @@ class DeprecatedStandinEditor extends React__namespace.Component {
26041
26042
 
26042
26043
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
26043
26044
  const {
26044
- InfoTip: InfoTip$j,
26045
+ InfoTip: InfoTip$k,
26045
26046
  InlineIcon: InlineIcon$5
26046
26047
  } = perseus.components;
26047
26048
  const {
@@ -26122,14 +26123,14 @@ class DropdownEditor extends React__namespace.Component {
26122
26123
  className: "perseus-widget-dropdown"
26123
26124
  }, /*#__PURE__*/React__namespace.createElement("div", {
26124
26125
  className: "dropdown-info"
26125
- }, "Dropdown", /*#__PURE__*/React__namespace.createElement(InfoTip$j, null, /*#__PURE__*/React__namespace.createElement("p", null, "The drop down is useful for making inequalities in a custom format. We normally use the symbols ", "<", ",", " ", ">", ", \u2264, \u2265 (in that order) which you can copy into the choices. When possible, use the \"multiple choice\" answer type instead."))), /*#__PURE__*/React__namespace.createElement("div", {
26126
+ }, "Dropdown", /*#__PURE__*/React__namespace.createElement(InfoTip$k, null, /*#__PURE__*/React__namespace.createElement("p", null, "The drop down is useful for making inequalities in a custom format. We normally use the symbols ", "<", ",", " ", ">", ", \u2264, \u2265 (in that order) which you can copy into the choices. When possible, use the \"multiple choice\" answer type instead."))), /*#__PURE__*/React__namespace.createElement("div", {
26126
26127
  className: "dropdown-placeholder"
26127
26128
  }, /*#__PURE__*/React__namespace.createElement("input", {
26128
26129
  type: "text",
26129
26130
  placeholder: "Placeholder value",
26130
26131
  value: this.props.placeholder,
26131
26132
  onChange: this.onPlaceholderChange
26132
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$j, null, /*#__PURE__*/React__namespace.createElement("p", null, "This value will appear as the drop down default. It should give the user some indication of the values available in the drop down itself, e.g., Yes/No/Maybe."))), /*#__PURE__*/React__namespace.createElement("div", {
26133
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$k, null, /*#__PURE__*/React__namespace.createElement("p", null, "This value will appear as the drop down default. It should give the user some indication of the values available in the drop down itself, e.g., Yes/No/Maybe."))), /*#__PURE__*/React__namespace.createElement("div", {
26133
26134
  className: "clearfix"
26134
26135
  }), /*#__PURE__*/React__namespace.createElement("ul", {
26135
26136
  className: "dropdown-choices"
@@ -26432,7 +26433,7 @@ const SortableItem = createReactClass__default["default"]({
26432
26433
  }
26433
26434
  return /*#__PURE__*/React__namespace.createElement("li", {
26434
26435
  draggable: this.props.draggable,
26435
- className: [dragState, aphrodite.css(styles$M.sortableListItem)].join(" "),
26436
+ className: [dragState, aphrodite.css(styles$N.sortableListItem)].join(" "),
26436
26437
  onDragStart: this.handleDragStart,
26437
26438
  onDrop: this.handleDrop,
26438
26439
  onDragEnter: this.handleDragEnter,
@@ -26440,14 +26441,14 @@ const SortableItem = createReactClass__default["default"]({
26440
26441
  }, this.props.component);
26441
26442
  }
26442
26443
  });
26443
- const styles$M = aphrodite.StyleSheet.create({
26444
+ const styles$N = aphrodite.StyleSheet.create({
26444
26445
  sortableListItem: {
26445
26446
  margin: "5px 0"
26446
26447
  }
26447
26448
  });
26448
26449
 
26449
26450
  const {
26450
- InfoTip: InfoTip$i
26451
+ InfoTip: InfoTip$j
26451
26452
  } = perseus.components;
26452
26453
 
26453
26454
  // types for iterables
@@ -26700,28 +26701,28 @@ class ExpressionEditor extends React__namespace.Component {
26700
26701
  onChange: this.handleToggleDiv
26701
26702
  }));
26702
26703
  return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingSmall, null, "Global Options"), /*#__PURE__*/React__namespace.createElement("div", {
26703
- className: aphrodite.css(styles$L.paddedY)
26704
+ className: aphrodite.css(styles$M.paddedY)
26704
26705
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26705
26706
  label: "Visible label",
26706
26707
  value: this.props.visibleLabel || "",
26707
26708
  onChange: this.change("visibleLabel")
26708
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "Optional visible text; strongly encouraged to help learners using dictation software, but can be omitted if the surrounding content provides enough context."))), /*#__PURE__*/React__namespace.createElement("div", {
26709
- className: aphrodite.css(styles$L.paddedY)
26709
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$j, null, /*#__PURE__*/React__namespace.createElement("p", null, "Optional visible text; strongly encouraged to help learners using dictation software, but can be omitted if the surrounding content provides enough context."))), /*#__PURE__*/React__namespace.createElement("div", {
26710
+ className: aphrodite.css(styles$M.paddedY)
26710
26711
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26711
26712
  label: "Aria label",
26712
26713
  value: this.props.ariaLabel || "",
26713
26714
  onChange: this.change("ariaLabel")
26714
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writting accessible labels, please see", " ", /*#__PURE__*/React__namespace.createElement("a", {
26715
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$j, null, /*#__PURE__*/React__namespace.createElement("p", null, "Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writting accessible labels, please see", " ", /*#__PURE__*/React__namespace.createElement("a", {
26715
26716
  href: "https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",
26716
26717
  target: "_blank"
26717
26718
  }, "this article.")))), /*#__PURE__*/React__namespace.createElement("div", {
26718
- className: aphrodite.css(styles$L.paddedY)
26719
+ className: aphrodite.css(styles$M.paddedY)
26719
26720
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26720
26721
  label: "Function variables",
26721
26722
  value: this.state.functionsInternal,
26722
26723
  onChange: this.handleFunctions
26723
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "Single-letter variables listed here will be interpreted as functions. This let us know that f(x) means \"f of x\" and not \"f times x\"."))), /*#__PURE__*/React__namespace.createElement("div", {
26724
- className: aphrodite.css(styles$L.paddedY)
26724
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$j, null, /*#__PURE__*/React__namespace.createElement("p", null, "Single-letter variables listed here will be interpreted as functions. This let us know that f(x) means \"f of x\" and not \"f times x\"."))), /*#__PURE__*/React__namespace.createElement("div", {
26725
+ className: aphrodite.css(styles$M.paddedY)
26725
26726
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26726
26727
  label: "Use \xD7 instead of \u22C5 for multiplication",
26727
26728
  checked: this.props.times,
@@ -26730,8 +26731,8 @@ class ExpressionEditor extends React__namespace.Component {
26730
26731
  times: value
26731
26732
  });
26732
26733
  }
26733
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "For pre-algebra problems this option displays multiplication as \\times instead of \\cdot in both the rendered output and the acceptable formats examples."))), /*#__PURE__*/React__namespace.createElement("div", {
26734
- className: aphrodite.css(styles$L.paddedY)
26734
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$j, null, /*#__PURE__*/React__namespace.createElement("p", null, "For pre-algebra problems this option displays multiplication as \\times instead of \\cdot in both the rendered output and the acceptable formats examples."))), /*#__PURE__*/React__namespace.createElement("div", {
26735
+ className: aphrodite.css(styles$M.paddedY)
26735
26736
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingXSmall, null, "Button Sets"), buttonSetChoices), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingSmall, null, "Answers"), /*#__PURE__*/React__namespace.createElement("p", {
26736
26737
  style: {
26737
26738
  margin: "4px 0"
@@ -26798,18 +26799,18 @@ class AnswerOption extends React__namespace.Component {
26798
26799
  color: "destructive",
26799
26800
  light: true
26800
26801
  }, "Delete");
26801
- const answerStatusCss = aphrodite.css(styles$L.answerStatus, this.props.considered === "wrong" && styles$L.answerStatusWrong, this.props.considered === "correct" && styles$L.answerStatusCorrect, this.props.considered === "ungraded" && styles$L.answerStatusUngraded);
26802
+ const answerStatusCss = aphrodite.css(styles$M.answerStatus, this.props.considered === "wrong" && styles$M.answerStatusWrong, this.props.considered === "correct" && styles$M.answerStatusCorrect, this.props.considered === "ungraded" && styles$M.answerStatusUngraded);
26802
26803
  return /*#__PURE__*/React__namespace.createElement("div", {
26803
- className: aphrodite.css(styles$L.answerOption)
26804
+ className: aphrodite.css(styles$M.answerOption)
26804
26805
  }, /*#__PURE__*/React__namespace.createElement("div", {
26805
- className: aphrodite.css(styles$L.answerHandle)
26806
+ className: aphrodite.css(styles$M.answerHandle)
26806
26807
  }), /*#__PURE__*/React__namespace.createElement("div", {
26807
- className: aphrodite.css(styles$L.answerBody)
26808
+ className: aphrodite.css(styles$M.answerBody)
26808
26809
  }, /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("button", {
26809
26810
  onClick: this.toggleConsidered,
26810
26811
  className: answerStatusCss
26811
26812
  }, this.props.considered), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(perseus.Expression, this.props.expressionProps))), /*#__PURE__*/React__namespace.createElement("div", {
26812
- className: aphrodite.css(styles$L.paddedY, styles$L.paddedX)
26813
+ className: aphrodite.css(styles$M.paddedY, styles$M.paddedX)
26813
26814
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26814
26815
  label: "Answer expression must have the same form.",
26815
26816
  checked: this.props.form,
@@ -26818,8 +26819,8 @@ class AnswerOption extends React__namespace.Component {
26818
26819
  form: value
26819
26820
  });
26820
26821
  }
26821
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "The student's answer must be in the same form. Commutativity and excess negative signs are ignored."))), /*#__PURE__*/React__namespace.createElement("div", {
26822
- className: aphrodite.css(styles$L.paddedY, styles$L.paddedX)
26822
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$j, null, /*#__PURE__*/React__namespace.createElement("p", null, "The student's answer must be in the same form. Commutativity and excess negative signs are ignored."))), /*#__PURE__*/React__namespace.createElement("div", {
26823
+ className: aphrodite.css(styles$M.paddedY, styles$M.paddedX)
26823
26824
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26824
26825
  label: "Answer expression must be fully expanded and simplified.",
26825
26826
  checked: this.props.simplify,
@@ -26828,12 +26829,12 @@ class AnswerOption extends React__namespace.Component {
26828
26829
  simplify: value
26829
26830
  });
26830
26831
  }
26831
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "The student's answer must be fully expanded and simplified. Answering this equation (x^2+2x+1) with this factored equation (x+1)^2 will render this response \"Your answer is not fully expanded and simplified.\""))), /*#__PURE__*/React__namespace.createElement("div", {
26832
- className: aphrodite.css(styles$L.buttonRow, styles$L.paddedY)
26832
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$j, null, /*#__PURE__*/React__namespace.createElement("p", null, "The student's answer must be fully expanded and simplified. Answering this equation (x^2+2x+1) with this factored equation (x+1)^2 will render this response \"Your answer is not fully expanded and simplified.\""))), /*#__PURE__*/React__namespace.createElement("div", {
26833
+ className: aphrodite.css(styles$M.buttonRow, styles$M.paddedY)
26833
26834
  }, removeButton)));
26834
26835
  }
26835
26836
  }
26836
- const styles$L = aphrodite.StyleSheet.create({
26837
+ const styles$M = aphrodite.StyleSheet.create({
26837
26838
  paddedX: {
26838
26839
  paddingLeft: wonderBlocksTokens.spacing.xSmall_8,
26839
26840
  paddingRight: wonderBlocksTokens.spacing.xSmall_8
@@ -26945,10 +26946,10 @@ class GradedGroupEditor extends React__namespace.Component {
26945
26946
  }, /*#__PURE__*/React__namespace.createElement("div", {
26946
26947
  className: "perseus-widget-row"
26947
26948
  }, /*#__PURE__*/React__namespace.createElement("label", {
26948
- className: aphrodite.css(styles$K.title)
26949
+ className: aphrodite.css(styles$L.title)
26949
26950
  }, "Title:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$5, {
26950
26951
  value: this.props.title,
26951
- className: aphrodite.css(styles$K.input)
26952
+ className: aphrodite.css(styles$L.input)
26952
26953
  // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
26953
26954
  ,
26954
26955
  onChange: this.change("title")
@@ -26973,7 +26974,7 @@ class GradedGroupEditor extends React__namespace.Component {
26973
26974
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$4, iconPlus$1), " Add a hint"), this.props.hint && /*#__PURE__*/React__namespace.createElement("div", {
26974
26975
  className: "perseus-hint-editor"
26975
26976
  }, /*#__PURE__*/React__namespace.createElement("div", {
26976
- className: aphrodite.css(styles$K.hintsTitle)
26977
+ className: aphrodite.css(styles$L.hintsTitle)
26977
26978
  }, "Hint"), /*#__PURE__*/React__namespace.createElement(Editor, {
26978
26979
  ref: this.hintEditor,
26979
26980
  content: this.props.hint ? this.props.hint.content : "",
@@ -26995,7 +26996,7 @@ class GradedGroupEditor extends React__namespace.Component {
26995
26996
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$4, iconTrash$2), " Remove this hint")));
26996
26997
  }
26997
26998
  }
26998
- const styles$K = aphrodite.StyleSheet.create({
26999
+ const styles$L = aphrodite.StyleSheet.create({
26999
27000
  title: {
27000
27001
  fontSize: 18,
27001
27002
  fontWeight: "bold"
@@ -27082,7 +27083,7 @@ const setArrayItem = (list, i, value) => [...list.slice(0, i), value, ...list.sl
27082
27083
  /* eslint-disable react/forbid-prop-types, react/no-unsafe */
27083
27084
  const {
27084
27085
  ButtonGroup: ButtonGroup$7,
27085
- InfoTip: InfoTip$h,
27086
+ InfoTip: InfoTip$i,
27086
27087
  RangeInput: RangeInput$6
27087
27088
  } = perseus.components;
27088
27089
  const defaultBackgroundImage$3 = {
@@ -27546,7 +27547,7 @@ const GraphSettings = createReactClass__default["default"]({
27546
27547
  },
27547
27548
  onKeyPress: this.changeBackgroundUrl,
27548
27549
  onBlur: this.changeBackgroundUrl
27549
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$h, null, /*#__PURE__*/React__namespace.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background.")))), ___default["default"].contains(this.props.editableSettings, "measure") && /*#__PURE__*/React__namespace.createElement("div", {
27550
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$i, null, /*#__PURE__*/React__namespace.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background.")))), ___default["default"].contains(this.props.editableSettings, "measure") && /*#__PURE__*/React__namespace.createElement("div", {
27550
27551
  className: "misc-settings"
27551
27552
  }, /*#__PURE__*/React__namespace.createElement("div", {
27552
27553
  className: "perseus-widget-row"
@@ -27592,7 +27593,7 @@ const GraphSettings = createReactClass__default["default"]({
27592
27593
  });
27593
27594
 
27594
27595
  const {
27595
- InfoTip: InfoTip$g,
27596
+ InfoTip: InfoTip$h,
27596
27597
  MultiButtonGroup: MultiButtonGroup$1
27597
27598
  } = perseus.components;
27598
27599
  const {
@@ -27686,7 +27687,7 @@ class GrapherEditor extends React__namespace.Component {
27686
27687
  className: "perseus-error"
27687
27688
  }, this.props.graph.valid);
27688
27689
  }
27689
- return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", null, "Correct answer", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$g, null, /*#__PURE__*/React__namespace.createElement("p", null, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer.")), " ", ": ", equationString), /*#__PURE__*/React__namespace.createElement(GraphSettings, {
27690
+ return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", null, "Correct answer", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$h, null, /*#__PURE__*/React__namespace.createElement("p", null, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer.")), " ", ": ", equationString), /*#__PURE__*/React__namespace.createElement(GraphSettings, {
27690
27691
  editableSettings: ["graph", "snap", "image"],
27691
27692
  box: getInteractiveBoxFromSizeClass$1(sizeClass),
27692
27693
  range: this.props.graph.range,
@@ -27946,7 +27947,7 @@ class IframeEditor extends React__namespace.Component {
27946
27947
 
27947
27948
  /* eslint-disable jsx-a11y/anchor-is-valid */
27948
27949
  const {
27949
- InfoTip: InfoTip$f,
27950
+ InfoTip: InfoTip$g,
27950
27951
  InlineIcon: InlineIcon$3,
27951
27952
  RangeInput: RangeInput$5
27952
27953
  } = perseus.components;
@@ -28147,7 +28148,7 @@ class ImageEditor extends React__namespace.Component {
28147
28148
  style: {
28148
28149
  width: "100%"
28149
28150
  }
28150
- }))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Dimensions:"), /*#__PURE__*/React__namespace.createElement("p", null, backgroundImage.width, "x", backgroundImage.height))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Alt text:", /*#__PURE__*/React__namespace.createElement(InfoTip$f, null, "This is important for screenreaders. The content of this alt text will be formatted as markdown (tables, emphasis, etc. are supported).")), /*#__PURE__*/React__namespace.createElement(Editor, {
28151
+ }))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Dimensions:"), /*#__PURE__*/React__namespace.createElement("p", null, backgroundImage.width, "x", backgroundImage.height))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("div", null, "Alt text:", /*#__PURE__*/React__namespace.createElement(InfoTip$g, null, "This is important for screenreaders. The content of this alt text will be formatted as markdown (tables, emphasis, etc. are supported).")), /*#__PURE__*/React__namespace.createElement(Editor, {
28151
28152
  apiOptions: this.props.apiOptions,
28152
28153
  content: this.props.alt,
28153
28154
  onChange: props => {
@@ -28171,7 +28172,7 @@ class ImageEditor extends React__namespace.Component {
28171
28172
  }, this.state.backgroundImageError);
28172
28173
  return /*#__PURE__*/React__namespace.createElement("div", {
28173
28174
  className: "perseus-image-editor"
28174
- }, /*#__PURE__*/React__namespace.createElement("label", null, "Image url:", /*#__PURE__*/React__namespace.createElement(InfoTip$f, null, "Paste an image or graphie image URL."), this.state.backgroundImageError && backgroundImageErrorText, /*#__PURE__*/React__namespace.createElement(BlurInput, {
28175
+ }, /*#__PURE__*/React__namespace.createElement("label", null, "Image url:", /*#__PURE__*/React__namespace.createElement(InfoTip$g, null, "Paste an image or graphie image URL."), this.state.backgroundImageError && backgroundImageErrorText, /*#__PURE__*/React__namespace.createElement(BlurInput, {
28175
28176
  value: backgroundImage.url || "",
28176
28177
  style: {
28177
28178
  width: 332
@@ -28182,7 +28183,7 @@ class ImageEditor extends React__namespace.Component {
28182
28183
  }
28183
28184
 
28184
28185
  const {
28185
- InfoTip: InfoTip$e
28186
+ InfoTip: InfoTip$f
28186
28187
  } = perseus.components;
28187
28188
  const answerTypes = {
28188
28189
  number: {
@@ -28275,7 +28276,7 @@ class InputNumberEditor extends React__namespace.Component {
28275
28276
  value: "optional"
28276
28277
  }, "will be accepted"), /*#__PURE__*/React__namespace.createElement("option", {
28277
28278
  value: "enforced"
28278
- }, "will be marked wrong"))), /*#__PURE__*/React__namespace.createElement(InfoTip$e, null, /*#__PURE__*/React__namespace.createElement("p", null, "Normally select \"will not be graded\". This will give the user a message saying the answer is correct but not simplified. The user will then have to simplify it and re-enter, but will not be penalized. (5th grade and anything after)"), /*#__PURE__*/React__namespace.createElement("p", null, "Select \"will be accepted\" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)"), /*#__PURE__*/React__namespace.createElement("p", null, "Select \"will be marked wrong\" only if we are specifically assessing the ability to simplify."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("input", {
28279
+ }, "will be marked wrong"))), /*#__PURE__*/React__namespace.createElement(InfoTip$f, null, /*#__PURE__*/React__namespace.createElement("p", null, "Normally select \"will not be graded\". This will give the user a message saying the answer is correct but not simplified. The user will then have to simplify it and re-enter, but will not be penalized. (5th grade and anything after)"), /*#__PURE__*/React__namespace.createElement("p", null, "Select \"will be accepted\" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)"), /*#__PURE__*/React__namespace.createElement("p", null, "Select \"will be marked wrong\" only if we are specifically assessing the ability to simplify."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("input", {
28279
28280
  type: "checkbox",
28280
28281
  checked: this.props.inexact,
28281
28282
  onChange: e => {
@@ -28311,7 +28312,7 @@ class InputNumberEditor extends React__namespace.Component {
28311
28312
  });
28312
28313
  },
28313
28314
  "aria-label": "Answer type"
28314
- }, answerTypeOptions), /*#__PURE__*/React__namespace.createElement(InfoTip$e, null, /*#__PURE__*/React__namespace.createElement("p", null, "Use the default \"Numbers\" unless the answer must be in a specific form (e.g., question is about converting decimals to fractions)."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, "Width", " ", /*#__PURE__*/React__namespace.createElement("select", {
28315
+ }, answerTypeOptions), /*#__PURE__*/React__namespace.createElement(InfoTip$f, null, /*#__PURE__*/React__namespace.createElement("p", null, "Use the default \"Numbers\" unless the answer must be in a specific form (e.g., question is about converting decimals to fractions)."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, "Width", " ", /*#__PURE__*/React__namespace.createElement("select", {
28315
28316
  value: this.props.size,
28316
28317
  onChange: e => {
28317
28318
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type '"small" | "normal" | undefined'.
@@ -28323,7 +28324,7 @@ class InputNumberEditor extends React__namespace.Component {
28323
28324
  value: "normal"
28324
28325
  }, "Normal (80px)"), /*#__PURE__*/React__namespace.createElement("option", {
28325
28326
  value: "small"
28326
- }, "Small (40px)"))), /*#__PURE__*/React__namespace.createElement(InfoTip$e, null, /*#__PURE__*/React__namespace.createElement("p", null, "Use size \"Normal\" for all text boxes, unless there are multiple text boxes in one line and the answer area is too narrow to fit them."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("input", {
28327
+ }, "Small (40px)"))), /*#__PURE__*/React__namespace.createElement(InfoTip$f, null, /*#__PURE__*/React__namespace.createElement("p", null, "Use size \"Normal\" for all text boxes, unless there are multiple text boxes in one line and the answer area is too narrow to fit them."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("label", null, /*#__PURE__*/React__namespace.createElement("input", {
28327
28328
  type: "checkbox",
28328
28329
  checked: this.props.rightAlign,
28329
28330
  onChange: e => {
@@ -28486,13 +28487,13 @@ function MathquillInput(props) {
28486
28487
  }
28487
28488
  });
28488
28489
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
28489
- style: styles$J.outerWrapper
28490
+ style: styles$K.outerWrapper
28490
28491
  }, /*#__PURE__*/React__namespace.createElement("span", {
28491
28492
  ref: mathFieldWrapperRef,
28492
28493
  className: "perseus-math-input mq-editable-field mq-math-mode"
28493
28494
  }));
28494
28495
  }
28495
- const styles$J = aphrodite.StyleSheet.create({
28496
+ const styles$K = aphrodite.StyleSheet.create({
28496
28497
  outerWrapper: {
28497
28498
  display: "inline-block",
28498
28499
  borderStyle: "solid",
@@ -29621,7 +29622,7 @@ const GraphPointsCountSelector = _ref => {
29621
29622
  // Never uses placeholder, always has value
29622
29623
  ,
29623
29624
  placeholder: "",
29624
- style: styles$I.singleSelectShort
29625
+ style: styles$J.singleSelectShort
29625
29626
  }, [...[...Array(7).keys()].map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29626
29627
  key: n,
29627
29628
  value: `${n}`,
@@ -29632,7 +29633,7 @@ const GraphPointsCountSelector = _ref => {
29632
29633
  label: "unlimited"
29633
29634
  })]);
29634
29635
  };
29635
- const styles$I = aphrodite.StyleSheet.create({
29636
+ const styles$J = aphrodite.StyleSheet.create({
29636
29637
  singleSelectShort: {
29637
29638
  // Non-standard spacing, but it's the smallest we can go
29638
29639
  // without running into styling issues with the dropdown.
@@ -29645,7 +29646,7 @@ const GraphTypeSelector = props => {
29645
29646
  selectedValue: props.graphType,
29646
29647
  onChange: props.onChange,
29647
29648
  placeholder: "Select an answer type",
29648
- style: styles$H.singleSelectShort
29649
+ style: styles$I.singleSelectShort
29649
29650
  }, props.showNoneOption && /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29650
29651
  value: "none",
29651
29652
  label: "None"
@@ -29681,7 +29682,7 @@ const GraphTypeSelector = props => {
29681
29682
  label: "Angle"
29682
29683
  }));
29683
29684
  };
29684
- const styles$H = aphrodite.StyleSheet.create({
29685
+ const styles$I = aphrodite.StyleSheet.create({
29685
29686
  singleSelectShort: {
29686
29687
  // Non-standard spacing, but it's the smallest we can go
29687
29688
  // without running into styling issues with the dropdown.
@@ -29697,11 +29698,11 @@ function Heading(_ref) {
29697
29698
  onToggle
29698
29699
  } = _ref;
29699
29700
  return /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
29700
- style: [styles$G.container, !isCollapsible && styles$G.notClickable],
29701
+ style: [styles$H.container, !isCollapsible && styles$H.notClickable],
29701
29702
  disabled: !isCollapsible,
29702
29703
  onClick: () => isCollapsible && onToggle?.(!isOpen)
29703
29704
  }, () => /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29704
- style: styles$G.heading
29705
+ style: styles$H.heading
29705
29706
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
29706
29707
  style: {
29707
29708
  fontSize: 14,
@@ -29711,7 +29712,7 @@ function Heading(_ref) {
29711
29712
  isExpanded: isOpen
29712
29713
  })));
29713
29714
  }
29714
- const styles$G = aphrodite.StyleSheet.create({
29715
+ const styles$H = aphrodite.StyleSheet.create({
29715
29716
  container: {
29716
29717
  marginTop: wonderBlocksTokens.spacing.small_12,
29717
29718
  // NOTE(jeremy): This is the inverse of the @editorPadding CSS
@@ -29771,15 +29772,18 @@ function InteractiveGraphDescription(props) {
29771
29772
  isOpen: isOpen,
29772
29773
  onToggle: setIsOpen
29773
29774
  }), isOpen && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelXSmall, {
29774
- style: styles$F.caption
29775
- }, "Use these fields to describe the graph as a whole. These are used by screen readers to describe content to users who are visually impaired."), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
29775
+ style: styles$G.caption
29776
+ }, "Use these fields to describe the graph as a whole. These are used by screen readers to describe content to users who may be visually impaired."), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
29776
29777
  tag: "label"
29777
29778
  }, "Title", /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
29778
29779
  value: ariaLabelValue,
29779
29780
  onChange: newValue => onChange({
29780
- fullGraphAriaLabel: newValue
29781
+ fullGraphAriaLabel:
29782
+ // Save as undefined if the new value
29783
+ // is an empty string.
29784
+ newValue || undefined
29781
29785
  }),
29782
- style: styles$F.spaceAbove
29786
+ style: styles$G.spaceAbove
29783
29787
  })), /*#__PURE__*/React__namespace.createElement(Strut, {
29784
29788
  size: wonderBlocksTokens.spacing.small_12
29785
29789
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
@@ -29789,12 +29793,15 @@ function InteractiveGraphDescription(props) {
29789
29793
  resizeType: "vertical",
29790
29794
  value: ariaDescriptionValue,
29791
29795
  onChange: newValue => onChange({
29792
- fullGraphAriaDescription: newValue
29796
+ fullGraphAriaDescription:
29797
+ // Save as undefined if the new value
29798
+ // is an empty string.
29799
+ newValue || undefined
29793
29800
  }),
29794
- style: styles$F.spaceAbove
29801
+ style: styles$G.spaceAbove
29795
29802
  }))));
29796
29803
  }
29797
- const styles$F = aphrodite.StyleSheet.create({
29804
+ const styles$G = aphrodite.StyleSheet.create({
29798
29805
  caption: {
29799
29806
  color: wonderBlocksTokens.color.offBlack64,
29800
29807
  paddingTop: wonderBlocksTokens.spacing.xxSmall_6,
@@ -29814,16 +29821,16 @@ const LabeledRow = props => {
29814
29821
  style
29815
29822
  } = props;
29816
29823
  return /*#__PURE__*/React__namespace.createElement("label", {
29817
- className: aphrodite.css(styles$E.label)
29824
+ className: aphrodite.css(styles$F.label)
29818
29825
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29819
- style: [styles$E.row, style]
29826
+ style: [styles$F.row, style]
29820
29827
  }, labelSide === "start" || /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29821
- style: styles$E.spaceEnd
29828
+ style: styles$F.spaceEnd
29822
29829
  }, label), children, labelSide === "end" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29823
- style: styles$E.spaceStart
29830
+ style: styles$F.spaceStart
29824
29831
  }, label)));
29825
29832
  };
29826
- const styles$E = aphrodite.StyleSheet.create({
29833
+ const styles$F = aphrodite.StyleSheet.create({
29827
29834
  label: {
29828
29835
  width: "fit-content"
29829
29836
  },
@@ -29844,7 +29851,7 @@ const styles$E = aphrodite.StyleSheet.create({
29844
29851
  /* eslint-disable react/forbid-prop-types, react/no-unsafe */
29845
29852
  const {
29846
29853
  ButtonGroup: ButtonGroup$2,
29847
- InfoTip: InfoTip$d,
29854
+ InfoTip: InfoTip$e,
29848
29855
  RangeInput: RangeInput$4
29849
29856
  } = perseus.components;
29850
29857
  const defaultBackgroundImage$1 = {
@@ -30242,10 +30249,10 @@ class InteractiveGraphSettings extends React__namespace.Component {
30242
30249
  }
30243
30250
  }))), /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30244
30251
  label: "Background image URL:",
30245
- style: styles$D.resetSpaceTop
30252
+ style: styles$E.resetSpaceTop
30246
30253
  }, /*#__PURE__*/React__namespace.createElement("input", {
30247
30254
  type: "text",
30248
- className: aphrodite.css(styles$D.backgroundUrlInput),
30255
+ className: aphrodite.css(styles$E.backgroundUrlInput),
30249
30256
  ref: this.bgUrlRef,
30250
30257
  value: this.state.backgroundImage.url || "",
30251
30258
  onChange: e => {
@@ -30260,10 +30267,10 @@ class InteractiveGraphSettings extends React__namespace.Component {
30260
30267
  },
30261
30268
  onKeyPress: this.changeBackgroundUrl,
30262
30269
  onBlur: this.changeBackgroundUrl
30263
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$d, 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, {
30264
- style: styles$D.protractorSection
30270
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$e, 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, {
30271
+ style: styles$E.protractorSection
30265
30272
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30266
- style: styles$D.checkboxRow
30273
+ style: styles$E.checkboxRow
30267
30274
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
30268
30275
  label: "Show protractor",
30269
30276
  checked: this.props.showProtractor,
@@ -30272,7 +30279,7 @@ class InteractiveGraphSettings extends React__namespace.Component {
30272
30279
  showProtractor: value
30273
30280
  });
30274
30281
  },
30275
- style: styles$D.resetSpaceTop
30282
+ style: styles$E.resetSpaceTop
30276
30283
  })), this.props.showProtractor && /*#__PURE__*/React__namespace.createElement(Banner__default["default"], {
30277
30284
  layout: "floating",
30278
30285
  text: "The protractor is not accessible. Please consider an alternate approach.",
@@ -30280,7 +30287,7 @@ class InteractiveGraphSettings extends React__namespace.Component {
30280
30287
  }))));
30281
30288
  }
30282
30289
  }
30283
- const styles$D = aphrodite.StyleSheet.create({
30290
+ const styles$E = aphrodite.StyleSheet.create({
30284
30291
  resetSpaceTop: {
30285
30292
  marginTop: 0
30286
30293
  },
@@ -30319,14 +30326,14 @@ const SegmentCountSelector = _ref => {
30319
30326
  const num = +newValue;
30320
30327
  onChange(num);
30321
30328
  },
30322
- style: styles$C.singleSelectShort
30329
+ style: styles$D.singleSelectShort
30323
30330
  }, ___default["default"].range(1, 7).map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30324
30331
  key: n,
30325
30332
  value: `${n}`,
30326
30333
  label: `${n} segment${n > 1 ? "s" : ""}`
30327
30334
  })));
30328
30335
  };
30329
- const styles$C = aphrodite.StyleSheet.create({
30336
+ const styles$D = aphrodite.StyleSheet.create({
30330
30337
  singleSelectShort: {
30331
30338
  // Non-standard spacing, but it's the smallest we can go
30332
30339
  // without running into styling issues with the dropdown.
@@ -30351,17 +30358,17 @@ const LockedFigureSelect = props => {
30351
30358
  figureTypes.push("label");
30352
30359
  }
30353
30360
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30354
- style: styles$B.container
30361
+ style: styles$C.container
30355
30362
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionMenu, {
30356
30363
  menuText: "Add locked figure",
30357
- style: styles$B.addElementSelect
30364
+ style: styles$C.addElementSelect
30358
30365
  }, figureTypes.map(figureType => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
30359
30366
  key: `${id}-${figureType}`,
30360
30367
  label: figureType,
30361
30368
  onClick: () => onChange(figureType)
30362
30369
  }))));
30363
30370
  };
30364
- const styles$B = aphrodite.StyleSheet.create({
30371
+ const styles$C = aphrodite.StyleSheet.create({
30365
30372
  container: {
30366
30373
  marginTop: wonderBlocksTokens.spacing.xSmall_8
30367
30374
  },
@@ -30478,18 +30485,18 @@ const AngleInput = props => {
30478
30485
  }
30479
30486
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30480
30487
  tag: "label",
30481
- style: styles$A.row
30488
+ style: styles$B.row
30482
30489
  }, "angle (degrees)", /*#__PURE__*/React__namespace.createElement(Strut, {
30483
30490
  size: wonderBlocksTokens.spacing.xxSmall_6
30484
30491
  }), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
30485
30492
  value: angleInput,
30486
30493
  onChange: handleAngleChange,
30487
- style: styles$A.textField
30494
+ style: styles$B.textField
30488
30495
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
30489
30496
  size: wonderBlocksTokens.spacing.xxSmall_6
30490
30497
  }));
30491
30498
  };
30492
- const styles$A = aphrodite.StyleSheet.create({
30499
+ const styles$B = aphrodite.StyleSheet.create({
30493
30500
  row: {
30494
30501
  display: "flex",
30495
30502
  flexDirection: "row",
@@ -30538,30 +30545,30 @@ const CoordinatePairInput = props => {
30538
30545
  onChange(newCoords);
30539
30546
  }
30540
30547
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30541
- style: [styles$z.row, style]
30548
+ style: [styles$A.row, style]
30542
30549
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30543
30550
  tag: "label",
30544
- style: styles$z.row
30551
+ style: styles$A.row
30545
30552
  }, labels ? labels[0] : "x coord", /*#__PURE__*/React__namespace.createElement(Strut, {
30546
30553
  size: wonderBlocksTokens.spacing.xxSmall_6
30547
30554
  }), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
30548
30555
  value: coordState[0],
30549
30556
  onChange: newValue => handleCoordChange(newValue, 0),
30550
- style: [styles$z.textField, error ? styles$z.errorField : undefined]
30557
+ style: [styles$A.textField, error ? styles$A.errorField : undefined]
30551
30558
  })), /*#__PURE__*/React__namespace.createElement(Strut, {
30552
30559
  size: wonderBlocksTokens.spacing.medium_16
30553
30560
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30554
30561
  tag: "label",
30555
- style: styles$z.row
30562
+ style: styles$A.row
30556
30563
  }, labels ? labels[1] : "y coord", /*#__PURE__*/React__namespace.createElement(Strut, {
30557
30564
  size: wonderBlocksTokens.spacing.xxSmall_6
30558
30565
  }), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
30559
30566
  value: coordState[1],
30560
30567
  onChange: newValue => handleCoordChange(newValue, 1),
30561
- style: [styles$z.textField, error ? styles$z.errorField : undefined]
30568
+ style: [styles$A.textField, error ? styles$A.errorField : undefined]
30562
30569
  })));
30563
30570
  };
30564
- const styles$z = aphrodite.StyleSheet.create({
30571
+ const styles$A = aphrodite.StyleSheet.create({
30565
30572
  row: {
30566
30573
  display: "flex",
30567
30574
  flexDirection: "row",
@@ -30594,14 +30601,14 @@ const PerseusEditorAccordion = props => {
30594
30601
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksAccordion.AccordionSection, {
30595
30602
  expanded: expanded,
30596
30603
  onToggle: onToggle,
30597
- style: [styles$y.container, containerStyle],
30598
- headerStyle: styles$y.accordionHeader,
30604
+ style: [styles$z.container, containerStyle],
30605
+ headerStyle: styles$z.accordionHeader,
30599
30606
  header: header
30600
30607
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30601
- style: [styles$y.accordionPanel, panelStyle]
30608
+ style: [styles$z.accordionPanel, panelStyle]
30602
30609
  }, children)));
30603
30610
  };
30604
- const styles$y = aphrodite.StyleSheet.create({
30611
+ const styles$z = aphrodite.StyleSheet.create({
30605
30612
  container: {
30606
30613
  backgroundColor: wonderBlocksTokens.color.fadedBlue8,
30607
30614
  marginTop: wonderBlocksTokens.spacing.xSmall_8
@@ -30632,13 +30639,13 @@ const ColorSwatch = props => {
30632
30639
  "aria-label":
30633
30640
  // Don't include an aria label for decorative circles.
30634
30641
  !decorative ? `${color}, ${filled ? "filled" : "open"}` : undefined,
30635
- style: [styles$x.colorSwatch, {
30642
+ style: [styles$y.colorSwatch, {
30636
30643
  border: `4px solid ${perseus.lockedFigureColors[color]}`,
30637
30644
  backgroundColor: filled ? perseus.lockedFigureColors[color] : wonderBlocksTokens.color.white
30638
30645
  }]
30639
30646
  });
30640
30647
  };
30641
- const styles$x = aphrodite.StyleSheet.create({
30648
+ const styles$y = aphrodite.StyleSheet.create({
30642
30649
  colorSwatch: {
30643
30650
  // Add a white outline so that the color swatch is visible when
30644
30651
  // the dropdown option is highlighted with its blue background.
@@ -30657,10 +30664,10 @@ const ColorSelect = props => {
30657
30664
  onChange
30658
30665
  } = props;
30659
30666
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30660
- style: [styles$w.row, style]
30667
+ style: [styles$x.row, style]
30661
30668
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30662
30669
  tag: "label",
30663
- style: styles$w.row
30670
+ style: styles$x.row
30664
30671
  }, "color", /*#__PURE__*/React__namespace.createElement(Strut, {
30665
30672
  size: wonderBlocksTokens.spacing.xxSmall_6
30666
30673
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -30679,7 +30686,7 @@ const ColorSelect = props => {
30679
30686
  })
30680
30687
  })))));
30681
30688
  };
30682
- const styles$w = aphrodite.StyleSheet.create({
30689
+ const styles$x = aphrodite.StyleSheet.create({
30683
30690
  row: {
30684
30691
  display: "flex",
30685
30692
  flexDirection: "row",
@@ -30698,17 +30705,17 @@ const EllipseSwatch = props => {
30698
30705
  } = props;
30699
30706
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30700
30707
  "aria-label": `${color}, stroke ${strokeStyle}, fill ${fillStyle}`,
30701
- style: [styles$v.container, {
30708
+ style: [styles$w.container, {
30702
30709
  border: `4px ${strokeStyle} ${perseus.lockedFigureColors[color]}`
30703
30710
  }]
30704
30711
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30705
- style: [styles$v.innerCircle, {
30712
+ style: [styles$w.innerCircle, {
30706
30713
  backgroundColor: perseus.lockedFigureColors[color],
30707
30714
  opacity: fillStyle === "white" ? 0 : perseus.lockedFigureFillStyles[fillStyle]
30708
30715
  }]
30709
30716
  }));
30710
30717
  };
30711
- const styles$v = aphrodite.StyleSheet.create({
30718
+ const styles$w = aphrodite.StyleSheet.create({
30712
30719
  container: {
30713
30720
  // Add a white outline so that the color swatch is visible when
30714
30721
  // the dropdown option is highlighted with its blue background.
@@ -30734,7 +30741,7 @@ const LineStrokeSelect = props => {
30734
30741
  } = props;
30735
30742
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30736
30743
  tag: "label",
30737
- style: styles$u.lineStrokeSelect
30744
+ style: styles$v.lineStrokeSelect
30738
30745
  }, "stroke", /*#__PURE__*/React__namespace.createElement(Strut, {
30739
30746
  size: wonderBlocksTokens.spacing.xxxSmall_4
30740
30747
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -30751,7 +30758,7 @@ const LineStrokeSelect = props => {
30751
30758
  label: "dashed"
30752
30759
  })));
30753
30760
  };
30754
- const styles$u = aphrodite.StyleSheet.create({
30761
+ const styles$v = aphrodite.StyleSheet.create({
30755
30762
  lineStrokeSelect: {
30756
30763
  display: "flex",
30757
30764
  flexDirection: "row",
@@ -30761,6 +30768,66 @@ const styles$u = aphrodite.StyleSheet.create({
30761
30768
  }
30762
30769
  });
30763
30770
 
30771
+ const {
30772
+ InfoTip: InfoTip$d
30773
+ } = perseus.components;
30774
+ function LockedFigureAria(props) {
30775
+ const {
30776
+ ariaLabel,
30777
+ prePopulatedAriaLabel,
30778
+ onChangeProps
30779
+ } = props;
30780
+ const id = React__namespace.useId();
30781
+ const ariaLabelId = `aria-label-${id}`;
30782
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(Strut, {
30783
+ size: wonderBlocksTokens.spacing.xSmall_8
30784
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30785
+ style: styles$u.row
30786
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30787
+ tag: "label",
30788
+ htmlFor: ariaLabelId
30789
+ }, "Aria label"), /*#__PURE__*/React__namespace.createElement(Spring, null), /*#__PURE__*/React__namespace.createElement(InfoTip$d, null, "Aria label is used by screen readers to describe content to users who may be visually impaired. ", /*#__PURE__*/React__namespace.createElement("br", null), /*#__PURE__*/React__namespace.createElement("br", null), "Populating this field will make it so that users can use a screen reader to navigate to this point and hear the description.", /*#__PURE__*/React__namespace.createElement("br", null), /*#__PURE__*/React__namespace.createElement("br", null), "If you leave this field blank, the point will be hidden from screen readers. Users will not be able to navigate to this point using a screen reader.")), /*#__PURE__*/React__namespace.createElement(Strut, {
30790
+ size: wonderBlocksTokens.spacing.xxSmall_6
30791
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelXSmall, {
30792
+ style: styles$u.caption
30793
+ }, "The figure is hidden from screen readers if this field is left blank."), /*#__PURE__*/React__namespace.createElement(Strut, {
30794
+ size: wonderBlocksTokens.spacing.xxSmall_6
30795
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextArea, {
30796
+ id: ariaLabelId,
30797
+ value: ariaLabel ?? "",
30798
+ onChange: newValue => {
30799
+ onChangeProps({
30800
+ // Save as undefined if the field is empty.
30801
+ ariaLabel: newValue || undefined
30802
+ });
30803
+ },
30804
+ placeholder: "Ex. Point at (x, y)",
30805
+ rows: 1,
30806
+ resizeType: "vertical"
30807
+ }), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
30808
+ kind: "tertiary",
30809
+ startIcon: pencilCircle__default["default"],
30810
+ style: styles$u.button,
30811
+ onClick: () => {
30812
+ onChangeProps({
30813
+ ariaLabel: prePopulatedAriaLabel
30814
+ });
30815
+ }
30816
+ }, "Auto-generate"));
30817
+ }
30818
+ const styles$u = aphrodite.StyleSheet.create({
30819
+ row: {
30820
+ flexDirection: "row",
30821
+ alignItems: "center"
30822
+ },
30823
+ button: {
30824
+ alignSelf: "start"
30825
+ },
30826
+ caption: {
30827
+ color: wonderBlocksTokens.color.offBlack64
30828
+ }
30829
+ });
30830
+
30764
30831
  /**
30765
30832
  * The part of a locked figure settings panel that contains actions
30766
30833
  * for this panel and its associated locked figure, including
@@ -30824,132 +30891,442 @@ const styles$t = aphrodite.StyleSheet.create({
30824
30891
  }
30825
30892
  });
30826
30893
 
30827
- const {
30828
- InfoTip: InfoTip$c
30829
- } = perseus.components;
30830
- const LockedEllipseSettings = props => {
30894
+ /**
30895
+ * LockedLabelSettings is a component that allows the user to edit the
30896
+ * settings of specifically a locked label on the graph within the
30897
+ * Interactive Graph widget.
30898
+ *
30899
+ * Used in the interactive graph editor's locked figures section.
30900
+ */
30901
+ function LockedLabelSettings(props) {
30831
30902
  const {
30832
- center,
30833
- radius,
30834
- angle,
30903
+ type,
30904
+ coord,
30835
30905
  color,
30836
- fillStyle,
30837
- strokeStyle,
30906
+ size,
30907
+ text,
30838
30908
  expanded,
30839
- onToggle,
30840
30909
  onChangeProps,
30841
30910
  onMove,
30842
- onRemove
30911
+ onRemove,
30912
+ onToggle,
30913
+ containerStyle
30843
30914
  } = props;
30844
- function handleColorChange(newValue) {
30845
- onChangeProps({
30846
- color: newValue
30847
- });
30848
- }
30849
30915
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
30850
30916
  expanded: expanded,
30851
30917
  onToggle: onToggle,
30852
- header:
30853
- /*#__PURE__*/
30854
- // Summary: Ellipse, center, radius, color (opacity, dashed)
30855
- React__namespace.createElement(wonderBlocksCore.View, {
30856
- style: styles$s.row
30857
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`), /*#__PURE__*/React__namespace.createElement(Strut, {
30918
+ header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30919
+ style: [styles$s.row, styles$s.accordionHeaderContainer]
30920
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Label (", coord[0], ", ", coord[1], ")"), /*#__PURE__*/React__namespace.createElement(Strut, {
30858
30921
  size: wonderBlocksTokens.spacing.xSmall_8
30859
- }), /*#__PURE__*/React__namespace.createElement(EllipseSwatch, {
30860
- color: props.color,
30861
- fillStyle: fillStyle,
30862
- strokeStyle: strokeStyle
30863
- }))
30864
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30865
- style: styles$s.row
30922
+ }), text !== "" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
30923
+ style: [{
30924
+ backgroundColor: wonderBlocksTokens.color.white,
30925
+ color: perseus.lockedFigureColors[color]
30926
+ }, styles$s.accordionHeader]
30927
+ }, text)),
30928
+ containerStyle: containerStyle
30866
30929
  }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
30867
- coord: center,
30868
- style: styles$s.spaceUnder,
30869
- onChange: newCoords => onChangeProps({
30870
- center: newCoords
30871
- })
30872
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30930
+ coord: coord,
30931
+ onChange: newCoords => {
30932
+ onChangeProps({
30933
+ coord: newCoords
30934
+ });
30935
+ },
30873
30936
  style: styles$s.spaceUnder
30874
- }, /*#__PURE__*/React__namespace.createElement(InfoTip$c, null, "The coordinates for the center of the ellipse."))), /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
30875
- coord: radius,
30876
- labels: ["x radius", "y radius"],
30877
- style: styles$s.spaceUnder,
30878
- onChange: newCoords => onChangeProps({
30879
- radius: newCoords
30880
- })
30881
- }), /*#__PURE__*/React__namespace.createElement(AngleInput, {
30882
- angle: angle,
30883
- onChange: newAngle => onChangeProps({
30884
- angle: newAngle
30885
- })
30886
- }), /*#__PURE__*/React__namespace.createElement(Strut, {
30887
- size: wonderBlocksTokens.spacing.xSmall_8
30888
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30937
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30938
+ tag: "label",
30889
30939
  style: [styles$s.row, styles$s.spaceUnder]
30940
+ }, "TeX", /*#__PURE__*/React__namespace.createElement(Strut, {
30941
+ size: wonderBlocksTokens.spacing.xSmall_8
30942
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30943
+ value: text,
30944
+ placeholder: "ex. x^2 or \\frac{1}{2}",
30945
+ onChange: newValue => onChangeProps({
30946
+ text: newValue
30947
+ })
30948
+ })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30949
+ style: styles$s.row
30890
30950
  }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30891
30951
  selectedValue: color,
30892
- onChange: handleColorChange
30952
+ onChange: newColor => {
30953
+ onChangeProps({
30954
+ color: newColor
30955
+ });
30956
+ },
30957
+ style: styles$s.spaceUnder
30893
30958
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
30894
30959
  size: wonderBlocksTokens.spacing.medium_16
30895
30960
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30896
30961
  tag: "label",
30897
- style: [styles$s.row, styles$s.truncatedWidth]
30898
- }, "fill", /*#__PURE__*/React__namespace.createElement(Strut, {
30899
- size: wonderBlocksTokens.spacing.xxSmall_6
30962
+ style: styles$s.row
30963
+ }, "size", /*#__PURE__*/React__namespace.createElement(Strut, {
30964
+ size: wonderBlocksTokens.spacing.xSmall_8
30900
30965
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30901
- selectedValue: fillStyle,
30902
- onChange: value => onChangeProps({
30903
- fillStyle: value
30966
+ selectedValue: size,
30967
+ onChange: newValue => onChangeProps({
30968
+ size: newValue
30904
30969
  })
30905
- // Placeholder is required, but never gets used.
30970
+ // Placeholder is required, but never gets used since
30971
+ // we have a label for the select.
30906
30972
  ,
30907
30973
  placeholder: ""
30908
- }, Object.keys(perseus.lockedFigureFillStyles).map(option => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30909
- key: option,
30910
- value: option,
30911
- label: option
30912
- }))))), /*#__PURE__*/React__namespace.createElement(LineStrokeSelect, {
30913
- selectedValue: strokeStyle,
30914
- onChange: value => onChangeProps({
30915
- strokeStyle: value
30916
- })
30917
- }), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
30918
- figureType: props.type,
30974
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30975
+ value: "small",
30976
+ label: "small"
30977
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30978
+ value: "medium",
30979
+ label: "medium"
30980
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30981
+ value: "large",
30982
+ label: "large"
30983
+ })))), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
30984
+ figureType: type,
30919
30985
  onMove: onMove,
30920
30986
  onRemove: onRemove
30921
30987
  }));
30922
- };
30988
+ }
30923
30989
  const styles$s = aphrodite.StyleSheet.create({
30990
+ accordionHeaderContainer: {
30991
+ // Stop the label summary from wrapping.
30992
+ whiteSpace: "nowrap"
30993
+ },
30994
+ accordionHeader: {
30995
+ padding: wonderBlocksTokens.spacing.xxxSmall_4,
30996
+ marginInlineEnd: wonderBlocksTokens.spacing.xSmall_8,
30997
+ borderRadius: wonderBlocksTokens.spacing.xxxSmall_4,
30998
+ textOverflow: "ellipsis",
30999
+ overflow: "hidden"
31000
+ },
30924
31001
  row: {
30925
31002
  display: "flex",
30926
31003
  flexDirection: "row",
30927
- alignItems: "center"
31004
+ alignItems: "center",
31005
+ // Allow truncation, stop bleeding over the edge.
31006
+ minWidth: 0
30928
31007
  },
30929
31008
  spaceUnder: {
30930
31009
  marginBottom: wonderBlocksTokens.spacing.xSmall_8
30931
- },
30932
- truncatedWidth: {
30933
- // Allow truncation, stop bleeding over the edge.
30934
- minWidth: 0
30935
31010
  }
30936
31011
  });
30937
31012
 
30938
- const LineSwatch = props => {
30939
- const {
30940
- color,
30941
- lineStyle
30942
- } = props;
30943
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30944
- style: styles$r.container
30945
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31013
+ const DEFAULT_COLOR = "grayH";
31014
+ function getDefaultFigureForType(type) {
31015
+ switch (type) {
31016
+ case "point":
31017
+ return {
31018
+ type: "point",
31019
+ coord: [0, 0],
31020
+ color: DEFAULT_COLOR,
31021
+ filled: true
31022
+ };
31023
+ case "line":
31024
+ return {
31025
+ type: "line",
31026
+ kind: "line",
31027
+ points: [getDefaultFigureForType("point"), {
31028
+ ...getDefaultFigureForType("point"),
31029
+ coord: [2, 2]
31030
+ }],
31031
+ color: DEFAULT_COLOR,
31032
+ lineStyle: "solid",
31033
+ showPoint1: false,
31034
+ showPoint2: false
31035
+ };
31036
+ case "vector":
31037
+ return {
31038
+ type: "vector",
31039
+ points: [[0, 0], [2, 2]],
31040
+ color: DEFAULT_COLOR
31041
+ };
31042
+ case "ellipse":
31043
+ return {
31044
+ type: "ellipse",
31045
+ center: [0, 0],
31046
+ radius: [1, 1],
31047
+ angle: 0,
31048
+ color: DEFAULT_COLOR,
31049
+ fillStyle: "none",
31050
+ strokeStyle: "solid"
31051
+ };
31052
+ case "polygon":
31053
+ return {
31054
+ type: "polygon",
31055
+ points: [[0, 2], [-1, 0], [1, 0]],
31056
+ color: DEFAULT_COLOR,
31057
+ showVertices: false,
31058
+ fillStyle: "none",
31059
+ strokeStyle: "solid"
31060
+ };
31061
+ case "function":
31062
+ return {
31063
+ type: "function",
31064
+ color: DEFAULT_COLOR,
31065
+ strokeStyle: "solid",
31066
+ equation: "x^2",
31067
+ directionalAxis: "x"
31068
+ };
31069
+ case "label":
31070
+ return {
31071
+ type: "label",
31072
+ coord: [0, 0],
31073
+ text: "",
31074
+ color: DEFAULT_COLOR,
31075
+ size: "medium"
31076
+ };
31077
+ default:
31078
+ throw new wonderStuffCore.UnreachableCaseError(type);
31079
+ }
31080
+ }
31081
+
31082
+ const {
31083
+ InfoTip: InfoTip$c
31084
+ } = perseus.components;
31085
+ const LockedEllipseSettings = props => {
31086
+ const {
31087
+ flags,
31088
+ center,
31089
+ radius,
31090
+ angle,
31091
+ color,
31092
+ labels,
31093
+ ariaLabel,
31094
+ fillStyle,
31095
+ strokeStyle,
31096
+ expanded,
31097
+ onToggle,
31098
+ onChangeProps,
31099
+ onMove,
31100
+ onRemove
31101
+ } = props;
31102
+ function getPrepopulatedAriaLabel() {
31103
+ const isCircle = radius[0] === radius[1];
31104
+ let str = "";
31105
+ if (isCircle) {
31106
+ str += `Circle with radius ${radius[0]}`;
31107
+ } else {
31108
+ str += `Ellipse with x radius ${radius[0]} and y radius ${radius[1]}`;
31109
+ }
31110
+ str += `, centered at (${center[0]}, ${center[1]})`;
31111
+ if (!isCircle && angle !== 0) {
31112
+ str += `, rotated by ${radianToDegree(angle)} degrees`;
31113
+ }
31114
+ if (labels && labels.length > 0) {
31115
+ str += ", with label";
31116
+ // Make it "with labels" instead of "with label" if there are
31117
+ // multiple labels.
31118
+ if (labels.length > 1) {
31119
+ str += "s";
31120
+ }
31121
+
31122
+ // Separate additional labels with commas.
31123
+ str += ` ${labels.map(l => l.text).join(", ")}`;
31124
+ }
31125
+ return str;
31126
+ }
31127
+ function handleCenterChange(newCoord) {
31128
+ const xOffset = newCoord[0] - center[0];
31129
+ const yOffset = newCoord[1] - center[1];
31130
+ const newProps = {
31131
+ center: newCoord
31132
+ };
31133
+
31134
+ // Update the coord by the same amount as the point for all labels
31135
+ newProps.labels = labels?.map(label => ({
31136
+ ...label,
31137
+ coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31138
+ }));
31139
+ onChangeProps(newProps);
31140
+ }
31141
+ function handleColorChange(newValue) {
31142
+ const newProps = {
31143
+ color: newValue
31144
+ };
31145
+
31146
+ // Update the color of the all labels to match the point
31147
+ newProps.labels = labels?.map(label => ({
31148
+ ...label,
31149
+ color: newValue
31150
+ }));
31151
+ onChangeProps(newProps);
31152
+ }
31153
+ function handleLabelChange(updatedLabel, labelIndex) {
31154
+ if (!labels) {
31155
+ return;
31156
+ }
31157
+ const updatedLabels = [...labels];
31158
+ updatedLabels[labelIndex] = {
31159
+ ...labels[labelIndex],
31160
+ ...updatedLabel
31161
+ };
31162
+ onChangeProps({
31163
+ labels: updatedLabels
31164
+ });
31165
+ }
31166
+ function handleLabelRemove(labelIndex) {
31167
+ if (!labels) {
31168
+ return;
31169
+ }
31170
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31171
+ onChangeProps({
31172
+ labels: updatedLabels
31173
+ });
31174
+ }
31175
+ return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31176
+ expanded: expanded,
31177
+ onToggle: onToggle,
31178
+ header:
31179
+ /*#__PURE__*/
31180
+ // Summary: Ellipse, center, radius, color (opacity, dashed)
31181
+ React__namespace.createElement(wonderBlocksCore.View, {
31182
+ style: styles$r.row
31183
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`), /*#__PURE__*/React__namespace.createElement(Strut, {
31184
+ size: wonderBlocksTokens.spacing.xSmall_8
31185
+ }), /*#__PURE__*/React__namespace.createElement(EllipseSwatch, {
31186
+ color: props.color,
31187
+ fillStyle: fillStyle,
31188
+ strokeStyle: strokeStyle
31189
+ }))
31190
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31191
+ style: styles$r.row
31192
+ }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31193
+ coord: center,
31194
+ style: styles$r.spaceUnder,
31195
+ onChange: handleCenterChange
31196
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31197
+ style: styles$r.spaceUnder
31198
+ }, /*#__PURE__*/React__namespace.createElement(InfoTip$c, null, "The coordinates for the center of the ellipse."))), /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31199
+ coord: radius,
31200
+ labels: ["x radius", "y radius"],
31201
+ style: styles$r.spaceUnder,
31202
+ onChange: newCoords => onChangeProps({
31203
+ radius: newCoords
31204
+ })
31205
+ }), /*#__PURE__*/React__namespace.createElement(AngleInput, {
31206
+ angle: angle,
31207
+ onChange: newAngle => onChangeProps({
31208
+ angle: newAngle
31209
+ })
31210
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
31211
+ size: wonderBlocksTokens.spacing.xSmall_8
31212
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31213
+ style: [styles$r.row, styles$r.spaceUnder]
31214
+ }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31215
+ selectedValue: color,
31216
+ onChange: handleColorChange
31217
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
31218
+ size: wonderBlocksTokens.spacing.medium_16
31219
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31220
+ tag: "label",
31221
+ style: [styles$r.row, styles$r.truncatedWidth]
31222
+ }, "fill", /*#__PURE__*/React__namespace.createElement(Strut, {
31223
+ size: wonderBlocksTokens.spacing.xxSmall_6
31224
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
31225
+ selectedValue: fillStyle,
31226
+ onChange: value => onChangeProps({
31227
+ fillStyle: value
31228
+ })
31229
+ // Placeholder is required, but never gets used.
31230
+ ,
31231
+ placeholder: ""
31232
+ }, Object.keys(perseus.lockedFigureFillStyles).map(option => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31233
+ key: option,
31234
+ value: option,
31235
+ label: option
31236
+ }))))), /*#__PURE__*/React__namespace.createElement(LineStrokeSelect, {
31237
+ selectedValue: strokeStyle,
31238
+ onChange: value => onChangeProps({
31239
+ strokeStyle: value
31240
+ })
31241
+ }), flags?.["mafs"]?.["locked-figures-aria"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
31242
+ size: wonderBlocksTokens.spacing.small_12
31243
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31244
+ style: styles$r.horizontalRule
31245
+ }), /*#__PURE__*/React__namespace.createElement(LockedFigureAria, {
31246
+ ariaLabel: ariaLabel,
31247
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
31248
+ onChangeProps: newProps => {
31249
+ onChangeProps(newProps);
31250
+ }
31251
+ })), flags?.["mafs"]?.["locked-ellipse-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
31252
+ size: wonderBlocksTokens.spacing.xxxSmall_4
31253
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31254
+ style: styles$r.horizontalRule
31255
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
31256
+ size: wonderBlocksTokens.spacing.small_12
31257
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, null, "Visible labels"), labels?.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
31258
+ expanded: true,
31259
+ onChangeProps: newLabel => {
31260
+ handleLabelChange(newLabel, labelIndex);
31261
+ },
31262
+ onRemove: () => {
31263
+ handleLabelRemove(labelIndex);
31264
+ },
31265
+ containerStyle: styles$r.labelContainer
31266
+ }))), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
31267
+ kind: "tertiary",
31268
+ startIcon: plusCircle__default["default"],
31269
+ onClick: () => {
31270
+ const newLabel = {
31271
+ ...getDefaultFigureForType("label"),
31272
+ coord: [center[0],
31273
+ // Additional vertical offset for each
31274
+ // label so they don't overlap.
31275
+ center[1] - (labels?.length ?? 0)],
31276
+ // Default to the same color as the ellipse
31277
+ color: color
31278
+ };
31279
+ onChangeProps({
31280
+ labels: [...(labels ?? []), newLabel]
31281
+ });
31282
+ },
31283
+ style: styles$r.addButton
31284
+ }, "Add visible label")), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31285
+ figureType: props.type,
31286
+ onMove: onMove,
31287
+ onRemove: onRemove
31288
+ }));
31289
+ };
31290
+ const styles$r = aphrodite.StyleSheet.create({
31291
+ row: {
31292
+ display: "flex",
31293
+ flexDirection: "row",
31294
+ alignItems: "center"
31295
+ },
31296
+ spaceUnder: {
31297
+ marginBottom: wonderBlocksTokens.spacing.xSmall_8
31298
+ },
31299
+ truncatedWidth: {
31300
+ // Allow truncation, stop bleeding over the edge.
31301
+ minWidth: 0
31302
+ },
31303
+ addButton: {
31304
+ alignSelf: "start"
31305
+ },
31306
+ labelContainer: {
31307
+ backgroundColor: wonderBlocksTokens.color.white
31308
+ },
31309
+ horizontalRule: {
31310
+ height: 1,
31311
+ backgroundColor: wonderBlocksTokens.color.offBlack16
31312
+ }
31313
+ });
31314
+
31315
+ const LineSwatch = props => {
31316
+ const {
31317
+ color,
31318
+ lineStyle
31319
+ } = props;
31320
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31321
+ style: styles$q.container
31322
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30946
31323
  "aria-label": `${color}, ${lineStyle}`,
30947
- style: [styles$r.lineSwatch, {
31324
+ style: [styles$q.lineSwatch, {
30948
31325
  border: `5px ${lineStyle} ${perseus.lockedFigureColors[color]}`
30949
31326
  }]
30950
31327
  }));
30951
31328
  };
30952
- const styles$r = aphrodite.StyleSheet.create({
31329
+ const styles$q = aphrodite.StyleSheet.create({
30953
31330
  container: {
30954
31331
  backgroundColor: wonderBlocksTokens.color.white,
30955
31332
  justifyContent: "center",
@@ -30967,25 +31344,21 @@ const examples = {
30967
31344
  trigonometric: ["sin(x) * 3", "arctan(2x) + 4"]
30968
31345
  };
30969
31346
 
30970
- /**
30971
- * LockedFunctionSettings is a component that allows the user to edit the
30972
- * settings of specifically a locked function on the graph.
30973
- *
30974
- * Used in the interactive graph editor's locked figures section.
30975
- */
30976
31347
  const LockedFunctionSettings = props => {
30977
31348
  const {
31349
+ flags,
30978
31350
  color: lineColor,
30979
31351
  strokeStyle,
30980
31352
  equation,
30981
31353
  directionalAxis,
30982
31354
  domain,
31355
+ labels,
31356
+ ariaLabel,
30983
31357
  onChangeProps,
30984
31358
  onMove,
30985
31359
  onRemove
30986
31360
  } = props;
30987
31361
  const equationPrefix = directionalAxis === "x" ? "y=" : "x=";
30988
- const domainRangeText = directionalAxis === "x" ? "domain" : "range";
30989
31362
  const lineLabel = `Function (${equationPrefix}${equation})`;
30990
31363
 
30991
31364
  // Tracking the string value of domain/range constraints to handle interim state of
@@ -30997,6 +31370,27 @@ const LockedFunctionSettings = props => {
30997
31370
  // "useEffect" used to maintain parity between domain/range constraints and their string representation.
30998
31371
  setDomainEntries([domain && domain[0] !== -Infinity ? domain[0].toString() : "", domain && domain[1] !== Infinity ? domain[1].toString() : ""]);
30999
31372
  }, [domain]);
31373
+ function getPrepopulatedAriaLabel() {
31374
+ let str = `Function with equation ${equationPrefix}${equation}`;
31375
+
31376
+ // Add the domain/range constraints to the aria label
31377
+ // if they are not the default values.
31378
+ if (domain && !(domain[0] === -Infinity && domain[1] === Infinity)) {
31379
+ str += `, domain from ${domain[0]} to ${domain[1]}`;
31380
+ }
31381
+ if (labels && labels.length > 0) {
31382
+ str += ", with label";
31383
+ // Make it "with labels" instead of "with label" if there are
31384
+ // multiple labels.
31385
+ if (labels.length > 1) {
31386
+ str += "s";
31387
+ }
31388
+
31389
+ // Separate additional labels with commas.
31390
+ str += ` ${labels.map(l => l.text).join(", ")}`;
31391
+ }
31392
+ return str;
31393
+ }
31000
31394
 
31001
31395
  // Generic function for handling property changes (except for 'domain/range')
31002
31396
  function handlePropChange(property, newValue) {
@@ -31022,21 +31416,55 @@ const LockedFunctionSettings = props => {
31022
31416
  } else if (newValueString === "" && limitIndex === 1) {
31023
31417
  newValue = Infinity;
31024
31418
  }
31025
- newDomain[limitIndex] = newValue;
31419
+ newDomain[limitIndex] = newValue;
31420
+ onChangeProps({
31421
+ domain: newDomain
31422
+ });
31423
+ }
31424
+ const exampleCategories = Object.keys(examples);
31425
+ const exampleCategorySelected = exampleCategory !== "";
31426
+ const exampleContent = exampleCategorySelected ? examples[exampleCategory] : ["Select category to see example equations"];
31427
+ function handleColorChange(newValue) {
31428
+ const newProps = {
31429
+ color: newValue
31430
+ };
31431
+
31432
+ // Update the color of the all labels to match the point
31433
+ newProps.labels = labels?.map(label => ({
31434
+ ...label,
31435
+ color: newValue
31436
+ }));
31437
+ onChangeProps(newProps);
31438
+ }
31439
+ function handleLabelChange(updatedLabel, labelIndex) {
31440
+ if (!labels) {
31441
+ return;
31442
+ }
31443
+ const updatedLabels = [...labels];
31444
+ updatedLabels[labelIndex] = {
31445
+ ...labels[labelIndex],
31446
+ ...updatedLabel
31447
+ };
31448
+ onChangeProps({
31449
+ labels: updatedLabels
31450
+ });
31451
+ }
31452
+ function handleLabelRemove(labelIndex) {
31453
+ if (!labels) {
31454
+ return;
31455
+ }
31456
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31026
31457
  onChangeProps({
31027
- domain: newDomain
31458
+ labels: updatedLabels
31028
31459
  });
31029
31460
  }
31030
- const exampleCategories = Object.keys(examples);
31031
- const exampleCategorySelected = exampleCategory !== "";
31032
- const exampleContent = exampleCategorySelected ? examples[exampleCategory] : ["Select category to see example equations"];
31033
31461
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31034
31462
  expanded: props.expanded,
31035
31463
  onToggle: props.onToggle,
31036
31464
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31037
- style: styles$q.row
31465
+ style: styles$p.row
31038
31466
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
31039
- style: styles$q.accordionHeader
31467
+ style: styles$p.accordionHeader
31040
31468
  }, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
31041
31469
  size: wonderBlocksTokens.spacing.xSmall_8
31042
31470
  }), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
@@ -31044,12 +31472,10 @@ const LockedFunctionSettings = props => {
31044
31472
  lineStyle: strokeStyle
31045
31473
  }))
31046
31474
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31047
- style: [styles$q.row, styles$q.spaceUnder]
31475
+ style: [styles$p.row, styles$p.spaceUnder]
31048
31476
  }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31049
31477
  selectedValue: lineColor,
31050
- onChange: newValue => {
31051
- handlePropChange("color", newValue);
31052
- }
31478
+ onChange: handleColorChange
31053
31479
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
31054
31480
  size: wonderBlocksTokens.spacing.small_12
31055
31481
  }), /*#__PURE__*/React__namespace.createElement(LineStrokeSelect, {
@@ -31058,14 +31484,14 @@ const LockedFunctionSettings = props => {
31058
31484
  handlePropChange("strokeStyle", newValue);
31059
31485
  }
31060
31486
  })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31061
- style: [styles$q.row, styles$q.rowSpace]
31487
+ style: [styles$p.row, styles$p.rowSpace]
31062
31488
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
31063
31489
  selectedValue: directionalAxis,
31064
31490
  onChange: newValue => {
31065
31491
  handlePropChange("directionalAxis", newValue);
31066
31492
  },
31067
31493
  "aria-label": "equation prefix",
31068
- style: [styles$q.dropdownLabel, styles$q.axisMenu]
31494
+ style: [styles$p.dropdownLabel, styles$p.axisMenu]
31069
31495
  // Placeholder is required, but never gets used.
31070
31496
  ,
31071
31497
  placeholder: ""
@@ -31084,17 +31510,17 @@ const LockedFunctionSettings = props => {
31084
31510
  onChange: newValue => {
31085
31511
  handlePropChange("equation", newValue);
31086
31512
  },
31087
- style: [styles$q.textField]
31513
+ style: [styles$p.textField]
31088
31514
  })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31089
- style: [styles$q.row, styles$q.rowSpace]
31515
+ style: [styles$p.row, styles$p.rowSpace]
31090
31516
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31091
31517
  tag: "label",
31092
- style: [styles$q.dropdownLabel, styles$q.domainMin]
31093
- }, `${domainRangeText} min`, /*#__PURE__*/React__namespace.createElement(Strut, {
31518
+ style: [styles$p.dropdownLabel, styles$p.domainMin]
31519
+ }, "domain min", /*#__PURE__*/React__namespace.createElement(Strut, {
31094
31520
  size: wonderBlocksTokens.spacing.xxSmall_6
31095
31521
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
31096
31522
  type: "number",
31097
- style: styles$q.domainMinField,
31523
+ style: styles$p.domainMinField,
31098
31524
  value: domainEntries[0],
31099
31525
  onChange: newValue => {
31100
31526
  handleDomainChange(0, newValue);
@@ -31103,13 +31529,13 @@ const LockedFunctionSettings = props => {
31103
31529
  size: wonderBlocksTokens.spacing.medium_16
31104
31530
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31105
31531
  tag: "label",
31106
- "aria-label": `${domainRangeText} max`,
31107
- style: [styles$q.dropdownLabel, styles$q.domainMax]
31532
+ "aria-label": "domain max",
31533
+ style: [styles$p.dropdownLabel, styles$p.domainMax]
31108
31534
  }, "max", /*#__PURE__*/React__namespace.createElement(Strut, {
31109
31535
  size: wonderBlocksTokens.spacing.xxSmall_6
31110
31536
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
31111
31537
  type: "number",
31112
- style: styles$q.domainMaxField,
31538
+ style: styles$p.domainMaxField,
31113
31539
  value: domainEntries[1],
31114
31540
  onChange: newValue => {
31115
31541
  handleDomainChange(1, newValue);
@@ -31117,11 +31543,11 @@ const LockedFunctionSettings = props => {
31117
31543
  }))), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31118
31544
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Example Functions"),
31119
31545
  expanded: false,
31120
- containerStyle: styles$q.exampleWorkspace,
31121
- panelStyle: styles$q.exampleAccordionPanel
31546
+ containerStyle: styles$p.exampleWorkspace,
31547
+ panelStyle: styles$p.exampleAccordionPanel
31122
31548
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31123
31549
  tag: "label",
31124
- style: styles$q.dropdownLabel
31550
+ style: styles$p.dropdownLabel
31125
31551
  }, "Choose a category", /*#__PURE__*/React__namespace.createElement(Strut, {
31126
31552
  size: wonderBlocksTokens.spacing.xxSmall_6
31127
31553
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -31135,13 +31561,58 @@ const LockedFunctionSettings = props => {
31135
31561
  label: category
31136
31562
  });
31137
31563
  }))), exampleCategorySelected && /*#__PURE__*/React__namespace.createElement("ul", {
31138
- className: aphrodite.css(styles$q.exampleContainer)
31564
+ className: aphrodite.css(styles$p.exampleContainer)
31139
31565
  }, exampleContent.map((example, index) => /*#__PURE__*/React__namespace.createElement(ExampleItem, {
31566
+ key: index,
31140
31567
  category: exampleCategory,
31141
31568
  example: example,
31142
31569
  index: index,
31143
31570
  pasteEquationFn: handlePropChange
31144
- })))), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31571
+ })))), flags?.["mafs"]?.["locked-figures-aria"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
31572
+ size: wonderBlocksTokens.spacing.small_12
31573
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31574
+ style: styles$p.horizontalRule
31575
+ }), /*#__PURE__*/React__namespace.createElement(LockedFigureAria, {
31576
+ ariaLabel: ariaLabel,
31577
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
31578
+ onChangeProps: newProps => {
31579
+ onChangeProps(newProps);
31580
+ }
31581
+ })), flags?.["mafs"]?.["locked-function-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
31582
+ size: wonderBlocksTokens.spacing.xxxSmall_4
31583
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31584
+ style: styles$p.horizontalRule
31585
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
31586
+ size: wonderBlocksTokens.spacing.small_12
31587
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, null, "Visible labels"), labels?.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({
31588
+ key: labelIndex
31589
+ }, label, {
31590
+ expanded: true,
31591
+ onChangeProps: newLabel => {
31592
+ handleLabelChange(newLabel, labelIndex);
31593
+ },
31594
+ onRemove: () => {
31595
+ handleLabelRemove(labelIndex);
31596
+ },
31597
+ containerStyle: styles$p.labelContainer
31598
+ }))), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
31599
+ kind: "tertiary",
31600
+ startIcon: plusCircle__default["default"],
31601
+ onClick: () => {
31602
+ const newLabel = {
31603
+ ...getDefaultFigureForType("label"),
31604
+ // Vertical offset for each label so they
31605
+ // don't overlap.
31606
+ coord: [0, -(labels?.length ?? 0)],
31607
+ // Default to the same color as the function
31608
+ color: lineColor
31609
+ };
31610
+ onChangeProps({
31611
+ labels: [...(labels ?? []), newLabel]
31612
+ });
31613
+ },
31614
+ style: styles$p.addButton
31615
+ }, "Add visible label")), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31145
31616
  figureType: props.type,
31146
31617
  onMove: onMove,
31147
31618
  onRemove: onRemove
@@ -31157,29 +31628,29 @@ const ExampleItem = props => {
31157
31628
  const exampleId = React.useId();
31158
31629
  return /*#__PURE__*/React__namespace.createElement("li", {
31159
31630
  key: `${category}-${index}`,
31160
- className: aphrodite.css(styles$q.exampleRow)
31631
+ className: aphrodite.css(styles$p.exampleRow)
31161
31632
  }, /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
31162
31633
  icon: autoPasteIcon__default["default"],
31163
31634
  "aria-label": "paste example",
31164
31635
  "aria-describedby": exampleId,
31165
31636
  onClick: () => pasteEquationFn("equation", example),
31166
31637
  size: "medium",
31167
- style: styles$q.copyPasteButton
31638
+ style: styles$p.copyPasteButton
31168
31639
  }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
31169
31640
  icon: copyIcon__default["default"],
31170
31641
  "aria-label": "copy example",
31171
31642
  "aria-describedby": exampleId,
31172
31643
  onClick: () => navigator.clipboard.writeText(example),
31173
31644
  size: "medium",
31174
- style: styles$q.copyPasteButton
31645
+ style: styles$p.copyPasteButton
31175
31646
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
31176
31647
  size: wonderBlocksTokens.spacing.xxxSmall_4
31177
31648
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31178
- style: styles$q.exampleContent,
31649
+ style: styles$p.exampleContent,
31179
31650
  id: exampleId
31180
31651
  }, example));
31181
31652
  };
31182
- const styles$q = aphrodite.StyleSheet.create({
31653
+ const styles$p = aphrodite.StyleSheet.create({
31183
31654
  accordionHeader: {
31184
31655
  textOverflow: "ellipsis",
31185
31656
  // A maximum width needs to be specified in order for the ellipsis to work.
@@ -31270,227 +31741,48 @@ const styles$q = aphrodite.StyleSheet.create({
31270
31741
  },
31271
31742
  textField: {
31272
31743
  flexGrow: "1"
31273
- }
31274
- });
31275
-
31276
- /**
31277
- * LockedLabelSettings is a component that allows the user to edit the
31278
- * settings of specifically a locked label on the graph within the
31279
- * Interactive Graph widget.
31280
- *
31281
- * Used in the interactive graph editor's locked figures section.
31282
- */
31283
- function LockedLabelSettings(props) {
31284
- const {
31285
- type,
31286
- coord,
31287
- color,
31288
- size,
31289
- text,
31290
- expanded,
31291
- onChangeProps,
31292
- onMove,
31293
- onRemove,
31294
- onToggle,
31295
- containerStyle
31296
- } = props;
31297
- return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31298
- expanded: expanded,
31299
- onToggle: onToggle,
31300
- header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31301
- style: [styles$p.row, styles$p.accordionHeaderContainer]
31302
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Label (", coord[0], ", ", coord[1], ")"), /*#__PURE__*/React__namespace.createElement(Strut, {
31303
- size: wonderBlocksTokens.spacing.xSmall_8
31304
- }), text !== "" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
31305
- style: [{
31306
- backgroundColor: wonderBlocksTokens.color.white,
31307
- color: perseus.lockedFigureColors[color]
31308
- }, styles$p.accordionHeader]
31309
- }, text)),
31310
- containerStyle: containerStyle
31311
- }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31312
- coord: coord,
31313
- onChange: newCoords => {
31314
- onChangeProps({
31315
- coord: newCoords
31316
- });
31317
- },
31318
- style: styles$p.spaceUnder
31319
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31320
- tag: "label",
31321
- style: [styles$p.row, styles$p.spaceUnder]
31322
- }, "TeX", /*#__PURE__*/React__namespace.createElement(Strut, {
31323
- size: wonderBlocksTokens.spacing.xSmall_8
31324
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
31325
- value: text,
31326
- placeholder: "ex. x^2 or \\frac{1}{2}",
31327
- onChange: newValue => onChangeProps({
31328
- text: newValue
31329
- })
31330
- })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31331
- style: styles$p.row
31332
- }, onMove && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31333
- selectedValue: color,
31334
- onChange: newColor => {
31335
- onChangeProps({
31336
- color: newColor
31337
- });
31338
- },
31339
- style: styles$p.spaceUnder
31340
- }), /*#__PURE__*/React__namespace.createElement(Strut, {
31341
- size: wonderBlocksTokens.spacing.medium_16
31342
- })), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31343
- tag: "label",
31344
- style: styles$p.row
31345
- }, "size", /*#__PURE__*/React__namespace.createElement(Strut, {
31346
- size: wonderBlocksTokens.spacing.xSmall_8
31347
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
31348
- selectedValue: size,
31349
- onChange: newValue => onChangeProps({
31350
- size: newValue
31351
- })
31352
- // Placeholder is required, but never gets used since
31353
- // we have a label for the select.
31354
- ,
31355
- placeholder: ""
31356
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31357
- value: "small",
31358
- label: "small"
31359
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31360
- value: "medium",
31361
- label: "medium"
31362
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31363
- value: "large",
31364
- label: "large"
31365
- })))), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31366
- figureType: type,
31367
- onMove: onMove,
31368
- onRemove: onRemove
31369
- }));
31370
- }
31371
- const styles$p = aphrodite.StyleSheet.create({
31372
- accordionHeaderContainer: {
31373
- // Stop the label summary from wrapping.
31374
- whiteSpace: "nowrap"
31375
31744
  },
31376
- accordionHeader: {
31377
- padding: wonderBlocksTokens.spacing.xxxSmall_4,
31378
- marginInlineEnd: wonderBlocksTokens.spacing.xSmall_8,
31379
- borderRadius: wonderBlocksTokens.spacing.xxxSmall_4,
31380
- textOverflow: "ellipsis",
31381
- overflow: "hidden"
31745
+ // Label settings styles
31746
+ addButton: {
31747
+ alignSelf: "start"
31382
31748
  },
31383
- row: {
31384
- display: "flex",
31385
- flexDirection: "row",
31386
- alignItems: "center",
31387
- // Allow truncation, stop bleeding over the edge.
31388
- minWidth: 0
31749
+ horizontalRule: {
31750
+ height: 1,
31751
+ backgroundColor: wonderBlocksTokens.color.offBlack16
31389
31752
  },
31390
- spaceUnder: {
31391
- marginBottom: wonderBlocksTokens.spacing.xSmall_8
31392
- }
31393
- });
31394
-
31395
- const LabeledSwitch = props => {
31396
- const {
31397
- checked,
31398
- label,
31399
- style,
31400
- onChange
31401
- } = props;
31402
- const ids = wonderBlocksCore.useUniqueIdWithMock();
31403
- const switchId = ids.get("switch");
31404
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31405
- style: [styles$o.row, style]
31406
- }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
31407
- id: switchId,
31408
- checked: checked,
31409
- onChange: onChange
31410
- }), /*#__PURE__*/React__namespace.createElement(Strut, {
31411
- size: wonderBlocksTokens.spacing.xSmall_8
31412
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31413
- tag: "label",
31414
- htmlFor: switchId
31415
- }, label));
31416
- };
31417
- const styles$o = aphrodite.StyleSheet.create({
31418
- row: {
31419
- flexDirection: "row",
31420
- alignItems: "center"
31421
- }
31422
- });
31423
-
31424
- const DEFAULT_COLOR = "grayH";
31425
- function getDefaultFigureForType(type) {
31426
- switch (type) {
31427
- case "point":
31428
- return {
31429
- type: "point",
31430
- coord: [0, 0],
31431
- color: DEFAULT_COLOR,
31432
- filled: true,
31433
- labels: []
31434
- };
31435
- case "line":
31436
- return {
31437
- type: "line",
31438
- kind: "line",
31439
- points: [getDefaultFigureForType("point"), {
31440
- ...getDefaultFigureForType("point"),
31441
- coord: [2, 2]
31442
- }],
31443
- color: DEFAULT_COLOR,
31444
- lineStyle: "solid",
31445
- showPoint1: false,
31446
- showPoint2: false,
31447
- labels: []
31448
- };
31449
- case "vector":
31450
- return {
31451
- type: "vector",
31452
- points: [[0, 0], [2, 2]],
31453
- color: DEFAULT_COLOR
31454
- };
31455
- case "ellipse":
31456
- return {
31457
- type: "ellipse",
31458
- center: [0, 0],
31459
- radius: [1, 1],
31460
- angle: 0,
31461
- color: DEFAULT_COLOR,
31462
- fillStyle: "none",
31463
- strokeStyle: "solid"
31464
- };
31465
- case "polygon":
31466
- return {
31467
- type: "polygon",
31468
- points: [[0, 2], [-1, 0], [1, 0]],
31469
- color: DEFAULT_COLOR,
31470
- showVertices: false,
31471
- fillStyle: "none",
31472
- strokeStyle: "solid"
31473
- };
31474
- case "function":
31475
- return {
31476
- type: "function",
31477
- color: DEFAULT_COLOR,
31478
- strokeStyle: "solid",
31479
- equation: "x^2",
31480
- directionalAxis: "x"
31481
- };
31482
- case "label":
31483
- return {
31484
- type: "label",
31485
- coord: [0, 0],
31486
- text: "",
31487
- color: DEFAULT_COLOR,
31488
- size: "medium"
31489
- };
31490
- default:
31491
- throw new wonderStuffCore.UnreachableCaseError(type);
31753
+ labelContainer: {
31754
+ backgroundColor: wonderBlocksTokens.color.white
31492
31755
  }
31493
- }
31756
+ });
31757
+
31758
+ const LabeledSwitch = props => {
31759
+ const {
31760
+ checked,
31761
+ label,
31762
+ style,
31763
+ onChange
31764
+ } = props;
31765
+ const ids = wonderBlocksCore.useUniqueIdWithMock();
31766
+ const switchId = ids.get("switch");
31767
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31768
+ style: [styles$o.row, style]
31769
+ }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
31770
+ id: switchId,
31771
+ checked: checked,
31772
+ onChange: onChange
31773
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
31774
+ size: wonderBlocksTokens.spacing.xSmall_8
31775
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31776
+ tag: "label",
31777
+ htmlFor: switchId
31778
+ }, label));
31779
+ };
31780
+ const styles$o = aphrodite.StyleSheet.create({
31781
+ row: {
31782
+ flexDirection: "row",
31783
+ alignItems: "center"
31784
+ }
31785
+ });
31494
31786
 
31495
31787
  const LockedPointSettings = props => {
31496
31788
  const {
@@ -31500,6 +31792,7 @@ const LockedPointSettings = props => {
31500
31792
  color: pointColor,
31501
31793
  filled = true,
31502
31794
  labels,
31795
+ ariaLabel,
31503
31796
  onChangeProps,
31504
31797
  onMove,
31505
31798
  onRemove,
@@ -31510,16 +31803,43 @@ const LockedPointSettings = props => {
31510
31803
  onToggle
31511
31804
  } = props;
31512
31805
  const isDefiningPoint = !onMove && !onRemove;
31806
+
31807
+ /**
31808
+ * Get a prepopulated aria label for the point.
31809
+ *
31810
+ * If the point has no labels, the aria label will just be
31811
+ * "Point at (x, y)".
31812
+ *
31813
+ * If the point has labels, the aria label will be
31814
+ * "Point at (x, y) with label1, label2, label3".
31815
+ */
31816
+ function getPrepopulatedAriaLabel() {
31817
+ let str = `Point at (${coord[0]}, ${coord[1]})`;
31818
+ if (labels && labels.length > 0) {
31819
+ str += " with label";
31820
+ // Make it "with labels" instead of "with label" if there are
31821
+ // multiple labels.
31822
+ if (labels.length > 1) {
31823
+ str += "s";
31824
+ }
31825
+
31826
+ // Separate additional labels with commas.
31827
+ str += ` ${labels.map(l => l.text).join(", ")}`;
31828
+ }
31829
+ return str;
31830
+ }
31513
31831
  function handleColorChange(newValue) {
31514
31832
  const newProps = {
31515
31833
  color: newValue
31516
31834
  };
31517
31835
 
31518
31836
  // Update the color of the all labels to match the point
31519
- newProps.labels = labels.map(label => ({
31520
- ...label,
31521
- color: newValue
31522
- }));
31837
+ if (labels) {
31838
+ newProps.labels = labels.map(label => ({
31839
+ ...label,
31840
+ color: newValue
31841
+ }));
31842
+ }
31523
31843
  onChangeProps(newProps);
31524
31844
  }
31525
31845
  function handleCoordChange(newCoord) {
@@ -31530,13 +31850,18 @@ const LockedPointSettings = props => {
31530
31850
  };
31531
31851
 
31532
31852
  // Update the coord by the same amount as the point for all labels
31533
- newProps.labels = labels.map(label => ({
31534
- ...label,
31535
- coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31536
- }));
31853
+ if (labels) {
31854
+ newProps.labels = labels.map(label => ({
31855
+ ...label,
31856
+ coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31857
+ }));
31858
+ }
31537
31859
  onChangeProps(newProps);
31538
31860
  }
31539
31861
  function handleLabelChange(updatedLabel, labelIndex) {
31862
+ if (!labels) {
31863
+ return;
31864
+ }
31540
31865
  const updatedLabels = [...labels];
31541
31866
  updatedLabels[labelIndex] = {
31542
31867
  ...labels[labelIndex],
@@ -31547,6 +31872,9 @@ const LockedPointSettings = props => {
31547
31872
  });
31548
31873
  }
31549
31874
  function handleLabelRemove(labelIndex) {
31875
+ if (!labels) {
31876
+ return;
31877
+ }
31550
31878
  const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31551
31879
  onChangeProps({
31552
31880
  labels: updatedLabels
@@ -31589,7 +31917,23 @@ const LockedPointSettings = props => {
31589
31917
  filled: !newValue
31590
31918
  });
31591
31919
  }
31592
- })), (!isDefiningPoint && flags?.["mafs"]?.["locked-point-labels"] || isDefiningPoint && flags?.["mafs"]?.["locked-line-labels"]) && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, labels.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
31920
+ })), !isDefiningPoint && flags?.["mafs"]?.["locked-figures-aria"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
31921
+ size: wonderBlocksTokens.spacing.small_12
31922
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31923
+ style: styles$n.horizontalRule
31924
+ }), /*#__PURE__*/React__namespace.createElement(LockedFigureAria, {
31925
+ ariaLabel: ariaLabel,
31926
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
31927
+ onChangeProps: newProps => {
31928
+ onChangeProps(newProps);
31929
+ }
31930
+ })), (!isDefiningPoint && flags?.["mafs"]?.["locked-point-labels"] || isDefiningPoint && flags?.["mafs"]?.["locked-line-labels"]) && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
31931
+ size: wonderBlocksTokens.spacing.xxxSmall_4
31932
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31933
+ style: styles$n.horizontalRule
31934
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
31935
+ size: wonderBlocksTokens.spacing.small_12
31936
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, null, "Visible labels"), labels?.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
31593
31937
  containerStyle: !isDefiningPoint && styles$n.lockedPointLabelContainer,
31594
31938
  expanded: true,
31595
31939
  onChangeProps: newLabel => {
@@ -31610,12 +31954,12 @@ const LockedPointSettings = props => {
31610
31954
  coord: [coord[0] + 0.5,
31611
31955
  // Additional offset for each label so
31612
31956
  // they don't overlap.
31613
- coord[1] - 1 * labels?.length],
31957
+ coord[1] - 1 * (labels?.length ?? 0)],
31614
31958
  // Default to the same color as the point
31615
31959
  color: pointColor
31616
31960
  };
31617
31961
  onChangeProps({
31618
- labels: [...labels, newLabel]
31962
+ labels: [...(labels ?? []), newLabel]
31619
31963
  });
31620
31964
  },
31621
31965
  style: styles$n.addButton
@@ -31651,6 +31995,10 @@ const styles$n = aphrodite.StyleSheet.create({
31651
31995
  },
31652
31996
  addButton: {
31653
31997
  alignSelf: "start"
31998
+ },
31999
+ horizontalRule: {
32000
+ height: 1,
32001
+ backgroundColor: wonderBlocksTokens.color.offBlack16
31654
32002
  }
31655
32003
  });
31656
32004
 
@@ -31665,6 +32013,7 @@ const LockedLineSettings = props => {
31665
32013
  showPoint1,
31666
32014
  showPoint2,
31667
32015
  labels,
32016
+ ariaLabel,
31668
32017
  onChangeProps,
31669
32018
  onMove,
31670
32019
  onRemove
@@ -31676,6 +32025,21 @@ const LockedLineSettings = props => {
31676
32025
 
31677
32026
  // Check if the line has length 0.
31678
32027
  const isInvalid = kmath.vector.equal(point1.coord, point2.coord);
32028
+ function getPrepopulatedAriaLabel() {
32029
+ let str = `${capitalizeKind} from (${point1.coord[0]}, ${point1.coord[1]}) to (${point2.coord[0]}, ${point2.coord[1]})`;
32030
+ if (labels && labels.length > 0) {
32031
+ str += " with label";
32032
+ // Make it "with labels" instead of "with label" if there are
32033
+ // multiple labels.
32034
+ if (labels.length > 1) {
32035
+ str += "s";
32036
+ }
32037
+
32038
+ // Separate additional labels with commas.
32039
+ str += ` ${labels.map(l => l.text).join(", ")}`;
32040
+ }
32041
+ return str;
32042
+ }
31679
32043
  function handleChangePoint(newPointProps, index) {
31680
32044
  const newPoints = [...points];
31681
32045
  newPoints[index] = {
@@ -31688,7 +32052,7 @@ const LockedLineSettings = props => {
31688
32052
  const oldMidpoint = mafs.vec.midpoint(points[0].coord, points[1].coord);
31689
32053
  const newMidpoint = mafs.vec.midpoint(newPoints[0].coord, newPoints[1].coord);
31690
32054
  const offset = [newMidpoint[0] - oldMidpoint[0], newMidpoint[1] - oldMidpoint[1]];
31691
- const newLabels = labels.map((label, labelIndex) => ({
32055
+ const newLabels = labels?.map((label, labelIndex) => ({
31692
32056
  ...label,
31693
32057
  coord: [label.coord[0] + offset[0], label.coord[1] + offset[1]]
31694
32058
  }));
@@ -31698,7 +32062,7 @@ const LockedLineSettings = props => {
31698
32062
  });
31699
32063
  }
31700
32064
  function handleColorChange(newColor) {
31701
- const newLabels = labels.map(label => ({
32065
+ const newLabels = labels?.map(label => ({
31702
32066
  ...label,
31703
32067
  color: newColor
31704
32068
  }));
@@ -31708,14 +32072,14 @@ const LockedLineSettings = props => {
31708
32072
  points: [{
31709
32073
  ...point1,
31710
32074
  color: newColor,
31711
- labels: point1.labels.map(label => ({
32075
+ labels: point1.labels?.map(label => ({
31712
32076
  ...label,
31713
32077
  color: newColor
31714
32078
  }))
31715
32079
  }, {
31716
32080
  ...point2,
31717
32081
  color: newColor,
31718
- labels: point2.labels.map(label => ({
32082
+ labels: point2.labels?.map(label => ({
31719
32083
  ...label,
31720
32084
  color: newColor
31721
32085
  }))
@@ -31725,6 +32089,9 @@ const LockedLineSettings = props => {
31725
32089
  });
31726
32090
  }
31727
32091
  function handleLabelChange(updatedLabel, labelIndex) {
32092
+ if (!labels) {
32093
+ return;
32094
+ }
31728
32095
  const updatedLabels = [...labels];
31729
32096
  updatedLabels[labelIndex] = {
31730
32097
  ...labels[labelIndex],
@@ -31735,6 +32102,9 @@ const LockedLineSettings = props => {
31735
32102
  });
31736
32103
  }
31737
32104
  function handleLabelRemove(labelIndex) {
32105
+ if (!labels) {
32106
+ return;
32107
+ }
31738
32108
  const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31739
32109
  onChangeProps({
31740
32110
  labels: updatedLabels
@@ -31809,9 +32179,23 @@ const LockedLineSettings = props => {
31809
32179
  showPoint2: newValue
31810
32180
  }),
31811
32181
  onChangeProps: newProps => handleChangePoint(newProps, 1)
31812
- })), flags?.["mafs"]?.["locked-line-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32182
+ })), flags?.["mafs"]?.["locked-figures-aria"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
32183
+ size: wonderBlocksTokens.spacing.small_12
32184
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32185
+ style: styles$m.horizontalRule
32186
+ }), /*#__PURE__*/React__namespace.createElement(LockedFigureAria, {
32187
+ ariaLabel: ariaLabel,
32188
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
32189
+ onChangeProps: newProps => {
32190
+ onChangeProps(newProps);
32191
+ }
32192
+ })), flags?.["mafs"]?.["locked-line-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
32193
+ size: wonderBlocksTokens.spacing.xxxSmall_4
32194
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31813
32195
  style: styles$m.horizontalRule
31814
- }), labels.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
32196
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
32197
+ size: wonderBlocksTokens.spacing.small_12
32198
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, null, "Visible labels"), labels?.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
31815
32199
  expanded: true,
31816
32200
  onChangeProps: newLabel => {
31817
32201
  handleLabelChange(newLabel, labelIndex);
@@ -31827,15 +32211,15 @@ const LockedLineSettings = props => {
31827
32211
  // Additional vertical offset for each label so
31828
32212
  // they don't overlap.
31829
32213
  const offsetPerLabel = [0, -1];
31830
- const labelLocation = mafs.vec.add(mafs.vec.scale(offsetPerLabel, labels.length), mafs.vec.midpoint(points[0].coord, points[1].coord));
32214
+ const labelLocation = mafs.vec.add(mafs.vec.scale(offsetPerLabel, labels?.length ?? 0), mafs.vec.midpoint(points[0].coord, points[1].coord));
31831
32215
  const newLabel = {
31832
32216
  ...getDefaultFigureForType("label"),
31833
32217
  coord: labelLocation,
31834
- // Default to the same color as the point
32218
+ // Default to the same color as the line
31835
32219
  color: lineColor
31836
32220
  };
31837
32221
  onChangeProps({
31838
- labels: [...labels, newLabel]
32222
+ labels: [...(labels ?? []), newLabel]
31839
32223
  });
31840
32224
  },
31841
32225
  style: styles$m.addButton
@@ -31861,8 +32245,6 @@ const styles$m = aphrodite.StyleSheet.create({
31861
32245
  alignSelf: "start"
31862
32246
  },
31863
32247
  horizontalRule: {
31864
- marginTop: wonderBlocksTokens.spacing.small_12,
31865
- marginBottom: wonderBlocksTokens.spacing.xxxSmall_4,
31866
32248
  height: 1,
31867
32249
  backgroundColor: wonderBlocksTokens.color.offBlack16
31868
32250
  },
@@ -31908,58 +32290,127 @@ const styles$l = aphrodite.StyleSheet.create({
31908
32290
 
31909
32291
  const LockedPolygonSettings = props => {
31910
32292
  const {
32293
+ flags,
31911
32294
  points,
31912
32295
  color,
31913
32296
  showVertices,
31914
32297
  fillStyle,
31915
32298
  strokeStyle,
32299
+ labels,
32300
+ ariaLabel,
31916
32301
  expanded,
31917
32302
  onToggle,
31918
32303
  onChangeProps,
31919
32304
  onMove,
31920
32305
  onRemove
31921
32306
  } = props;
32307
+ function getPrepopulatedAriaLabel() {
32308
+ let str = `Polygon with ${points.length} sides, vertices at `;
32309
+
32310
+ // Add the coordinates of each point to the aria label
32311
+ str += points.map(_ref => {
32312
+ let [x, y] = _ref;
32313
+ return `(${x}, ${y})`;
32314
+ }).join(", ");
32315
+ if (labels && labels.length > 0) {
32316
+ str += ", with label";
32317
+ // Make it "with labels" instead of "with label" if there are
32318
+ // multiple labels.
32319
+ if (labels.length > 1) {
32320
+ str += "s";
32321
+ }
32322
+
32323
+ // Separate additional labels with commas.
32324
+ str += ` ${labels.map(l => l.text).join(", ")}`;
32325
+ }
32326
+ return str;
32327
+ }
31922
32328
  function handleColorChange(newValue) {
31923
- onChangeProps({
32329
+ const newProps = {
31924
32330
  color: newValue
31925
- });
32331
+ };
32332
+
32333
+ // Update the color of the all labels to match the point
32334
+ newProps.labels = labels?.map(label => ({
32335
+ ...label,
32336
+ color: newValue
32337
+ }));
32338
+ onChangeProps(newProps);
31926
32339
  }
31927
32340
  function handlePolygonMove(movement) {
31928
32341
  switch (movement) {
31929
32342
  case "up":
31930
32343
  onChangeProps({
31931
- points: points.map(_ref => {
31932
- let [x, y] = _ref;
32344
+ points: points.map(_ref2 => {
32345
+ let [x, y] = _ref2;
31933
32346
  return [x, y + 1];
31934
- })
32347
+ }),
32348
+ labels: labels?.map(label => ({
32349
+ ...label,
32350
+ coord: [label.coord[0], label.coord[1] + 1]
32351
+ }))
31935
32352
  });
31936
32353
  break;
31937
32354
  case "down":
31938
32355
  onChangeProps({
31939
- points: points.map(_ref2 => {
31940
- let [x, y] = _ref2;
32356
+ points: points.map(_ref3 => {
32357
+ let [x, y] = _ref3;
31941
32358
  return [x, y - 1];
31942
- })
32359
+ }),
32360
+ labels: labels?.map(label => ({
32361
+ ...label,
32362
+ coord: [label.coord[0], label.coord[1] - 1]
32363
+ }))
31943
32364
  });
31944
32365
  break;
31945
32366
  case "left":
31946
32367
  onChangeProps({
31947
- points: points.map(_ref3 => {
31948
- let [x, y] = _ref3;
32368
+ points: points.map(_ref4 => {
32369
+ let [x, y] = _ref4;
31949
32370
  return [x - 1, y];
31950
- })
32371
+ }),
32372
+ labels: labels?.map(label => ({
32373
+ ...label,
32374
+ coord: [label.coord[0] - 1, label.coord[1]]
32375
+ }))
31951
32376
  });
31952
32377
  break;
31953
32378
  case "right":
31954
32379
  onChangeProps({
31955
- points: points.map(_ref4 => {
31956
- let [x, y] = _ref4;
32380
+ points: points.map(_ref5 => {
32381
+ let [x, y] = _ref5;
31957
32382
  return [x + 1, y];
31958
- })
32383
+ }),
32384
+ labels: labels?.map(label => ({
32385
+ ...label,
32386
+ coord: [label.coord[0] + 1, label.coord[1]]
32387
+ }))
31959
32388
  });
31960
32389
  break;
31961
32390
  }
31962
32391
  }
32392
+ function handleLabelChange(updatedLabel, labelIndex) {
32393
+ if (!labels) {
32394
+ return;
32395
+ }
32396
+ const updatedLabels = [...labels];
32397
+ updatedLabels[labelIndex] = {
32398
+ ...labels[labelIndex],
32399
+ ...updatedLabel
32400
+ };
32401
+ onChangeProps({
32402
+ labels: updatedLabels
32403
+ });
32404
+ }
32405
+ function handleLabelRemove(labelIndex) {
32406
+ if (!labels) {
32407
+ return;
32408
+ }
32409
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
32410
+ onChangeProps({
32411
+ labels: updatedLabels
32412
+ });
32413
+ }
31963
32414
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31964
32415
  expanded: expanded,
31965
32416
  onToggle: onToggle,
@@ -32088,7 +32539,50 @@ const LockedPolygonSettings = props => {
32088
32539
  size: "small",
32089
32540
  icon: arrowFatRight__default["default"],
32090
32541
  onClick: () => handlePolygonMove("right")
32091
- }))))), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
32542
+ }))))), flags?.["mafs"]?.["locked-figures-aria"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
32543
+ size: wonderBlocksTokens.spacing.small_12
32544
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32545
+ style: styles$k.horizontalRule
32546
+ }), /*#__PURE__*/React__namespace.createElement(LockedFigureAria, {
32547
+ ariaLabel: ariaLabel,
32548
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
32549
+ onChangeProps: newProps => {
32550
+ onChangeProps(newProps);
32551
+ }
32552
+ })), flags?.["mafs"]?.["locked-polygon-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
32553
+ size: wonderBlocksTokens.spacing.xxxSmall_4
32554
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32555
+ style: styles$k.horizontalRule
32556
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
32557
+ size: wonderBlocksTokens.spacing.small_12
32558
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, null, "Visible labels"), labels?.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
32559
+ expanded: true,
32560
+ onChangeProps: newLabel => {
32561
+ handleLabelChange(newLabel, labelIndex);
32562
+ },
32563
+ onRemove: () => {
32564
+ handleLabelRemove(labelIndex);
32565
+ },
32566
+ containerStyle: styles$k.labelContainer
32567
+ }))), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
32568
+ kind: "tertiary",
32569
+ startIcon: plusCircle__default["default"],
32570
+ onClick: () => {
32571
+ const newLabel = {
32572
+ ...getDefaultFigureForType("label"),
32573
+ coord: [points[0][0],
32574
+ // Additional vertical offset for each
32575
+ // label so they don't overlap.
32576
+ points[0][1] - (labels?.length ?? 0)],
32577
+ // Default to the same color as the ellipse
32578
+ color: color
32579
+ };
32580
+ onChangeProps({
32581
+ labels: [...(labels ?? []), newLabel]
32582
+ });
32583
+ },
32584
+ style: styles$k.addButton
32585
+ }, "Add visible label")), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
32092
32586
  figureType: props.type,
32093
32587
  onMove: onMove,
32094
32588
  onRemove: onRemove
@@ -32127,20 +32621,28 @@ const styles$k = aphrodite.StyleSheet.create({
32127
32621
  truncatedWidth: {
32128
32622
  // Allow truncation, stop bleeding over the edge.
32129
32623
  minWidth: 0
32624
+ },
32625
+ // Styles for the visible labels section
32626
+ addButton: {
32627
+ alignSelf: "start"
32628
+ },
32629
+ labelContainer: {
32630
+ backgroundColor: wonderBlocksTokens.color.white
32631
+ },
32632
+ horizontalRule: {
32633
+ height: 1,
32634
+ backgroundColor: wonderBlocksTokens.color.offBlack16
32130
32635
  }
32131
32636
  });
32132
32637
 
32133
- /**
32134
- * LockedVectorSettings is a component that allows the user to edit the
32135
- * settings of specifically a locked vector on the graph.
32136
- *
32137
- * Used in the interactive graph editor's locked figures section.
32138
- */
32139
32638
  const lengthErrorMessage = "The vector cannot have length 0.";
32140
32639
  const LockedVectorSettings = props => {
32141
32640
  const {
32641
+ flags,
32142
32642
  points,
32143
32643
  color: lineColor,
32644
+ labels,
32645
+ ariaLabel,
32144
32646
  onChangeProps,
32145
32647
  onMove,
32146
32648
  onRemove
@@ -32150,18 +32652,72 @@ const LockedVectorSettings = props => {
32150
32652
 
32151
32653
  // Check if the line has length 0.
32152
32654
  const isInvalid = kmath.vector.equal(tail, tip);
32655
+ function getPrepopulatedAriaLabel() {
32656
+ let str = `Vector from (${tail[0]}, ${tail[1]}) to (${tip[0]}, ${tip[1]})`;
32657
+ if (labels && labels.length > 0) {
32658
+ str += " with label";
32659
+ // Make it "with labels" instead of "with label" if there are
32660
+ // multiple labels.
32661
+ if (labels.length > 1) {
32662
+ str += "s";
32663
+ }
32664
+
32665
+ // Separate additional labels with commas.
32666
+ str += ` ${labels.map(l => l.text).join(", ")}`;
32667
+ }
32668
+ return str;
32669
+ }
32153
32670
  function handleChangePoint(newCoord, index) {
32154
32671
  if (typeof newCoord !== "undefined") {
32155
32672
  const newPoints = [...points];
32156
32673
  newPoints[index] = [...newCoord];
32674
+
32675
+ // Update labels to match the new points
32676
+ const oldMidpoint = mafs.vec.midpoint(tail, tip);
32677
+ const newMidpoint = mafs.vec.midpoint(newPoints[0], newPoints[1]);
32678
+ const offset = mafs.vec.sub(newMidpoint, oldMidpoint);
32679
+ const newLabels = labels?.map(label => ({
32680
+ ...label,
32681
+ coord: mafs.vec.add(label.coord, offset)
32682
+ }));
32157
32683
  onChangeProps({
32158
- points: newPoints
32684
+ points: newPoints,
32685
+ labels: newLabels
32159
32686
  });
32160
32687
  }
32161
32688
  }
32162
32689
  function handleColorChange(newColor) {
32163
- onChangeProps({
32690
+ const newProps = {
32691
+ color: newColor
32692
+ };
32693
+
32694
+ // Update the color of the all labels to match the point
32695
+ newProps.labels = labels?.map(label => ({
32696
+ ...label,
32164
32697
  color: newColor
32698
+ }));
32699
+ onChangeProps(newProps);
32700
+ }
32701
+ function handleLabelChange(updatedLabel, labelIndex) {
32702
+ if (!labels) {
32703
+ return;
32704
+ }
32705
+ const updatedLabels = [...labels];
32706
+ updatedLabels[labelIndex] = {
32707
+ ...labels[labelIndex],
32708
+ ...updatedLabel
32709
+ };
32710
+ onChangeProps({
32711
+ labels: updatedLabels
32712
+ });
32713
+ }
32714
+ function handleLabelRemove(labelIndex) {
32715
+ if (!labels) {
32716
+ return;
32717
+ }
32718
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
32719
+ onChangeProps({
32720
+ labels: updatedLabels
32165
32721
  });
32166
32722
  }
32167
32723
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
@@ -32210,7 +32766,51 @@ const LockedVectorSettings = props => {
32210
32766
  onChange: newProps => {
32211
32767
  handleChangePoint(newProps, 1);
32212
32768
  }
32213
- })), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
32769
+ })), flags?.["mafs"]?.["locked-figures-aria"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
32770
+ size: wonderBlocksTokens.spacing.small_12
32771
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32772
+ style: styles$j.horizontalRule
32773
+ }), /*#__PURE__*/React__namespace.createElement(LockedFigureAria, {
32774
+ ariaLabel: ariaLabel,
32775
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
32776
+ onChangeProps: newProps => {
32777
+ onChangeProps(newProps);
32778
+ }
32779
+ })), flags?.["mafs"]?.["locked-vector-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Strut, {
32780
+ size: wonderBlocksTokens.spacing.xxxSmall_4
32781
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32782
+ style: styles$j.horizontalRule
32783
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
32784
+ size: wonderBlocksTokens.spacing.small_12
32785
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, null, "Visible labels"), labels?.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
32786
+ expanded: true,
32787
+ onChangeProps: newLabel => {
32788
+ handleLabelChange(newLabel, labelIndex);
32789
+ },
32790
+ onRemove: () => {
32791
+ handleLabelRemove(labelIndex);
32792
+ },
32793
+ containerStyle: styles$j.labelContainer
32794
+ }))), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
32795
+ kind: "tertiary",
32796
+ startIcon: plusCircle__default["default"],
32797
+ onClick: () => {
32798
+ // Additional vertical offset for each label so
32799
+ // they don't overlap.
32800
+ const offsetPerLabel = [0, -1];
32801
+ const labelLocation = mafs.vec.add(mafs.vec.scale(offsetPerLabel, labels?.length ?? 0), mafs.vec.midpoint(tail, tip));
32802
+ const newLabel = {
32803
+ ...getDefaultFigureForType("label"),
32804
+ coord: labelLocation,
32805
+ // Default to the same color as the vector
32806
+ color: lineColor
32807
+ };
32808
+ onChangeProps({
32809
+ labels: [...(labels ?? []), newLabel]
32810
+ });
32811
+ },
32812
+ style: styles$j.addButton
32813
+ }, "Add visible label")), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
32214
32814
  figureType: props.type,
32215
32815
  onMove: onMove,
32216
32816
  onRemove: onRemove
@@ -32234,6 +32834,16 @@ const styles$j = aphrodite.StyleSheet.create({
32234
32834
  row: {
32235
32835
  flexDirection: "row",
32236
32836
  alignItems: "center"
32837
+ },
32838
+ addButton: {
32839
+ alignSelf: "start"
32840
+ },
32841
+ horizontalRule: {
32842
+ height: 1,
32843
+ backgroundColor: wonderBlocksTokens.color.offBlack16
32844
+ },
32845
+ labelContainer: {
32846
+ backgroundColor: wonderBlocksTokens.color.white
32237
32847
  }
32238
32848
  });
32239
32849