@khanacademy/perseus-editor 14.3.0 → 14.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -27,6 +27,7 @@ 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');
31
32
  var IconButton = require('@khanacademy/wonder-blocks-icon-button');
32
33
  var caretDoubleDownIcon = require('@phosphor-icons/core/bold/caret-double-down-bold.svg');
@@ -36,7 +37,7 @@ var caretUpIcon = require('@phosphor-icons/core/bold/caret-up-bold.svg');
36
37
  var trashIcon = require('@phosphor-icons/core/bold/trash-bold.svg');
37
38
  var copyIcon = require('@phosphor-icons/core/assets/regular/copy.svg');
38
39
  var autoPasteIcon = require('@phosphor-icons/core/assets/regular/note-pencil.svg');
39
- var plusCircle = require('@phosphor-icons/core/regular/plus-circle.svg');
40
+ var mafs = require('mafs');
40
41
  var arrowFatDown = require('@phosphor-icons/core/regular/arrow-fat-down.svg');
41
42
  var arrowFatLeft = require('@phosphor-icons/core/regular/arrow-fat-left.svg');
42
43
  var arrowFatRight = require('@phosphor-icons/core/regular/arrow-fat-right.svg');
@@ -77,6 +78,7 @@ var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
77
78
  var KAS__namespace = /*#__PURE__*/_interopNamespace(KAS);
78
79
  var Button__default = /*#__PURE__*/_interopDefaultLegacy(Button);
79
80
  var Banner__default = /*#__PURE__*/_interopDefaultLegacy(Banner);
81
+ var plusCircle__default = /*#__PURE__*/_interopDefaultLegacy(plusCircle);
80
82
  var IconButton__default = /*#__PURE__*/_interopDefaultLegacy(IconButton);
81
83
  var caretDoubleDownIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretDoubleDownIcon);
82
84
  var caretDoubleUpIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretDoubleUpIcon);
@@ -85,7 +87,6 @@ var caretUpIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretUpIcon);
85
87
  var trashIcon__default = /*#__PURE__*/_interopDefaultLegacy(trashIcon);
86
88
  var copyIcon__default = /*#__PURE__*/_interopDefaultLegacy(copyIcon);
87
89
  var autoPasteIcon__default = /*#__PURE__*/_interopDefaultLegacy(autoPasteIcon);
88
- var plusCircle__default = /*#__PURE__*/_interopDefaultLegacy(plusCircle);
89
90
  var arrowFatDown__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatDown);
90
91
  var arrowFatLeft__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatLeft);
91
92
  var arrowFatRight__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatRight);
@@ -95,7 +96,7 @@ var arrowCounterClockwise__default = /*#__PURE__*/_interopDefaultLegacy(arrowCou
95
96
 
96
97
  // This file is processed by a Rollup plugin (replace) to inject the production
97
98
  const libName = "@khanacademy/perseus-editor";
98
- const libVersion = "14.3.0";
99
+ const libVersion = "14.5.0";
99
100
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
100
101
 
101
102
  function _extends() {
@@ -290,13 +291,13 @@ class SectionControlButton extends React__namespace.Component {
290
291
  role: "button",
291
292
  hideDefaultFocusRing: true,
292
293
  "aria-label": title,
293
- style: styles$U.button
294
+ style: styles$T.button
294
295
  }, _ref => {
295
296
  return /*#__PURE__*/React__namespace.createElement(InlineIcon$b, icon);
296
297
  });
297
298
  }
298
299
  }
299
- const styles$U = aphrodite.StyleSheet.create({
300
+ const styles$T = aphrodite.StyleSheet.create({
300
301
  button: {
301
302
  backgroundColor: wonderBlocksTokens.color.gold,
302
303
  margin: 2,
@@ -20677,11 +20678,11 @@ class Spring extends React__namespace.Component {
20677
20678
  } = this.props;
20678
20679
  return React__namespace.createElement(wonderBlocksCore.View, {
20679
20680
  "aria-hidden": "true",
20680
- style: [styles$T.grow, style]
20681
+ style: [styles$S.grow, style]
20681
20682
  });
20682
20683
  }
20683
20684
  }
20684
- const styles$T = aphrodite.StyleSheet.create({
20685
+ const styles$S = aphrodite.StyleSheet.create({
20685
20686
  grow: {
20686
20687
  flexGrow: 1
20687
20688
  }
@@ -20749,7 +20750,7 @@ class WidgetEditor extends React__namespace.Component {
20749
20750
  constructor(props) {
20750
20751
  super(props);
20751
20752
  this.state = {
20752
- showWidget: false,
20753
+ showWidget: props.widgetIsOpen ?? true,
20753
20754
  widgetInfo: _upgradeWidgetInfo(props)
20754
20755
  };
20755
20756
  this.widget = /*#__PURE__*/React__namespace.createRef();
@@ -20760,6 +20761,12 @@ class WidgetEditor extends React__namespace.Component {
20760
20761
  this.setState({
20761
20762
  widgetInfo: _upgradeWidgetInfo(nextProps)
20762
20763
  });
20764
+ // user can update internal state while the widget is handled globally
20765
+ if (nextProps.widgetIsOpen != null && nextProps.widgetIsOpen !== this.props.widgetIsOpen) {
20766
+ this.setState({
20767
+ showWidget: nextProps.widgetIsOpen
20768
+ });
20769
+ }
20763
20770
  }
20764
20771
  _toggleWidget = e => {
20765
20772
  e.preventDefault();
@@ -20918,13 +20925,13 @@ class WidgetSelect extends React__namespace.Component {
20918
20925
  * that collapse a region.
20919
20926
  */
20920
20927
  function ToggleableCaret(props) {
20921
- const iconStyle = props.isExpanded ? styles$S.expanded : styles$S.collapsed;
20928
+ const iconStyle = props.isExpanded ? styles$R.expanded : styles$R.collapsed;
20922
20929
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksIcon.PhosphorIcon, {
20923
20930
  icon: caretRight__default["default"],
20924
20931
  style: iconStyle
20925
20932
  });
20926
20933
  }
20927
- const styles$S = aphrodite.StyleSheet.create({
20934
+ const styles$R = aphrodite.StyleSheet.create({
20928
20935
  collapsed: {
20929
20936
  transition: ".15s"
20930
20937
  },
@@ -20954,16 +20961,16 @@ class TexErrorView extends React__namespace.Component {
20954
20961
  showErrors
20955
20962
  } = this.state;
20956
20963
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20957
- style: styles$R.errorContainer
20964
+ style: styles$Q.errorContainer
20958
20965
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20959
- style: styles$R.title,
20966
+ style: styles$Q.title,
20960
20967
  onClick: this.handleToggleTexErrors
20961
20968
  }, /*#__PURE__*/React__namespace.createElement(ToggleableCaret, {
20962
20969
  isExpanded: showErrors
20963
20970
  }), "\xA0 TeX Errors (", errorList.length, ")"), showErrors && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20964
- style: styles$R.errorExplanation
20971
+ style: styles$Q.errorExplanation
20965
20972
  }, "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, {
20966
- style: styles$R.error,
20973
+ style: styles$Q.error,
20967
20974
  key: index
20968
20975
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
20969
20976
  style: {
@@ -20972,7 +20979,7 @@ class TexErrorView extends React__namespace.Component {
20972
20979
  }, e.math), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, e.message))));
20973
20980
  }
20974
20981
  }
20975
- const styles$R = aphrodite.StyleSheet.create({
20982
+ const styles$Q = aphrodite.StyleSheet.create({
20976
20983
  title: {
20977
20984
  backgroundColor: "#eee",
20978
20985
  fontSize: "1.25em",
@@ -21168,7 +21175,8 @@ class Editor extends React__namespace.Component {
21168
21175
  // eslint-disable-next-line react/jsx-no-bind
21169
21176
  ,
21170
21177
  onRemove: this._handleWidgetEditorRemove.bind(this, id),
21171
- apiOptions: this.props.apiOptions
21178
+ apiOptions: this.props.apiOptions,
21179
+ widgetIsOpen: this.props.widgetIsOpen
21172
21180
  }, this.props.widgets[id]));
21173
21181
  }
21174
21182
  _handleWidgetEditorChange = (id, newWidgetInfo, cb, silent) => {
@@ -21935,8 +21943,7 @@ class IframeContentRenderer extends React__namespace.Component {
21935
21943
  this._lastData = data;
21936
21944
 
21937
21945
  // We can't use JSON.stringify/parse for this because the apiOptions
21938
- // includes the functions GroupMetadataEditor, groupAnnotator,
21939
- // onFocusChange, and onInputError.
21946
+ // includes the functions GroupMetadataEditor, groupAnnotator, and onFocusChange.
21940
21947
  // @ts-expect-error - TS2339 - Property 'iframeDataStore' does not exist on type 'Window & typeof globalThis'.
21941
21948
  window.iframeDataStore[this.iframeID] = data;
21942
21949
  frame.contentWindow.postMessage(this.iframeID, "*");
@@ -24049,7 +24056,7 @@ class ItemExtrasEditor extends React__namespace.Component {
24049
24056
  }
24050
24057
  }
24051
24058
  const ItemExtraCheckbox = props => /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
24052
- style: [styles$Q.checkbox, props.indent ? styles$Q.indented : undefined]
24059
+ style: [styles$P.checkbox, props.indent ? styles$P.indented : undefined]
24053
24060
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
24054
24061
  label: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
24055
24062
  style: {
@@ -24059,7 +24066,7 @@ const ItemExtraCheckbox = props => /*#__PURE__*/React__namespace.createElement(w
24059
24066
  checked: props.checked,
24060
24067
  onChange: newCheckedState => props.onChange(newCheckedState)
24061
24068
  }));
24062
- const styles$Q = aphrodite.StyleSheet.create({
24069
+ const styles$P = aphrodite.StyleSheet.create({
24063
24070
  indented: {
24064
24071
  marginInlineStart: wonderBlocksTokens.spacing.large_24
24065
24072
  }
@@ -24129,7 +24136,8 @@ class ItemEditor extends React__namespace.Component {
24129
24136
  imageUploader: this.props.imageUploader,
24130
24137
  onChange: this.handleEditorChange,
24131
24138
  apiOptions: this.props.apiOptions,
24132
- showWordCount: true
24139
+ showWordCount: true,
24140
+ widgetIsOpen: this.props.widgetIsOpen
24133
24141
  }, this.props.question))), /*#__PURE__*/React__namespace.createElement("div", {
24134
24142
  className: "perseus-editor-right-cell"
24135
24143
  }, /*#__PURE__*/React__namespace.createElement("div", {
@@ -24187,7 +24195,8 @@ class EditorPage extends React__namespace.Component {
24187
24195
  json: ___default["default"].pick(this.props, "question", "answerArea", "hints", "itemDataVersion"),
24188
24196
  gradeMessage: "",
24189
24197
  wasAnswered: false,
24190
- highlightLint: true
24198
+ highlightLint: true,
24199
+ widgetsAreOpen: this.props.widgetsAreOpen ?? true
24191
24200
  };
24192
24201
  this._isMounted = false;
24193
24202
  }
@@ -24339,6 +24348,7 @@ class EditorPage extends React__namespace.Component {
24339
24348
  wasAnswered: this.state.wasAnswered,
24340
24349
  gradeMessage: this.state.gradeMessage,
24341
24350
  deviceType: this.props.previewDevice,
24351
+ widgetIsOpen: this.state.widgetsAreOpen,
24342
24352
  apiOptions: deviceBasedApiOptions,
24343
24353
  previewURL: this.props.previewURL
24344
24354
  }), (!this.props.developerMode || !this.props.jsonMode) && /*#__PURE__*/React__namespace.createElement(CombinedHintsEditor, {
@@ -24722,12 +24732,12 @@ class SimpleButton extends React__namespace.Component {
24722
24732
  ...otherProps
24723
24733
  } = this.props;
24724
24734
  return /*#__PURE__*/React__namespace.createElement("div", _extends({
24725
- className: aphrodite.css(styles$P.baseButton, color === "green" && styles$P.green, color === "orange" && styles$P.orange),
24735
+ className: aphrodite.css(styles$O.baseButton, color === "green" && styles$O.green, color === "orange" && styles$O.orange),
24726
24736
  onClick: onClick
24727
24737
  }, otherProps), children);
24728
24738
  }
24729
24739
  }
24730
- const styles$P = aphrodite.StyleSheet.create({
24740
+ const styles$O = aphrodite.StyleSheet.create({
24731
24741
  baseButton: {
24732
24742
  top: "0",
24733
24743
  fontSize: "11px",
@@ -24940,23 +24950,23 @@ const LeafContainer = _ref2 => {
24940
24950
  } = _ref2;
24941
24951
  const hasPreviewHeading = shape.type === "content" || shape.type === "hint";
24942
24952
  const previewHeading = hasPreviewHeading && /*#__PURE__*/React__namespace.createElement("div", {
24943
- className: aphrodite.css(styles$O.containerHeader)
24953
+ className: aphrodite.css(styles$N.containerHeader)
24944
24954
  }, /*#__PURE__*/React__namespace.createElement(Header, {
24945
24955
  depth: path.length,
24946
- className: aphrodite.css(styles$O.containerTitle)
24956
+ className: aphrodite.css(styles$N.containerTitle)
24947
24957
  }, capitalize(name)));
24948
24958
  return /*#__PURE__*/React__namespace.createElement("div", {
24949
- className: aphrodite.css(styles$O.container)
24959
+ className: aphrodite.css(styles$N.container)
24950
24960
  }, /*#__PURE__*/React__namespace.createElement("span", {
24951
- className: aphrodite.css(styles$O.row, styles$O.rowHeading)
24961
+ className: aphrodite.css(styles$N.row, styles$N.rowHeading)
24952
24962
  }, /*#__PURE__*/React__namespace.createElement("div", {
24953
- className: aphrodite.css(styles$O.columnLeft)
24963
+ className: aphrodite.css(styles$N.columnLeft)
24954
24964
  }, /*#__PURE__*/React__namespace.createElement("div", {
24955
- className: "pod-title " + aphrodite.css(styles$O.containerHeader)
24965
+ className: "pod-title " + aphrodite.css(styles$N.containerHeader)
24956
24966
  }, /*#__PURE__*/React__namespace.createElement("div", {
24957
- className: aphrodite.css(styles$O.containerTitle)
24967
+ className: aphrodite.css(styles$N.containerTitle)
24958
24968
  }, capitalize(name)), controls)), /*#__PURE__*/React__namespace.createElement("div", {
24959
- className: aphrodite.css(styles$O.columnRight)
24969
+ className: aphrodite.css(styles$N.columnRight)
24960
24970
  }, previewHeading)), children);
24961
24971
  };
24962
24972
  const ArrayContainer = props => {
@@ -24969,11 +24979,11 @@ const ArrayContainer = props => {
24969
24979
  actions
24970
24980
  } = props;
24971
24981
  return /*#__PURE__*/React__namespace.createElement("div", {
24972
- className: aphrodite.css(styles$O.container)
24982
+ className: aphrodite.css(styles$N.container)
24973
24983
  }, controls && /*#__PURE__*/React__namespace.createElement("div", {
24974
- className: aphrodite.css(styles$O.columnLeft, styles$O.containerHeader)
24984
+ className: aphrodite.css(styles$N.columnLeft, styles$N.containerHeader)
24975
24985
  }, controls), /*#__PURE__*/React__namespace.createElement("div", null, children), /*#__PURE__*/React__namespace.createElement("div", {
24976
- className: aphrodite.css(styles$O.columnLeft)
24986
+ className: aphrodite.css(styles$N.columnLeft)
24977
24987
  }, /*#__PURE__*/React__namespace.createElement("a", {
24978
24988
  href: "javascript:void 0",
24979
24989
  onClick: () => actions.addArrayElement(path, shape.elementShape)
@@ -24987,28 +24997,28 @@ const ObjectContainer = _ref3 => {
24987
24997
  path
24988
24998
  } = _ref3;
24989
24999
  const headingEditor = /*#__PURE__*/React__namespace.createElement("div", {
24990
- className: aphrodite.css(styles$O.containerHeader)
25000
+ className: aphrodite.css(styles$N.containerHeader)
24991
25001
  }, /*#__PURE__*/React__namespace.createElement(Header, {
24992
25002
  depth: path.length,
24993
- className: aphrodite.css(styles$O.containerTitle)
25003
+ className: aphrodite.css(styles$N.containerTitle)
24994
25004
  }, capitalize(name)), controls);
24995
25005
  const headingPreview = (name || controls) && /*#__PURE__*/React__namespace.createElement("div", {
24996
- className: aphrodite.css(styles$O.containerHeader, styles$O.previewCollectionHeader)
25006
+ className: aphrodite.css(styles$N.containerHeader, styles$N.previewCollectionHeader)
24997
25007
  }, /*#__PURE__*/React__namespace.createElement(Header, {
24998
25008
  depth: path.length,
24999
- className: aphrodite.css(styles$O.containerTitle)
25009
+ className: aphrodite.css(styles$N.containerTitle)
25000
25010
  }, capitalize(name)));
25001
25011
  const hasBothHeadings = headingEditor && headingPreview;
25002
25012
  return /*#__PURE__*/React__namespace.createElement("div", {
25003
- className: aphrodite.css(styles$O.container)
25013
+ className: aphrodite.css(styles$N.container)
25004
25014
  }, hasBothHeadings && /*#__PURE__*/React__namespace.createElement("span", {
25005
- className: aphrodite.css(styles$O.row)
25015
+ className: aphrodite.css(styles$N.row)
25006
25016
  }, /*#__PURE__*/React__namespace.createElement("div", {
25007
- className: aphrodite.css(styles$O.columnLeft)
25017
+ className: aphrodite.css(styles$N.columnLeft)
25008
25018
  }, headingEditor), /*#__PURE__*/React__namespace.createElement("div", {
25009
- className: aphrodite.css(styles$O.columnRight)
25019
+ className: aphrodite.css(styles$N.columnRight)
25010
25020
  }, headingPreview)), /*#__PURE__*/React__namespace.createElement("div", {
25011
- className: aphrodite.css(path.length > 0 && styles$O.contentIndent)
25021
+ className: aphrodite.css(path.length > 0 && styles$N.contentIndent)
25012
25022
  }, children));
25013
25023
  };
25014
25024
 
@@ -25128,11 +25138,11 @@ const ItemNodeContent = withStickiness(props => {
25128
25138
  className: "framework-perseus"
25129
25139
  }, lens(renderers).get(path));
25130
25140
  return /*#__PURE__*/React__namespace.createElement("span", null, /*#__PURE__*/React__namespace.createElement("div", {
25131
- className: aphrodite.css(styles$O.row)
25141
+ className: aphrodite.css(styles$N.row)
25132
25142
  }, /*#__PURE__*/React__namespace.createElement("div", {
25133
- className: aphrodite.css(styles$O.columnLeft)
25143
+ className: aphrodite.css(styles$N.columnLeft)
25134
25144
  }, /*#__PURE__*/React__namespace.createElement("div", {
25135
- className: aphrodite.css(sticky && styles$O.sticky)
25145
+ className: aphrodite.css(sticky && styles$N.sticky)
25136
25146
  },
25137
25147
  /*#__PURE__*/
25138
25148
  // @ts-expect-error - TS2769 - No overload matches this call.
@@ -25140,9 +25150,9 @@ const ItemNodeContent = withStickiness(props => {
25140
25150
  onChange: newVal => actions.mergeValueAtPath(path, newVal),
25141
25151
  apiOptions: apiOptions
25142
25152
  })))), /*#__PURE__*/React__namespace.createElement("div", {
25143
- className: aphrodite.css(styles$O.columnRight)
25153
+ className: aphrodite.css(styles$N.columnRight)
25144
25154
  }, /*#__PURE__*/React__namespace.createElement("div", {
25145
- className: aphrodite.css(sticky && styles$O.sticky)
25155
+ className: aphrodite.css(sticky && styles$N.sticky)
25146
25156
  }, preview))));
25147
25157
  });
25148
25158
  const HintNodeContent = withStickiness(props => {
@@ -25158,13 +25168,13 @@ const HintNodeContent = withStickiness(props => {
25158
25168
  className: "framework-perseus"
25159
25169
  }, lens(renderers).get(path));
25160
25170
  return /*#__PURE__*/React__namespace.createElement("div", {
25161
- className: aphrodite.css(styles$O.row)
25171
+ className: aphrodite.css(styles$N.row)
25162
25172
  }, /*#__PURE__*/React__namespace.createElement("div", {
25163
- className: aphrodite.css(styles$O.columnLeft)
25173
+ className: aphrodite.css(styles$N.columnLeft)
25164
25174
  }, /*#__PURE__*/React__namespace.createElement("div", {
25165
- className: aphrodite.css(sticky && styles$O.sticky)
25175
+ className: aphrodite.css(sticky && styles$N.sticky)
25166
25176
  }, /*#__PURE__*/React__namespace.createElement(HintEditor, _extends({}, data, {
25167
- className: aphrodite.css(styles$O.hintEditor),
25177
+ className: aphrodite.css(styles$N.hintEditor),
25168
25178
  onChange: newVal => actions.mergeValueAtPath(path, newVal),
25169
25179
  apiOptions: apiOptions,
25170
25180
  showTitle: false,
@@ -25179,9 +25189,9 @@ const HintNodeContent = withStickiness(props => {
25179
25189
  isFirst: true,
25180
25190
  isLast: true
25181
25191
  })))), /*#__PURE__*/React__namespace.createElement("div", {
25182
- className: aphrodite.css(styles$O.columnRight)
25192
+ className: aphrodite.css(styles$N.columnRight)
25183
25193
  }, /*#__PURE__*/React__namespace.createElement("div", {
25184
- className: aphrodite.css(sticky && styles$O.sticky)
25194
+ className: aphrodite.css(sticky && styles$N.sticky)
25185
25195
  }, preview)));
25186
25196
  });
25187
25197
  const TagsNodeContent = props => {
@@ -25198,9 +25208,9 @@ const TagsNodeContent = props => {
25198
25208
  return null;
25199
25209
  }
25200
25210
  return /*#__PURE__*/React__namespace.createElement("div", {
25201
- className: aphrodite.css(styles$O.columnLeft)
25211
+ className: aphrodite.css(styles$N.columnLeft)
25202
25212
  }, /*#__PURE__*/React__namespace.createElement("div", {
25203
- className: aphrodite.css(styles$O.tagsEditor)
25213
+ className: aphrodite.css(styles$N.tagsEditor)
25204
25214
  }, /*#__PURE__*/React__namespace.createElement(GroupMetadataEditor, {
25205
25215
  value: data,
25206
25216
  onChange: newVal => actions.setValueAtPath(path, newVal),
@@ -25231,23 +25241,23 @@ const ArrayNodeContent = props => {
25231
25241
  const subpath = path.concat(i);
25232
25242
  const controls = [i > 0 && /*#__PURE__*/React__namespace.createElement("div", {
25233
25243
  key: "moveArrayElementUp",
25234
- className: aphrodite.css(styles$O.control)
25244
+ className: aphrodite.css(styles$N.control)
25235
25245
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25236
25246
  color: "orange",
25237
25247
  title: "Move up",
25238
25248
  onClick: () => actions.moveArrayElementUp(subpath)
25239
25249
  }, /*#__PURE__*/React__namespace.createElement("div", {
25240
- className: aphrodite.css(styles$O.verticalFlip)
25250
+ className: aphrodite.css(styles$N.verticalFlip)
25241
25251
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconChevronDown)))), i < data.length - 1 && /*#__PURE__*/React__namespace.createElement("div", {
25242
25252
  key: "moveArrayElementDown",
25243
- className: aphrodite.css(styles$O.control)
25253
+ className: aphrodite.css(styles$N.control)
25244
25254
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25245
25255
  color: "orange",
25246
25256
  title: "Move down",
25247
25257
  onClick: () => actions.moveArrayElementDown(subpath)
25248
25258
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconChevronDown))), /*#__PURE__*/React__namespace.createElement("div", {
25249
25259
  key: "removeArrayElement",
25250
- className: aphrodite.css(styles$O.control)
25260
+ className: aphrodite.css(styles$N.control)
25251
25261
  }, /*#__PURE__*/React__namespace.createElement(SimpleButton, {
25252
25262
  color: "orange",
25253
25263
  title: "Delete",
@@ -25255,7 +25265,7 @@ const ArrayNodeContent = props => {
25255
25265
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$6, iconTrash$4)))];
25256
25266
  return /*#__PURE__*/React__namespace.createElement("div", {
25257
25267
  key: i,
25258
- className: aphrodite.css(styles$O.arrayElement, !elementIsLeaf && styles$O.arrayElementAndNotLeaf)
25268
+ className: aphrodite.css(styles$N.arrayElement, !elementIsLeaf && styles$N.arrayElementAndNotLeaf)
25259
25269
  }, /*#__PURE__*/React__namespace.createElement(NodeContainer, _extends({}, otherProps, {
25260
25270
  key: i,
25261
25271
  shape: shape.elementShape,
@@ -25281,7 +25291,7 @@ const ObjectNodeContent = props => {
25281
25291
  // made sense to the shape's author is the order in which we'll iterate :)
25282
25292
  const children = Object.keys(shape.shape).map(subkey => /*#__PURE__*/React__namespace.createElement("div", {
25283
25293
  key: subkey,
25284
- className: aphrodite.css(styles$O.objectElement)
25294
+ className: aphrodite.css(styles$N.objectElement)
25285
25295
  }, /*#__PURE__*/React__namespace.createElement(NodeContainer, _extends({}, otherProps, {
25286
25296
  shape: shape.shape[subkey],
25287
25297
  data: data[subkey],
@@ -25451,7 +25461,7 @@ class MultiRendererEditor extends React__namespace.Component {
25451
25461
  }, this._renderContent());
25452
25462
  }
25453
25463
  }
25454
- const styles$O = aphrodite.StyleSheet.create({
25464
+ const styles$N = aphrodite.StyleSheet.create({
25455
25465
  // This is used in a number of places throughout this file.
25456
25466
  container: {},
25457
25467
  // eslint-disable-next-line react-native/no-unused-styles
@@ -26421,7 +26431,7 @@ const SortableItem = createReactClass__default["default"]({
26421
26431
  }
26422
26432
  return /*#__PURE__*/React__namespace.createElement("li", {
26423
26433
  draggable: this.props.draggable,
26424
- className: [dragState, aphrodite.css(styles$N.sortableListItem)].join(" "),
26434
+ className: [dragState, aphrodite.css(styles$M.sortableListItem)].join(" "),
26425
26435
  onDragStart: this.handleDragStart,
26426
26436
  onDrop: this.handleDrop,
26427
26437
  onDragEnter: this.handleDragEnter,
@@ -26429,7 +26439,7 @@ const SortableItem = createReactClass__default["default"]({
26429
26439
  }, this.props.component);
26430
26440
  }
26431
26441
  });
26432
- const styles$N = aphrodite.StyleSheet.create({
26442
+ const styles$M = aphrodite.StyleSheet.create({
26433
26443
  sortableListItem: {
26434
26444
  margin: "5px 0"
26435
26445
  }
@@ -26689,13 +26699,13 @@ class ExpressionEditor extends React__namespace.Component {
26689
26699
  onChange: this.handleToggleDiv
26690
26700
  }));
26691
26701
  return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingSmall, null, "Global Options"), /*#__PURE__*/React__namespace.createElement("div", {
26692
- className: aphrodite.css(styles$M.paddedY)
26702
+ className: aphrodite.css(styles$L.paddedY)
26693
26703
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26694
26704
  label: "Visible label",
26695
26705
  value: this.props.visibleLabel || "",
26696
26706
  onChange: this.change("visibleLabel")
26697
26707
  }), /*#__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", {
26698
- className: aphrodite.css(styles$M.paddedY)
26708
+ className: aphrodite.css(styles$L.paddedY)
26699
26709
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26700
26710
  label: "Aria label",
26701
26711
  value: this.props.ariaLabel || "",
@@ -26704,13 +26714,13 @@ class ExpressionEditor extends React__namespace.Component {
26704
26714
  href: "https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",
26705
26715
  target: "_blank"
26706
26716
  }, "this article.")))), /*#__PURE__*/React__namespace.createElement("div", {
26707
- className: aphrodite.css(styles$M.paddedY)
26717
+ className: aphrodite.css(styles$L.paddedY)
26708
26718
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.LabeledTextField, {
26709
26719
  label: "Function variables",
26710
26720
  value: this.state.functionsInternal,
26711
26721
  onChange: this.handleFunctions
26712
26722
  }), /*#__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", {
26713
- className: aphrodite.css(styles$M.paddedY)
26723
+ className: aphrodite.css(styles$L.paddedY)
26714
26724
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26715
26725
  label: "Use \xD7 instead of \u22C5 for multiplication",
26716
26726
  checked: this.props.times,
@@ -26720,7 +26730,7 @@ class ExpressionEditor extends React__namespace.Component {
26720
26730
  });
26721
26731
  }
26722
26732
  }), /*#__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", {
26723
- className: aphrodite.css(styles$M.paddedY)
26733
+ className: aphrodite.css(styles$L.paddedY)
26724
26734
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingXSmall, null, "Button Sets"), buttonSetChoices), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingSmall, null, "Answers"), /*#__PURE__*/React__namespace.createElement("p", {
26725
26735
  style: {
26726
26736
  margin: "4px 0"
@@ -26787,18 +26797,18 @@ class AnswerOption extends React__namespace.Component {
26787
26797
  color: "destructive",
26788
26798
  light: true
26789
26799
  }, "Delete");
26790
- 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);
26800
+ 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);
26791
26801
  return /*#__PURE__*/React__namespace.createElement("div", {
26792
- className: aphrodite.css(styles$M.answerOption)
26802
+ className: aphrodite.css(styles$L.answerOption)
26793
26803
  }, /*#__PURE__*/React__namespace.createElement("div", {
26794
- className: aphrodite.css(styles$M.answerHandle)
26804
+ className: aphrodite.css(styles$L.answerHandle)
26795
26805
  }), /*#__PURE__*/React__namespace.createElement("div", {
26796
- className: aphrodite.css(styles$M.answerBody)
26806
+ className: aphrodite.css(styles$L.answerBody)
26797
26807
  }, /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("button", {
26798
26808
  onClick: this.toggleConsidered,
26799
26809
  className: answerStatusCss
26800
26810
  }, this.props.considered), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(perseus.Expression, this.props.expressionProps))), /*#__PURE__*/React__namespace.createElement("div", {
26801
- className: aphrodite.css(styles$M.paddedY, styles$M.paddedX)
26811
+ className: aphrodite.css(styles$L.paddedY, styles$L.paddedX)
26802
26812
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26803
26813
  label: "Answer expression must have the same form.",
26804
26814
  checked: this.props.form,
@@ -26808,7 +26818,7 @@ class AnswerOption extends React__namespace.Component {
26808
26818
  });
26809
26819
  }
26810
26820
  }), /*#__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", {
26811
- className: aphrodite.css(styles$M.paddedY, styles$M.paddedX)
26821
+ className: aphrodite.css(styles$L.paddedY, styles$L.paddedX)
26812
26822
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
26813
26823
  label: "Answer expression must be fully expanded and simplified.",
26814
26824
  checked: this.props.simplify,
@@ -26818,11 +26828,11 @@ class AnswerOption extends React__namespace.Component {
26818
26828
  });
26819
26829
  }
26820
26830
  }), /*#__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", {
26821
- className: aphrodite.css(styles$M.buttonRow, styles$M.paddedY)
26831
+ className: aphrodite.css(styles$L.buttonRow, styles$L.paddedY)
26822
26832
  }, removeButton)));
26823
26833
  }
26824
26834
  }
26825
- const styles$M = aphrodite.StyleSheet.create({
26835
+ const styles$L = aphrodite.StyleSheet.create({
26826
26836
  paddedX: {
26827
26837
  paddingLeft: wonderBlocksTokens.spacing.xSmall_8,
26828
26838
  paddingRight: wonderBlocksTokens.spacing.xSmall_8
@@ -26934,10 +26944,10 @@ class GradedGroupEditor extends React__namespace.Component {
26934
26944
  }, /*#__PURE__*/React__namespace.createElement("div", {
26935
26945
  className: "perseus-widget-row"
26936
26946
  }, /*#__PURE__*/React__namespace.createElement("label", {
26937
- className: aphrodite.css(styles$L.title)
26947
+ className: aphrodite.css(styles$K.title)
26938
26948
  }, "Title:", " ", /*#__PURE__*/React__namespace.createElement(TextInput$5, {
26939
26949
  value: this.props.title,
26940
- className: aphrodite.css(styles$L.input)
26950
+ className: aphrodite.css(styles$K.input)
26941
26951
  // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
26942
26952
  ,
26943
26953
  onChange: this.change("title")
@@ -26962,7 +26972,7 @@ class GradedGroupEditor extends React__namespace.Component {
26962
26972
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$4, iconPlus$1), " Add a hint"), this.props.hint && /*#__PURE__*/React__namespace.createElement("div", {
26963
26973
  className: "perseus-hint-editor"
26964
26974
  }, /*#__PURE__*/React__namespace.createElement("div", {
26965
- className: aphrodite.css(styles$L.hintsTitle)
26975
+ className: aphrodite.css(styles$K.hintsTitle)
26966
26976
  }, "Hint"), /*#__PURE__*/React__namespace.createElement(Editor, {
26967
26977
  ref: this.hintEditor,
26968
26978
  content: this.props.hint ? this.props.hint.content : "",
@@ -26984,7 +26994,7 @@ class GradedGroupEditor extends React__namespace.Component {
26984
26994
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon$4, iconTrash$2), " Remove this hint")));
26985
26995
  }
26986
26996
  }
26987
- const styles$L = aphrodite.StyleSheet.create({
26997
+ const styles$K = aphrodite.StyleSheet.create({
26988
26998
  title: {
26989
26999
  fontSize: 18,
26990
27000
  fontWeight: "bold"
@@ -28475,13 +28485,13 @@ function MathquillInput(props) {
28475
28485
  }
28476
28486
  });
28477
28487
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
28478
- style: styles$K.outerWrapper
28488
+ style: styles$J.outerWrapper
28479
28489
  }, /*#__PURE__*/React__namespace.createElement("span", {
28480
28490
  ref: mathFieldWrapperRef,
28481
28491
  className: "perseus-math-input mq-editable-field mq-math-mode"
28482
28492
  }));
28483
28493
  }
28484
- const styles$K = aphrodite.StyleSheet.create({
28494
+ const styles$J = aphrodite.StyleSheet.create({
28485
28495
  outerWrapper: {
28486
28496
  display: "inline-block",
28487
28497
  borderStyle: "solid",
@@ -29610,7 +29620,7 @@ const GraphPointsCountSelector = _ref => {
29610
29620
  // Never uses placeholder, always has value
29611
29621
  ,
29612
29622
  placeholder: "",
29613
- style: styles$J.singleSelectShort
29623
+ style: styles$I.singleSelectShort
29614
29624
  }, [...[...Array(7).keys()].map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29615
29625
  key: n,
29616
29626
  value: `${n}`,
@@ -29621,7 +29631,7 @@ const GraphPointsCountSelector = _ref => {
29621
29631
  label: "unlimited"
29622
29632
  })]);
29623
29633
  };
29624
- const styles$J = aphrodite.StyleSheet.create({
29634
+ const styles$I = aphrodite.StyleSheet.create({
29625
29635
  singleSelectShort: {
29626
29636
  // Non-standard spacing, but it's the smallest we can go
29627
29637
  // without running into styling issues with the dropdown.
@@ -29634,7 +29644,7 @@ const GraphTypeSelector = props => {
29634
29644
  selectedValue: props.graphType,
29635
29645
  onChange: props.onChange,
29636
29646
  placeholder: "Select an answer type",
29637
- style: styles$I.singleSelectShort
29647
+ style: styles$H.singleSelectShort
29638
29648
  }, props.showNoneOption && /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29639
29649
  value: "none",
29640
29650
  label: "None"
@@ -29670,7 +29680,7 @@ const GraphTypeSelector = props => {
29670
29680
  label: "Angle"
29671
29681
  }));
29672
29682
  };
29673
- const styles$I = aphrodite.StyleSheet.create({
29683
+ const styles$H = aphrodite.StyleSheet.create({
29674
29684
  singleSelectShort: {
29675
29685
  // Non-standard spacing, but it's the smallest we can go
29676
29686
  // without running into styling issues with the dropdown.
@@ -29686,11 +29696,11 @@ function Heading(_ref) {
29686
29696
  onToggle
29687
29697
  } = _ref;
29688
29698
  return /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
29689
- style: [styles$H.container, !isCollapsible && styles$H.notClickable],
29699
+ style: [styles$G.container, !isCollapsible && styles$G.notClickable],
29690
29700
  disabled: !isCollapsible,
29691
29701
  onClick: () => isCollapsible && onToggle?.(!isOpen)
29692
29702
  }, () => /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29693
- style: styles$H.heading
29703
+ style: styles$G.heading
29694
29704
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
29695
29705
  style: {
29696
29706
  fontSize: 14,
@@ -29700,7 +29710,7 @@ function Heading(_ref) {
29700
29710
  isExpanded: isOpen
29701
29711
  })));
29702
29712
  }
29703
- const styles$H = aphrodite.StyleSheet.create({
29713
+ const styles$G = aphrodite.StyleSheet.create({
29704
29714
  container: {
29705
29715
  marginTop: wonderBlocksTokens.spacing.small_12,
29706
29716
  // NOTE(jeremy): This is the inverse of the @editorPadding CSS
@@ -29760,15 +29770,18 @@ function InteractiveGraphDescription(props) {
29760
29770
  isOpen: isOpen,
29761
29771
  onToggle: setIsOpen
29762
29772
  }), isOpen && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelXSmall, {
29763
- style: styles$G.caption
29773
+ style: styles$F.caption
29764
29774
  }, "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, {
29765
29775
  tag: "label"
29766
29776
  }, "Title", /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
29767
29777
  value: ariaLabelValue,
29768
29778
  onChange: newValue => onChange({
29769
- fullGraphAriaLabel: newValue
29779
+ fullGraphAriaLabel:
29780
+ // Save as undefined if the new value
29781
+ // is an empty string.
29782
+ newValue || undefined
29770
29783
  }),
29771
- style: styles$G.spaceAbove
29784
+ style: styles$F.spaceAbove
29772
29785
  })), /*#__PURE__*/React__namespace.createElement(Strut, {
29773
29786
  size: wonderBlocksTokens.spacing.small_12
29774
29787
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
@@ -29778,12 +29791,15 @@ function InteractiveGraphDescription(props) {
29778
29791
  resizeType: "vertical",
29779
29792
  value: ariaDescriptionValue,
29780
29793
  onChange: newValue => onChange({
29781
- fullGraphAriaDescription: newValue
29794
+ fullGraphAriaDescription:
29795
+ // Save as undefined if the new value
29796
+ // is an empty string.
29797
+ newValue || undefined
29782
29798
  }),
29783
- style: styles$G.spaceAbove
29799
+ style: styles$F.spaceAbove
29784
29800
  }))));
29785
29801
  }
29786
- const styles$G = aphrodite.StyleSheet.create({
29802
+ const styles$F = aphrodite.StyleSheet.create({
29787
29803
  caption: {
29788
29804
  color: wonderBlocksTokens.color.offBlack64,
29789
29805
  paddingTop: wonderBlocksTokens.spacing.xxSmall_6,
@@ -29803,16 +29819,16 @@ const LabeledRow = props => {
29803
29819
  style
29804
29820
  } = props;
29805
29821
  return /*#__PURE__*/React__namespace.createElement("label", {
29806
- className: aphrodite.css(styles$F.label)
29822
+ className: aphrodite.css(styles$E.label)
29807
29823
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29808
- style: [styles$F.row, style]
29824
+ style: [styles$E.row, style]
29809
29825
  }, labelSide === "start" || /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29810
- style: styles$F.spaceEnd
29826
+ style: styles$E.spaceEnd
29811
29827
  }, label), children, labelSide === "end" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29812
- style: styles$F.spaceStart
29828
+ style: styles$E.spaceStart
29813
29829
  }, label)));
29814
29830
  };
29815
- const styles$F = aphrodite.StyleSheet.create({
29831
+ const styles$E = aphrodite.StyleSheet.create({
29816
29832
  label: {
29817
29833
  width: "fit-content"
29818
29834
  },
@@ -30231,10 +30247,10 @@ class InteractiveGraphSettings extends React__namespace.Component {
30231
30247
  }
30232
30248
  }))), /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30233
30249
  label: "Background image URL:",
30234
- style: styles$E.resetSpaceTop
30250
+ style: styles$D.resetSpaceTop
30235
30251
  }, /*#__PURE__*/React__namespace.createElement("input", {
30236
30252
  type: "text",
30237
- className: aphrodite.css(styles$E.backgroundUrlInput),
30253
+ className: aphrodite.css(styles$D.backgroundUrlInput),
30238
30254
  ref: this.bgUrlRef,
30239
30255
  value: this.state.backgroundImage.url || "",
30240
30256
  onChange: e => {
@@ -30250,9 +30266,9 @@ class InteractiveGraphSettings extends React__namespace.Component {
30250
30266
  onKeyPress: this.changeBackgroundUrl,
30251
30267
  onBlur: this.changeBackgroundUrl
30252
30268
  }), /*#__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, {
30253
- style: styles$E.protractorSection
30269
+ style: styles$D.protractorSection
30254
30270
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30255
- style: styles$E.checkboxRow
30271
+ style: styles$D.checkboxRow
30256
30272
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
30257
30273
  label: "Show protractor",
30258
30274
  checked: this.props.showProtractor,
@@ -30261,7 +30277,7 @@ class InteractiveGraphSettings extends React__namespace.Component {
30261
30277
  showProtractor: value
30262
30278
  });
30263
30279
  },
30264
- style: styles$E.resetSpaceTop
30280
+ style: styles$D.resetSpaceTop
30265
30281
  })), this.props.showProtractor && /*#__PURE__*/React__namespace.createElement(Banner__default["default"], {
30266
30282
  layout: "floating",
30267
30283
  text: "The protractor is not accessible. Please consider an alternate approach.",
@@ -30269,7 +30285,7 @@ class InteractiveGraphSettings extends React__namespace.Component {
30269
30285
  }))));
30270
30286
  }
30271
30287
  }
30272
- const styles$E = aphrodite.StyleSheet.create({
30288
+ const styles$D = aphrodite.StyleSheet.create({
30273
30289
  resetSpaceTop: {
30274
30290
  marginTop: 0
30275
30291
  },
@@ -30308,14 +30324,14 @@ const SegmentCountSelector = _ref => {
30308
30324
  const num = +newValue;
30309
30325
  onChange(num);
30310
30326
  },
30311
- style: styles$D.singleSelectShort
30327
+ style: styles$C.singleSelectShort
30312
30328
  }, ___default["default"].range(1, 7).map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30313
30329
  key: n,
30314
30330
  value: `${n}`,
30315
30331
  label: `${n} segment${n > 1 ? "s" : ""}`
30316
30332
  })));
30317
30333
  };
30318
- const styles$D = aphrodite.StyleSheet.create({
30334
+ const styles$C = aphrodite.StyleSheet.create({
30319
30335
  singleSelectShort: {
30320
30336
  // Non-standard spacing, but it's the smallest we can go
30321
30337
  // without running into styling issues with the dropdown.
@@ -30340,17 +30356,17 @@ const LockedFigureSelect = props => {
30340
30356
  figureTypes.push("label");
30341
30357
  }
30342
30358
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30343
- style: styles$C.container
30359
+ style: styles$B.container
30344
30360
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionMenu, {
30345
30361
  menuText: "Add locked figure",
30346
- style: styles$C.addElementSelect
30362
+ style: styles$B.addElementSelect
30347
30363
  }, figureTypes.map(figureType => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
30348
30364
  key: `${id}-${figureType}`,
30349
30365
  label: figureType,
30350
30366
  onClick: () => onChange(figureType)
30351
30367
  }))));
30352
30368
  };
30353
- const styles$C = aphrodite.StyleSheet.create({
30369
+ const styles$B = aphrodite.StyleSheet.create({
30354
30370
  container: {
30355
30371
  marginTop: wonderBlocksTokens.spacing.xSmall_8
30356
30372
  },
@@ -30467,18 +30483,18 @@ const AngleInput = props => {
30467
30483
  }
30468
30484
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30469
30485
  tag: "label",
30470
- style: styles$B.row
30486
+ style: styles$A.row
30471
30487
  }, "angle (degrees)", /*#__PURE__*/React__namespace.createElement(Strut, {
30472
30488
  size: wonderBlocksTokens.spacing.xxSmall_6
30473
30489
  }), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
30474
30490
  value: angleInput,
30475
30491
  onChange: handleAngleChange,
30476
- style: styles$B.textField
30492
+ style: styles$A.textField
30477
30493
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
30478
30494
  size: wonderBlocksTokens.spacing.xxSmall_6
30479
30495
  }));
30480
30496
  };
30481
- const styles$B = aphrodite.StyleSheet.create({
30497
+ const styles$A = aphrodite.StyleSheet.create({
30482
30498
  row: {
30483
30499
  display: "flex",
30484
30500
  flexDirection: "row",
@@ -30527,30 +30543,30 @@ const CoordinatePairInput = props => {
30527
30543
  onChange(newCoords);
30528
30544
  }
30529
30545
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30530
- style: [styles$A.row, style]
30546
+ style: [styles$z.row, style]
30531
30547
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30532
30548
  tag: "label",
30533
- style: styles$A.row
30549
+ style: styles$z.row
30534
30550
  }, labels ? labels[0] : "x coord", /*#__PURE__*/React__namespace.createElement(Strut, {
30535
30551
  size: wonderBlocksTokens.spacing.xxSmall_6
30536
30552
  }), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
30537
30553
  value: coordState[0],
30538
30554
  onChange: newValue => handleCoordChange(newValue, 0),
30539
- style: [styles$A.textField, error ? styles$A.errorField : undefined]
30555
+ style: [styles$z.textField, error ? styles$z.errorField : undefined]
30540
30556
  })), /*#__PURE__*/React__namespace.createElement(Strut, {
30541
30557
  size: wonderBlocksTokens.spacing.medium_16
30542
30558
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30543
30559
  tag: "label",
30544
- style: styles$A.row
30560
+ style: styles$z.row
30545
30561
  }, labels ? labels[1] : "y coord", /*#__PURE__*/React__namespace.createElement(Strut, {
30546
30562
  size: wonderBlocksTokens.spacing.xxSmall_6
30547
30563
  }), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
30548
30564
  value: coordState[1],
30549
30565
  onChange: newValue => handleCoordChange(newValue, 1),
30550
- style: [styles$A.textField, error ? styles$A.errorField : undefined]
30566
+ style: [styles$z.textField, error ? styles$z.errorField : undefined]
30551
30567
  })));
30552
30568
  };
30553
- const styles$A = aphrodite.StyleSheet.create({
30569
+ const styles$z = aphrodite.StyleSheet.create({
30554
30570
  row: {
30555
30571
  display: "flex",
30556
30572
  flexDirection: "row",
@@ -30583,14 +30599,14 @@ const PerseusEditorAccordion = props => {
30583
30599
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksAccordion.AccordionSection, {
30584
30600
  expanded: expanded,
30585
30601
  onToggle: onToggle,
30586
- style: [styles$z.container, containerStyle],
30587
- headerStyle: styles$z.accordionHeader,
30602
+ style: [styles$y.container, containerStyle],
30603
+ headerStyle: styles$y.accordionHeader,
30588
30604
  header: header
30589
30605
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30590
- style: [styles$z.accordionPanel, panelStyle]
30606
+ style: [styles$y.accordionPanel, panelStyle]
30591
30607
  }, children)));
30592
30608
  };
30593
- const styles$z = aphrodite.StyleSheet.create({
30609
+ const styles$y = aphrodite.StyleSheet.create({
30594
30610
  container: {
30595
30611
  backgroundColor: wonderBlocksTokens.color.fadedBlue8,
30596
30612
  marginTop: wonderBlocksTokens.spacing.xSmall_8
@@ -30621,13 +30637,13 @@ const ColorSwatch = props => {
30621
30637
  "aria-label":
30622
30638
  // Don't include an aria label for decorative circles.
30623
30639
  !decorative ? `${color}, ${filled ? "filled" : "open"}` : undefined,
30624
- style: [styles$y.colorSwatch, {
30640
+ style: [styles$x.colorSwatch, {
30625
30641
  border: `4px solid ${perseus.lockedFigureColors[color]}`,
30626
30642
  backgroundColor: filled ? perseus.lockedFigureColors[color] : wonderBlocksTokens.color.white
30627
30643
  }]
30628
30644
  });
30629
30645
  };
30630
- const styles$y = aphrodite.StyleSheet.create({
30646
+ const styles$x = aphrodite.StyleSheet.create({
30631
30647
  colorSwatch: {
30632
30648
  // Add a white outline so that the color swatch is visible when
30633
30649
  // the dropdown option is highlighted with its blue background.
@@ -30646,10 +30662,10 @@ const ColorSelect = props => {
30646
30662
  onChange
30647
30663
  } = props;
30648
30664
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30649
- style: [styles$x.row, style]
30665
+ style: [styles$w.row, style]
30650
30666
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30651
30667
  tag: "label",
30652
- style: styles$x.row
30668
+ style: styles$w.row
30653
30669
  }, "color", /*#__PURE__*/React__namespace.createElement(Strut, {
30654
30670
  size: wonderBlocksTokens.spacing.xxSmall_6
30655
30671
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -30668,7 +30684,7 @@ const ColorSelect = props => {
30668
30684
  })
30669
30685
  })))));
30670
30686
  };
30671
- const styles$x = aphrodite.StyleSheet.create({
30687
+ const styles$w = aphrodite.StyleSheet.create({
30672
30688
  row: {
30673
30689
  display: "flex",
30674
30690
  flexDirection: "row",
@@ -30687,17 +30703,17 @@ const EllipseSwatch = props => {
30687
30703
  } = props;
30688
30704
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30689
30705
  "aria-label": `${color}, stroke ${strokeStyle}, fill ${fillStyle}`,
30690
- style: [styles$w.container, {
30706
+ style: [styles$v.container, {
30691
30707
  border: `4px ${strokeStyle} ${perseus.lockedFigureColors[color]}`
30692
30708
  }]
30693
30709
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30694
- style: [styles$w.innerCircle, {
30710
+ style: [styles$v.innerCircle, {
30695
30711
  backgroundColor: perseus.lockedFigureColors[color],
30696
30712
  opacity: fillStyle === "white" ? 0 : perseus.lockedFigureFillStyles[fillStyle]
30697
30713
  }]
30698
30714
  }));
30699
30715
  };
30700
- const styles$w = aphrodite.StyleSheet.create({
30716
+ const styles$v = aphrodite.StyleSheet.create({
30701
30717
  container: {
30702
30718
  // Add a white outline so that the color swatch is visible when
30703
30719
  // the dropdown option is highlighted with its blue background.
@@ -30723,7 +30739,7 @@ const LineStrokeSelect = props => {
30723
30739
  } = props;
30724
30740
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30725
30741
  tag: "label",
30726
- style: styles$v.lineStrokeSelect
30742
+ style: styles$u.lineStrokeSelect
30727
30743
  }, "stroke", /*#__PURE__*/React__namespace.createElement(Strut, {
30728
30744
  size: wonderBlocksTokens.spacing.xxxSmall_4
30729
30745
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -30740,7 +30756,7 @@ const LineStrokeSelect = props => {
30740
30756
  label: "dashed"
30741
30757
  })));
30742
30758
  };
30743
- const styles$v = aphrodite.StyleSheet.create({
30759
+ const styles$u = aphrodite.StyleSheet.create({
30744
30760
  lineStrokeSelect: {
30745
30761
  display: "flex",
30746
30762
  flexDirection: "row",
@@ -30762,40 +30778,40 @@ const LockedFigureSettingsActions = props => {
30762
30778
  onRemove
30763
30779
  } = props;
30764
30780
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30765
- style: styles$u.container
30781
+ style: styles$t.container
30766
30782
  }, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
30767
30783
  startIcon: trashIcon__default["default"],
30768
30784
  "aria-label": `Delete locked ${figureType}`,
30769
30785
  onClick: onRemove,
30770
30786
  kind: "tertiary",
30771
- style: styles$u.deleteButton
30787
+ style: styles$t.deleteButton
30772
30788
  }, "Delete"), onMove && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Spring, null), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30773
30789
  icon: caretDoubleUpIcon__default["default"],
30774
30790
  size: "small",
30775
30791
  "aria-label": `Move locked ${figureType} to the back`,
30776
30792
  onClick: () => onMove("back"),
30777
- style: styles$u.iconButton
30793
+ style: styles$t.iconButton
30778
30794
  }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30779
30795
  icon: caretUpIcon__default["default"],
30780
30796
  size: "small",
30781
30797
  "aria-label": `Move locked ${figureType} backward`,
30782
30798
  onClick: () => onMove("backward"),
30783
- style: styles$u.iconButton
30799
+ style: styles$t.iconButton
30784
30800
  }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30785
30801
  icon: caretDownIcon__default["default"],
30786
30802
  size: "small",
30787
30803
  "aria-label": `Move locked ${figureType} forward`,
30788
30804
  onClick: () => onMove("forward"),
30789
- style: styles$u.iconButton
30805
+ style: styles$t.iconButton
30790
30806
  }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30791
30807
  icon: caretDoubleDownIcon__default["default"],
30792
30808
  size: "small",
30793
30809
  "aria-label": `Move locked ${figureType} to the front`,
30794
30810
  onClick: () => onMove("front"),
30795
- style: styles$u.iconButton
30811
+ style: styles$t.iconButton
30796
30812
  })));
30797
30813
  };
30798
- const styles$u = aphrodite.StyleSheet.create({
30814
+ const styles$t = aphrodite.StyleSheet.create({
30799
30815
  container: {
30800
30816
  width: "100%",
30801
30817
  flexDirection: "row",
@@ -30813,162 +30829,422 @@ const styles$u = aphrodite.StyleSheet.create({
30813
30829
  }
30814
30830
  });
30815
30831
 
30816
- const {
30817
- InfoTip: InfoTip$c
30818
- } = perseus.components;
30819
- const LockedEllipseSettings = props => {
30832
+ /**
30833
+ * LockedLabelSettings is a component that allows the user to edit the
30834
+ * settings of specifically a locked label on the graph within the
30835
+ * Interactive Graph widget.
30836
+ *
30837
+ * Used in the interactive graph editor's locked figures section.
30838
+ */
30839
+ function LockedLabelSettings(props) {
30820
30840
  const {
30821
- center,
30822
- radius,
30823
- angle,
30841
+ type,
30842
+ coord,
30824
30843
  color,
30825
- fillStyle,
30826
- strokeStyle,
30844
+ size,
30845
+ text,
30827
30846
  expanded,
30828
- onToggle,
30829
30847
  onChangeProps,
30830
30848
  onMove,
30831
- onRemove
30849
+ onRemove,
30850
+ onToggle,
30851
+ containerStyle
30832
30852
  } = props;
30833
- function handleColorChange(newValue) {
30834
- onChangeProps({
30835
- color: newValue
30836
- });
30837
- }
30838
30853
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
30839
30854
  expanded: expanded,
30840
30855
  onToggle: onToggle,
30841
- header:
30842
- /*#__PURE__*/
30843
- // Summary: Ellipse, center, radius, color (opacity, dashed)
30844
- React__namespace.createElement(wonderBlocksCore.View, {
30845
- style: styles$t.row
30846
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`), /*#__PURE__*/React__namespace.createElement(Strut, {
30856
+ header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30857
+ style: [styles$s.row, styles$s.accordionHeaderContainer]
30858
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Label (", coord[0], ", ", coord[1], ")"), /*#__PURE__*/React__namespace.createElement(Strut, {
30847
30859
  size: wonderBlocksTokens.spacing.xSmall_8
30848
- }), /*#__PURE__*/React__namespace.createElement(EllipseSwatch, {
30849
- color: props.color,
30850
- fillStyle: fillStyle,
30851
- strokeStyle: strokeStyle
30852
- }))
30853
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30854
- style: styles$t.row
30860
+ }), text !== "" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
30861
+ style: [{
30862
+ backgroundColor: wonderBlocksTokens.color.white,
30863
+ color: perseus.lockedFigureColors[color]
30864
+ }, styles$s.accordionHeader]
30865
+ }, text)),
30866
+ containerStyle: containerStyle
30855
30867
  }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
30856
- coord: center,
30857
- style: styles$t.spaceUnder,
30858
- onChange: newCoords => onChangeProps({
30859
- center: newCoords
30860
- })
30861
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30862
- style: styles$t.spaceUnder
30863
- }, /*#__PURE__*/React__namespace.createElement(InfoTip$c, null, "The coordinates for the center of the ellipse."))), /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
30864
- coord: radius,
30865
- labels: ["x radius", "y radius"],
30866
- style: styles$t.spaceUnder,
30867
- onChange: newCoords => onChangeProps({
30868
- radius: newCoords
30869
- })
30870
- }), /*#__PURE__*/React__namespace.createElement(AngleInput, {
30871
- angle: angle,
30872
- onChange: newAngle => onChangeProps({
30873
- angle: newAngle
30874
- })
30875
- }), /*#__PURE__*/React__namespace.createElement(Strut, {
30868
+ coord: coord,
30869
+ onChange: newCoords => {
30870
+ onChangeProps({
30871
+ coord: newCoords
30872
+ });
30873
+ },
30874
+ style: styles$s.spaceUnder
30875
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30876
+ tag: "label",
30877
+ style: [styles$s.row, styles$s.spaceUnder]
30878
+ }, "TeX", /*#__PURE__*/React__namespace.createElement(Strut, {
30876
30879
  size: wonderBlocksTokens.spacing.xSmall_8
30877
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30878
- style: [styles$t.row, styles$t.spaceUnder]
30879
- }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30880
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30881
+ value: text,
30882
+ placeholder: "ex. x^2 or \\frac{1}{2}",
30883
+ onChange: newValue => onChangeProps({
30884
+ text: newValue
30885
+ })
30886
+ })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30887
+ style: styles$s.row
30888
+ }, onMove && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30880
30889
  selectedValue: color,
30881
- onChange: handleColorChange
30890
+ onChange: newColor => {
30891
+ onChangeProps({
30892
+ color: newColor
30893
+ });
30894
+ },
30895
+ style: styles$s.spaceUnder
30882
30896
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
30883
30897
  size: wonderBlocksTokens.spacing.medium_16
30884
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30898
+ })), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30885
30899
  tag: "label",
30886
- style: [styles$t.row, styles$t.truncatedWidth]
30887
- }, "fill", /*#__PURE__*/React__namespace.createElement(Strut, {
30888
- size: wonderBlocksTokens.spacing.xxSmall_6
30900
+ style: styles$s.row
30901
+ }, "size", /*#__PURE__*/React__namespace.createElement(Strut, {
30902
+ size: wonderBlocksTokens.spacing.xSmall_8
30889
30903
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30890
- selectedValue: fillStyle,
30891
- onChange: value => onChangeProps({
30892
- fillStyle: value
30904
+ selectedValue: size,
30905
+ onChange: newValue => onChangeProps({
30906
+ size: newValue
30893
30907
  })
30894
- // Placeholder is required, but never gets used.
30908
+ // Placeholder is required, but never gets used since
30909
+ // we have a label for the select.
30895
30910
  ,
30896
30911
  placeholder: ""
30897
- }, Object.keys(perseus.lockedFigureFillStyles).map(option => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30898
- key: option,
30899
- value: option,
30900
- label: option
30901
- }))))), /*#__PURE__*/React__namespace.createElement(LineStrokeSelect, {
30902
- selectedValue: strokeStyle,
30903
- onChange: value => onChangeProps({
30904
- strokeStyle: value
30905
- })
30906
- }), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
30907
- figureType: props.type,
30912
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30913
+ value: "small",
30914
+ label: "small"
30915
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30916
+ value: "medium",
30917
+ label: "medium"
30918
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30919
+ value: "large",
30920
+ label: "large"
30921
+ })))), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
30922
+ figureType: type,
30908
30923
  onMove: onMove,
30909
30924
  onRemove: onRemove
30910
30925
  }));
30911
- };
30912
- const styles$t = aphrodite.StyleSheet.create({
30926
+ }
30927
+ const styles$s = aphrodite.StyleSheet.create({
30928
+ accordionHeaderContainer: {
30929
+ // Stop the label summary from wrapping.
30930
+ whiteSpace: "nowrap"
30931
+ },
30932
+ accordionHeader: {
30933
+ padding: wonderBlocksTokens.spacing.xxxSmall_4,
30934
+ marginInlineEnd: wonderBlocksTokens.spacing.xSmall_8,
30935
+ borderRadius: wonderBlocksTokens.spacing.xxxSmall_4,
30936
+ textOverflow: "ellipsis",
30937
+ overflow: "hidden"
30938
+ },
30913
30939
  row: {
30914
30940
  display: "flex",
30915
30941
  flexDirection: "row",
30916
- alignItems: "center"
30917
- },
30918
- spaceUnder: {
30919
- marginBottom: wonderBlocksTokens.spacing.xSmall_8
30920
- },
30921
- truncatedWidth: {
30942
+ alignItems: "center",
30922
30943
  // Allow truncation, stop bleeding over the edge.
30923
30944
  minWidth: 0
30924
- }
30925
- });
30926
-
30927
- const LineSwatch = props => {
30928
- const {
30929
- color,
30930
- lineStyle
30931
- } = props;
30932
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30933
- style: styles$s.container
30934
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30935
- "aria-label": `${color}, ${lineStyle}`,
30936
- style: [styles$s.lineSwatch, {
30937
- border: `5px ${lineStyle} ${perseus.lockedFigureColors[color]}`
30938
- }]
30939
- }));
30940
- };
30941
- const styles$s = aphrodite.StyleSheet.create({
30942
- container: {
30943
- backgroundColor: wonderBlocksTokens.color.white,
30944
- justifyContent: "center",
30945
- padding: wonderBlocksTokens.spacing.xSmall_8,
30946
- borderRadius: wonderBlocksTokens.spacing.xxxSmall_4
30947
30945
  },
30948
- lineSwatch: {
30949
- width: 40
30946
+ spaceUnder: {
30947
+ marginBottom: wonderBlocksTokens.spacing.xSmall_8
30950
30948
  }
30951
30949
  });
30952
30950
 
30953
- const examples = {
30954
- linear: ["x + 5", "1/2x - 2"],
30955
- polynomial: ["1/2x^2 + 3x - 4", "(1/3)x^3 - 2x^2 + 3x - 4"],
30956
- trigonometric: ["sin(x) * 3", "arctan(2x) + 4"]
30957
- };
30958
-
30959
- /**
30960
- * LockedFunctionSettings is a component that allows the user to edit the
30961
- * settings of specifically a locked function on the graph.
30962
- *
30963
- * Used in the interactive graph editor's locked figures section.
30964
- */
30965
- const LockedFunctionSettings = props => {
30966
- const {
30967
- color: lineColor,
30968
- strokeStyle,
30969
- equation,
30970
- directionalAxis,
30951
+ const DEFAULT_COLOR = "grayH";
30952
+ function getDefaultFigureForType(type) {
30953
+ switch (type) {
30954
+ case "point":
30955
+ return {
30956
+ type: "point",
30957
+ coord: [0, 0],
30958
+ color: DEFAULT_COLOR,
30959
+ filled: true
30960
+ };
30961
+ case "line":
30962
+ return {
30963
+ type: "line",
30964
+ kind: "line",
30965
+ points: [getDefaultFigureForType("point"), {
30966
+ ...getDefaultFigureForType("point"),
30967
+ coord: [2, 2]
30968
+ }],
30969
+ color: DEFAULT_COLOR,
30970
+ lineStyle: "solid",
30971
+ showPoint1: false,
30972
+ showPoint2: false
30973
+ };
30974
+ case "vector":
30975
+ return {
30976
+ type: "vector",
30977
+ points: [[0, 0], [2, 2]],
30978
+ color: DEFAULT_COLOR
30979
+ };
30980
+ case "ellipse":
30981
+ return {
30982
+ type: "ellipse",
30983
+ center: [0, 0],
30984
+ radius: [1, 1],
30985
+ angle: 0,
30986
+ color: DEFAULT_COLOR,
30987
+ fillStyle: "none",
30988
+ strokeStyle: "solid"
30989
+ };
30990
+ case "polygon":
30991
+ return {
30992
+ type: "polygon",
30993
+ points: [[0, 2], [-1, 0], [1, 0]],
30994
+ color: DEFAULT_COLOR,
30995
+ showVertices: false,
30996
+ fillStyle: "none",
30997
+ strokeStyle: "solid"
30998
+ };
30999
+ case "function":
31000
+ return {
31001
+ type: "function",
31002
+ color: DEFAULT_COLOR,
31003
+ strokeStyle: "solid",
31004
+ equation: "x^2",
31005
+ directionalAxis: "x"
31006
+ };
31007
+ case "label":
31008
+ return {
31009
+ type: "label",
31010
+ coord: [0, 0],
31011
+ text: "",
31012
+ color: DEFAULT_COLOR,
31013
+ size: "medium"
31014
+ };
31015
+ default:
31016
+ throw new wonderStuffCore.UnreachableCaseError(type);
31017
+ }
31018
+ }
31019
+
31020
+ const {
31021
+ InfoTip: InfoTip$c
31022
+ } = perseus.components;
31023
+ const LockedEllipseSettings = props => {
31024
+ const {
31025
+ flags,
31026
+ center,
31027
+ radius,
31028
+ angle,
31029
+ color,
31030
+ labels,
31031
+ fillStyle,
31032
+ strokeStyle,
31033
+ expanded,
31034
+ onToggle,
31035
+ onChangeProps,
31036
+ onMove,
31037
+ onRemove
31038
+ } = props;
31039
+ function handleCenterChange(newCoord) {
31040
+ const xOffset = newCoord[0] - center[0];
31041
+ const yOffset = newCoord[1] - center[1];
31042
+ const newProps = {
31043
+ center: newCoord
31044
+ };
31045
+
31046
+ // Update the coord by the same amount as the point for all labels
31047
+ newProps.labels = labels?.map(label => ({
31048
+ ...label,
31049
+ coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31050
+ }));
31051
+ onChangeProps(newProps);
31052
+ }
31053
+ function handleColorChange(newValue) {
31054
+ const newProps = {
31055
+ color: newValue
31056
+ };
31057
+
31058
+ // Update the color of the all labels to match the point
31059
+ newProps.labels = labels?.map(label => ({
31060
+ ...label,
31061
+ color: newValue
31062
+ }));
31063
+ onChangeProps(newProps);
31064
+ }
31065
+ function handleLabelChange(updatedLabel, labelIndex) {
31066
+ if (!labels) {
31067
+ return;
31068
+ }
31069
+ const updatedLabels = [...labels];
31070
+ updatedLabels[labelIndex] = {
31071
+ ...labels[labelIndex],
31072
+ ...updatedLabel
31073
+ };
31074
+ onChangeProps({
31075
+ labels: updatedLabels
31076
+ });
31077
+ }
31078
+ function handleLabelRemove(labelIndex) {
31079
+ if (!labels) {
31080
+ return;
31081
+ }
31082
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31083
+ onChangeProps({
31084
+ labels: updatedLabels
31085
+ });
31086
+ }
31087
+ return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31088
+ expanded: expanded,
31089
+ onToggle: onToggle,
31090
+ header:
31091
+ /*#__PURE__*/
31092
+ // Summary: Ellipse, center, radius, color (opacity, dashed)
31093
+ React__namespace.createElement(wonderBlocksCore.View, {
31094
+ style: styles$r.row
31095
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`), /*#__PURE__*/React__namespace.createElement(Strut, {
31096
+ size: wonderBlocksTokens.spacing.xSmall_8
31097
+ }), /*#__PURE__*/React__namespace.createElement(EllipseSwatch, {
31098
+ color: props.color,
31099
+ fillStyle: fillStyle,
31100
+ strokeStyle: strokeStyle
31101
+ }))
31102
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31103
+ style: styles$r.row
31104
+ }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31105
+ coord: center,
31106
+ style: styles$r.spaceUnder,
31107
+ onChange: handleCenterChange
31108
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31109
+ style: styles$r.spaceUnder
31110
+ }, /*#__PURE__*/React__namespace.createElement(InfoTip$c, null, "The coordinates for the center of the ellipse."))), /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31111
+ coord: radius,
31112
+ labels: ["x radius", "y radius"],
31113
+ style: styles$r.spaceUnder,
31114
+ onChange: newCoords => onChangeProps({
31115
+ radius: newCoords
31116
+ })
31117
+ }), /*#__PURE__*/React__namespace.createElement(AngleInput, {
31118
+ angle: angle,
31119
+ onChange: newAngle => onChangeProps({
31120
+ angle: newAngle
31121
+ })
31122
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
31123
+ size: wonderBlocksTokens.spacing.xSmall_8
31124
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31125
+ style: [styles$r.row, styles$r.spaceUnder]
31126
+ }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31127
+ selectedValue: color,
31128
+ onChange: handleColorChange
31129
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
31130
+ size: wonderBlocksTokens.spacing.medium_16
31131
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31132
+ tag: "label",
31133
+ style: [styles$r.row, styles$r.truncatedWidth]
31134
+ }, "fill", /*#__PURE__*/React__namespace.createElement(Strut, {
31135
+ size: wonderBlocksTokens.spacing.xxSmall_6
31136
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
31137
+ selectedValue: fillStyle,
31138
+ onChange: value => onChangeProps({
31139
+ fillStyle: value
31140
+ })
31141
+ // Placeholder is required, but never gets used.
31142
+ ,
31143
+ placeholder: ""
31144
+ }, Object.keys(perseus.lockedFigureFillStyles).map(option => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31145
+ key: option,
31146
+ value: option,
31147
+ label: option
31148
+ }))))), /*#__PURE__*/React__namespace.createElement(LineStrokeSelect, {
31149
+ selectedValue: strokeStyle,
31150
+ onChange: value => onChangeProps({
31151
+ strokeStyle: value
31152
+ })
31153
+ }), flags?.["mafs"]?.["locked-ellipse-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, labels?.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
31154
+ expanded: true,
31155
+ onChangeProps: newLabel => {
31156
+ handleLabelChange(newLabel, labelIndex);
31157
+ },
31158
+ onRemove: () => {
31159
+ handleLabelRemove(labelIndex);
31160
+ },
31161
+ containerStyle: styles$r.labelContainer
31162
+ }))), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
31163
+ kind: "tertiary",
31164
+ startIcon: plusCircle__default["default"],
31165
+ onClick: () => {
31166
+ const newLabel = {
31167
+ ...getDefaultFigureForType("label"),
31168
+ coord: [center[0],
31169
+ // Additional vertical offset for each
31170
+ // label so they don't overlap.
31171
+ center[1] - (labels?.length ?? 0)],
31172
+ // Default to the same color as the ellipse
31173
+ color: color
31174
+ };
31175
+ onChangeProps({
31176
+ labels: [...(labels ?? []), newLabel]
31177
+ });
31178
+ },
31179
+ style: styles$r.addButton
31180
+ }, "Add visible label")), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31181
+ figureType: props.type,
31182
+ onMove: onMove,
31183
+ onRemove: onRemove
31184
+ }));
31185
+ };
31186
+ const styles$r = aphrodite.StyleSheet.create({
31187
+ row: {
31188
+ display: "flex",
31189
+ flexDirection: "row",
31190
+ alignItems: "center"
31191
+ },
31192
+ spaceUnder: {
31193
+ marginBottom: wonderBlocksTokens.spacing.xSmall_8
31194
+ },
31195
+ truncatedWidth: {
31196
+ // Allow truncation, stop bleeding over the edge.
31197
+ minWidth: 0
31198
+ },
31199
+ addButton: {
31200
+ alignSelf: "start"
31201
+ },
31202
+ labelContainer: {
31203
+ backgroundColor: wonderBlocksTokens.color.white
31204
+ }
31205
+ });
31206
+
31207
+ const LineSwatch = props => {
31208
+ const {
31209
+ color,
31210
+ lineStyle
31211
+ } = props;
31212
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31213
+ style: styles$q.container
31214
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31215
+ "aria-label": `${color}, ${lineStyle}`,
31216
+ style: [styles$q.lineSwatch, {
31217
+ border: `5px ${lineStyle} ${perseus.lockedFigureColors[color]}`
31218
+ }]
31219
+ }));
31220
+ };
31221
+ const styles$q = aphrodite.StyleSheet.create({
31222
+ container: {
31223
+ backgroundColor: wonderBlocksTokens.color.white,
31224
+ justifyContent: "center",
31225
+ padding: wonderBlocksTokens.spacing.xSmall_8,
31226
+ borderRadius: wonderBlocksTokens.spacing.xxxSmall_4
31227
+ },
31228
+ lineSwatch: {
31229
+ width: 40
31230
+ }
31231
+ });
31232
+
31233
+ const examples = {
31234
+ linear: ["x + 5", "1/2x - 2"],
31235
+ polynomial: ["1/2x^2 + 3x - 4", "(1/3)x^3 - 2x^2 + 3x - 4"],
31236
+ trigonometric: ["sin(x) * 3", "arctan(2x) + 4"]
31237
+ };
31238
+
31239
+ const LockedFunctionSettings = props => {
31240
+ const {
31241
+ flags,
31242
+ color: lineColor,
31243
+ strokeStyle,
31244
+ equation,
31245
+ directionalAxis,
30971
31246
  domain,
31247
+ labels,
30972
31248
  onChangeProps,
30973
31249
  onMove,
30974
31250
  onRemove
@@ -31019,13 +31295,47 @@ const LockedFunctionSettings = props => {
31019
31295
  const exampleCategories = Object.keys(examples);
31020
31296
  const exampleCategorySelected = exampleCategory !== "";
31021
31297
  const exampleContent = exampleCategorySelected ? examples[exampleCategory] : ["Select category to see example equations"];
31298
+ function handleColorChange(newValue) {
31299
+ const newProps = {
31300
+ color: newValue
31301
+ };
31302
+
31303
+ // Update the color of the all labels to match the point
31304
+ newProps.labels = labels?.map(label => ({
31305
+ ...label,
31306
+ color: newValue
31307
+ }));
31308
+ onChangeProps(newProps);
31309
+ }
31310
+ function handleLabelChange(updatedLabel, labelIndex) {
31311
+ if (!labels) {
31312
+ return;
31313
+ }
31314
+ const updatedLabels = [...labels];
31315
+ updatedLabels[labelIndex] = {
31316
+ ...labels[labelIndex],
31317
+ ...updatedLabel
31318
+ };
31319
+ onChangeProps({
31320
+ labels: updatedLabels
31321
+ });
31322
+ }
31323
+ function handleLabelRemove(labelIndex) {
31324
+ if (!labels) {
31325
+ return;
31326
+ }
31327
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31328
+ onChangeProps({
31329
+ labels: updatedLabels
31330
+ });
31331
+ }
31022
31332
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31023
31333
  expanded: props.expanded,
31024
31334
  onToggle: props.onToggle,
31025
31335
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31026
- style: styles$r.row
31336
+ style: styles$p.row
31027
31337
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
31028
- style: styles$r.accordionHeader
31338
+ style: styles$p.accordionHeader
31029
31339
  }, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
31030
31340
  size: wonderBlocksTokens.spacing.xSmall_8
31031
31341
  }), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
@@ -31033,12 +31343,10 @@ const LockedFunctionSettings = props => {
31033
31343
  lineStyle: strokeStyle
31034
31344
  }))
31035
31345
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31036
- style: [styles$r.row, styles$r.spaceUnder]
31346
+ style: [styles$p.row, styles$p.spaceUnder]
31037
31347
  }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31038
31348
  selectedValue: lineColor,
31039
- onChange: newValue => {
31040
- handlePropChange("color", newValue);
31041
- }
31349
+ onChange: handleColorChange
31042
31350
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
31043
31351
  size: wonderBlocksTokens.spacing.small_12
31044
31352
  }), /*#__PURE__*/React__namespace.createElement(LineStrokeSelect, {
@@ -31047,14 +31355,14 @@ const LockedFunctionSettings = props => {
31047
31355
  handlePropChange("strokeStyle", newValue);
31048
31356
  }
31049
31357
  })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31050
- style: [styles$r.row, styles$r.rowSpace]
31358
+ style: [styles$p.row, styles$p.rowSpace]
31051
31359
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
31052
31360
  selectedValue: directionalAxis,
31053
31361
  onChange: newValue => {
31054
31362
  handlePropChange("directionalAxis", newValue);
31055
31363
  },
31056
31364
  "aria-label": "equation prefix",
31057
- style: [styles$r.dropdownLabel, styles$r.axisMenu]
31365
+ style: [styles$p.dropdownLabel, styles$p.axisMenu]
31058
31366
  // Placeholder is required, but never gets used.
31059
31367
  ,
31060
31368
  placeholder: ""
@@ -31073,17 +31381,17 @@ const LockedFunctionSettings = props => {
31073
31381
  onChange: newValue => {
31074
31382
  handlePropChange("equation", newValue);
31075
31383
  },
31076
- style: [styles$r.textField]
31384
+ style: [styles$p.textField]
31077
31385
  })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31078
- style: [styles$r.row, styles$r.rowSpace]
31386
+ style: [styles$p.row, styles$p.rowSpace]
31079
31387
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31080
31388
  tag: "label",
31081
- style: [styles$r.dropdownLabel, styles$r.domainMin]
31389
+ style: [styles$p.dropdownLabel, styles$p.domainMin]
31082
31390
  }, `${domainRangeText} min`, /*#__PURE__*/React__namespace.createElement(Strut, {
31083
31391
  size: wonderBlocksTokens.spacing.xxSmall_6
31084
31392
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
31085
31393
  type: "number",
31086
- style: styles$r.domainMinField,
31394
+ style: styles$p.domainMinField,
31087
31395
  value: domainEntries[0],
31088
31396
  onChange: newValue => {
31089
31397
  handleDomainChange(0, newValue);
@@ -31093,12 +31401,12 @@ const LockedFunctionSettings = props => {
31093
31401
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31094
31402
  tag: "label",
31095
31403
  "aria-label": `${domainRangeText} max`,
31096
- style: [styles$r.dropdownLabel, styles$r.domainMax]
31404
+ style: [styles$p.dropdownLabel, styles$p.domainMax]
31097
31405
  }, "max", /*#__PURE__*/React__namespace.createElement(Strut, {
31098
31406
  size: wonderBlocksTokens.spacing.xxSmall_6
31099
31407
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
31100
31408
  type: "number",
31101
- style: styles$r.domainMaxField,
31409
+ style: styles$p.domainMaxField,
31102
31410
  value: domainEntries[1],
31103
31411
  onChange: newValue => {
31104
31412
  handleDomainChange(1, newValue);
@@ -31106,11 +31414,11 @@ const LockedFunctionSettings = props => {
31106
31414
  }))), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31107
31415
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Example Functions"),
31108
31416
  expanded: false,
31109
- containerStyle: styles$r.exampleWorkspace,
31110
- panelStyle: styles$r.exampleAccordionPanel
31417
+ containerStyle: styles$p.exampleWorkspace,
31418
+ panelStyle: styles$p.exampleAccordionPanel
31111
31419
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31112
31420
  tag: "label",
31113
- style: styles$r.dropdownLabel
31421
+ style: styles$p.dropdownLabel
31114
31422
  }, "Choose a category", /*#__PURE__*/React__namespace.createElement(Strut, {
31115
31423
  size: wonderBlocksTokens.spacing.xxSmall_6
31116
31424
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -31124,13 +31432,41 @@ const LockedFunctionSettings = props => {
31124
31432
  label: category
31125
31433
  });
31126
31434
  }))), exampleCategorySelected && /*#__PURE__*/React__namespace.createElement("ul", {
31127
- className: aphrodite.css(styles$r.exampleContainer)
31435
+ className: aphrodite.css(styles$p.exampleContainer)
31128
31436
  }, exampleContent.map((example, index) => /*#__PURE__*/React__namespace.createElement(ExampleItem, {
31129
31437
  category: exampleCategory,
31130
31438
  example: example,
31131
31439
  index: index,
31132
31440
  pasteEquationFn: handlePropChange
31133
- })))), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31441
+ })))), flags?.["mafs"]?.["locked-function-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31442
+ style: styles$p.horizontalRule
31443
+ }), labels?.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
31444
+ expanded: true,
31445
+ onChangeProps: newLabel => {
31446
+ handleLabelChange(newLabel, labelIndex);
31447
+ },
31448
+ onRemove: () => {
31449
+ handleLabelRemove(labelIndex);
31450
+ },
31451
+ containerStyle: styles$p.labelContainer
31452
+ }))), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
31453
+ kind: "tertiary",
31454
+ startIcon: plusCircle__default["default"],
31455
+ onClick: () => {
31456
+ const newLabel = {
31457
+ ...getDefaultFigureForType("label"),
31458
+ // Vertical offset for each label so they
31459
+ // don't overlap.
31460
+ coord: [0, -(labels?.length ?? 0)],
31461
+ // Default to the same color as the function
31462
+ color: lineColor
31463
+ };
31464
+ onChangeProps({
31465
+ labels: [...(labels ?? []), newLabel]
31466
+ });
31467
+ },
31468
+ style: styles$p.addButton
31469
+ }, "Add visible label")), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31134
31470
  figureType: props.type,
31135
31471
  onMove: onMove,
31136
31472
  onRemove: onRemove
@@ -31146,29 +31482,29 @@ const ExampleItem = props => {
31146
31482
  const exampleId = React.useId();
31147
31483
  return /*#__PURE__*/React__namespace.createElement("li", {
31148
31484
  key: `${category}-${index}`,
31149
- className: aphrodite.css(styles$r.exampleRow)
31485
+ className: aphrodite.css(styles$p.exampleRow)
31150
31486
  }, /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
31151
31487
  icon: autoPasteIcon__default["default"],
31152
31488
  "aria-label": "paste example",
31153
31489
  "aria-describedby": exampleId,
31154
31490
  onClick: () => pasteEquationFn("equation", example),
31155
31491
  size: "medium",
31156
- style: styles$r.copyPasteButton
31492
+ style: styles$p.copyPasteButton
31157
31493
  }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
31158
31494
  icon: copyIcon__default["default"],
31159
31495
  "aria-label": "copy example",
31160
31496
  "aria-describedby": exampleId,
31161
31497
  onClick: () => navigator.clipboard.writeText(example),
31162
31498
  size: "medium",
31163
- style: styles$r.copyPasteButton
31499
+ style: styles$p.copyPasteButton
31164
31500
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
31165
31501
  size: wonderBlocksTokens.spacing.xxxSmall_4
31166
31502
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31167
- style: styles$r.exampleContent,
31503
+ style: styles$p.exampleContent,
31168
31504
  id: exampleId
31169
31505
  }, example));
31170
31506
  };
31171
- const styles$r = aphrodite.StyleSheet.create({
31507
+ const styles$p = aphrodite.StyleSheet.create({
31172
31508
  accordionHeader: {
31173
31509
  textOverflow: "ellipsis",
31174
31510
  // A maximum width needs to be specified in order for the ellipsis to work.
@@ -31259,126 +31595,18 @@ const styles$r = aphrodite.StyleSheet.create({
31259
31595
  },
31260
31596
  textField: {
31261
31597
  flexGrow: "1"
31262
- }
31263
- });
31264
-
31265
- /**
31266
- * LockedLabelSettings is a component that allows the user to edit the
31267
- * settings of specifically a locked label on the graph within the
31268
- * Interactive Graph widget.
31269
- *
31270
- * Used in the interactive graph editor's locked figures section.
31271
- */
31272
- function LockedLabelSettings(props) {
31273
- const {
31274
- type,
31275
- coord,
31276
- color,
31277
- size,
31278
- text,
31279
- expanded,
31280
- onChangeProps,
31281
- onMove,
31282
- onRemove,
31283
- onToggle
31284
- } = props;
31285
- return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31286
- expanded: expanded,
31287
- onToggle: onToggle,
31288
- header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31289
- style: [styles$q.row, styles$q.accordionHeaderContainer]
31290
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Label (", coord[0], ", ", coord[1], ")"), /*#__PURE__*/React__namespace.createElement(Strut, {
31291
- size: wonderBlocksTokens.spacing.xSmall_8
31292
- }), text !== "" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
31293
- style: [{
31294
- backgroundColor: wonderBlocksTokens.color.white,
31295
- color: perseus.lockedFigureColors[color]
31296
- }, styles$q.accordionHeader]
31297
- }, text)),
31298
- containerStyle: !onMove && styles$q.innerLabelAccordionPanel
31299
- }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31300
- coord: coord,
31301
- onChange: newCoords => {
31302
- onChangeProps({
31303
- coord: newCoords
31304
- });
31305
- },
31306
- style: styles$q.spaceUnder
31307
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31308
- tag: "label",
31309
- style: [styles$q.row, styles$q.spaceUnder]
31310
- }, "TeX", /*#__PURE__*/React__namespace.createElement(Strut, {
31311
- size: wonderBlocksTokens.spacing.xSmall_8
31312
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
31313
- value: text,
31314
- placeholder: "ex. x^2 or \\frac{1}{2}",
31315
- onChange: newValue => onChangeProps({
31316
- text: newValue
31317
- })
31318
- })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31319
- style: styles$q.row
31320
- }, onMove && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31321
- selectedValue: color,
31322
- onChange: newColor => {
31323
- onChangeProps({
31324
- color: newColor
31325
- });
31326
- },
31327
- style: styles$q.spaceUnder
31328
- }), /*#__PURE__*/React__namespace.createElement(Strut, {
31329
- size: wonderBlocksTokens.spacing.medium_16
31330
- })), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31331
- tag: "label",
31332
- style: styles$q.row
31333
- }, "size", /*#__PURE__*/React__namespace.createElement(Strut, {
31334
- size: wonderBlocksTokens.spacing.xSmall_8
31335
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
31336
- selectedValue: size,
31337
- onChange: newValue => onChangeProps({
31338
- size: newValue
31339
- })
31340
- // Placeholder is required, but never gets used since
31341
- // we have a label for the select.
31342
- ,
31343
- placeholder: ""
31344
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31345
- value: "small",
31346
- label: "small"
31347
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31348
- value: "medium",
31349
- label: "medium"
31350
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31351
- value: "large",
31352
- label: "large"
31353
- })))), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31354
- figureType: type,
31355
- onMove: onMove,
31356
- onRemove: onRemove
31357
- }));
31358
- }
31359
- const styles$q = aphrodite.StyleSheet.create({
31360
- accordionHeaderContainer: {
31361
- // Stop the label summary from wrapping.
31362
- whiteSpace: "nowrap"
31363
- },
31364
- accordionHeader: {
31365
- padding: wonderBlocksTokens.spacing.xxxSmall_4,
31366
- marginInlineEnd: wonderBlocksTokens.spacing.xSmall_8,
31367
- borderRadius: wonderBlocksTokens.spacing.xxxSmall_4,
31368
- textOverflow: "ellipsis",
31369
- overflow: "hidden"
31370
31598
  },
31371
- row: {
31372
- display: "flex",
31373
- flexDirection: "row",
31374
- alignItems: "center",
31375
- // Allow truncation, stop bleeding over the edge.
31376
- minWidth: 0
31599
+ // Label settings styles
31600
+ addButton: {
31601
+ alignSelf: "start"
31377
31602
  },
31378
- spaceUnder: {
31379
- marginBottom: wonderBlocksTokens.spacing.xSmall_8
31603
+ horizontalRule: {
31604
+ marginTop: wonderBlocksTokens.spacing.small_12,
31605
+ marginBottom: wonderBlocksTokens.spacing.xxxSmall_4,
31606
+ height: 1,
31607
+ backgroundColor: wonderBlocksTokens.color.offBlack16
31380
31608
  },
31381
- innerLabelAccordionPanel: {
31609
+ labelContainer: {
31382
31610
  backgroundColor: wonderBlocksTokens.color.white
31383
31611
  }
31384
31612
  });
@@ -31393,7 +31621,7 @@ const LabeledSwitch = props => {
31393
31621
  const ids = wonderBlocksCore.useUniqueIdWithMock();
31394
31622
  const switchId = ids.get("switch");
31395
31623
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31396
- style: [styles$p.row, style]
31624
+ style: [styles$o.row, style]
31397
31625
  }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
31398
31626
  id: switchId,
31399
31627
  checked: checked,
@@ -31405,71 +31633,112 @@ const LabeledSwitch = props => {
31405
31633
  htmlFor: switchId
31406
31634
  }, label));
31407
31635
  };
31408
- const styles$p = aphrodite.StyleSheet.create({
31636
+ const styles$o = aphrodite.StyleSheet.create({
31409
31637
  row: {
31410
31638
  flexDirection: "row",
31411
31639
  alignItems: "center"
31412
31640
  }
31413
31641
  });
31414
31642
 
31415
- /**
31416
- * DefiningPointSettings is a component that allows the user to edit the
31417
- * settings of a point that defines a locked figure (ex. line) on the graph.
31418
- *
31419
- * Used in the interactive graph editor's locked figures section.
31420
- */
31421
- const DefiningPointSettings = props => {
31643
+ const LockedPointSettings = props => {
31422
31644
  const {
31645
+ flags,
31646
+ headerLabel,
31423
31647
  coord,
31424
31648
  color: pointColor,
31425
31649
  filled = true,
31426
- label,
31427
- showPoint = "false",
31428
- error,
31650
+ labels,
31429
31651
  onChangeProps,
31430
- onTogglePoint,
31652
+ onMove,
31653
+ onRemove,
31654
+ // defining point props
31655
+ showPoint,
31431
31656
  expanded,
31657
+ onTogglePoint,
31432
31658
  onToggle
31433
31659
  } = props;
31660
+ const isDefiningPoint = !onMove && !onRemove;
31434
31661
  function handleColorChange(newValue) {
31435
- onChangeProps({
31662
+ const newProps = {
31436
31663
  color: newValue
31664
+ };
31665
+
31666
+ // Update the color of the all labels to match the point
31667
+ if (labels) {
31668
+ newProps.labels = labels.map(label => ({
31669
+ ...label,
31670
+ color: newValue
31671
+ }));
31672
+ }
31673
+ onChangeProps(newProps);
31674
+ }
31675
+ function handleCoordChange(newCoord) {
31676
+ const xOffset = newCoord[0] - coord[0];
31677
+ const yOffset = newCoord[1] - coord[1];
31678
+ const newProps = {
31679
+ coord: newCoord
31680
+ };
31681
+
31682
+ // Update the coord by the same amount as the point for all labels
31683
+ if (labels) {
31684
+ newProps.labels = labels.map(label => ({
31685
+ ...label,
31686
+ coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31687
+ }));
31688
+ }
31689
+ onChangeProps(newProps);
31690
+ }
31691
+ function handleLabelChange(updatedLabel, labelIndex) {
31692
+ if (!labels) {
31693
+ return;
31694
+ }
31695
+ const updatedLabels = [...labels];
31696
+ updatedLabels[labelIndex] = {
31697
+ ...labels[labelIndex],
31698
+ ...updatedLabel
31699
+ };
31700
+ onChangeProps({
31701
+ labels: updatedLabels
31702
+ });
31703
+ }
31704
+ function handleLabelRemove(labelIndex) {
31705
+ if (!labels) {
31706
+ return;
31707
+ }
31708
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31709
+ onChangeProps({
31710
+ labels: updatedLabels
31437
31711
  });
31438
31712
  }
31439
31713
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31440
31714
  expanded: expanded,
31441
31715
  onToggle: onToggle,
31442
- containerStyle: styles$o.container,
31443
- panelStyle: styles$o.accordionPanel,
31716
+ containerStyle: isDefiningPoint ? styles$n.definingContainer : undefined,
31717
+ panelStyle: isDefiningPoint ? styles$n.definingPanel : undefined,
31444
31718
  header:
31445
31719
  /*#__PURE__*/
31446
31720
  // Summary: Point, coords, color (filled/open)
31447
31721
  React__namespace.createElement(wonderBlocksCore.View, {
31448
- style: styles$o.row
31449
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `${label || "Point"} (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React__namespace.createElement(Strut, {
31722
+ style: styles$n.row
31723
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `${headerLabel || "Point"} (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React__namespace.createElement(Strut, {
31450
31724
  size: wonderBlocksTokens.spacing.xSmall_8
31451
- }), showPoint && /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
31725
+ }), /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
31452
31726
  color: pointColor,
31453
31727
  filled: filled
31454
31728
  }))
31455
31729
  }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31456
31730
  coord: coord,
31457
- error: !!error,
31458
- style: styles$o.spaceUnder,
31459
- onChange: newCoords => {
31460
- onChangeProps({
31461
- coord: newCoords
31462
- });
31463
- }
31731
+ style: styles$n.spaceUnder,
31732
+ onChange: handleCoordChange
31464
31733
  }), onTogglePoint && /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
31465
31734
  label: "show point on graph",
31466
31735
  checked: !!showPoint,
31467
- style: showPoint && styles$o.spaceUnder,
31736
+ style: showPoint && styles$n.spaceUnder,
31468
31737
  onChange: onTogglePoint
31469
- }), showPoint && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31738
+ }), (!isDefiningPoint || showPoint) && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31470
31739
  selectedValue: pointColor,
31471
31740
  onChange: handleColorChange,
31472
- style: styles$o.spaceUnder
31741
+ style: styles$n.spaceUnder
31473
31742
  }), /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
31474
31743
  label: "open point",
31475
31744
  checked: !filled,
@@ -31478,19 +31747,58 @@ const DefiningPointSettings = props => {
31478
31747
  filled: !newValue
31479
31748
  });
31480
31749
  }
31481
- })));
31750
+ })), (!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, {
31751
+ containerStyle: !isDefiningPoint && styles$n.lockedPointLabelContainer,
31752
+ expanded: true,
31753
+ onChangeProps: newLabel => {
31754
+ handleLabelChange(newLabel, labelIndex);
31755
+ },
31756
+ onRemove: () => {
31757
+ handleLabelRemove(labelIndex);
31758
+ }
31759
+ }))), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
31760
+ kind: "tertiary",
31761
+ startIcon: plusCircle__default["default"],
31762
+ onClick: () => {
31763
+ const newLabel = {
31764
+ ...getDefaultFigureForType("label"),
31765
+ // Place the label at the same position
31766
+ // as the point. Add a small offset to
31767
+ // avoid crowding.
31768
+ coord: [coord[0] + 0.5,
31769
+ // Additional offset for each label so
31770
+ // they don't overlap.
31771
+ coord[1] - 1 * (labels?.length ?? 0)],
31772
+ // Default to the same color as the point
31773
+ color: pointColor
31774
+ };
31775
+ onChangeProps({
31776
+ labels: [...(labels ?? []), newLabel]
31777
+ });
31778
+ },
31779
+ style: styles$n.addButton
31780
+ }, "Add visible label")), onRemove && /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31781
+ figureType: props.type,
31782
+ onMove: onMove,
31783
+ onRemove: onRemove
31784
+ }));
31482
31785
  };
31483
- const styles$o = aphrodite.StyleSheet.create({
31484
- container: {
31786
+ const styles$n = aphrodite.StyleSheet.create({
31787
+ definingContainer: {
31485
31788
  marginTop: wonderBlocksTokens.spacing.xSmall_8,
31486
31789
  marginBottom: 0,
31487
31790
  marginLeft: -wonderBlocksTokens.spacing.xxxSmall_4,
31488
31791
  marginRight: -wonderBlocksTokens.spacing.xxxSmall_4,
31489
31792
  backgroundColor: wonderBlocksTokens.color.white
31490
31793
  },
31491
- accordionPanel: {
31794
+ definingPanel: {
31492
31795
  // Need more space since we don't have the actions' margins.
31493
- paddingBottom: wonderBlocksTokens.spacing.medium_16
31796
+ paddingBottom: wonderBlocksTokens.spacing.xxSmall_6
31797
+ },
31798
+ // A regular point (NOT a defining point) has label
31799
+ // accordions with white backgrounds.
31800
+ lockedPointLabelContainer: {
31801
+ backgroundColor: wonderBlocksTokens.color.white
31494
31802
  },
31495
31803
  row: {
31496
31804
  flexDirection: "row",
@@ -31498,18 +31806,23 @@ const styles$o = aphrodite.StyleSheet.create({
31498
31806
  },
31499
31807
  spaceUnder: {
31500
31808
  marginBottom: wonderBlocksTokens.spacing.xSmall_8
31809
+ },
31810
+ addButton: {
31811
+ alignSelf: "start"
31501
31812
  }
31502
31813
  });
31503
31814
 
31504
31815
  const lengthZeroStr = "The line cannot have length 0.";
31505
31816
  const LockedLineSettings = props => {
31506
31817
  const {
31818
+ flags,
31507
31819
  kind,
31508
31820
  points,
31509
31821
  color: lineColor,
31510
31822
  lineStyle = "solid",
31511
31823
  showPoint1,
31512
31824
  showPoint2,
31825
+ labels,
31513
31826
  onChangeProps,
31514
31827
  onMove,
31515
31828
  onRemove
@@ -31527,28 +31840,75 @@ const LockedLineSettings = props => {
31527
31840
  ...points[index],
31528
31841
  ...newPointProps
31529
31842
  };
31843
+
31844
+ // Update labels to be centered between the two points,
31845
+ // retaining existing offset.
31846
+ const oldMidpoint = mafs.vec.midpoint(points[0].coord, points[1].coord);
31847
+ const newMidpoint = mafs.vec.midpoint(newPoints[0].coord, newPoints[1].coord);
31848
+ const offset = [newMidpoint[0] - oldMidpoint[0], newMidpoint[1] - oldMidpoint[1]];
31849
+ const newLabels = labels?.map((label, labelIndex) => ({
31850
+ ...label,
31851
+ coord: [label.coord[0] + offset[0], label.coord[1] + offset[1]]
31852
+ }));
31530
31853
  onChangeProps({
31531
- points: newPoints
31854
+ points: newPoints,
31855
+ labels: newLabels
31532
31856
  });
31533
31857
  }
31534
31858
  function handleColorChange(newColor) {
31859
+ const newLabels = labels?.map(label => ({
31860
+ ...label,
31861
+ color: newColor
31862
+ }));
31535
31863
  onChangeProps({
31536
31864
  color: newColor,
31537
31865
  // Keep the line's points' colors in sync with the line color.
31538
31866
  points: [{
31539
31867
  ...point1,
31540
- color: newColor
31868
+ color: newColor,
31869
+ labels: point1.labels?.map(label => ({
31870
+ ...label,
31871
+ color: newColor
31872
+ }))
31541
31873
  }, {
31542
31874
  ...point2,
31543
- color: newColor
31544
- }]
31875
+ color: newColor,
31876
+ labels: point2.labels?.map(label => ({
31877
+ ...label,
31878
+ color: newColor
31879
+ }))
31880
+ }],
31881
+ // Keep the line's labels' colors in sync with the line color.
31882
+ labels: newLabels
31883
+ });
31884
+ }
31885
+ function handleLabelChange(updatedLabel, labelIndex) {
31886
+ if (!labels) {
31887
+ return;
31888
+ }
31889
+ const updatedLabels = [...labels];
31890
+ updatedLabels[labelIndex] = {
31891
+ ...labels[labelIndex],
31892
+ ...updatedLabel
31893
+ };
31894
+ onChangeProps({
31895
+ labels: updatedLabels
31896
+ });
31897
+ }
31898
+ function handleLabelRemove(labelIndex) {
31899
+ if (!labels) {
31900
+ return;
31901
+ }
31902
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31903
+ onChangeProps({
31904
+ labels: updatedLabels
31545
31905
  });
31546
31906
  }
31547
31907
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31548
31908
  expanded: props.expanded,
31549
31909
  onToggle: props.onToggle,
31550
31910
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31551
- style: styles$n.row
31911
+ style: styles$m.row
31552
31912
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
31553
31913
  size: wonderBlocksTokens.spacing.xSmall_8
31554
31914
  }), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
@@ -31557,7 +31917,7 @@ const LockedLineSettings = props => {
31557
31917
  }))
31558
31918
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31559
31919
  tag: "label",
31560
- style: [styles$n.row, styles$n.spaceUnder]
31920
+ style: [styles$m.row, styles$m.spaceUnder]
31561
31921
  }, "kind", /*#__PURE__*/React__namespace.createElement(Strut, {
31562
31922
  size: wonderBlocksTokens.spacing.xxxSmall_4
31563
31923
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -31578,7 +31938,7 @@ const LockedLineSettings = props => {
31578
31938
  value: "segment",
31579
31939
  label: "segment"
31580
31940
  }))), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31581
- style: styles$n.row
31941
+ style: styles$m.row
31582
31942
  }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31583
31943
  selectedValue: lineColor,
31584
31944
  onChange: handleColorChange
@@ -31590,9 +31950,11 @@ const LockedLineSettings = props => {
31590
31950
  lineStyle: value
31591
31951
  })
31592
31952
  })), isInvalid && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31593
- style: styles$n.errorText
31594
- }, lengthZeroStr), /*#__PURE__*/React__namespace.createElement(DefiningPointSettings, _extends({
31595
- label: "Point 1",
31953
+ style: styles$m.errorText
31954
+ }, lengthZeroStr), /*#__PURE__*/React__namespace.createElement(LockedPointSettings, _extends({
31955
+ flags: flags,
31956
+ headerLabel: "Point 1",
31957
+ expanded: true,
31596
31958
  showPoint: showPoint1,
31597
31959
  error: isInvalid ? lengthZeroStr : null
31598
31960
  }, point1, {
@@ -31600,8 +31962,10 @@ const LockedLineSettings = props => {
31600
31962
  showPoint1: newValue
31601
31963
  }),
31602
31964
  onChangeProps: newProps => handleChangePoint(newProps, 0)
31603
- })), /*#__PURE__*/React__namespace.createElement(DefiningPointSettings, _extends({
31604
- label: "Point 2",
31965
+ })), /*#__PURE__*/React__namespace.createElement(LockedPointSettings, _extends({
31966
+ flags: flags,
31967
+ headerLabel: "Point 2",
31968
+ expanded: true,
31605
31969
  showPoint: showPoint2,
31606
31970
  error: isInvalid ? lengthZeroStr : null
31607
31971
  }, point2, {
@@ -31609,206 +31973,33 @@ const LockedLineSettings = props => {
31609
31973
  showPoint2: newValue
31610
31974
  }),
31611
31975
  onChangeProps: newProps => handleChangePoint(newProps, 1)
31612
- })), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31613
- figureType: props.type,
31614
- onMove: onMove,
31615
- onRemove: onRemove
31616
- }));
31617
- };
31618
- const styles$n = aphrodite.StyleSheet.create({
31619
- row: {
31620
- display: "flex",
31621
- flexDirection: "row",
31622
- alignItems: "center"
31623
- },
31624
- spaceUnder: {
31625
- marginBottom: wonderBlocksTokens.spacing.xSmall_8
31626
- },
31627
- errorText: {
31628
- color: wonderBlocksTokens.color.red
31629
- }
31630
- });
31631
-
31632
- const DEFAULT_COLOR = "grayH";
31633
- function getDefaultFigureForType(type) {
31634
- switch (type) {
31635
- case "point":
31636
- return {
31637
- type: "point",
31638
- coord: [0, 0],
31639
- color: DEFAULT_COLOR,
31640
- filled: true,
31641
- labels: []
31642
- };
31643
- case "line":
31644
- return {
31645
- type: "line",
31646
- kind: "line",
31647
- points: [getDefaultFigureForType("point"), {
31648
- ...getDefaultFigureForType("point"),
31649
- coord: [2, 2]
31650
- }],
31651
- color: DEFAULT_COLOR,
31652
- lineStyle: "solid",
31653
- showPoint1: false,
31654
- showPoint2: false
31655
- };
31656
- case "vector":
31657
- return {
31658
- type: "vector",
31659
- points: [[0, 0], [2, 2]],
31660
- color: DEFAULT_COLOR
31661
- };
31662
- case "ellipse":
31663
- return {
31664
- type: "ellipse",
31665
- center: [0, 0],
31666
- radius: [1, 1],
31667
- angle: 0,
31668
- color: DEFAULT_COLOR,
31669
- fillStyle: "none",
31670
- strokeStyle: "solid"
31671
- };
31672
- case "polygon":
31673
- return {
31674
- type: "polygon",
31675
- points: [[0, 2], [-1, 0], [1, 0]],
31676
- color: DEFAULT_COLOR,
31677
- showVertices: false,
31678
- fillStyle: "none",
31679
- strokeStyle: "solid"
31680
- };
31681
- case "function":
31682
- return {
31683
- type: "function",
31684
- color: DEFAULT_COLOR,
31685
- strokeStyle: "solid",
31686
- equation: "x^2",
31687
- directionalAxis: "x"
31688
- };
31689
- case "label":
31690
- return {
31691
- type: "label",
31692
- coord: [0, 0],
31693
- text: "",
31694
- color: DEFAULT_COLOR,
31695
- size: "medium"
31696
- };
31697
- default:
31698
- throw new wonderStuffCore.UnreachableCaseError(type);
31699
- }
31700
- }
31701
-
31702
- const LockedPointSettings = props => {
31703
- const {
31704
- flags,
31705
- coord,
31706
- color: pointColor,
31707
- filled = true,
31708
- labels,
31709
- onChangeProps,
31710
- onMove,
31711
- onRemove
31712
- } = props;
31713
- function handleColorChange(newValue) {
31714
- const newProps = {
31715
- color: newValue
31716
- };
31717
-
31718
- // Update the color of the all labels to match the point
31719
- newProps.labels = labels.map(label => ({
31720
- ...label,
31721
- color: newValue
31722
- }));
31723
- onChangeProps(newProps);
31724
- }
31725
- function handleCoordChange(newCoord) {
31726
- const xOffset = newCoord[0] - coord[0];
31727
- const yOffset = newCoord[1] - coord[1];
31728
- const newProps = {
31729
- coord: newCoord
31730
- };
31731
-
31732
- // Update the coord by the same amount as the point for all labels
31733
- newProps.labels = labels.map(label => ({
31734
- ...label,
31735
- coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31736
- }));
31737
- onChangeProps(newProps);
31738
- }
31739
- function handleLabelChange(updatedLabel, labelIndex) {
31740
- const updatedLabels = [...labels];
31741
- updatedLabels[labelIndex] = {
31742
- ...labels[labelIndex],
31743
- ...updatedLabel
31744
- };
31745
- onChangeProps({
31746
- labels: updatedLabels
31747
- });
31748
- }
31749
- function handleLabelRemove(labelIndex) {
31750
- const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31751
- onChangeProps({
31752
- labels: updatedLabels
31753
- });
31754
- }
31755
- return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31756
- expanded: props.expanded,
31757
- onToggle: props.onToggle,
31758
- header:
31759
- /*#__PURE__*/
31760
- // Summary: Point, coords, color (filled/open)
31761
- React__namespace.createElement(wonderBlocksCore.View, {
31762
- style: styles$m.row
31763
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Point (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React__namespace.createElement(Strut, {
31764
- size: wonderBlocksTokens.spacing.xSmall_8
31765
- }), /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
31766
- color: pointColor,
31767
- filled: filled
31768
- }))
31769
- }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31770
- coord: coord,
31771
- style: styles$m.spaceUnder,
31772
- onChange: handleCoordChange
31773
- }), /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31774
- selectedValue: pointColor,
31775
- onChange: handleColorChange,
31776
- style: styles$m.spaceUnder
31777
- }), /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
31778
- label: "open point",
31779
- checked: !filled,
31780
- onChange: newValue => {
31781
- onChangeProps({
31782
- filled: !newValue
31783
- });
31784
- },
31785
- style: styles$m.spaceUnder
31786
- }), flags?.["mafs"]?.["locked-point-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, labels.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
31976
+ })), flags?.["mafs"]?.["locked-line-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31977
+ style: styles$m.horizontalRule
31978
+ }), labels?.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
31787
31979
  expanded: true,
31788
31980
  onChangeProps: newLabel => {
31789
31981
  handleLabelChange(newLabel, labelIndex);
31790
31982
  },
31791
31983
  onRemove: () => {
31792
31984
  handleLabelRemove(labelIndex);
31793
- }
31985
+ },
31986
+ containerStyle: styles$m.labelContainer
31794
31987
  }))), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
31795
31988
  kind: "tertiary",
31796
31989
  startIcon: plusCircle__default["default"],
31797
31990
  onClick: () => {
31991
+ // Additional vertical offset for each label so
31992
+ // they don't overlap.
31993
+ const offsetPerLabel = [0, -1];
31994
+ const labelLocation = mafs.vec.add(mafs.vec.scale(offsetPerLabel, labels?.length ?? 0), mafs.vec.midpoint(points[0].coord, points[1].coord));
31798
31995
  const newLabel = {
31799
31996
  ...getDefaultFigureForType("label"),
31800
- // Place the label at the same position
31801
- // as the point. Add a small offset to
31802
- // avoid crowding.
31803
- coord: [coord[0] + 0.5,
31804
- // Additional offset for each label so
31805
- // they don't overlap.
31806
- coord[1] - 1 * labels?.length],
31807
- // Default to the same color as the point
31808
- color: pointColor
31997
+ coord: labelLocation,
31998
+ // Default to the same color as the line
31999
+ color: lineColor
31809
32000
  };
31810
32001
  onChangeProps({
31811
- labels: [...labels, newLabel]
32002
+ labels: [...(labels ?? []), newLabel]
31812
32003
  });
31813
32004
  },
31814
32005
  style: styles$m.addButton
@@ -31820,14 +32011,27 @@ const LockedPointSettings = props => {
31820
32011
  };
31821
32012
  const styles$m = aphrodite.StyleSheet.create({
31822
32013
  row: {
32014
+ display: "flex",
31823
32015
  flexDirection: "row",
31824
32016
  alignItems: "center"
31825
32017
  },
31826
32018
  spaceUnder: {
31827
32019
  marginBottom: wonderBlocksTokens.spacing.xSmall_8
31828
32020
  },
32021
+ errorText: {
32022
+ color: wonderBlocksTokens.color.red
32023
+ },
31829
32024
  addButton: {
31830
32025
  alignSelf: "start"
32026
+ },
32027
+ horizontalRule: {
32028
+ marginTop: wonderBlocksTokens.spacing.small_12,
32029
+ marginBottom: wonderBlocksTokens.spacing.xxxSmall_4,
32030
+ height: 1,
32031
+ backgroundColor: wonderBlocksTokens.color.offBlack16
32032
+ },
32033
+ labelContainer: {
32034
+ backgroundColor: wonderBlocksTokens.color.white
31831
32035
  }
31832
32036
  });
31833
32037
 
@@ -32090,17 +32294,13 @@ const styles$k = aphrodite.StyleSheet.create({
32090
32294
  }
32091
32295
  });
32092
32296
 
32093
- /**
32094
- * LockedVectorSettings is a component that allows the user to edit the
32095
- * settings of specifically a locked vector on the graph.
32096
- *
32097
- * Used in the interactive graph editor's locked figures section.
32098
- */
32099
32297
  const lengthErrorMessage = "The vector cannot have length 0.";
32100
32298
  const LockedVectorSettings = props => {
32101
32299
  const {
32300
+ flags,
32102
32301
  points,
32103
32302
  color: lineColor,
32303
+ labels,
32104
32304
  onChangeProps,
32105
32305
  onMove,
32106
32306
  onRemove
@@ -32114,14 +32314,53 @@ const LockedVectorSettings = props => {
32114
32314
  if (typeof newCoord !== "undefined") {
32115
32315
  const newPoints = [...points];
32116
32316
  newPoints[index] = [...newCoord];
32317
+
32318
+ // Update labels to match the new points
32319
+ const oldMidpoint = mafs.vec.midpoint(tail, tip);
32320
+ const newMidpoint = mafs.vec.midpoint(newPoints[0], newPoints[1]);
32321
+ const offset = mafs.vec.sub(newMidpoint, oldMidpoint);
32322
+ const newLabels = labels?.map(label => ({
32323
+ ...label,
32324
+ coord: mafs.vec.add(label.coord, offset)
32325
+ }));
32117
32326
  onChangeProps({
32118
- points: newPoints
32327
+ points: newPoints,
32328
+ labels: newLabels
32119
32329
  });
32120
32330
  }
32121
32331
  }
32122
32332
  function handleColorChange(newColor) {
32123
- onChangeProps({
32333
+ const newProps = {
32334
+ color: newColor
32335
+ };
32336
+
32337
+ // Update the color of the all labels to match the point
32338
+ newProps.labels = labels?.map(label => ({
32339
+ ...label,
32124
32340
  color: newColor
32341
+ }));
32342
+ onChangeProps(newProps);
32343
+ }
32344
+ function handleLabelChange(updatedLabel, labelIndex) {
32345
+ if (!labels) {
32346
+ return;
32347
+ }
32348
+ const updatedLabels = [...labels];
32349
+ updatedLabels[labelIndex] = {
32350
+ ...labels[labelIndex],
32351
+ ...updatedLabel
32352
+ };
32353
+ onChangeProps({
32354
+ labels: updatedLabels
32355
+ });
32356
+ }
32357
+ function handleLabelRemove(labelIndex) {
32358
+ if (!labels) {
32359
+ return;
32360
+ }
32361
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
32362
+ onChangeProps({
32363
+ labels: updatedLabels
32125
32364
  });
32126
32365
  }
32127
32366
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
@@ -32170,7 +32409,37 @@ const LockedVectorSettings = props => {
32170
32409
  onChange: newProps => {
32171
32410
  handleChangePoint(newProps, 1);
32172
32411
  }
32173
- })), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
32412
+ })), flags?.["mafs"]?.["locked-vector-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32413
+ style: styles$j.horizontalRule
32414
+ }), labels?.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
32415
+ expanded: true,
32416
+ onChangeProps: newLabel => {
32417
+ handleLabelChange(newLabel, labelIndex);
32418
+ },
32419
+ onRemove: () => {
32420
+ handleLabelRemove(labelIndex);
32421
+ },
32422
+ containerStyle: styles$j.labelContainer
32423
+ }))), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
32424
+ kind: "tertiary",
32425
+ startIcon: plusCircle__default["default"],
32426
+ onClick: () => {
32427
+ // Additional vertical offset for each label so
32428
+ // they don't overlap.
32429
+ const offsetPerLabel = [0, -1];
32430
+ const labelLocation = mafs.vec.add(mafs.vec.scale(offsetPerLabel, labels?.length ?? 0), mafs.vec.midpoint(tail, tip));
32431
+ const newLabel = {
32432
+ ...getDefaultFigureForType("label"),
32433
+ coord: labelLocation,
32434
+ // Default to the same color as the vector
32435
+ color: lineColor
32436
+ };
32437
+ onChangeProps({
32438
+ labels: [...(labels ?? []), newLabel]
32439
+ });
32440
+ },
32441
+ style: styles$j.addButton
32442
+ }, "Add visible label")), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
32174
32443
  figureType: props.type,
32175
32444
  onMove: onMove,
32176
32445
  onRemove: onRemove
@@ -32194,6 +32463,18 @@ const styles$j = aphrodite.StyleSheet.create({
32194
32463
  row: {
32195
32464
  flexDirection: "row",
32196
32465
  alignItems: "center"
32466
+ },
32467
+ addButton: {
32468
+ alignSelf: "start"
32469
+ },
32470
+ horizontalRule: {
32471
+ marginTop: wonderBlocksTokens.spacing.small_12,
32472
+ marginBottom: wonderBlocksTokens.spacing.xxxSmall_4,
32473
+ height: 1,
32474
+ backgroundColor: wonderBlocksTokens.color.offBlack16
32475
+ },
32476
+ labelContainer: {
32477
+ backgroundColor: wonderBlocksTokens.color.white
32197
32478
  }
32198
32479
  });
32199
32480