@khanacademy/perseus-editor 14.4.0 → 14.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/index.js CHANGED
@@ -25,7 +25,9 @@ import { useMathInputI18n, createMathField } from '@khanacademy/math-input';
25
25
  import { vector, number } from '@khanacademy/kmath';
26
26
  import { SingleSelect, OptionItem, ActionMenu, ActionItem } from '@khanacademy/wonder-blocks-dropdown';
27
27
  import Banner from '@khanacademy/wonder-blocks-banner';
28
+ import plusCircle from '@phosphor-icons/core/regular/plus-circle.svg';
28
29
  import { AccordionSection } from '@khanacademy/wonder-blocks-accordion';
30
+ import pencilCircle from '@phosphor-icons/core/regular/pencil-circle.svg';
29
31
  import IconButton from '@khanacademy/wonder-blocks-icon-button';
30
32
  import caretDoubleDownIcon from '@phosphor-icons/core/bold/caret-double-down-bold.svg';
31
33
  import caretDoubleUpIcon from '@phosphor-icons/core/bold/caret-double-up-bold.svg';
@@ -34,7 +36,6 @@ import caretUpIcon from '@phosphor-icons/core/bold/caret-up-bold.svg';
34
36
  import trashIcon from '@phosphor-icons/core/bold/trash-bold.svg';
35
37
  import copyIcon from '@phosphor-icons/core/assets/regular/copy.svg';
36
38
  import autoPasteIcon from '@phosphor-icons/core/assets/regular/note-pencil.svg';
37
- import plusCircle from '@phosphor-icons/core/regular/plus-circle.svg';
38
39
  import { vec } from 'mafs';
39
40
  import arrowFatDown from '@phosphor-icons/core/regular/arrow-fat-down.svg';
40
41
  import arrowFatLeft from '@phosphor-icons/core/regular/arrow-fat-left.svg';
@@ -45,7 +46,7 @@ import arrowCounterClockwise from '@phosphor-icons/core/bold/arrow-counter-clock
45
46
 
46
47
  // This file is processed by a Rollup plugin (replace) to inject the production
47
48
  const libName = "@khanacademy/perseus-editor";
48
- const libVersion = "14.4.0";
49
+ const libVersion = "14.6.1";
49
50
  addLibraryVersionToPerseusDebug(libName, libVersion);
50
51
 
51
52
  function _extends() {
@@ -230,7 +231,7 @@ class SectionControlButton extends React.Component {
230
231
  role: "button",
231
232
  hideDefaultFocusRing: true,
232
233
  "aria-label": title,
233
- style: styles$T.button
234
+ style: styles$U.button
234
235
  }, ({
235
236
  hovered,
236
237
  focused,
@@ -238,7 +239,7 @@ class SectionControlButton extends React.Component {
238
239
  }) => /*#__PURE__*/React.createElement(InlineIcon$b, icon));
239
240
  }
240
241
  }
241
- const styles$T = StyleSheet.create({
242
+ const styles$U = StyleSheet.create({
242
243
  button: {
243
244
  backgroundColor: color.gold,
244
245
  margin: 2,
@@ -20629,11 +20630,11 @@ class Spring extends React.Component {
20629
20630
  } = this.props;
20630
20631
  return React.createElement(View, {
20631
20632
  "aria-hidden": "true",
20632
- style: [styles$S.grow, style]
20633
+ style: [styles$T.grow, style]
20633
20634
  });
20634
20635
  }
20635
20636
  }
20636
- const styles$S = StyleSheet.create({
20637
+ const styles$T = StyleSheet.create({
20637
20638
  grow: {
20638
20639
  flexGrow: 1
20639
20640
  }
@@ -20877,13 +20878,13 @@ class WidgetSelect extends React.Component {
20877
20878
  * that collapse a region.
20878
20879
  */
20879
20880
  function ToggleableCaret(props) {
20880
- const iconStyle = props.isExpanded ? styles$R.expanded : styles$R.collapsed;
20881
+ const iconStyle = props.isExpanded ? styles$S.expanded : styles$S.collapsed;
20881
20882
  return /*#__PURE__*/React.createElement(PhosphorIcon, {
20882
20883
  icon: caretRight,
20883
20884
  style: iconStyle
20884
20885
  });
20885
20886
  }
20886
- const styles$R = StyleSheet.create({
20887
+ const styles$S = StyleSheet.create({
20887
20888
  collapsed: {
20888
20889
  transition: ".15s"
20889
20890
  },
@@ -20916,16 +20917,16 @@ class TexErrorView extends React.Component {
20916
20917
  showErrors
20917
20918
  } = this.state;
20918
20919
  return /*#__PURE__*/React.createElement(View, {
20919
- style: styles$Q.errorContainer
20920
+ style: styles$R.errorContainer
20920
20921
  }, /*#__PURE__*/React.createElement(View, {
20921
- style: styles$Q.title,
20922
+ style: styles$R.title,
20922
20923
  onClick: this.handleToggleTexErrors
20923
20924
  }, /*#__PURE__*/React.createElement(ToggleableCaret, {
20924
20925
  isExpanded: showErrors
20925
20926
  }), "\xA0 TeX Errors (", errorList.length, ")"), showErrors && /*#__PURE__*/React.createElement(View, {
20926
- style: styles$Q.errorExplanation
20927
+ style: styles$R.errorExplanation
20927
20928
  }, "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.createElement(View, {
20928
- style: styles$Q.error,
20929
+ style: styles$R.error,
20929
20930
  key: index
20930
20931
  }, /*#__PURE__*/React.createElement(View, {
20931
20932
  style: {
@@ -20934,7 +20935,7 @@ class TexErrorView extends React.Component {
20934
20935
  }, e.math), /*#__PURE__*/React.createElement(View, null, e.message))));
20935
20936
  }
20936
20937
  }
20937
- const styles$Q = StyleSheet.create({
20938
+ const styles$R = StyleSheet.create({
20938
20939
  title: {
20939
20940
  backgroundColor: "#eee",
20940
20941
  fontSize: "1.25em",
@@ -21904,8 +21905,7 @@ class IframeContentRenderer extends React.Component {
21904
21905
  this._lastData = data;
21905
21906
 
21906
21907
  // We can't use JSON.stringify/parse for this because the apiOptions
21907
- // includes the functions GroupMetadataEditor, groupAnnotator,
21908
- // onFocusChange, and onInputError.
21908
+ // includes the functions GroupMetadataEditor, groupAnnotator, and onFocusChange.
21909
21909
  // @ts-expect-error - TS2339 - Property 'iframeDataStore' does not exist on type 'Window & typeof globalThis'.
21910
21910
  window.iframeDataStore[this.iframeID] = data;
21911
21911
  frame.contentWindow.postMessage(this.iframeID, "*");
@@ -23591,7 +23591,7 @@ class StructuredItemDiff extends React.Component {
23591
23591
 
23592
23592
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
23593
23593
  const {
23594
- InfoTip: InfoTip$m,
23594
+ InfoTip: InfoTip$n,
23595
23595
  InlineIcon: InlineIcon$7
23596
23596
  } = components;
23597
23597
  const {
@@ -23663,7 +23663,7 @@ class HintEditor extends React.Component {
23663
23663
  type: "button",
23664
23664
  className: this.props.isFirst ? "hidden" : "",
23665
23665
  onClick: _.partial(this.props.onMove, -1)
23666
- }, /*#__PURE__*/React.createElement(InlineIcon$7, iconCircleArrowUp)), " ", this.props.isLast && /*#__PURE__*/React.createElement(InfoTip$m, null, /*#__PURE__*/React.createElement("p", null, "The last hint is automatically bolded."))), /*#__PURE__*/React.createElement("input", {
23666
+ }, /*#__PURE__*/React.createElement(InlineIcon$7, iconCircleArrowUp)), " ", this.props.isLast && /*#__PURE__*/React.createElement(InfoTip$n, null, /*#__PURE__*/React.createElement("p", null, "The last hint is automatically bolded."))), /*#__PURE__*/React.createElement("input", {
23667
23667
  type: "checkbox"
23668
23668
  // @ts-expect-error - TS2322 - Type 'boolean | null | undefined' is not assignable to type 'boolean | undefined'.
23669
23669
  ,
@@ -23909,7 +23909,7 @@ CombinedHintsEditor.defaultProps = {
23909
23909
  };
23910
23910
 
23911
23911
  const {
23912
- InfoTip: InfoTip$l
23912
+ InfoTip: InfoTip$m
23913
23913
  } = components;
23914
23914
  class ItemExtrasEditor extends React.Component {
23915
23915
  constructor(...args) {
@@ -24048,17 +24048,17 @@ ItemExtrasEditor.defaultProps = {
24048
24048
  zTable: false
24049
24049
  };
24050
24050
  const ItemExtraCheckbox = props => /*#__PURE__*/React.createElement(View, {
24051
- style: [styles$P.checkbox, props.indent ? styles$P.indented : undefined]
24051
+ style: [styles$Q.checkbox, props.indent ? styles$Q.indented : undefined]
24052
24052
  }, /*#__PURE__*/React.createElement(Checkbox$1, {
24053
24053
  label: /*#__PURE__*/React.createElement(View, {
24054
24054
  style: {
24055
24055
  flexDirection: "row"
24056
24056
  }
24057
- }, props.label, " ", /*#__PURE__*/React.createElement(InfoTip$l, null, props.infoTip)),
24057
+ }, props.label, " ", /*#__PURE__*/React.createElement(InfoTip$m, null, props.infoTip)),
24058
24058
  checked: props.checked,
24059
24059
  onChange: newCheckedState => props.onChange(newCheckedState)
24060
24060
  }));
24061
- const styles$P = StyleSheet.create({
24061
+ const styles$Q = StyleSheet.create({
24062
24062
  indented: {
24063
24063
  marginInlineStart: spacing.large_24
24064
24064
  }
@@ -24720,7 +24720,7 @@ class SimpleButton extends React.Component {
24720
24720
  } = _this$props,
24721
24721
  otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded$3);
24722
24722
  return /*#__PURE__*/React.createElement("div", _extends({
24723
- className: css(styles$O.baseButton, color === "green" && styles$O.green, color === "orange" && styles$O.orange),
24723
+ className: css(styles$P.baseButton, color === "green" && styles$P.green, color === "orange" && styles$P.orange),
24724
24724
  onClick: onClick
24725
24725
  }, otherProps), children);
24726
24726
  }
@@ -24735,7 +24735,7 @@ SimpleButton.defaultProps = {
24735
24735
  color: "green",
24736
24736
  onClick: () => {}
24737
24737
  };
24738
- const styles$O = StyleSheet.create({
24738
+ const styles$P = StyleSheet.create({
24739
24739
  baseButton: {
24740
24740
  top: "0",
24741
24741
  fontSize: "11px",
@@ -24955,23 +24955,23 @@ const LeafContainer = ({
24955
24955
  }) => {
24956
24956
  const hasPreviewHeading = shape.type === "content" || shape.type === "hint";
24957
24957
  const previewHeading = hasPreviewHeading && /*#__PURE__*/React.createElement("div", {
24958
- className: css(styles$N.containerHeader)
24958
+ className: css(styles$O.containerHeader)
24959
24959
  }, /*#__PURE__*/React.createElement(Header, {
24960
24960
  depth: path.length,
24961
- className: css(styles$N.containerTitle)
24961
+ className: css(styles$O.containerTitle)
24962
24962
  }, capitalize(name)));
24963
24963
  return /*#__PURE__*/React.createElement("div", {
24964
- className: css(styles$N.container)
24964
+ className: css(styles$O.container)
24965
24965
  }, /*#__PURE__*/React.createElement("span", {
24966
- className: css(styles$N.row, styles$N.rowHeading)
24966
+ className: css(styles$O.row, styles$O.rowHeading)
24967
24967
  }, /*#__PURE__*/React.createElement("div", {
24968
- className: css(styles$N.columnLeft)
24968
+ className: css(styles$O.columnLeft)
24969
24969
  }, /*#__PURE__*/React.createElement("div", {
24970
- className: "pod-title " + css(styles$N.containerHeader)
24970
+ className: "pod-title " + css(styles$O.containerHeader)
24971
24971
  }, /*#__PURE__*/React.createElement("div", {
24972
- className: css(styles$N.containerTitle)
24972
+ className: css(styles$O.containerTitle)
24973
24973
  }, capitalize(name)), controls)), /*#__PURE__*/React.createElement("div", {
24974
- className: css(styles$N.columnRight)
24974
+ className: css(styles$O.columnRight)
24975
24975
  }, previewHeading)), children);
24976
24976
  };
24977
24977
  const ArrayContainer = props => {
@@ -24984,11 +24984,11 @@ const ArrayContainer = props => {
24984
24984
  actions
24985
24985
  } = props;
24986
24986
  return /*#__PURE__*/React.createElement("div", {
24987
- className: css(styles$N.container)
24987
+ className: css(styles$O.container)
24988
24988
  }, controls && /*#__PURE__*/React.createElement("div", {
24989
- className: css(styles$N.columnLeft, styles$N.containerHeader)
24989
+ className: css(styles$O.columnLeft, styles$O.containerHeader)
24990
24990
  }, controls), /*#__PURE__*/React.createElement("div", null, children), /*#__PURE__*/React.createElement("div", {
24991
- className: css(styles$N.columnLeft)
24991
+ className: css(styles$O.columnLeft)
24992
24992
  }, /*#__PURE__*/React.createElement("a", {
24993
24993
  href: "javascript:void 0",
24994
24994
  onClick: () => actions.addArrayElement(path, shape.elementShape)
@@ -25001,28 +25001,28 @@ const ObjectContainer = ({
25001
25001
  path
25002
25002
  }) => {
25003
25003
  const headingEditor = /*#__PURE__*/React.createElement("div", {
25004
- className: css(styles$N.containerHeader)
25004
+ className: css(styles$O.containerHeader)
25005
25005
  }, /*#__PURE__*/React.createElement(Header, {
25006
25006
  depth: path.length,
25007
- className: css(styles$N.containerTitle)
25007
+ className: css(styles$O.containerTitle)
25008
25008
  }, capitalize(name)), controls);
25009
25009
  const headingPreview = (name || controls) && /*#__PURE__*/React.createElement("div", {
25010
- className: css(styles$N.containerHeader, styles$N.previewCollectionHeader)
25010
+ className: css(styles$O.containerHeader, styles$O.previewCollectionHeader)
25011
25011
  }, /*#__PURE__*/React.createElement(Header, {
25012
25012
  depth: path.length,
25013
- className: css(styles$N.containerTitle)
25013
+ className: css(styles$O.containerTitle)
25014
25014
  }, capitalize(name)));
25015
25015
  const hasBothHeadings = headingEditor && headingPreview;
25016
25016
  return /*#__PURE__*/React.createElement("div", {
25017
- className: css(styles$N.container)
25017
+ className: css(styles$O.container)
25018
25018
  }, hasBothHeadings && /*#__PURE__*/React.createElement("span", {
25019
- className: css(styles$N.row)
25019
+ className: css(styles$O.row)
25020
25020
  }, /*#__PURE__*/React.createElement("div", {
25021
- className: css(styles$N.columnLeft)
25021
+ className: css(styles$O.columnLeft)
25022
25022
  }, headingEditor), /*#__PURE__*/React.createElement("div", {
25023
- className: css(styles$N.columnRight)
25023
+ className: css(styles$O.columnRight)
25024
25024
  }, headingPreview)), /*#__PURE__*/React.createElement("div", {
25025
- className: css(path.length > 0 && styles$N.contentIndent)
25025
+ className: css(path.length > 0 && styles$O.contentIndent)
25026
25026
  }, children));
25027
25027
  };
25028
25028
 
@@ -25145,11 +25145,11 @@ const ItemNodeContent = withStickiness(props => {
25145
25145
  className: "framework-perseus"
25146
25146
  }, lens(renderers).get(path));
25147
25147
  return /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement("div", {
25148
- className: css(styles$N.row)
25148
+ className: css(styles$O.row)
25149
25149
  }, /*#__PURE__*/React.createElement("div", {
25150
- className: css(styles$N.columnLeft)
25150
+ className: css(styles$O.columnLeft)
25151
25151
  }, /*#__PURE__*/React.createElement("div", {
25152
- className: css(sticky && styles$N.sticky)
25152
+ className: css(sticky && styles$O.sticky)
25153
25153
  },
25154
25154
  /*#__PURE__*/
25155
25155
  // @ts-expect-error - TS2769 - No overload matches this call.
@@ -25157,9 +25157,9 @@ const ItemNodeContent = withStickiness(props => {
25157
25157
  onChange: newVal => actions.mergeValueAtPath(path, newVal),
25158
25158
  apiOptions: apiOptions
25159
25159
  })))), /*#__PURE__*/React.createElement("div", {
25160
- className: css(styles$N.columnRight)
25160
+ className: css(styles$O.columnRight)
25161
25161
  }, /*#__PURE__*/React.createElement("div", {
25162
- className: css(sticky && styles$N.sticky)
25162
+ className: css(sticky && styles$O.sticky)
25163
25163
  }, preview))));
25164
25164
  });
25165
25165
  const HintNodeContent = withStickiness(props => {
@@ -25175,13 +25175,13 @@ const HintNodeContent = withStickiness(props => {
25175
25175
  className: "framework-perseus"
25176
25176
  }, lens(renderers).get(path));
25177
25177
  return /*#__PURE__*/React.createElement("div", {
25178
- className: css(styles$N.row)
25178
+ className: css(styles$O.row)
25179
25179
  }, /*#__PURE__*/React.createElement("div", {
25180
- className: css(styles$N.columnLeft)
25180
+ className: css(styles$O.columnLeft)
25181
25181
  }, /*#__PURE__*/React.createElement("div", {
25182
- className: css(sticky && styles$N.sticky)
25182
+ className: css(sticky && styles$O.sticky)
25183
25183
  }, /*#__PURE__*/React.createElement(HintEditor, _extends({}, data, {
25184
- className: css(styles$N.hintEditor),
25184
+ className: css(styles$O.hintEditor),
25185
25185
  onChange: newVal => actions.mergeValueAtPath(path, newVal),
25186
25186
  apiOptions: apiOptions,
25187
25187
  showTitle: false,
@@ -25196,9 +25196,9 @@ const HintNodeContent = withStickiness(props => {
25196
25196
  isFirst: true,
25197
25197
  isLast: true
25198
25198
  })))), /*#__PURE__*/React.createElement("div", {
25199
- className: css(styles$N.columnRight)
25199
+ className: css(styles$O.columnRight)
25200
25200
  }, /*#__PURE__*/React.createElement("div", {
25201
- className: css(sticky && styles$N.sticky)
25201
+ className: css(sticky && styles$O.sticky)
25202
25202
  }, preview)));
25203
25203
  });
25204
25204
  const TagsNodeContent = props => {
@@ -25215,9 +25215,9 @@ const TagsNodeContent = props => {
25215
25215
  return null;
25216
25216
  }
25217
25217
  return /*#__PURE__*/React.createElement("div", {
25218
- className: css(styles$N.columnLeft)
25218
+ className: css(styles$O.columnLeft)
25219
25219
  }, /*#__PURE__*/React.createElement("div", {
25220
- className: css(styles$N.tagsEditor)
25220
+ className: css(styles$O.tagsEditor)
25221
25221
  }, /*#__PURE__*/React.createElement(GroupMetadataEditor, {
25222
25222
  value: data,
25223
25223
  onChange: newVal => actions.setValueAtPath(path, newVal),
@@ -25248,23 +25248,23 @@ const ArrayNodeContent = props => {
25248
25248
  const subpath = path.concat(i);
25249
25249
  const controls = [i > 0 && /*#__PURE__*/React.createElement("div", {
25250
25250
  key: "moveArrayElementUp",
25251
- className: css(styles$N.control)
25251
+ className: css(styles$O.control)
25252
25252
  }, /*#__PURE__*/React.createElement(SimpleButton, {
25253
25253
  color: "orange",
25254
25254
  title: "Move up",
25255
25255
  onClick: () => actions.moveArrayElementUp(subpath)
25256
25256
  }, /*#__PURE__*/React.createElement("div", {
25257
- className: css(styles$N.verticalFlip)
25257
+ className: css(styles$O.verticalFlip)
25258
25258
  }, /*#__PURE__*/React.createElement(InlineIcon$6, iconChevronDown)))), i < data.length - 1 && /*#__PURE__*/React.createElement("div", {
25259
25259
  key: "moveArrayElementDown",
25260
- className: css(styles$N.control)
25260
+ className: css(styles$O.control)
25261
25261
  }, /*#__PURE__*/React.createElement(SimpleButton, {
25262
25262
  color: "orange",
25263
25263
  title: "Move down",
25264
25264
  onClick: () => actions.moveArrayElementDown(subpath)
25265
25265
  }, /*#__PURE__*/React.createElement(InlineIcon$6, iconChevronDown))), /*#__PURE__*/React.createElement("div", {
25266
25266
  key: "removeArrayElement",
25267
- className: css(styles$N.control)
25267
+ className: css(styles$O.control)
25268
25268
  }, /*#__PURE__*/React.createElement(SimpleButton, {
25269
25269
  color: "orange",
25270
25270
  title: "Delete",
@@ -25272,7 +25272,7 @@ const ArrayNodeContent = props => {
25272
25272
  }, /*#__PURE__*/React.createElement(InlineIcon$6, iconTrash$4)))];
25273
25273
  return /*#__PURE__*/React.createElement("div", {
25274
25274
  key: i,
25275
- className: css(styles$N.arrayElement, !elementIsLeaf && styles$N.arrayElementAndNotLeaf)
25275
+ className: css(styles$O.arrayElement, !elementIsLeaf && styles$O.arrayElementAndNotLeaf)
25276
25276
  }, /*#__PURE__*/React.createElement(NodeContainer, _extends({}, otherProps, {
25277
25277
  key: i,
25278
25278
  shape: shape.elementShape,
@@ -25298,7 +25298,7 @@ const ObjectNodeContent = props => {
25298
25298
  // made sense to the shape's author is the order in which we'll iterate :)
25299
25299
  const children = Object.keys(shape.shape).map(subkey => /*#__PURE__*/React.createElement("div", {
25300
25300
  key: subkey,
25301
- className: css(styles$N.objectElement)
25301
+ className: css(styles$O.objectElement)
25302
25302
  }, /*#__PURE__*/React.createElement(NodeContainer, _extends({}, otherProps, {
25303
25303
  shape: shape.shape[subkey],
25304
25304
  data: data[subkey],
@@ -25465,7 +25465,7 @@ class MultiRendererEditor extends React.Component {
25465
25465
  }, this._renderContent());
25466
25466
  }
25467
25467
  }
25468
- const styles$N = StyleSheet.create({
25468
+ const styles$O = StyleSheet.create({
25469
25469
  // This is used in a number of places throughout this file.
25470
25470
  container: {},
25471
25471
  // eslint-disable-next-line react-native/no-unused-styles
@@ -25760,7 +25760,7 @@ class BlurInput extends React.Component {
25760
25760
  }
25761
25761
 
25762
25762
  const {
25763
- InfoTip: InfoTip$k
25763
+ InfoTip: InfoTip$l
25764
25764
  } = components;
25765
25765
  const DEFAULT_WIDTH = 400;
25766
25766
  const DEFAULT_HEIGHT = 400;
@@ -25924,7 +25924,7 @@ class CSProgramEditor extends React.Component {
25924
25924
  showEditor: value
25925
25925
  });
25926
25926
  }
25927
- }), /*#__PURE__*/React.createElement(InfoTip$k, null, "If you show the editor, you should use the \"full-width\" alignment to make room for the width of the editor."), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement(Checkbox$1, {
25927
+ }), /*#__PURE__*/React.createElement(InfoTip$l, null, "If you show the editor, you should use the \"full-width\" alignment to make room for the width of the editor."), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement(Checkbox$1, {
25928
25928
  label: "Show Buttons",
25929
25929
  checked: this.props.showButtons,
25930
25930
  onChange: value => {
@@ -25936,7 +25936,7 @@ class CSProgramEditor extends React.Component {
25936
25936
  name: "settings",
25937
25937
  pairs: this.props.settings,
25938
25938
  onChange: this._handleSettingsChange
25939
- }), /*#__PURE__*/React.createElement(InfoTip$k, null, "Settings that you add here are available to the program as an object returned by ", /*#__PURE__*/React.createElement("code", null, "Program.settings()"))));
25939
+ }), /*#__PURE__*/React.createElement(InfoTip$l, null, "Settings that you add here are available to the program as an object returned by ", /*#__PURE__*/React.createElement("code", null, "Program.settings()"))));
25940
25940
  }
25941
25941
  }
25942
25942
  CSProgramEditor.propTypes = _extends({}, Changeable.propTypes);
@@ -26022,7 +26022,7 @@ DeprecatedStandinEditor.widgetName = "deprecated-standin";
26022
26022
 
26023
26023
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
26024
26024
  const {
26025
- InfoTip: InfoTip$j,
26025
+ InfoTip: InfoTip$k,
26026
26026
  InlineIcon: InlineIcon$5
26027
26027
  } = components;
26028
26028
  const {
@@ -26091,14 +26091,14 @@ class DropdownEditor extends React.Component {
26091
26091
  className: "perseus-widget-dropdown"
26092
26092
  }, /*#__PURE__*/React.createElement("div", {
26093
26093
  className: "dropdown-info"
26094
- }, "Dropdown", /*#__PURE__*/React.createElement(InfoTip$j, null, /*#__PURE__*/React.createElement("p", null, "The drop down is useful for making inequalities in a custom format. We normally use the symbols ", "<", ",", " ", ">", ", \u2264, \u2265 (in that order) which you can copy into the choices. When possible, use the \"multiple choice\" answer type instead."))), /*#__PURE__*/React.createElement("div", {
26094
+ }, "Dropdown", /*#__PURE__*/React.createElement(InfoTip$k, null, /*#__PURE__*/React.createElement("p", null, "The drop down is useful for making inequalities in a custom format. We normally use the symbols ", "<", ",", " ", ">", ", \u2264, \u2265 (in that order) which you can copy into the choices. When possible, use the \"multiple choice\" answer type instead."))), /*#__PURE__*/React.createElement("div", {
26095
26095
  className: "dropdown-placeholder"
26096
26096
  }, /*#__PURE__*/React.createElement("input", {
26097
26097
  type: "text",
26098
26098
  placeholder: "Placeholder value",
26099
26099
  value: this.props.placeholder,
26100
26100
  onChange: this.onPlaceholderChange
26101
- }), /*#__PURE__*/React.createElement(InfoTip$j, null, /*#__PURE__*/React.createElement("p", null, "This value will appear as the drop down default. It should give the user some indication of the values available in the drop down itself, e.g., Yes/No/Maybe."))), /*#__PURE__*/React.createElement("div", {
26101
+ }), /*#__PURE__*/React.createElement(InfoTip$k, null, /*#__PURE__*/React.createElement("p", null, "This value will appear as the drop down default. It should give the user some indication of the values available in the drop down itself, e.g., Yes/No/Maybe."))), /*#__PURE__*/React.createElement("div", {
26102
26102
  className: "clearfix"
26103
26103
  }), /*#__PURE__*/React.createElement("ul", {
26104
26104
  className: "dropdown-choices"
@@ -26411,7 +26411,7 @@ const SortableItem = createReactClass({
26411
26411
  }
26412
26412
  return /*#__PURE__*/React.createElement("li", {
26413
26413
  draggable: this.props.draggable,
26414
- className: [dragState, css(styles$M.sortableListItem)].join(" "),
26414
+ className: [dragState, css(styles$N.sortableListItem)].join(" "),
26415
26415
  onDragStart: this.handleDragStart,
26416
26416
  onDrop: this.handleDrop,
26417
26417
  onDragEnter: this.handleDragEnter,
@@ -26419,14 +26419,14 @@ const SortableItem = createReactClass({
26419
26419
  }, this.props.component);
26420
26420
  }
26421
26421
  });
26422
- const styles$M = StyleSheet.create({
26422
+ const styles$N = StyleSheet.create({
26423
26423
  sortableListItem: {
26424
26424
  margin: "5px 0"
26425
26425
  }
26426
26426
  });
26427
26427
 
26428
26428
  const {
26429
- InfoTip: InfoTip$i
26429
+ InfoTip: InfoTip$j
26430
26430
  } = components;
26431
26431
 
26432
26432
  // types for iterables
@@ -26667,28 +26667,28 @@ class ExpressionEditor extends React.Component {
26667
26667
  onChange: this.handleToggleDiv
26668
26668
  }));
26669
26669
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(HeadingSmall, null, "Global Options"), /*#__PURE__*/React.createElement("div", {
26670
- className: css(styles$L.paddedY)
26670
+ className: css(styles$M.paddedY)
26671
26671
  }, /*#__PURE__*/React.createElement(LabeledTextField, {
26672
26672
  label: "Visible label",
26673
26673
  value: this.props.visibleLabel || "",
26674
26674
  onChange: this.change("visibleLabel")
26675
- }), /*#__PURE__*/React.createElement(InfoTip$i, null, /*#__PURE__*/React.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.createElement("div", {
26676
- className: css(styles$L.paddedY)
26675
+ }), /*#__PURE__*/React.createElement(InfoTip$j, null, /*#__PURE__*/React.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.createElement("div", {
26676
+ className: css(styles$M.paddedY)
26677
26677
  }, /*#__PURE__*/React.createElement(LabeledTextField, {
26678
26678
  label: "Aria label",
26679
26679
  value: this.props.ariaLabel || "",
26680
26680
  onChange: this.change("ariaLabel")
26681
- }), /*#__PURE__*/React.createElement(InfoTip$i, null, /*#__PURE__*/React.createElement("p", null, "Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writting accessible labels, please see", " ", /*#__PURE__*/React.createElement("a", {
26681
+ }), /*#__PURE__*/React.createElement(InfoTip$j, null, /*#__PURE__*/React.createElement("p", null, "Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writting accessible labels, please see", " ", /*#__PURE__*/React.createElement("a", {
26682
26682
  href: "https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",
26683
26683
  target: "_blank"
26684
26684
  }, "this article.")))), /*#__PURE__*/React.createElement("div", {
26685
- className: css(styles$L.paddedY)
26685
+ className: css(styles$M.paddedY)
26686
26686
  }, /*#__PURE__*/React.createElement(LabeledTextField, {
26687
26687
  label: "Function variables",
26688
26688
  value: this.state.functionsInternal,
26689
26689
  onChange: this.handleFunctions
26690
- }), /*#__PURE__*/React.createElement(InfoTip$i, null, /*#__PURE__*/React.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.createElement("div", {
26691
- className: css(styles$L.paddedY)
26690
+ }), /*#__PURE__*/React.createElement(InfoTip$j, null, /*#__PURE__*/React.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.createElement("div", {
26691
+ className: css(styles$M.paddedY)
26692
26692
  }, /*#__PURE__*/React.createElement(Checkbox$1, {
26693
26693
  label: "Use \xD7 instead of \u22C5 for multiplication",
26694
26694
  checked: this.props.times,
@@ -26697,8 +26697,8 @@ class ExpressionEditor extends React.Component {
26697
26697
  times: value
26698
26698
  });
26699
26699
  }
26700
- }), /*#__PURE__*/React.createElement(InfoTip$i, null, /*#__PURE__*/React.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.createElement("div", {
26701
- className: css(styles$L.paddedY)
26700
+ }), /*#__PURE__*/React.createElement(InfoTip$j, null, /*#__PURE__*/React.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.createElement("div", {
26701
+ className: css(styles$M.paddedY)
26702
26702
  }, /*#__PURE__*/React.createElement(HeadingXSmall, null, "Button Sets"), buttonSetChoices), /*#__PURE__*/React.createElement(HeadingSmall, null, "Answers"), /*#__PURE__*/React.createElement("p", {
26703
26703
  style: {
26704
26704
  margin: "4px 0"
@@ -26769,18 +26769,18 @@ class AnswerOption extends React.Component {
26769
26769
  color: "destructive",
26770
26770
  light: true
26771
26771
  }, "Delete");
26772
- const answerStatusCss = 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);
26772
+ const answerStatusCss = 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);
26773
26773
  return /*#__PURE__*/React.createElement("div", {
26774
- className: css(styles$L.answerOption)
26774
+ className: css(styles$M.answerOption)
26775
26775
  }, /*#__PURE__*/React.createElement("div", {
26776
- className: css(styles$L.answerHandle)
26776
+ className: css(styles$M.answerHandle)
26777
26777
  }), /*#__PURE__*/React.createElement("div", {
26778
- className: css(styles$L.answerBody)
26778
+ className: css(styles$M.answerBody)
26779
26779
  }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("button", {
26780
26780
  onClick: this.toggleConsidered,
26781
26781
  className: answerStatusCss
26782
26782
  }, this.props.considered), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Expression, this.props.expressionProps))), /*#__PURE__*/React.createElement("div", {
26783
- className: css(styles$L.paddedY, styles$L.paddedX)
26783
+ className: css(styles$M.paddedY, styles$M.paddedX)
26784
26784
  }, /*#__PURE__*/React.createElement(Checkbox$1, {
26785
26785
  label: "Answer expression must have the same form.",
26786
26786
  checked: this.props.form,
@@ -26789,8 +26789,8 @@ class AnswerOption extends React.Component {
26789
26789
  form: value
26790
26790
  });
26791
26791
  }
26792
- }), /*#__PURE__*/React.createElement(InfoTip$i, null, /*#__PURE__*/React.createElement("p", null, "The student's answer must be in the same form. Commutativity and excess negative signs are ignored."))), /*#__PURE__*/React.createElement("div", {
26793
- className: css(styles$L.paddedY, styles$L.paddedX)
26792
+ }), /*#__PURE__*/React.createElement(InfoTip$j, null, /*#__PURE__*/React.createElement("p", null, "The student's answer must be in the same form. Commutativity and excess negative signs are ignored."))), /*#__PURE__*/React.createElement("div", {
26793
+ className: css(styles$M.paddedY, styles$M.paddedX)
26794
26794
  }, /*#__PURE__*/React.createElement(Checkbox$1, {
26795
26795
  label: "Answer expression must be fully expanded and simplified.",
26796
26796
  checked: this.props.simplify,
@@ -26799,12 +26799,12 @@ class AnswerOption extends React.Component {
26799
26799
  simplify: value
26800
26800
  });
26801
26801
  }
26802
- }), /*#__PURE__*/React.createElement(InfoTip$i, null, /*#__PURE__*/React.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.createElement("div", {
26803
- className: css(styles$L.buttonRow, styles$L.paddedY)
26802
+ }), /*#__PURE__*/React.createElement(InfoTip$j, null, /*#__PURE__*/React.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.createElement("div", {
26803
+ className: css(styles$M.buttonRow, styles$M.paddedY)
26804
26804
  }, removeButton)));
26805
26805
  }
26806
26806
  }
26807
- const styles$L = StyleSheet.create({
26807
+ const styles$M = StyleSheet.create({
26808
26808
  paddedX: {
26809
26809
  paddingLeft: spacing.xSmall_8,
26810
26810
  paddingRight: spacing.xSmall_8
@@ -26899,10 +26899,10 @@ class GradedGroupEditor extends React.Component {
26899
26899
  }, /*#__PURE__*/React.createElement("div", {
26900
26900
  className: "perseus-widget-row"
26901
26901
  }, /*#__PURE__*/React.createElement("label", {
26902
- className: css(styles$K.title)
26902
+ className: css(styles$L.title)
26903
26903
  }, "Title:", " ", /*#__PURE__*/React.createElement(TextInput$5, {
26904
26904
  value: this.props.title,
26905
- className: css(styles$K.input)
26905
+ className: css(styles$L.input)
26906
26906
  // @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
26907
26907
  ,
26908
26908
  onChange: this.change("title")
@@ -26927,7 +26927,7 @@ class GradedGroupEditor extends React.Component {
26927
26927
  }, /*#__PURE__*/React.createElement(InlineIcon$4, iconPlus$1), " Add a hint"), this.props.hint && /*#__PURE__*/React.createElement("div", {
26928
26928
  className: "perseus-hint-editor"
26929
26929
  }, /*#__PURE__*/React.createElement("div", {
26930
- className: css(styles$K.hintsTitle)
26930
+ className: css(styles$L.hintsTitle)
26931
26931
  }, "Hint"), /*#__PURE__*/React.createElement(Editor, {
26932
26932
  ref: this.hintEditor,
26933
26933
  content: this.props.hint ? this.props.hint.content : "",
@@ -26964,7 +26964,7 @@ GradedGroupEditor.defaultProps = {
26964
26964
  images: {},
26965
26965
  hint: null
26966
26966
  };
26967
- const styles$K = StyleSheet.create({
26967
+ const styles$L = StyleSheet.create({
26968
26968
  title: {
26969
26969
  fontSize: 18,
26970
26970
  fontWeight: "bold"
@@ -27042,7 +27042,7 @@ const setArrayItem = (list, i, value) => [...list.slice(0, i), value, ...list.sl
27042
27042
 
27043
27043
  const {
27044
27044
  ButtonGroup: ButtonGroup$7,
27045
- InfoTip: InfoTip$h,
27045
+ InfoTip: InfoTip$i,
27046
27046
  RangeInput: RangeInput$6
27047
27047
  } = components;
27048
27048
  const defaultBackgroundImage$3 = {
@@ -27501,7 +27501,7 @@ const GraphSettings = createReactClass({
27501
27501
  },
27502
27502
  onKeyPress: this.changeBackgroundUrl,
27503
27503
  onBlur: this.changeBackgroundUrl
27504
- }), /*#__PURE__*/React.createElement(InfoTip$h, null, /*#__PURE__*/React.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background.")))), _.contains(this.props.editableSettings, "measure") && /*#__PURE__*/React.createElement("div", {
27504
+ }), /*#__PURE__*/React.createElement(InfoTip$i, null, /*#__PURE__*/React.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background.")))), _.contains(this.props.editableSettings, "measure") && /*#__PURE__*/React.createElement("div", {
27505
27505
  className: "misc-settings"
27506
27506
  }, /*#__PURE__*/React.createElement("div", {
27507
27507
  className: "perseus-widget-row"
@@ -27547,7 +27547,7 @@ const GraphSettings = createReactClass({
27547
27547
  });
27548
27548
 
27549
27549
  const {
27550
- InfoTip: InfoTip$g,
27550
+ InfoTip: InfoTip$h,
27551
27551
  MultiButtonGroup: MultiButtonGroup$1
27552
27552
  } = components;
27553
27553
  const {
@@ -27630,7 +27630,7 @@ class GrapherEditor extends React.Component {
27630
27630
  className: "perseus-error"
27631
27631
  }, this.props.graph.valid);
27632
27632
  }
27633
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", null, "Correct answer", " ", /*#__PURE__*/React.createElement(InfoTip$g, null, /*#__PURE__*/React.createElement("p", null, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer.")), " ", ": ", equationString), /*#__PURE__*/React.createElement(GraphSettings, {
27633
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", null, "Correct answer", " ", /*#__PURE__*/React.createElement(InfoTip$h, null, /*#__PURE__*/React.createElement("p", null, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer.")), " ", ": ", equationString), /*#__PURE__*/React.createElement(GraphSettings, {
27634
27634
  editableSettings: ["graph", "snap", "image"],
27635
27635
  box: getInteractiveBoxFromSizeClass$1(sizeClass),
27636
27636
  range: this.props.graph.range,
@@ -27880,7 +27880,7 @@ IframeEditor.defaultProps = {
27880
27880
 
27881
27881
  /* eslint-disable jsx-a11y/anchor-is-valid */
27882
27882
  const {
27883
- InfoTip: InfoTip$f,
27883
+ InfoTip: InfoTip$g,
27884
27884
  InlineIcon: InlineIcon$3,
27885
27885
  RangeInput: RangeInput$5
27886
27886
  } = components;
@@ -28070,7 +28070,7 @@ class ImageEditor extends React.Component {
28070
28070
  style: {
28071
28071
  width: "100%"
28072
28072
  }
28073
- }))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("div", null, "Dimensions:"), /*#__PURE__*/React.createElement("p", null, backgroundImage.width, "x", backgroundImage.height))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("div", null, "Alt text:", /*#__PURE__*/React.createElement(InfoTip$f, null, "This is important for screenreaders. The content of this alt text will be formatted as markdown (tables, emphasis, etc. are supported).")), /*#__PURE__*/React.createElement(Editor, {
28073
+ }))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("div", null, "Dimensions:"), /*#__PURE__*/React.createElement("p", null, backgroundImage.width, "x", backgroundImage.height))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("div", null, "Alt text:", /*#__PURE__*/React.createElement(InfoTip$g, null, "This is important for screenreaders. The content of this alt text will be formatted as markdown (tables, emphasis, etc. are supported).")), /*#__PURE__*/React.createElement(Editor, {
28074
28074
  apiOptions: this.props.apiOptions,
28075
28075
  content: this.props.alt,
28076
28076
  onChange: props => {
@@ -28094,7 +28094,7 @@ class ImageEditor extends React.Component {
28094
28094
  }, this.state.backgroundImageError);
28095
28095
  return /*#__PURE__*/React.createElement("div", {
28096
28096
  className: "perseus-image-editor"
28097
- }, /*#__PURE__*/React.createElement("label", null, "Image url:", /*#__PURE__*/React.createElement(InfoTip$f, null, "Paste an image or graphie image URL."), this.state.backgroundImageError && backgroundImageErrorText, /*#__PURE__*/React.createElement(BlurInput, {
28097
+ }, /*#__PURE__*/React.createElement("label", null, "Image url:", /*#__PURE__*/React.createElement(InfoTip$g, null, "Paste an image or graphie image URL."), this.state.backgroundImageError && backgroundImageErrorText, /*#__PURE__*/React.createElement(BlurInput, {
28098
28098
  value: backgroundImage.url || "",
28099
28099
  style: {
28100
28100
  width: 332
@@ -28116,7 +28116,7 @@ ImageEditor.defaultProps = {
28116
28116
  };
28117
28117
 
28118
28118
  const {
28119
- InfoTip: InfoTip$e
28119
+ InfoTip: InfoTip$f
28120
28120
  } = components;
28121
28121
  const answerTypes = {
28122
28122
  number: {
@@ -28202,7 +28202,7 @@ class InputNumberEditor extends React.Component {
28202
28202
  value: "optional"
28203
28203
  }, "will be accepted"), /*#__PURE__*/React.createElement("option", {
28204
28204
  value: "enforced"
28205
- }, "will be marked wrong"))), /*#__PURE__*/React.createElement(InfoTip$e, null, /*#__PURE__*/React.createElement("p", null, "Normally select \"will not be graded\". This will give the user a message saying the answer is correct but not simplified. The user will then have to simplify it and re-enter, but will not be penalized. (5th grade and anything after)"), /*#__PURE__*/React.createElement("p", null, "Select \"will be accepted\" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)"), /*#__PURE__*/React.createElement("p", null, "Select \"will be marked wrong\" only if we are specifically assessing the ability to simplify."))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
28205
+ }, "will be marked wrong"))), /*#__PURE__*/React.createElement(InfoTip$f, null, /*#__PURE__*/React.createElement("p", null, "Normally select \"will not be graded\". This will give the user a message saying the answer is correct but not simplified. The user will then have to simplify it and re-enter, but will not be penalized. (5th grade and anything after)"), /*#__PURE__*/React.createElement("p", null, "Select \"will be accepted\" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)"), /*#__PURE__*/React.createElement("p", null, "Select \"will be marked wrong\" only if we are specifically assessing the ability to simplify."))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
28206
28206
  type: "checkbox",
28207
28207
  checked: this.props.inexact,
28208
28208
  onChange: e => {
@@ -28238,7 +28238,7 @@ class InputNumberEditor extends React.Component {
28238
28238
  });
28239
28239
  },
28240
28240
  "aria-label": "Answer type"
28241
- }, answerTypeOptions), /*#__PURE__*/React.createElement(InfoTip$e, null, /*#__PURE__*/React.createElement("p", null, "Use the default \"Numbers\" unless the answer must be in a specific form (e.g., question is about converting decimals to fractions)."))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, "Width", " ", /*#__PURE__*/React.createElement("select", {
28241
+ }, answerTypeOptions), /*#__PURE__*/React.createElement(InfoTip$f, null, /*#__PURE__*/React.createElement("p", null, "Use the default \"Numbers\" unless the answer must be in a specific form (e.g., question is about converting decimals to fractions)."))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, "Width", " ", /*#__PURE__*/React.createElement("select", {
28242
28242
  value: this.props.size,
28243
28243
  onChange: e => {
28244
28244
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type '"small" | "normal" | undefined'.
@@ -28250,7 +28250,7 @@ class InputNumberEditor extends React.Component {
28250
28250
  value: "normal"
28251
28251
  }, "Normal (80px)"), /*#__PURE__*/React.createElement("option", {
28252
28252
  value: "small"
28253
- }, "Small (40px)"))), /*#__PURE__*/React.createElement(InfoTip$e, null, /*#__PURE__*/React.createElement("p", null, "Use size \"Normal\" for all text boxes, unless there are multiple text boxes in one line and the answer area is too narrow to fit them."))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
28253
+ }, "Small (40px)"))), /*#__PURE__*/React.createElement(InfoTip$f, null, /*#__PURE__*/React.createElement("p", null, "Use size \"Normal\" for all text boxes, unless there are multiple text boxes in one line and the answer area is too narrow to fit them."))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
28254
28254
  type: "checkbox",
28255
28255
  checked: this.props.rightAlign,
28256
28256
  onChange: e => {
@@ -28423,13 +28423,13 @@ function MathquillInput(props) {
28423
28423
  }
28424
28424
  });
28425
28425
  return /*#__PURE__*/React.createElement(View, {
28426
- style: styles$J.outerWrapper
28426
+ style: styles$K.outerWrapper
28427
28427
  }, /*#__PURE__*/React.createElement("span", {
28428
28428
  ref: mathFieldWrapperRef,
28429
28429
  className: "perseus-math-input mq-editable-field mq-math-mode"
28430
28430
  }));
28431
28431
  }
28432
- const styles$J = StyleSheet.create({
28432
+ const styles$K = StyleSheet.create({
28433
28433
  outerWrapper: {
28434
28434
  display: "inline-block",
28435
28435
  borderStyle: "solid",
@@ -29533,7 +29533,7 @@ const GraphPointsCountSelector = ({
29533
29533
  // Never uses placeholder, always has value
29534
29534
  ,
29535
29535
  placeholder: "",
29536
- style: styles$I.singleSelectShort
29536
+ style: styles$J.singleSelectShort
29537
29537
  }, [...[...Array(7).keys()].map(n => /*#__PURE__*/React.createElement(OptionItem, {
29538
29538
  key: n,
29539
29539
  value: `${n}`,
@@ -29544,7 +29544,7 @@ const GraphPointsCountSelector = ({
29544
29544
  label: "unlimited"
29545
29545
  })]);
29546
29546
  };
29547
- const styles$I = StyleSheet.create({
29547
+ const styles$J = StyleSheet.create({
29548
29548
  singleSelectShort: {
29549
29549
  // Non-standard spacing, but it's the smallest we can go
29550
29550
  // without running into styling issues with the dropdown.
@@ -29557,7 +29557,7 @@ const GraphTypeSelector = props => {
29557
29557
  selectedValue: props.graphType,
29558
29558
  onChange: props.onChange,
29559
29559
  placeholder: "Select an answer type",
29560
- style: styles$H.singleSelectShort
29560
+ style: styles$I.singleSelectShort
29561
29561
  }, props.showNoneOption && /*#__PURE__*/React.createElement(OptionItem, {
29562
29562
  value: "none",
29563
29563
  label: "None"
@@ -29593,7 +29593,7 @@ const GraphTypeSelector = props => {
29593
29593
  label: "Angle"
29594
29594
  }));
29595
29595
  };
29596
- const styles$H = StyleSheet.create({
29596
+ const styles$I = StyleSheet.create({
29597
29597
  singleSelectShort: {
29598
29598
  // Non-standard spacing, but it's the smallest we can go
29599
29599
  // without running into styling issues with the dropdown.
@@ -29608,11 +29608,11 @@ function Heading({
29608
29608
  onToggle
29609
29609
  }) {
29610
29610
  return /*#__PURE__*/React.createElement(Clickable, {
29611
- style: [styles$G.container, !isCollapsible && styles$G.notClickable],
29611
+ style: [styles$H.container, !isCollapsible && styles$H.notClickable],
29612
29612
  disabled: !isCollapsible,
29613
29613
  onClick: () => isCollapsible && (onToggle == null ? void 0 : onToggle(!isOpen))
29614
29614
  }, () => /*#__PURE__*/React.createElement(View, {
29615
- style: styles$G.heading
29615
+ style: styles$H.heading
29616
29616
  }, /*#__PURE__*/React.createElement(LabelLarge, {
29617
29617
  style: {
29618
29618
  fontSize: 14,
@@ -29622,7 +29622,7 @@ function Heading({
29622
29622
  isExpanded: isOpen
29623
29623
  })));
29624
29624
  }
29625
- const styles$G = StyleSheet.create({
29625
+ const styles$H = StyleSheet.create({
29626
29626
  container: {
29627
29627
  marginTop: spacing.small_12,
29628
29628
  // NOTE(jeremy): This is the inverse of the @editorPadding CSS
@@ -29682,15 +29682,18 @@ function InteractiveGraphDescription(props) {
29682
29682
  isOpen: isOpen,
29683
29683
  onToggle: setIsOpen
29684
29684
  }), isOpen && /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(LabelXSmall, {
29685
- style: styles$F.caption
29686
- }, "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.createElement(LabelLarge, {
29685
+ style: styles$G.caption
29686
+ }, "Use these fields to describe the graph as a whole. These are used by screen readers to describe content to users who may be visually impaired."), /*#__PURE__*/React.createElement(LabelLarge, {
29687
29687
  tag: "label"
29688
29688
  }, "Title", /*#__PURE__*/React.createElement(TextField, {
29689
29689
  value: ariaLabelValue,
29690
29690
  onChange: newValue => onChange({
29691
- fullGraphAriaLabel: newValue
29691
+ fullGraphAriaLabel:
29692
+ // Save as undefined if the new value
29693
+ // is an empty string.
29694
+ newValue || undefined
29692
29695
  }),
29693
- style: styles$F.spaceAbove
29696
+ style: styles$G.spaceAbove
29694
29697
  })), /*#__PURE__*/React.createElement(Strut, {
29695
29698
  size: spacing.small_12
29696
29699
  }), /*#__PURE__*/React.createElement(LabelLarge, {
@@ -29700,12 +29703,15 @@ function InteractiveGraphDescription(props) {
29700
29703
  resizeType: "vertical",
29701
29704
  value: ariaDescriptionValue,
29702
29705
  onChange: newValue => onChange({
29703
- fullGraphAriaDescription: newValue
29706
+ fullGraphAriaDescription:
29707
+ // Save as undefined if the new value
29708
+ // is an empty string.
29709
+ newValue || undefined
29704
29710
  }),
29705
- style: styles$F.spaceAbove
29711
+ style: styles$G.spaceAbove
29706
29712
  }))));
29707
29713
  }
29708
- const styles$F = StyleSheet.create({
29714
+ const styles$G = StyleSheet.create({
29709
29715
  caption: {
29710
29716
  color: color.offBlack64,
29711
29717
  paddingTop: spacing.xxSmall_6,
@@ -29725,16 +29731,16 @@ const LabeledRow = props => {
29725
29731
  style
29726
29732
  } = props;
29727
29733
  return /*#__PURE__*/React.createElement("label", {
29728
- className: css(styles$E.label)
29734
+ className: css(styles$F.label)
29729
29735
  }, /*#__PURE__*/React.createElement(View, {
29730
- style: [styles$E.row, style]
29736
+ style: [styles$F.row, style]
29731
29737
  }, labelSide === "start" || /*#__PURE__*/React.createElement(LabelSmall, {
29732
- style: styles$E.spaceEnd
29738
+ style: styles$F.spaceEnd
29733
29739
  }, label), children, labelSide === "end" && /*#__PURE__*/React.createElement(LabelSmall, {
29734
- style: styles$E.spaceStart
29740
+ style: styles$F.spaceStart
29735
29741
  }, label)));
29736
29742
  };
29737
- const styles$E = StyleSheet.create({
29743
+ const styles$F = StyleSheet.create({
29738
29744
  label: {
29739
29745
  width: "fit-content"
29740
29746
  },
@@ -29754,7 +29760,7 @@ const styles$E = StyleSheet.create({
29754
29760
 
29755
29761
  const {
29756
29762
  ButtonGroup: ButtonGroup$2,
29757
- InfoTip: InfoTip$d,
29763
+ InfoTip: InfoTip$e,
29758
29764
  RangeInput: RangeInput$4
29759
29765
  } = components;
29760
29766
  const defaultBackgroundImage$1 = {
@@ -30128,10 +30134,10 @@ class InteractiveGraphSettings extends React.Component {
30128
30134
  }
30129
30135
  }))), /*#__PURE__*/React.createElement(LabeledRow, {
30130
30136
  label: "Background image URL:",
30131
- style: styles$D.resetSpaceTop
30137
+ style: styles$E.resetSpaceTop
30132
30138
  }, /*#__PURE__*/React.createElement("input", {
30133
30139
  type: "text",
30134
- className: css(styles$D.backgroundUrlInput),
30140
+ className: css(styles$E.backgroundUrlInput),
30135
30141
  ref: this.bgUrlRef,
30136
30142
  value: this.state.backgroundImage.url || "",
30137
30143
  onChange: e => {
@@ -30144,10 +30150,10 @@ class InteractiveGraphSettings extends React.Component {
30144
30150
  },
30145
30151
  onKeyPress: this.changeBackgroundUrl,
30146
30152
  onBlur: this.changeBackgroundUrl
30147
- }), /*#__PURE__*/React.createElement(InfoTip$d, null, /*#__PURE__*/React.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background."))), /*#__PURE__*/React.createElement(View, {
30148
- style: styles$D.protractorSection
30153
+ }), /*#__PURE__*/React.createElement(InfoTip$e, null, /*#__PURE__*/React.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background."))), /*#__PURE__*/React.createElement(View, {
30154
+ style: styles$E.protractorSection
30149
30155
  }, /*#__PURE__*/React.createElement(View, {
30150
- style: styles$D.checkboxRow
30156
+ style: styles$E.checkboxRow
30151
30157
  }, /*#__PURE__*/React.createElement(Checkbox$1, {
30152
30158
  label: "Show protractor",
30153
30159
  checked: this.props.showProtractor,
@@ -30156,7 +30162,7 @@ class InteractiveGraphSettings extends React.Component {
30156
30162
  showProtractor: value
30157
30163
  });
30158
30164
  },
30159
- style: styles$D.resetSpaceTop
30165
+ style: styles$E.resetSpaceTop
30160
30166
  })), this.props.showProtractor && /*#__PURE__*/React.createElement(Banner, {
30161
30167
  layout: "floating",
30162
30168
  text: "The protractor is not accessible. Please consider an alternate approach.",
@@ -30177,7 +30183,7 @@ InteractiveGraphSettings.defaultProps = {
30177
30183
  showProtractor: false,
30178
30184
  showTooltips: false
30179
30185
  };
30180
- const styles$D = StyleSheet.create({
30186
+ const styles$E = StyleSheet.create({
30181
30187
  resetSpaceTop: {
30182
30188
  marginTop: 0
30183
30189
  },
@@ -30214,13 +30220,13 @@ const SegmentCountSelector = ({
30214
30220
  const num = +newValue;
30215
30221
  onChange(num);
30216
30222
  },
30217
- style: styles$C.singleSelectShort
30223
+ style: styles$D.singleSelectShort
30218
30224
  }, _.range(1, 7).map(n => /*#__PURE__*/React.createElement(OptionItem, {
30219
30225
  key: n,
30220
30226
  value: `${n}`,
30221
30227
  label: `${n} segment${n > 1 ? "s" : ""}`
30222
30228
  })));
30223
- const styles$C = StyleSheet.create({
30229
+ const styles$D = StyleSheet.create({
30224
30230
  singleSelectShort: {
30225
30231
  // Non-standard spacing, but it's the smallest we can go
30226
30232
  // without running into styling issues with the dropdown.
@@ -30245,17 +30251,17 @@ const LockedFigureSelect = props => {
30245
30251
  figureTypes.push("label");
30246
30252
  }
30247
30253
  return /*#__PURE__*/React.createElement(View, {
30248
- style: styles$B.container
30254
+ style: styles$C.container
30249
30255
  }, /*#__PURE__*/React.createElement(ActionMenu, {
30250
30256
  menuText: "Add locked figure",
30251
- style: styles$B.addElementSelect
30257
+ style: styles$C.addElementSelect
30252
30258
  }, figureTypes.map(figureType => /*#__PURE__*/React.createElement(ActionItem, {
30253
30259
  key: `${id}-${figureType}`,
30254
30260
  label: figureType,
30255
30261
  onClick: () => onChange(figureType)
30256
30262
  }))));
30257
30263
  };
30258
- const styles$B = StyleSheet.create({
30264
+ const styles$C = StyleSheet.create({
30259
30265
  container: {
30260
30266
  marginTop: spacing.xSmall_8
30261
30267
  },
@@ -30372,18 +30378,18 @@ const AngleInput = props => {
30372
30378
  }
30373
30379
  return /*#__PURE__*/React.createElement(LabelMedium, {
30374
30380
  tag: "label",
30375
- style: styles$A.row
30381
+ style: styles$B.row
30376
30382
  }, "angle (degrees)", /*#__PURE__*/React.createElement(Strut, {
30377
30383
  size: spacing.xxSmall_6
30378
30384
  }), /*#__PURE__*/React.createElement(ScrolllessNumberTextField, {
30379
30385
  value: angleInput,
30380
30386
  onChange: handleAngleChange,
30381
- style: styles$A.textField
30387
+ style: styles$B.textField
30382
30388
  }), /*#__PURE__*/React.createElement(Strut, {
30383
30389
  size: spacing.xxSmall_6
30384
30390
  }));
30385
30391
  };
30386
- const styles$A = StyleSheet.create({
30392
+ const styles$B = StyleSheet.create({
30387
30393
  row: {
30388
30394
  display: "flex",
30389
30395
  flexDirection: "row",
@@ -30432,30 +30438,30 @@ const CoordinatePairInput = props => {
30432
30438
  onChange(newCoords);
30433
30439
  }
30434
30440
  return /*#__PURE__*/React.createElement(View, {
30435
- style: [styles$z.row, style]
30441
+ style: [styles$A.row, style]
30436
30442
  }, /*#__PURE__*/React.createElement(LabelMedium, {
30437
30443
  tag: "label",
30438
- style: styles$z.row
30444
+ style: styles$A.row
30439
30445
  }, labels ? labels[0] : "x coord", /*#__PURE__*/React.createElement(Strut, {
30440
30446
  size: spacing.xxSmall_6
30441
30447
  }), /*#__PURE__*/React.createElement(ScrolllessNumberTextField, {
30442
30448
  value: coordState[0],
30443
30449
  onChange: newValue => handleCoordChange(newValue, 0),
30444
- style: [styles$z.textField, error ? styles$z.errorField : undefined]
30450
+ style: [styles$A.textField, error ? styles$A.errorField : undefined]
30445
30451
  })), /*#__PURE__*/React.createElement(Strut, {
30446
30452
  size: spacing.medium_16
30447
30453
  }), /*#__PURE__*/React.createElement(LabelMedium, {
30448
30454
  tag: "label",
30449
- style: styles$z.row
30455
+ style: styles$A.row
30450
30456
  }, labels ? labels[1] : "y coord", /*#__PURE__*/React.createElement(Strut, {
30451
30457
  size: spacing.xxSmall_6
30452
30458
  }), /*#__PURE__*/React.createElement(ScrolllessNumberTextField, {
30453
30459
  value: coordState[1],
30454
30460
  onChange: newValue => handleCoordChange(newValue, 1),
30455
- style: [styles$z.textField, error ? styles$z.errorField : undefined]
30461
+ style: [styles$A.textField, error ? styles$A.errorField : undefined]
30456
30462
  })));
30457
30463
  };
30458
- const styles$z = StyleSheet.create({
30464
+ const styles$A = StyleSheet.create({
30459
30465
  row: {
30460
30466
  display: "flex",
30461
30467
  flexDirection: "row",
@@ -30488,14 +30494,14 @@ const PerseusEditorAccordion = props => {
30488
30494
  }, /*#__PURE__*/React.createElement(AccordionSection, {
30489
30495
  expanded: expanded,
30490
30496
  onToggle: onToggle,
30491
- style: [styles$y.container, containerStyle],
30492
- headerStyle: styles$y.accordionHeader,
30497
+ style: [styles$z.container, containerStyle],
30498
+ headerStyle: styles$z.accordionHeader,
30493
30499
  header: header
30494
30500
  }, /*#__PURE__*/React.createElement(View, {
30495
- style: [styles$y.accordionPanel, panelStyle]
30501
+ style: [styles$z.accordionPanel, panelStyle]
30496
30502
  }, children)));
30497
30503
  };
30498
- const styles$y = StyleSheet.create({
30504
+ const styles$z = StyleSheet.create({
30499
30505
  container: {
30500
30506
  backgroundColor: color.fadedBlue8,
30501
30507
  marginTop: spacing.xSmall_8
@@ -30526,13 +30532,13 @@ const ColorSwatch = props => {
30526
30532
  "aria-label":
30527
30533
  // Don't include an aria label for decorative circles.
30528
30534
  !decorative ? `${color$1}, ${filled ? "filled" : "open"}` : undefined,
30529
- style: [styles$x.colorSwatch, {
30535
+ style: [styles$y.colorSwatch, {
30530
30536
  border: `4px solid ${lockedFigureColors[color$1]}`,
30531
30537
  backgroundColor: filled ? lockedFigureColors[color$1] : color.white
30532
30538
  }]
30533
30539
  });
30534
30540
  };
30535
- const styles$x = StyleSheet.create({
30541
+ const styles$y = StyleSheet.create({
30536
30542
  colorSwatch: {
30537
30543
  // Add a white outline so that the color swatch is visible when
30538
30544
  // the dropdown option is highlighted with its blue background.
@@ -30551,10 +30557,10 @@ const ColorSelect = props => {
30551
30557
  onChange
30552
30558
  } = props;
30553
30559
  return /*#__PURE__*/React.createElement(View, {
30554
- style: [styles$w.row, style]
30560
+ style: [styles$x.row, style]
30555
30561
  }, /*#__PURE__*/React.createElement(LabelMedium, {
30556
30562
  tag: "label",
30557
- style: styles$w.row
30563
+ style: styles$x.row
30558
30564
  }, "color", /*#__PURE__*/React.createElement(Strut, {
30559
30565
  size: spacing.xxSmall_6
30560
30566
  }), /*#__PURE__*/React.createElement(SingleSelect, {
@@ -30573,7 +30579,7 @@ const ColorSelect = props => {
30573
30579
  })
30574
30580
  })))));
30575
30581
  };
30576
- const styles$w = StyleSheet.create({
30582
+ const styles$x = StyleSheet.create({
30577
30583
  row: {
30578
30584
  display: "flex",
30579
30585
  flexDirection: "row",
@@ -30592,17 +30598,17 @@ const EllipseSwatch = props => {
30592
30598
  } = props;
30593
30599
  return /*#__PURE__*/React.createElement(View, {
30594
30600
  "aria-label": `${color}, stroke ${strokeStyle}, fill ${fillStyle}`,
30595
- style: [styles$v.container, {
30601
+ style: [styles$w.container, {
30596
30602
  border: `4px ${strokeStyle} ${lockedFigureColors[color]}`
30597
30603
  }]
30598
30604
  }, /*#__PURE__*/React.createElement(View, {
30599
- style: [styles$v.innerCircle, {
30605
+ style: [styles$w.innerCircle, {
30600
30606
  backgroundColor: lockedFigureColors[color],
30601
30607
  opacity: fillStyle === "white" ? 0 : lockedFigureFillStyles[fillStyle]
30602
30608
  }]
30603
30609
  }));
30604
30610
  };
30605
- const styles$v = StyleSheet.create({
30611
+ const styles$w = StyleSheet.create({
30606
30612
  container: {
30607
30613
  // Add a white outline so that the color swatch is visible when
30608
30614
  // the dropdown option is highlighted with its blue background.
@@ -30628,7 +30634,7 @@ const LineStrokeSelect = props => {
30628
30634
  } = props;
30629
30635
  return /*#__PURE__*/React.createElement(LabelMedium, {
30630
30636
  tag: "label",
30631
- style: styles$u.lineStrokeSelect
30637
+ style: styles$v.lineStrokeSelect
30632
30638
  }, "stroke", /*#__PURE__*/React.createElement(Strut, {
30633
30639
  size: spacing.xxxSmall_4
30634
30640
  }), /*#__PURE__*/React.createElement(SingleSelect, {
@@ -30645,7 +30651,7 @@ const LineStrokeSelect = props => {
30645
30651
  label: "dashed"
30646
30652
  })));
30647
30653
  };
30648
- const styles$u = StyleSheet.create({
30654
+ const styles$v = StyleSheet.create({
30649
30655
  lineStrokeSelect: {
30650
30656
  display: "flex",
30651
30657
  flexDirection: "row",
@@ -30655,6 +30661,66 @@ const styles$u = StyleSheet.create({
30655
30661
  }
30656
30662
  });
30657
30663
 
30664
+ const {
30665
+ InfoTip: InfoTip$d
30666
+ } = components;
30667
+ function LockedFigureAria(props) {
30668
+ const {
30669
+ ariaLabel,
30670
+ prePopulatedAriaLabel,
30671
+ onChangeProps
30672
+ } = props;
30673
+ const id = React.useId();
30674
+ const ariaLabelId = `aria-label-${id}`;
30675
+ return /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(Strut, {
30676
+ size: spacing.xSmall_8
30677
+ }), /*#__PURE__*/React.createElement(View, {
30678
+ style: styles$u.row
30679
+ }, /*#__PURE__*/React.createElement(LabelMedium, {
30680
+ tag: "label",
30681
+ htmlFor: ariaLabelId
30682
+ }, "Aria label"), /*#__PURE__*/React.createElement(Spring, null), /*#__PURE__*/React.createElement(InfoTip$d, null, "Aria label is used by screen readers to describe content to users who may be visually impaired. ", /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("br", null), "Populating this field will make it so that users can use a screen reader to navigate to this point and hear the description.", /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("br", null), "If you leave this field blank, the point will be hidden from screen readers. Users will not be able to navigate to this point using a screen reader.")), /*#__PURE__*/React.createElement(Strut, {
30683
+ size: spacing.xxSmall_6
30684
+ }), /*#__PURE__*/React.createElement(LabelXSmall, {
30685
+ style: styles$u.caption
30686
+ }, "The figure is hidden from screen readers if this field is left blank."), /*#__PURE__*/React.createElement(Strut, {
30687
+ size: spacing.xxSmall_6
30688
+ }), /*#__PURE__*/React.createElement(TextArea, {
30689
+ id: ariaLabelId,
30690
+ value: ariaLabel != null ? ariaLabel : "",
30691
+ onChange: newValue => {
30692
+ onChangeProps({
30693
+ // Save as undefined if the field is empty.
30694
+ ariaLabel: newValue || undefined
30695
+ });
30696
+ },
30697
+ placeholder: "Ex. Point at (x, y)",
30698
+ rows: 1,
30699
+ resizeType: "vertical"
30700
+ }), /*#__PURE__*/React.createElement(Button, {
30701
+ kind: "tertiary",
30702
+ startIcon: pencilCircle,
30703
+ style: styles$u.button,
30704
+ onClick: () => {
30705
+ onChangeProps({
30706
+ ariaLabel: prePopulatedAriaLabel
30707
+ });
30708
+ }
30709
+ }, "Auto-generate"));
30710
+ }
30711
+ const styles$u = StyleSheet.create({
30712
+ row: {
30713
+ flexDirection: "row",
30714
+ alignItems: "center"
30715
+ },
30716
+ button: {
30717
+ alignSelf: "start"
30718
+ },
30719
+ caption: {
30720
+ color: color.offBlack64
30721
+ }
30722
+ });
30723
+
30658
30724
  /**
30659
30725
  * The part of a locked figure settings panel that contains actions
30660
30726
  * for this panel and its associated locked figure, including
@@ -30718,132 +30784,437 @@ const styles$t = StyleSheet.create({
30718
30784
  }
30719
30785
  });
30720
30786
 
30721
- const {
30722
- InfoTip: InfoTip$c
30723
- } = components;
30724
- const LockedEllipseSettings = props => {
30787
+ /**
30788
+ * LockedLabelSettings is a component that allows the user to edit the
30789
+ * settings of specifically a locked label on the graph within the
30790
+ * Interactive Graph widget.
30791
+ *
30792
+ * Used in the interactive graph editor's locked figures section.
30793
+ */
30794
+ function LockedLabelSettings(props) {
30725
30795
  const {
30726
- center,
30727
- radius,
30728
- angle,
30729
- color,
30730
- fillStyle,
30731
- strokeStyle,
30796
+ type,
30797
+ coord,
30798
+ color: color$1,
30799
+ size,
30800
+ text,
30732
30801
  expanded,
30733
- onToggle,
30734
30802
  onChangeProps,
30735
30803
  onMove,
30736
- onRemove
30804
+ onRemove,
30805
+ onToggle,
30806
+ containerStyle
30737
30807
  } = props;
30738
- function handleColorChange(newValue) {
30739
- onChangeProps({
30740
- color: newValue
30741
- });
30742
- }
30743
30808
  return /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
30744
30809
  expanded: expanded,
30745
30810
  onToggle: onToggle,
30746
- header:
30747
- /*#__PURE__*/
30748
- // Summary: Ellipse, center, radius, color (opacity, dashed)
30749
- React.createElement(View, {
30750
- style: styles$s.row
30751
- }, /*#__PURE__*/React.createElement(LabelLarge, null, `Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`), /*#__PURE__*/React.createElement(Strut, {
30811
+ header: /*#__PURE__*/React.createElement(View, {
30812
+ style: [styles$s.row, styles$s.accordionHeaderContainer]
30813
+ }, /*#__PURE__*/React.createElement(LabelLarge, null, "Label (", coord[0], ", ", coord[1], ")"), /*#__PURE__*/React.createElement(Strut, {
30752
30814
  size: spacing.xSmall_8
30753
- }), /*#__PURE__*/React.createElement(EllipseSwatch, {
30754
- color: props.color,
30755
- fillStyle: fillStyle,
30756
- strokeStyle: strokeStyle
30757
- }))
30758
- }, /*#__PURE__*/React.createElement(View, {
30759
- style: styles$s.row
30815
+ }), text !== "" && /*#__PURE__*/React.createElement(LabelLarge, {
30816
+ style: [{
30817
+ backgroundColor: color.white,
30818
+ color: lockedFigureColors[color$1]
30819
+ }, styles$s.accordionHeader]
30820
+ }, text)),
30821
+ containerStyle: containerStyle
30760
30822
  }, /*#__PURE__*/React.createElement(CoordinatePairInput, {
30761
- coord: center,
30762
- style: styles$s.spaceUnder,
30763
- onChange: newCoords => onChangeProps({
30764
- center: newCoords
30765
- })
30766
- }), /*#__PURE__*/React.createElement(View, {
30823
+ coord: coord,
30824
+ onChange: newCoords => {
30825
+ onChangeProps({
30826
+ coord: newCoords
30827
+ });
30828
+ },
30767
30829
  style: styles$s.spaceUnder
30768
- }, /*#__PURE__*/React.createElement(InfoTip$c, null, "The coordinates for the center of the ellipse."))), /*#__PURE__*/React.createElement(CoordinatePairInput, {
30769
- coord: radius,
30770
- labels: ["x radius", "y radius"],
30771
- style: styles$s.spaceUnder,
30772
- onChange: newCoords => onChangeProps({
30773
- radius: newCoords
30774
- })
30775
- }), /*#__PURE__*/React.createElement(AngleInput, {
30776
- angle: angle,
30777
- onChange: newAngle => onChangeProps({
30778
- angle: newAngle
30779
- })
30780
- }), /*#__PURE__*/React.createElement(Strut, {
30781
- size: spacing.xSmall_8
30782
- }), /*#__PURE__*/React.createElement(View, {
30830
+ }), /*#__PURE__*/React.createElement(LabelMedium, {
30831
+ tag: "label",
30783
30832
  style: [styles$s.row, styles$s.spaceUnder]
30833
+ }, "TeX", /*#__PURE__*/React.createElement(Strut, {
30834
+ size: spacing.xSmall_8
30835
+ }), /*#__PURE__*/React.createElement(TextField, {
30836
+ value: text,
30837
+ placeholder: "ex. x^2 or \\frac{1}{2}",
30838
+ onChange: newValue => onChangeProps({
30839
+ text: newValue
30840
+ })
30841
+ })), /*#__PURE__*/React.createElement(View, {
30842
+ style: styles$s.row
30784
30843
  }, /*#__PURE__*/React.createElement(ColorSelect, {
30785
- selectedValue: color,
30786
- onChange: handleColorChange
30844
+ selectedValue: color$1,
30845
+ onChange: newColor => {
30846
+ onChangeProps({
30847
+ color: newColor
30848
+ });
30849
+ },
30850
+ style: styles$s.spaceUnder
30787
30851
  }), /*#__PURE__*/React.createElement(Strut, {
30788
30852
  size: spacing.medium_16
30789
30853
  }), /*#__PURE__*/React.createElement(LabelMedium, {
30790
30854
  tag: "label",
30791
- style: [styles$s.row, styles$s.truncatedWidth]
30792
- }, "fill", /*#__PURE__*/React.createElement(Strut, {
30793
- size: spacing.xxSmall_6
30855
+ style: styles$s.row
30856
+ }, "size", /*#__PURE__*/React.createElement(Strut, {
30857
+ size: spacing.xSmall_8
30794
30858
  }), /*#__PURE__*/React.createElement(SingleSelect, {
30795
- selectedValue: fillStyle,
30796
- onChange: value => onChangeProps({
30797
- fillStyle: value
30859
+ selectedValue: size,
30860
+ onChange: newValue => onChangeProps({
30861
+ size: newValue
30798
30862
  })
30799
- // Placeholder is required, but never gets used.
30863
+ // Placeholder is required, but never gets used since
30864
+ // we have a label for the select.
30800
30865
  ,
30801
30866
  placeholder: ""
30802
- }, Object.keys(lockedFigureFillStyles).map(option => /*#__PURE__*/React.createElement(OptionItem, {
30803
- key: option,
30804
- value: option,
30805
- label: option
30806
- }))))), /*#__PURE__*/React.createElement(LineStrokeSelect, {
30807
- selectedValue: strokeStyle,
30808
- onChange: value => onChangeProps({
30809
- strokeStyle: value
30810
- })
30811
- }), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
30812
- figureType: props.type,
30867
+ }, /*#__PURE__*/React.createElement(OptionItem, {
30868
+ value: "small",
30869
+ label: "small"
30870
+ }), /*#__PURE__*/React.createElement(OptionItem, {
30871
+ value: "medium",
30872
+ label: "medium"
30873
+ }), /*#__PURE__*/React.createElement(OptionItem, {
30874
+ value: "large",
30875
+ label: "large"
30876
+ })))), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
30877
+ figureType: type,
30813
30878
  onMove: onMove,
30814
30879
  onRemove: onRemove
30815
30880
  }));
30816
- };
30881
+ }
30817
30882
  const styles$s = StyleSheet.create({
30883
+ accordionHeaderContainer: {
30884
+ // Stop the label summary from wrapping.
30885
+ whiteSpace: "nowrap"
30886
+ },
30887
+ accordionHeader: {
30888
+ padding: spacing.xxxSmall_4,
30889
+ marginInlineEnd: spacing.xSmall_8,
30890
+ borderRadius: spacing.xxxSmall_4,
30891
+ textOverflow: "ellipsis",
30892
+ overflow: "hidden"
30893
+ },
30818
30894
  row: {
30819
30895
  display: "flex",
30820
30896
  flexDirection: "row",
30821
- alignItems: "center"
30897
+ alignItems: "center",
30898
+ // Allow truncation, stop bleeding over the edge.
30899
+ minWidth: 0
30822
30900
  },
30823
30901
  spaceUnder: {
30824
30902
  marginBottom: spacing.xSmall_8
30825
- },
30826
- truncatedWidth: {
30827
- // Allow truncation, stop bleeding over the edge.
30828
- minWidth: 0
30829
30903
  }
30830
30904
  });
30831
30905
 
30832
- const LineSwatch = props => {
30833
- const {
30834
- color,
30835
- lineStyle
30836
- } = props;
30906
+ const DEFAULT_COLOR = "grayH";
30907
+ function getDefaultFigureForType(type) {
30908
+ switch (type) {
30909
+ case "point":
30910
+ return {
30911
+ type: "point",
30912
+ coord: [0, 0],
30913
+ color: DEFAULT_COLOR,
30914
+ filled: true
30915
+ };
30916
+ case "line":
30917
+ return {
30918
+ type: "line",
30919
+ kind: "line",
30920
+ points: [getDefaultFigureForType("point"), _extends({}, getDefaultFigureForType("point"), {
30921
+ coord: [2, 2]
30922
+ })],
30923
+ color: DEFAULT_COLOR,
30924
+ lineStyle: "solid",
30925
+ showPoint1: false,
30926
+ showPoint2: false
30927
+ };
30928
+ case "vector":
30929
+ return {
30930
+ type: "vector",
30931
+ points: [[0, 0], [2, 2]],
30932
+ color: DEFAULT_COLOR
30933
+ };
30934
+ case "ellipse":
30935
+ return {
30936
+ type: "ellipse",
30937
+ center: [0, 0],
30938
+ radius: [1, 1],
30939
+ angle: 0,
30940
+ color: DEFAULT_COLOR,
30941
+ fillStyle: "none",
30942
+ strokeStyle: "solid"
30943
+ };
30944
+ case "polygon":
30945
+ return {
30946
+ type: "polygon",
30947
+ points: [[0, 2], [-1, 0], [1, 0]],
30948
+ color: DEFAULT_COLOR,
30949
+ showVertices: false,
30950
+ fillStyle: "none",
30951
+ strokeStyle: "solid"
30952
+ };
30953
+ case "function":
30954
+ return {
30955
+ type: "function",
30956
+ color: DEFAULT_COLOR,
30957
+ strokeStyle: "solid",
30958
+ equation: "x^2",
30959
+ directionalAxis: "x"
30960
+ };
30961
+ case "label":
30962
+ return {
30963
+ type: "label",
30964
+ coord: [0, 0],
30965
+ text: "",
30966
+ color: DEFAULT_COLOR,
30967
+ size: "medium"
30968
+ };
30969
+ default:
30970
+ throw new UnreachableCaseError(type);
30971
+ }
30972
+ }
30973
+
30974
+ const {
30975
+ InfoTip: InfoTip$c
30976
+ } = components;
30977
+ const LockedEllipseSettings = props => {
30978
+ var _flags$mafs, _flags$mafs2;
30979
+ const {
30980
+ flags,
30981
+ center,
30982
+ radius,
30983
+ angle,
30984
+ color,
30985
+ labels,
30986
+ ariaLabel,
30987
+ fillStyle,
30988
+ strokeStyle,
30989
+ expanded,
30990
+ onToggle,
30991
+ onChangeProps,
30992
+ onMove,
30993
+ onRemove
30994
+ } = props;
30995
+ function getPrepopulatedAriaLabel() {
30996
+ const isCircle = radius[0] === radius[1];
30997
+ let str = "";
30998
+ if (isCircle) {
30999
+ str += `Circle with radius ${radius[0]}`;
31000
+ } else {
31001
+ str += `Ellipse with x radius ${radius[0]} and y radius ${radius[1]}`;
31002
+ }
31003
+ str += `, centered at (${center[0]}, ${center[1]})`;
31004
+ if (!isCircle && angle !== 0) {
31005
+ str += `, rotated by ${radianToDegree(angle)} degrees`;
31006
+ }
31007
+ if (labels && labels.length > 0) {
31008
+ str += ", with label";
31009
+ // Make it "with labels" instead of "with label" if there are
31010
+ // multiple labels.
31011
+ if (labels.length > 1) {
31012
+ str += "s";
31013
+ }
31014
+
31015
+ // Separate additional labels with commas.
31016
+ str += ` ${labels.map(l => l.text).join(", ")}`;
31017
+ }
31018
+ return str;
31019
+ }
31020
+ function handleCenterChange(newCoord) {
31021
+ const xOffset = newCoord[0] - center[0];
31022
+ const yOffset = newCoord[1] - center[1];
31023
+ const newProps = {
31024
+ center: newCoord
31025
+ };
31026
+
31027
+ // Update the coord by the same amount as the point for all labels
31028
+ newProps.labels = labels == null ? void 0 : labels.map(label => _extends({}, label, {
31029
+ coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31030
+ }));
31031
+ onChangeProps(newProps);
31032
+ }
31033
+ function handleColorChange(newValue) {
31034
+ const newProps = {
31035
+ color: newValue
31036
+ };
31037
+
31038
+ // Update the color of the all labels to match the point
31039
+ newProps.labels = labels == null ? void 0 : labels.map(label => _extends({}, label, {
31040
+ color: newValue
31041
+ }));
31042
+ onChangeProps(newProps);
31043
+ }
31044
+ function handleLabelChange(updatedLabel, labelIndex) {
31045
+ if (!labels) {
31046
+ return;
31047
+ }
31048
+ const updatedLabels = [...labels];
31049
+ updatedLabels[labelIndex] = _extends({}, labels[labelIndex], updatedLabel);
31050
+ onChangeProps({
31051
+ labels: updatedLabels
31052
+ });
31053
+ }
31054
+ function handleLabelRemove(labelIndex) {
31055
+ if (!labels) {
31056
+ return;
31057
+ }
31058
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31059
+ onChangeProps({
31060
+ labels: updatedLabels
31061
+ });
31062
+ }
31063
+ return /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
31064
+ expanded: expanded,
31065
+ onToggle: onToggle,
31066
+ header:
31067
+ /*#__PURE__*/
31068
+ // Summary: Ellipse, center, radius, color (opacity, dashed)
31069
+ React.createElement(View, {
31070
+ style: styles$r.row
31071
+ }, /*#__PURE__*/React.createElement(LabelLarge, null, `Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`), /*#__PURE__*/React.createElement(Strut, {
31072
+ size: spacing.xSmall_8
31073
+ }), /*#__PURE__*/React.createElement(EllipseSwatch, {
31074
+ color: props.color,
31075
+ fillStyle: fillStyle,
31076
+ strokeStyle: strokeStyle
31077
+ }))
31078
+ }, /*#__PURE__*/React.createElement(View, {
31079
+ style: styles$r.row
31080
+ }, /*#__PURE__*/React.createElement(CoordinatePairInput, {
31081
+ coord: center,
31082
+ style: styles$r.spaceUnder,
31083
+ onChange: handleCenterChange
31084
+ }), /*#__PURE__*/React.createElement(View, {
31085
+ style: styles$r.spaceUnder
31086
+ }, /*#__PURE__*/React.createElement(InfoTip$c, null, "The coordinates for the center of the ellipse."))), /*#__PURE__*/React.createElement(CoordinatePairInput, {
31087
+ coord: radius,
31088
+ labels: ["x radius", "y radius"],
31089
+ style: styles$r.spaceUnder,
31090
+ onChange: newCoords => onChangeProps({
31091
+ radius: newCoords
31092
+ })
31093
+ }), /*#__PURE__*/React.createElement(AngleInput, {
31094
+ angle: angle,
31095
+ onChange: newAngle => onChangeProps({
31096
+ angle: newAngle
31097
+ })
31098
+ }), /*#__PURE__*/React.createElement(Strut, {
31099
+ size: spacing.xSmall_8
31100
+ }), /*#__PURE__*/React.createElement(View, {
31101
+ style: [styles$r.row, styles$r.spaceUnder]
31102
+ }, /*#__PURE__*/React.createElement(ColorSelect, {
31103
+ selectedValue: color,
31104
+ onChange: handleColorChange
31105
+ }), /*#__PURE__*/React.createElement(Strut, {
31106
+ size: spacing.medium_16
31107
+ }), /*#__PURE__*/React.createElement(LabelMedium, {
31108
+ tag: "label",
31109
+ style: [styles$r.row, styles$r.truncatedWidth]
31110
+ }, "fill", /*#__PURE__*/React.createElement(Strut, {
31111
+ size: spacing.xxSmall_6
31112
+ }), /*#__PURE__*/React.createElement(SingleSelect, {
31113
+ selectedValue: fillStyle,
31114
+ onChange: value => onChangeProps({
31115
+ fillStyle: value
31116
+ })
31117
+ // Placeholder is required, but never gets used.
31118
+ ,
31119
+ placeholder: ""
31120
+ }, Object.keys(lockedFigureFillStyles).map(option => /*#__PURE__*/React.createElement(OptionItem, {
31121
+ key: option,
31122
+ value: option,
31123
+ label: option
31124
+ }))))), /*#__PURE__*/React.createElement(LineStrokeSelect, {
31125
+ selectedValue: strokeStyle,
31126
+ onChange: value => onChangeProps({
31127
+ strokeStyle: value
31128
+ })
31129
+ }), (flags == null || (_flags$mafs = flags["mafs"]) == null ? void 0 : _flags$mafs["locked-figures-aria"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
31130
+ size: spacing.small_12
31131
+ }), /*#__PURE__*/React.createElement(View, {
31132
+ style: styles$r.horizontalRule
31133
+ }), /*#__PURE__*/React.createElement(LockedFigureAria, {
31134
+ ariaLabel: ariaLabel,
31135
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
31136
+ onChangeProps: newProps => {
31137
+ onChangeProps(newProps);
31138
+ }
31139
+ })), (flags == null || (_flags$mafs2 = flags["mafs"]) == null ? void 0 : _flags$mafs2["locked-ellipse-labels"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
31140
+ size: spacing.xxxSmall_4
31141
+ }), /*#__PURE__*/React.createElement(View, {
31142
+ style: styles$r.horizontalRule
31143
+ }), /*#__PURE__*/React.createElement(Strut, {
31144
+ size: spacing.small_12
31145
+ }), /*#__PURE__*/React.createElement(LabelMedium, null, "Visible labels"), labels == null ? void 0 : labels.map((label, labelIndex) => /*#__PURE__*/React.createElement(LockedLabelSettings, _extends({}, label, {
31146
+ expanded: true,
31147
+ onChangeProps: newLabel => {
31148
+ handleLabelChange(newLabel, labelIndex);
31149
+ },
31150
+ onRemove: () => {
31151
+ handleLabelRemove(labelIndex);
31152
+ },
31153
+ containerStyle: styles$r.labelContainer
31154
+ }))), /*#__PURE__*/React.createElement(Button, {
31155
+ kind: "tertiary",
31156
+ startIcon: plusCircle,
31157
+ onClick: () => {
31158
+ var _labels$length;
31159
+ const newLabel = _extends({}, getDefaultFigureForType("label"), {
31160
+ coord: [center[0],
31161
+ // Additional vertical offset for each
31162
+ // label so they don't overlap.
31163
+ center[1] - ((_labels$length = labels == null ? void 0 : labels.length) != null ? _labels$length : 0)],
31164
+ // Default to the same color as the ellipse
31165
+ color: color
31166
+ });
31167
+ onChangeProps({
31168
+ labels: [...(labels != null ? labels : []), newLabel]
31169
+ });
31170
+ },
31171
+ style: styles$r.addButton
31172
+ }, "Add visible label")), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
31173
+ figureType: props.type,
31174
+ onMove: onMove,
31175
+ onRemove: onRemove
31176
+ }));
31177
+ };
31178
+ const styles$r = StyleSheet.create({
31179
+ row: {
31180
+ display: "flex",
31181
+ flexDirection: "row",
31182
+ alignItems: "center"
31183
+ },
31184
+ spaceUnder: {
31185
+ marginBottom: spacing.xSmall_8
31186
+ },
31187
+ truncatedWidth: {
31188
+ // Allow truncation, stop bleeding over the edge.
31189
+ minWidth: 0
31190
+ },
31191
+ addButton: {
31192
+ alignSelf: "start"
31193
+ },
31194
+ labelContainer: {
31195
+ backgroundColor: color.white
31196
+ },
31197
+ horizontalRule: {
31198
+ height: 1,
31199
+ backgroundColor: color.offBlack16
31200
+ }
31201
+ });
31202
+
31203
+ const LineSwatch = props => {
31204
+ const {
31205
+ color,
31206
+ lineStyle
31207
+ } = props;
30837
31208
  return /*#__PURE__*/React.createElement(View, {
30838
- style: styles$r.container
31209
+ style: styles$q.container
30839
31210
  }, /*#__PURE__*/React.createElement(View, {
30840
31211
  "aria-label": `${color}, ${lineStyle}`,
30841
- style: [styles$r.lineSwatch, {
31212
+ style: [styles$q.lineSwatch, {
30842
31213
  border: `5px ${lineStyle} ${lockedFigureColors[color]}`
30843
31214
  }]
30844
31215
  }));
30845
31216
  };
30846
- const styles$r = StyleSheet.create({
31217
+ const styles$q = StyleSheet.create({
30847
31218
  container: {
30848
31219
  backgroundColor: color.white,
30849
31220
  justifyContent: "center",
@@ -30861,25 +31232,22 @@ const examples = {
30861
31232
  trigonometric: ["sin(x) * 3", "arctan(2x) + 4"]
30862
31233
  };
30863
31234
 
30864
- /**
30865
- * LockedFunctionSettings is a component that allows the user to edit the
30866
- * settings of specifically a locked function on the graph.
30867
- *
30868
- * Used in the interactive graph editor's locked figures section.
30869
- */
30870
31235
  const LockedFunctionSettings = props => {
31236
+ var _flags$mafs, _flags$mafs2;
30871
31237
  const {
31238
+ flags,
30872
31239
  color: lineColor,
30873
31240
  strokeStyle,
30874
31241
  equation,
30875
31242
  directionalAxis,
30876
31243
  domain,
31244
+ labels,
31245
+ ariaLabel,
30877
31246
  onChangeProps,
30878
31247
  onMove,
30879
31248
  onRemove
30880
31249
  } = props;
30881
31250
  const equationPrefix = directionalAxis === "x" ? "y=" : "x=";
30882
- const domainRangeText = directionalAxis === "x" ? "domain" : "range";
30883
31251
  const lineLabel = `Function (${equationPrefix}${equation})`;
30884
31252
 
30885
31253
  // Tracking the string value of domain/range constraints to handle interim state of
@@ -30891,6 +31259,27 @@ const LockedFunctionSettings = props => {
30891
31259
  // "useEffect" used to maintain parity between domain/range constraints and their string representation.
30892
31260
  setDomainEntries([domain && domain[0] !== -Infinity ? domain[0].toString() : "", domain && domain[1] !== Infinity ? domain[1].toString() : ""]);
30893
31261
  }, [domain]);
31262
+ function getPrepopulatedAriaLabel() {
31263
+ let str = `Function with equation ${equationPrefix}${equation}`;
31264
+
31265
+ // Add the domain/range constraints to the aria label
31266
+ // if they are not the default values.
31267
+ if (domain && !(domain[0] === -Infinity && domain[1] === Infinity)) {
31268
+ str += `, domain from ${domain[0]} to ${domain[1]}`;
31269
+ }
31270
+ if (labels && labels.length > 0) {
31271
+ str += ", with label";
31272
+ // Make it "with labels" instead of "with label" if there are
31273
+ // multiple labels.
31274
+ if (labels.length > 1) {
31275
+ str += "s";
31276
+ }
31277
+
31278
+ // Separate additional labels with commas.
31279
+ str += ` ${labels.map(l => l.text).join(", ")}`;
31280
+ }
31281
+ return str;
31282
+ }
30894
31283
 
30895
31284
  // Generic function for handling property changes (except for 'domain/range')
30896
31285
  function handlePropChange(property, newValue) {
@@ -30924,13 +31313,43 @@ const LockedFunctionSettings = props => {
30924
31313
  const exampleCategories = Object.keys(examples);
30925
31314
  const exampleCategorySelected = exampleCategory !== "";
30926
31315
  const exampleContent = exampleCategorySelected ? examples[exampleCategory] : ["Select category to see example equations"];
31316
+ function handleColorChange(newValue) {
31317
+ const newProps = {
31318
+ color: newValue
31319
+ };
31320
+
31321
+ // Update the color of the all labels to match the point
31322
+ newProps.labels = labels == null ? void 0 : labels.map(label => _extends({}, label, {
31323
+ color: newValue
31324
+ }));
31325
+ onChangeProps(newProps);
31326
+ }
31327
+ function handleLabelChange(updatedLabel, labelIndex) {
31328
+ if (!labels) {
31329
+ return;
31330
+ }
31331
+ const updatedLabels = [...labels];
31332
+ updatedLabels[labelIndex] = _extends({}, labels[labelIndex], updatedLabel);
31333
+ onChangeProps({
31334
+ labels: updatedLabels
31335
+ });
31336
+ }
31337
+ function handleLabelRemove(labelIndex) {
31338
+ if (!labels) {
31339
+ return;
31340
+ }
31341
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31342
+ onChangeProps({
31343
+ labels: updatedLabels
31344
+ });
31345
+ }
30927
31346
  return /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
30928
31347
  expanded: props.expanded,
30929
31348
  onToggle: props.onToggle,
30930
31349
  header: /*#__PURE__*/React.createElement(View, {
30931
- style: styles$q.row
31350
+ style: styles$p.row
30932
31351
  }, /*#__PURE__*/React.createElement(LabelLarge, {
30933
- style: styles$q.accordionHeader
31352
+ style: styles$p.accordionHeader
30934
31353
  }, lineLabel), /*#__PURE__*/React.createElement(Strut, {
30935
31354
  size: spacing.xSmall_8
30936
31355
  }), /*#__PURE__*/React.createElement(LineSwatch, {
@@ -30938,12 +31357,10 @@ const LockedFunctionSettings = props => {
30938
31357
  lineStyle: strokeStyle
30939
31358
  }))
30940
31359
  }, /*#__PURE__*/React.createElement(View, {
30941
- style: [styles$q.row, styles$q.spaceUnder]
31360
+ style: [styles$p.row, styles$p.spaceUnder]
30942
31361
  }, /*#__PURE__*/React.createElement(ColorSelect, {
30943
31362
  selectedValue: lineColor,
30944
- onChange: newValue => {
30945
- handlePropChange("color", newValue);
30946
- }
31363
+ onChange: handleColorChange
30947
31364
  }), /*#__PURE__*/React.createElement(Strut, {
30948
31365
  size: spacing.small_12
30949
31366
  }), /*#__PURE__*/React.createElement(LineStrokeSelect, {
@@ -30952,14 +31369,14 @@ const LockedFunctionSettings = props => {
30952
31369
  handlePropChange("strokeStyle", newValue);
30953
31370
  }
30954
31371
  })), /*#__PURE__*/React.createElement(View, {
30955
- style: [styles$q.row, styles$q.rowSpace]
31372
+ style: [styles$p.row, styles$p.rowSpace]
30956
31373
  }, /*#__PURE__*/React.createElement(SingleSelect, {
30957
31374
  selectedValue: directionalAxis,
30958
31375
  onChange: newValue => {
30959
31376
  handlePropChange("directionalAxis", newValue);
30960
31377
  },
30961
31378
  "aria-label": "equation prefix",
30962
- style: [styles$q.dropdownLabel, styles$q.axisMenu]
31379
+ style: [styles$p.dropdownLabel, styles$p.axisMenu]
30963
31380
  // Placeholder is required, but never gets used.
30964
31381
  ,
30965
31382
  placeholder: ""
@@ -30978,17 +31395,17 @@ const LockedFunctionSettings = props => {
30978
31395
  onChange: newValue => {
30979
31396
  handlePropChange("equation", newValue);
30980
31397
  },
30981
- style: [styles$q.textField]
31398
+ style: [styles$p.textField]
30982
31399
  })), /*#__PURE__*/React.createElement(View, {
30983
- style: [styles$q.row, styles$q.rowSpace]
31400
+ style: [styles$p.row, styles$p.rowSpace]
30984
31401
  }, /*#__PURE__*/React.createElement(LabelMedium, {
30985
31402
  tag: "label",
30986
- style: [styles$q.dropdownLabel, styles$q.domainMin]
30987
- }, `${domainRangeText} min`, /*#__PURE__*/React.createElement(Strut, {
31403
+ style: [styles$p.dropdownLabel, styles$p.domainMin]
31404
+ }, "domain min", /*#__PURE__*/React.createElement(Strut, {
30988
31405
  size: spacing.xxSmall_6
30989
31406
  }), /*#__PURE__*/React.createElement(TextField, {
30990
31407
  type: "number",
30991
- style: styles$q.domainMinField,
31408
+ style: styles$p.domainMinField,
30992
31409
  value: domainEntries[0],
30993
31410
  onChange: newValue => {
30994
31411
  handleDomainChange(0, newValue);
@@ -30997,13 +31414,13 @@ const LockedFunctionSettings = props => {
30997
31414
  size: spacing.medium_16
30998
31415
  }), /*#__PURE__*/React.createElement(LabelMedium, {
30999
31416
  tag: "label",
31000
- "aria-label": `${domainRangeText} max`,
31001
- style: [styles$q.dropdownLabel, styles$q.domainMax]
31417
+ "aria-label": "domain max",
31418
+ style: [styles$p.dropdownLabel, styles$p.domainMax]
31002
31419
  }, "max", /*#__PURE__*/React.createElement(Strut, {
31003
31420
  size: spacing.xxSmall_6
31004
31421
  }), /*#__PURE__*/React.createElement(TextField, {
31005
31422
  type: "number",
31006
- style: styles$q.domainMaxField,
31423
+ style: styles$p.domainMaxField,
31007
31424
  value: domainEntries[1],
31008
31425
  onChange: newValue => {
31009
31426
  handleDomainChange(1, newValue);
@@ -31011,11 +31428,11 @@ const LockedFunctionSettings = props => {
31011
31428
  }))), /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
31012
31429
  header: /*#__PURE__*/React.createElement(LabelLarge, null, "Example Functions"),
31013
31430
  expanded: false,
31014
- containerStyle: styles$q.exampleWorkspace,
31015
- panelStyle: styles$q.exampleAccordionPanel
31431
+ containerStyle: styles$p.exampleWorkspace,
31432
+ panelStyle: styles$p.exampleAccordionPanel
31016
31433
  }, /*#__PURE__*/React.createElement(LabelMedium, {
31017
31434
  tag: "label",
31018
- style: styles$q.dropdownLabel
31435
+ style: styles$p.dropdownLabel
31019
31436
  }, "Choose a category", /*#__PURE__*/React.createElement(Strut, {
31020
31437
  size: spacing.xxSmall_6
31021
31438
  }), /*#__PURE__*/React.createElement(SingleSelect, {
@@ -31029,13 +31446,58 @@ const LockedFunctionSettings = props => {
31029
31446
  label: category
31030
31447
  });
31031
31448
  }))), exampleCategorySelected && /*#__PURE__*/React.createElement("ul", {
31032
- className: css(styles$q.exampleContainer)
31449
+ className: css(styles$p.exampleContainer)
31033
31450
  }, exampleContent.map((example, index) => /*#__PURE__*/React.createElement(ExampleItem, {
31451
+ key: index,
31034
31452
  category: exampleCategory,
31035
31453
  example: example,
31036
31454
  index: index,
31037
31455
  pasteEquationFn: handlePropChange
31038
- })))), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
31456
+ })))), (flags == null || (_flags$mafs = flags["mafs"]) == null ? void 0 : _flags$mafs["locked-figures-aria"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
31457
+ size: spacing.small_12
31458
+ }), /*#__PURE__*/React.createElement(View, {
31459
+ style: styles$p.horizontalRule
31460
+ }), /*#__PURE__*/React.createElement(LockedFigureAria, {
31461
+ ariaLabel: ariaLabel,
31462
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
31463
+ onChangeProps: newProps => {
31464
+ onChangeProps(newProps);
31465
+ }
31466
+ })), (flags == null || (_flags$mafs2 = flags["mafs"]) == null ? void 0 : _flags$mafs2["locked-function-labels"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
31467
+ size: spacing.xxxSmall_4
31468
+ }), /*#__PURE__*/React.createElement(View, {
31469
+ style: styles$p.horizontalRule
31470
+ }), /*#__PURE__*/React.createElement(Strut, {
31471
+ size: spacing.small_12
31472
+ }), /*#__PURE__*/React.createElement(LabelMedium, null, "Visible labels"), labels == null ? void 0 : labels.map((label, labelIndex) => /*#__PURE__*/React.createElement(LockedLabelSettings, _extends({
31473
+ key: labelIndex
31474
+ }, label, {
31475
+ expanded: true,
31476
+ onChangeProps: newLabel => {
31477
+ handleLabelChange(newLabel, labelIndex);
31478
+ },
31479
+ onRemove: () => {
31480
+ handleLabelRemove(labelIndex);
31481
+ },
31482
+ containerStyle: styles$p.labelContainer
31483
+ }))), /*#__PURE__*/React.createElement(Button, {
31484
+ kind: "tertiary",
31485
+ startIcon: plusCircle,
31486
+ onClick: () => {
31487
+ var _labels$length;
31488
+ const newLabel = _extends({}, getDefaultFigureForType("label"), {
31489
+ // Vertical offset for each label so they
31490
+ // don't overlap.
31491
+ coord: [0, -((_labels$length = labels == null ? void 0 : labels.length) != null ? _labels$length : 0)],
31492
+ // Default to the same color as the function
31493
+ color: lineColor
31494
+ });
31495
+ onChangeProps({
31496
+ labels: [...(labels != null ? labels : []), newLabel]
31497
+ });
31498
+ },
31499
+ style: styles$p.addButton
31500
+ }, "Add visible label")), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
31039
31501
  figureType: props.type,
31040
31502
  onMove: onMove,
31041
31503
  onRemove: onRemove
@@ -31051,29 +31513,29 @@ const ExampleItem = props => {
31051
31513
  const exampleId = useId();
31052
31514
  return /*#__PURE__*/React.createElement("li", {
31053
31515
  key: `${category}-${index}`,
31054
- className: css(styles$q.exampleRow)
31516
+ className: css(styles$p.exampleRow)
31055
31517
  }, /*#__PURE__*/React.createElement(IconButton, {
31056
31518
  icon: autoPasteIcon,
31057
31519
  "aria-label": "paste example",
31058
31520
  "aria-describedby": exampleId,
31059
31521
  onClick: () => pasteEquationFn("equation", example),
31060
31522
  size: "medium",
31061
- style: styles$q.copyPasteButton
31523
+ style: styles$p.copyPasteButton
31062
31524
  }), /*#__PURE__*/React.createElement(IconButton, {
31063
31525
  icon: copyIcon,
31064
31526
  "aria-label": "copy example",
31065
31527
  "aria-describedby": exampleId,
31066
31528
  onClick: () => navigator.clipboard.writeText(example),
31067
31529
  size: "medium",
31068
- style: styles$q.copyPasteButton
31530
+ style: styles$p.copyPasteButton
31069
31531
  }), /*#__PURE__*/React.createElement(Strut, {
31070
31532
  size: spacing.xxxSmall_4
31071
31533
  }), /*#__PURE__*/React.createElement(View, {
31072
- style: styles$q.exampleContent,
31534
+ style: styles$p.exampleContent,
31073
31535
  id: exampleId
31074
31536
  }, example));
31075
31537
  };
31076
- const styles$q = StyleSheet.create({
31538
+ const styles$p = StyleSheet.create({
31077
31539
  accordionHeader: {
31078
31540
  textOverflow: "ellipsis",
31079
31541
  // A maximum width needs to be specified in order for the ellipsis to work.
@@ -31148,245 +31610,67 @@ const styles$q = StyleSheet.create({
31148
31610
  exampleRow: {
31149
31611
  alignItems: "center",
31150
31612
  display: "flex",
31151
- flexDirection: "row",
31152
- minHeight: "44px"
31153
- },
31154
- exampleWorkspace: {
31155
- background: color.white50
31156
- },
31157
- rowSpace: {
31158
- marginTop: spacing.xSmall_8
31159
- },
31160
- row: {
31161
- display: "flex",
31162
- flexDirection: "row",
31163
- alignItems: "center"
31164
- },
31165
- textField: {
31166
- flexGrow: "1"
31167
- }
31168
- });
31169
-
31170
- /**
31171
- * LockedLabelSettings is a component that allows the user to edit the
31172
- * settings of specifically a locked label on the graph within the
31173
- * Interactive Graph widget.
31174
- *
31175
- * Used in the interactive graph editor's locked figures section.
31176
- */
31177
- function LockedLabelSettings(props) {
31178
- const {
31179
- type,
31180
- coord,
31181
- color: color$1,
31182
- size,
31183
- text,
31184
- expanded,
31185
- onChangeProps,
31186
- onMove,
31187
- onRemove,
31188
- onToggle,
31189
- containerStyle
31190
- } = props;
31191
- return /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
31192
- expanded: expanded,
31193
- onToggle: onToggle,
31194
- header: /*#__PURE__*/React.createElement(View, {
31195
- style: [styles$p.row, styles$p.accordionHeaderContainer]
31196
- }, /*#__PURE__*/React.createElement(LabelLarge, null, "Label (", coord[0], ", ", coord[1], ")"), /*#__PURE__*/React.createElement(Strut, {
31197
- size: spacing.xSmall_8
31198
- }), text !== "" && /*#__PURE__*/React.createElement(LabelLarge, {
31199
- style: [{
31200
- backgroundColor: color.white,
31201
- color: lockedFigureColors[color$1]
31202
- }, styles$p.accordionHeader]
31203
- }, text)),
31204
- containerStyle: containerStyle
31205
- }, /*#__PURE__*/React.createElement(CoordinatePairInput, {
31206
- coord: coord,
31207
- onChange: newCoords => {
31208
- onChangeProps({
31209
- coord: newCoords
31210
- });
31211
- },
31212
- style: styles$p.spaceUnder
31213
- }), /*#__PURE__*/React.createElement(LabelMedium, {
31214
- tag: "label",
31215
- style: [styles$p.row, styles$p.spaceUnder]
31216
- }, "TeX", /*#__PURE__*/React.createElement(Strut, {
31217
- size: spacing.xSmall_8
31218
- }), /*#__PURE__*/React.createElement(TextField, {
31219
- value: text,
31220
- placeholder: "ex. x^2 or \\frac{1}{2}",
31221
- onChange: newValue => onChangeProps({
31222
- text: newValue
31223
- })
31224
- })), /*#__PURE__*/React.createElement(View, {
31225
- style: styles$p.row
31226
- }, onMove && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ColorSelect, {
31227
- selectedValue: color$1,
31228
- onChange: newColor => {
31229
- onChangeProps({
31230
- color: newColor
31231
- });
31232
- },
31233
- style: styles$p.spaceUnder
31234
- }), /*#__PURE__*/React.createElement(Strut, {
31235
- size: spacing.medium_16
31236
- })), /*#__PURE__*/React.createElement(LabelMedium, {
31237
- tag: "label",
31238
- style: styles$p.row
31239
- }, "size", /*#__PURE__*/React.createElement(Strut, {
31240
- size: spacing.xSmall_8
31241
- }), /*#__PURE__*/React.createElement(SingleSelect, {
31242
- selectedValue: size,
31243
- onChange: newValue => onChangeProps({
31244
- size: newValue
31245
- })
31246
- // Placeholder is required, but never gets used since
31247
- // we have a label for the select.
31248
- ,
31249
- placeholder: ""
31250
- }, /*#__PURE__*/React.createElement(OptionItem, {
31251
- value: "small",
31252
- label: "small"
31253
- }), /*#__PURE__*/React.createElement(OptionItem, {
31254
- value: "medium",
31255
- label: "medium"
31256
- }), /*#__PURE__*/React.createElement(OptionItem, {
31257
- value: "large",
31258
- label: "large"
31259
- })))), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
31260
- figureType: type,
31261
- onMove: onMove,
31262
- onRemove: onRemove
31263
- }));
31264
- }
31265
- const styles$p = StyleSheet.create({
31266
- accordionHeaderContainer: {
31267
- // Stop the label summary from wrapping.
31268
- whiteSpace: "nowrap"
31269
- },
31270
- accordionHeader: {
31271
- padding: spacing.xxxSmall_4,
31272
- marginInlineEnd: spacing.xSmall_8,
31273
- borderRadius: spacing.xxxSmall_4,
31274
- textOverflow: "ellipsis",
31275
- overflow: "hidden"
31276
- },
31277
- row: {
31278
- display: "flex",
31279
- flexDirection: "row",
31280
- alignItems: "center",
31281
- // Allow truncation, stop bleeding over the edge.
31282
- minWidth: 0
31283
- },
31284
- spaceUnder: {
31285
- marginBottom: spacing.xSmall_8
31286
- }
31287
- });
31288
-
31289
- const LabeledSwitch = props => {
31290
- const {
31291
- checked,
31292
- label,
31293
- style,
31294
- onChange
31295
- } = props;
31296
- const ids = useUniqueIdWithMock();
31297
- const switchId = ids.get("switch");
31298
- return /*#__PURE__*/React.createElement(View, {
31299
- style: [styles$o.row, style]
31300
- }, /*#__PURE__*/React.createElement(Switch, {
31301
- id: switchId,
31302
- checked: checked,
31303
- onChange: onChange
31304
- }), /*#__PURE__*/React.createElement(Strut, {
31305
- size: spacing.xSmall_8
31306
- }), /*#__PURE__*/React.createElement(LabelMedium, {
31307
- tag: "label",
31308
- htmlFor: switchId
31309
- }, label));
31310
- };
31311
- const styles$o = StyleSheet.create({
31312
- row: {
31313
- flexDirection: "row",
31314
- alignItems: "center"
31315
- }
31316
- });
31317
-
31318
- const DEFAULT_COLOR = "grayH";
31319
- function getDefaultFigureForType(type) {
31320
- switch (type) {
31321
- case "point":
31322
- return {
31323
- type: "point",
31324
- coord: [0, 0],
31325
- color: DEFAULT_COLOR,
31326
- filled: true,
31327
- labels: []
31328
- };
31329
- case "line":
31330
- return {
31331
- type: "line",
31332
- kind: "line",
31333
- points: [getDefaultFigureForType("point"), _extends({}, getDefaultFigureForType("point"), {
31334
- coord: [2, 2]
31335
- })],
31336
- color: DEFAULT_COLOR,
31337
- lineStyle: "solid",
31338
- showPoint1: false,
31339
- showPoint2: false,
31340
- labels: []
31341
- };
31342
- case "vector":
31343
- return {
31344
- type: "vector",
31345
- points: [[0, 0], [2, 2]],
31346
- color: DEFAULT_COLOR
31347
- };
31348
- case "ellipse":
31349
- return {
31350
- type: "ellipse",
31351
- center: [0, 0],
31352
- radius: [1, 1],
31353
- angle: 0,
31354
- color: DEFAULT_COLOR,
31355
- fillStyle: "none",
31356
- strokeStyle: "solid"
31357
- };
31358
- case "polygon":
31359
- return {
31360
- type: "polygon",
31361
- points: [[0, 2], [-1, 0], [1, 0]],
31362
- color: DEFAULT_COLOR,
31363
- showVertices: false,
31364
- fillStyle: "none",
31365
- strokeStyle: "solid"
31366
- };
31367
- case "function":
31368
- return {
31369
- type: "function",
31370
- color: DEFAULT_COLOR,
31371
- strokeStyle: "solid",
31372
- equation: "x^2",
31373
- directionalAxis: "x"
31374
- };
31375
- case "label":
31376
- return {
31377
- type: "label",
31378
- coord: [0, 0],
31379
- text: "",
31380
- color: DEFAULT_COLOR,
31381
- size: "medium"
31382
- };
31383
- default:
31384
- throw new UnreachableCaseError(type);
31613
+ flexDirection: "row",
31614
+ minHeight: "44px"
31615
+ },
31616
+ exampleWorkspace: {
31617
+ background: color.white50
31618
+ },
31619
+ rowSpace: {
31620
+ marginTop: spacing.xSmall_8
31621
+ },
31622
+ row: {
31623
+ display: "flex",
31624
+ flexDirection: "row",
31625
+ alignItems: "center"
31626
+ },
31627
+ textField: {
31628
+ flexGrow: "1"
31629
+ },
31630
+ // Label settings styles
31631
+ addButton: {
31632
+ alignSelf: "start"
31633
+ },
31634
+ horizontalRule: {
31635
+ height: 1,
31636
+ backgroundColor: color.offBlack16
31637
+ },
31638
+ labelContainer: {
31639
+ backgroundColor: color.white
31385
31640
  }
31386
- }
31641
+ });
31642
+
31643
+ const LabeledSwitch = props => {
31644
+ const {
31645
+ checked,
31646
+ label,
31647
+ style,
31648
+ onChange
31649
+ } = props;
31650
+ const ids = useUniqueIdWithMock();
31651
+ const switchId = ids.get("switch");
31652
+ return /*#__PURE__*/React.createElement(View, {
31653
+ style: [styles$o.row, style]
31654
+ }, /*#__PURE__*/React.createElement(Switch, {
31655
+ id: switchId,
31656
+ checked: checked,
31657
+ onChange: onChange
31658
+ }), /*#__PURE__*/React.createElement(Strut, {
31659
+ size: spacing.xSmall_8
31660
+ }), /*#__PURE__*/React.createElement(LabelMedium, {
31661
+ tag: "label",
31662
+ htmlFor: switchId
31663
+ }, label));
31664
+ };
31665
+ const styles$o = StyleSheet.create({
31666
+ row: {
31667
+ flexDirection: "row",
31668
+ alignItems: "center"
31669
+ }
31670
+ });
31387
31671
 
31388
31672
  const LockedPointSettings = props => {
31389
- var _flags$mafs, _flags$mafs2;
31673
+ var _flags$mafs, _flags$mafs2, _flags$mafs3;
31390
31674
  const {
31391
31675
  flags,
31392
31676
  headerLabel,
@@ -31394,6 +31678,7 @@ const LockedPointSettings = props => {
31394
31678
  color: pointColor,
31395
31679
  filled = true,
31396
31680
  labels,
31681
+ ariaLabel,
31397
31682
  onChangeProps,
31398
31683
  onMove,
31399
31684
  onRemove,
@@ -31404,15 +31689,42 @@ const LockedPointSettings = props => {
31404
31689
  onToggle
31405
31690
  } = props;
31406
31691
  const isDefiningPoint = !onMove && !onRemove;
31692
+
31693
+ /**
31694
+ * Get a prepopulated aria label for the point.
31695
+ *
31696
+ * If the point has no labels, the aria label will just be
31697
+ * "Point at (x, y)".
31698
+ *
31699
+ * If the point has labels, the aria label will be
31700
+ * "Point at (x, y) with label1, label2, label3".
31701
+ */
31702
+ function getPrepopulatedAriaLabel() {
31703
+ let str = `Point at (${coord[0]}, ${coord[1]})`;
31704
+ if (labels && labels.length > 0) {
31705
+ str += " with label";
31706
+ // Make it "with labels" instead of "with label" if there are
31707
+ // multiple labels.
31708
+ if (labels.length > 1) {
31709
+ str += "s";
31710
+ }
31711
+
31712
+ // Separate additional labels with commas.
31713
+ str += ` ${labels.map(l => l.text).join(", ")}`;
31714
+ }
31715
+ return str;
31716
+ }
31407
31717
  function handleColorChange(newValue) {
31408
31718
  const newProps = {
31409
31719
  color: newValue
31410
31720
  };
31411
31721
 
31412
31722
  // Update the color of the all labels to match the point
31413
- newProps.labels = labels.map(label => _extends({}, label, {
31414
- color: newValue
31415
- }));
31723
+ if (labels) {
31724
+ newProps.labels = labels.map(label => _extends({}, label, {
31725
+ color: newValue
31726
+ }));
31727
+ }
31416
31728
  onChangeProps(newProps);
31417
31729
  }
31418
31730
  function handleCoordChange(newCoord) {
@@ -31423,12 +31735,17 @@ const LockedPointSettings = props => {
31423
31735
  };
31424
31736
 
31425
31737
  // Update the coord by the same amount as the point for all labels
31426
- newProps.labels = labels.map(label => _extends({}, label, {
31427
- coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31428
- }));
31738
+ if (labels) {
31739
+ newProps.labels = labels.map(label => _extends({}, label, {
31740
+ coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31741
+ }));
31742
+ }
31429
31743
  onChangeProps(newProps);
31430
31744
  }
31431
31745
  function handleLabelChange(updatedLabel, labelIndex) {
31746
+ if (!labels) {
31747
+ return;
31748
+ }
31432
31749
  const updatedLabels = [...labels];
31433
31750
  updatedLabels[labelIndex] = _extends({}, labels[labelIndex], updatedLabel);
31434
31751
  onChangeProps({
@@ -31436,6 +31753,9 @@ const LockedPointSettings = props => {
31436
31753
  });
31437
31754
  }
31438
31755
  function handleLabelRemove(labelIndex) {
31756
+ if (!labels) {
31757
+ return;
31758
+ }
31439
31759
  const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31440
31760
  onChangeProps({
31441
31761
  labels: updatedLabels
@@ -31478,7 +31798,23 @@ const LockedPointSettings = props => {
31478
31798
  filled: !newValue
31479
31799
  });
31480
31800
  }
31481
- })), (!isDefiningPoint && (flags == null || (_flags$mafs = flags["mafs"]) == null ? void 0 : _flags$mafs["locked-point-labels"]) || isDefiningPoint && (flags == null || (_flags$mafs2 = flags["mafs"]) == null ? void 0 : _flags$mafs2["locked-line-labels"])) && /*#__PURE__*/React.createElement(React.Fragment, null, labels.map((label, labelIndex) => /*#__PURE__*/React.createElement(LockedLabelSettings, _extends({}, label, {
31801
+ })), !isDefiningPoint && (flags == null || (_flags$mafs = flags["mafs"]) == null ? void 0 : _flags$mafs["locked-figures-aria"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
31802
+ size: spacing.small_12
31803
+ }), /*#__PURE__*/React.createElement(View, {
31804
+ style: styles$n.horizontalRule
31805
+ }), /*#__PURE__*/React.createElement(LockedFigureAria, {
31806
+ ariaLabel: ariaLabel,
31807
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
31808
+ onChangeProps: newProps => {
31809
+ onChangeProps(newProps);
31810
+ }
31811
+ })), (!isDefiningPoint && (flags == null || (_flags$mafs2 = flags["mafs"]) == null ? void 0 : _flags$mafs2["locked-point-labels"]) || isDefiningPoint && (flags == null || (_flags$mafs3 = flags["mafs"]) == null ? void 0 : _flags$mafs3["locked-line-labels"])) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
31812
+ size: spacing.xxxSmall_4
31813
+ }), /*#__PURE__*/React.createElement(View, {
31814
+ style: styles$n.horizontalRule
31815
+ }), /*#__PURE__*/React.createElement(Strut, {
31816
+ size: spacing.small_12
31817
+ }), /*#__PURE__*/React.createElement(LabelMedium, null, "Visible labels"), labels == null ? void 0 : labels.map((label, labelIndex) => /*#__PURE__*/React.createElement(LockedLabelSettings, _extends({}, label, {
31482
31818
  containerStyle: !isDefiningPoint && styles$n.lockedPointLabelContainer,
31483
31819
  expanded: true,
31484
31820
  onChangeProps: newLabel => {
@@ -31491,6 +31827,7 @@ const LockedPointSettings = props => {
31491
31827
  kind: "tertiary",
31492
31828
  startIcon: plusCircle,
31493
31829
  onClick: () => {
31830
+ var _labels$length;
31494
31831
  const newLabel = _extends({}, getDefaultFigureForType("label"), {
31495
31832
  // Place the label at the same position
31496
31833
  // as the point. Add a small offset to
@@ -31498,12 +31835,12 @@ const LockedPointSettings = props => {
31498
31835
  coord: [coord[0] + 0.5,
31499
31836
  // Additional offset for each label so
31500
31837
  // they don't overlap.
31501
- coord[1] - 1 * (labels == null ? void 0 : labels.length)],
31838
+ coord[1] - 1 * ((_labels$length = labels == null ? void 0 : labels.length) != null ? _labels$length : 0)],
31502
31839
  // Default to the same color as the point
31503
31840
  color: pointColor
31504
31841
  });
31505
31842
  onChangeProps({
31506
- labels: [...labels, newLabel]
31843
+ labels: [...(labels != null ? labels : []), newLabel]
31507
31844
  });
31508
31845
  },
31509
31846
  style: styles$n.addButton
@@ -31539,12 +31876,16 @@ const styles$n = StyleSheet.create({
31539
31876
  },
31540
31877
  addButton: {
31541
31878
  alignSelf: "start"
31879
+ },
31880
+ horizontalRule: {
31881
+ height: 1,
31882
+ backgroundColor: color.offBlack16
31542
31883
  }
31543
31884
  });
31544
31885
 
31545
31886
  const lengthZeroStr = "The line cannot have length 0.";
31546
31887
  const LockedLineSettings = props => {
31547
- var _flags$mafs;
31888
+ var _flags$mafs, _flags$mafs2;
31548
31889
  const {
31549
31890
  flags,
31550
31891
  kind,
@@ -31554,6 +31895,7 @@ const LockedLineSettings = props => {
31554
31895
  showPoint1,
31555
31896
  showPoint2,
31556
31897
  labels,
31898
+ ariaLabel,
31557
31899
  onChangeProps,
31558
31900
  onMove,
31559
31901
  onRemove
@@ -31565,6 +31907,21 @@ const LockedLineSettings = props => {
31565
31907
 
31566
31908
  // Check if the line has length 0.
31567
31909
  const isInvalid = vector.equal(point1.coord, point2.coord);
31910
+ function getPrepopulatedAriaLabel() {
31911
+ let str = `${capitalizeKind} from (${point1.coord[0]}, ${point1.coord[1]}) to (${point2.coord[0]}, ${point2.coord[1]})`;
31912
+ if (labels && labels.length > 0) {
31913
+ str += " with label";
31914
+ // Make it "with labels" instead of "with label" if there are
31915
+ // multiple labels.
31916
+ if (labels.length > 1) {
31917
+ str += "s";
31918
+ }
31919
+
31920
+ // Separate additional labels with commas.
31921
+ str += ` ${labels.map(l => l.text).join(", ")}`;
31922
+ }
31923
+ return str;
31924
+ }
31568
31925
  function handleChangePoint(newPointProps, index) {
31569
31926
  const newPoints = [...points];
31570
31927
  newPoints[index] = _extends({}, points[index], newPointProps);
@@ -31574,7 +31931,7 @@ const LockedLineSettings = props => {
31574
31931
  const oldMidpoint = vec.midpoint(points[0].coord, points[1].coord);
31575
31932
  const newMidpoint = vec.midpoint(newPoints[0].coord, newPoints[1].coord);
31576
31933
  const offset = [newMidpoint[0] - oldMidpoint[0], newMidpoint[1] - oldMidpoint[1]];
31577
- const newLabels = labels.map((label, labelIndex) => _extends({}, label, {
31934
+ const newLabels = labels == null ? void 0 : labels.map((label, labelIndex) => _extends({}, label, {
31578
31935
  coord: [label.coord[0] + offset[0], label.coord[1] + offset[1]]
31579
31936
  }));
31580
31937
  onChangeProps({
@@ -31583,7 +31940,8 @@ const LockedLineSettings = props => {
31583
31940
  });
31584
31941
  }
31585
31942
  function handleColorChange(newColor) {
31586
- const newLabels = labels.map(label => _extends({}, label, {
31943
+ var _point1$labels, _point2$labels;
31944
+ const newLabels = labels == null ? void 0 : labels.map(label => _extends({}, label, {
31587
31945
  color: newColor
31588
31946
  }));
31589
31947
  onChangeProps({
@@ -31591,12 +31949,12 @@ const LockedLineSettings = props => {
31591
31949
  // Keep the line's points' colors in sync with the line color.
31592
31950
  points: [_extends({}, point1, {
31593
31951
  color: newColor,
31594
- labels: point1.labels.map(label => _extends({}, label, {
31952
+ labels: (_point1$labels = point1.labels) == null ? void 0 : _point1$labels.map(label => _extends({}, label, {
31595
31953
  color: newColor
31596
31954
  }))
31597
31955
  }), _extends({}, point2, {
31598
31956
  color: newColor,
31599
- labels: point2.labels.map(label => _extends({}, label, {
31957
+ labels: (_point2$labels = point2.labels) == null ? void 0 : _point2$labels.map(label => _extends({}, label, {
31600
31958
  color: newColor
31601
31959
  }))
31602
31960
  })],
@@ -31605,6 +31963,9 @@ const LockedLineSettings = props => {
31605
31963
  });
31606
31964
  }
31607
31965
  function handleLabelChange(updatedLabel, labelIndex) {
31966
+ if (!labels) {
31967
+ return;
31968
+ }
31608
31969
  const updatedLabels = [...labels];
31609
31970
  updatedLabels[labelIndex] = _extends({}, labels[labelIndex], updatedLabel);
31610
31971
  onChangeProps({
@@ -31612,6 +31973,9 @@ const LockedLineSettings = props => {
31612
31973
  });
31613
31974
  }
31614
31975
  function handleLabelRemove(labelIndex) {
31976
+ if (!labels) {
31977
+ return;
31978
+ }
31615
31979
  const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31616
31980
  onChangeProps({
31617
31981
  labels: updatedLabels
@@ -31686,9 +32050,23 @@ const LockedLineSettings = props => {
31686
32050
  showPoint2: newValue
31687
32051
  }),
31688
32052
  onChangeProps: newProps => handleChangePoint(newProps, 1)
31689
- })), (flags == null || (_flags$mafs = flags["mafs"]) == null ? void 0 : _flags$mafs["locked-line-labels"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, {
32053
+ })), (flags == null || (_flags$mafs = flags["mafs"]) == null ? void 0 : _flags$mafs["locked-figures-aria"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
32054
+ size: spacing.small_12
32055
+ }), /*#__PURE__*/React.createElement(View, {
32056
+ style: styles$m.horizontalRule
32057
+ }), /*#__PURE__*/React.createElement(LockedFigureAria, {
32058
+ ariaLabel: ariaLabel,
32059
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
32060
+ onChangeProps: newProps => {
32061
+ onChangeProps(newProps);
32062
+ }
32063
+ })), (flags == null || (_flags$mafs2 = flags["mafs"]) == null ? void 0 : _flags$mafs2["locked-line-labels"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
32064
+ size: spacing.xxxSmall_4
32065
+ }), /*#__PURE__*/React.createElement(View, {
31690
32066
  style: styles$m.horizontalRule
31691
- }), labels.map((label, labelIndex) => /*#__PURE__*/React.createElement(LockedLabelSettings, _extends({}, label, {
32067
+ }), /*#__PURE__*/React.createElement(Strut, {
32068
+ size: spacing.small_12
32069
+ }), /*#__PURE__*/React.createElement(LabelMedium, null, "Visible labels"), labels == null ? void 0 : labels.map((label, labelIndex) => /*#__PURE__*/React.createElement(LockedLabelSettings, _extends({}, label, {
31692
32070
  expanded: true,
31693
32071
  onChangeProps: newLabel => {
31694
32072
  handleLabelChange(newLabel, labelIndex);
@@ -31701,17 +32079,18 @@ const LockedLineSettings = props => {
31701
32079
  kind: "tertiary",
31702
32080
  startIcon: plusCircle,
31703
32081
  onClick: () => {
32082
+ var _labels$length;
31704
32083
  // Additional vertical offset for each label so
31705
32084
  // they don't overlap.
31706
32085
  const offsetPerLabel = [0, -1];
31707
- const labelLocation = vec.add(vec.scale(offsetPerLabel, labels.length), vec.midpoint(points[0].coord, points[1].coord));
32086
+ const labelLocation = vec.add(vec.scale(offsetPerLabel, (_labels$length = labels == null ? void 0 : labels.length) != null ? _labels$length : 0), vec.midpoint(points[0].coord, points[1].coord));
31708
32087
  const newLabel = _extends({}, getDefaultFigureForType("label"), {
31709
32088
  coord: labelLocation,
31710
- // Default to the same color as the point
32089
+ // Default to the same color as the line
31711
32090
  color: lineColor
31712
32091
  });
31713
32092
  onChangeProps({
31714
- labels: [...labels, newLabel]
32093
+ labels: [...(labels != null ? labels : []), newLabel]
31715
32094
  });
31716
32095
  },
31717
32096
  style: styles$m.addButton
@@ -31737,8 +32116,6 @@ const styles$m = StyleSheet.create({
31737
32116
  alignSelf: "start"
31738
32117
  },
31739
32118
  horizontalRule: {
31740
- marginTop: spacing.small_12,
31741
- marginBottom: spacing.xxxSmall_4,
31742
32119
  height: 1,
31743
32120
  backgroundColor: color.offBlack16
31744
32121
  },
@@ -31783,47 +32160,106 @@ const styles$l = StyleSheet.create({
31783
32160
  });
31784
32161
 
31785
32162
  const LockedPolygonSettings = props => {
32163
+ var _flags$mafs, _flags$mafs2;
31786
32164
  const {
32165
+ flags,
31787
32166
  points,
31788
32167
  color,
31789
32168
  showVertices,
31790
32169
  fillStyle,
31791
32170
  strokeStyle,
32171
+ labels,
32172
+ ariaLabel,
31792
32173
  expanded,
31793
32174
  onToggle,
31794
32175
  onChangeProps,
31795
32176
  onMove,
31796
32177
  onRemove
31797
32178
  } = props;
32179
+ function getPrepopulatedAriaLabel() {
32180
+ let str = `Polygon with ${points.length} sides, vertices at `;
32181
+
32182
+ // Add the coordinates of each point to the aria label
32183
+ str += points.map(([x, y]) => `(${x}, ${y})`).join(", ");
32184
+ if (labels && labels.length > 0) {
32185
+ str += ", with label";
32186
+ // Make it "with labels" instead of "with label" if there are
32187
+ // multiple labels.
32188
+ if (labels.length > 1) {
32189
+ str += "s";
32190
+ }
32191
+
32192
+ // Separate additional labels with commas.
32193
+ str += ` ${labels.map(l => l.text).join(", ")}`;
32194
+ }
32195
+ return str;
32196
+ }
31798
32197
  function handleColorChange(newValue) {
31799
- onChangeProps({
32198
+ const newProps = {
31800
32199
  color: newValue
31801
- });
32200
+ };
32201
+
32202
+ // Update the color of the all labels to match the point
32203
+ newProps.labels = labels == null ? void 0 : labels.map(label => _extends({}, label, {
32204
+ color: newValue
32205
+ }));
32206
+ onChangeProps(newProps);
31802
32207
  }
31803
32208
  function handlePolygonMove(movement) {
31804
32209
  switch (movement) {
31805
32210
  case "up":
31806
32211
  onChangeProps({
31807
- points: points.map(([x, y]) => [x, y + 1])
32212
+ points: points.map(([x, y]) => [x, y + 1]),
32213
+ labels: labels == null ? void 0 : labels.map(label => _extends({}, label, {
32214
+ coord: [label.coord[0], label.coord[1] + 1]
32215
+ }))
31808
32216
  });
31809
32217
  break;
31810
32218
  case "down":
31811
32219
  onChangeProps({
31812
- points: points.map(([x, y]) => [x, y - 1])
32220
+ points: points.map(([x, y]) => [x, y - 1]),
32221
+ labels: labels == null ? void 0 : labels.map(label => _extends({}, label, {
32222
+ coord: [label.coord[0], label.coord[1] - 1]
32223
+ }))
31813
32224
  });
31814
32225
  break;
31815
32226
  case "left":
31816
32227
  onChangeProps({
31817
- points: points.map(([x, y]) => [x - 1, y])
32228
+ points: points.map(([x, y]) => [x - 1, y]),
32229
+ labels: labels == null ? void 0 : labels.map(label => _extends({}, label, {
32230
+ coord: [label.coord[0] - 1, label.coord[1]]
32231
+ }))
31818
32232
  });
31819
32233
  break;
31820
32234
  case "right":
31821
32235
  onChangeProps({
31822
- points: points.map(([x, y]) => [x + 1, y])
32236
+ points: points.map(([x, y]) => [x + 1, y]),
32237
+ labels: labels == null ? void 0 : labels.map(label => _extends({}, label, {
32238
+ coord: [label.coord[0] + 1, label.coord[1]]
32239
+ }))
31823
32240
  });
31824
32241
  break;
31825
32242
  }
31826
32243
  }
32244
+ function handleLabelChange(updatedLabel, labelIndex) {
32245
+ if (!labels) {
32246
+ return;
32247
+ }
32248
+ const updatedLabels = [...labels];
32249
+ updatedLabels[labelIndex] = _extends({}, labels[labelIndex], updatedLabel);
32250
+ onChangeProps({
32251
+ labels: updatedLabels
32252
+ });
32253
+ }
32254
+ function handleLabelRemove(labelIndex) {
32255
+ if (!labels) {
32256
+ return;
32257
+ }
32258
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
32259
+ onChangeProps({
32260
+ labels: updatedLabels
32261
+ });
32262
+ }
31827
32263
  return /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
31828
32264
  expanded: expanded,
31829
32265
  onToggle: onToggle,
@@ -31952,7 +32388,50 @@ const LockedPolygonSettings = props => {
31952
32388
  size: "small",
31953
32389
  icon: arrowFatRight,
31954
32390
  onClick: () => handlePolygonMove("right")
31955
- }))))), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
32391
+ }))))), (flags == null || (_flags$mafs = flags["mafs"]) == null ? void 0 : _flags$mafs["locked-figures-aria"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
32392
+ size: spacing.small_12
32393
+ }), /*#__PURE__*/React.createElement(View, {
32394
+ style: styles$k.horizontalRule
32395
+ }), /*#__PURE__*/React.createElement(LockedFigureAria, {
32396
+ ariaLabel: ariaLabel,
32397
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
32398
+ onChangeProps: newProps => {
32399
+ onChangeProps(newProps);
32400
+ }
32401
+ })), (flags == null || (_flags$mafs2 = flags["mafs"]) == null ? void 0 : _flags$mafs2["locked-polygon-labels"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
32402
+ size: spacing.xxxSmall_4
32403
+ }), /*#__PURE__*/React.createElement(View, {
32404
+ style: styles$k.horizontalRule
32405
+ }), /*#__PURE__*/React.createElement(Strut, {
32406
+ size: spacing.small_12
32407
+ }), /*#__PURE__*/React.createElement(LabelMedium, null, "Visible labels"), labels == null ? void 0 : labels.map((label, labelIndex) => /*#__PURE__*/React.createElement(LockedLabelSettings, _extends({}, label, {
32408
+ expanded: true,
32409
+ onChangeProps: newLabel => {
32410
+ handleLabelChange(newLabel, labelIndex);
32411
+ },
32412
+ onRemove: () => {
32413
+ handleLabelRemove(labelIndex);
32414
+ },
32415
+ containerStyle: styles$k.labelContainer
32416
+ }))), /*#__PURE__*/React.createElement(Button, {
32417
+ kind: "tertiary",
32418
+ startIcon: plusCircle,
32419
+ onClick: () => {
32420
+ var _labels$length;
32421
+ const newLabel = _extends({}, getDefaultFigureForType("label"), {
32422
+ coord: [points[0][0],
32423
+ // Additional vertical offset for each
32424
+ // label so they don't overlap.
32425
+ points[0][1] - ((_labels$length = labels == null ? void 0 : labels.length) != null ? _labels$length : 0)],
32426
+ // Default to the same color as the ellipse
32427
+ color: color
32428
+ });
32429
+ onChangeProps({
32430
+ labels: [...(labels != null ? labels : []), newLabel]
32431
+ });
32432
+ },
32433
+ style: styles$k.addButton
32434
+ }, "Add visible label")), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
31956
32435
  figureType: props.type,
31957
32436
  onMove: onMove,
31958
32437
  onRemove: onRemove
@@ -31991,20 +32470,29 @@ const styles$k = StyleSheet.create({
31991
32470
  truncatedWidth: {
31992
32471
  // Allow truncation, stop bleeding over the edge.
31993
32472
  minWidth: 0
32473
+ },
32474
+ // Styles for the visible labels section
32475
+ addButton: {
32476
+ alignSelf: "start"
32477
+ },
32478
+ labelContainer: {
32479
+ backgroundColor: color.white
32480
+ },
32481
+ horizontalRule: {
32482
+ height: 1,
32483
+ backgroundColor: color.offBlack16
31994
32484
  }
31995
32485
  });
31996
32486
 
31997
- /**
31998
- * LockedVectorSettings is a component that allows the user to edit the
31999
- * settings of specifically a locked vector on the graph.
32000
- *
32001
- * Used in the interactive graph editor's locked figures section.
32002
- */
32003
32487
  const lengthErrorMessage = "The vector cannot have length 0.";
32004
32488
  const LockedVectorSettings = props => {
32489
+ var _flags$mafs, _flags$mafs2;
32005
32490
  const {
32491
+ flags,
32006
32492
  points,
32007
32493
  color: lineColor,
32494
+ labels,
32495
+ ariaLabel,
32008
32496
  onChangeProps,
32009
32497
  onMove,
32010
32498
  onRemove
@@ -32014,18 +32502,67 @@ const LockedVectorSettings = props => {
32014
32502
 
32015
32503
  // Check if the line has length 0.
32016
32504
  const isInvalid = vector.equal(tail, tip);
32505
+ function getPrepopulatedAriaLabel() {
32506
+ let str = `Vector from (${tail[0]}, ${tail[1]}) to (${tip[0]}, ${tip[1]})`;
32507
+ if (labels && labels.length > 0) {
32508
+ str += " with label";
32509
+ // Make it "with labels" instead of "with label" if there are
32510
+ // multiple labels.
32511
+ if (labels.length > 1) {
32512
+ str += "s";
32513
+ }
32514
+
32515
+ // Separate additional labels with commas.
32516
+ str += ` ${labels.map(l => l.text).join(", ")}`;
32517
+ }
32518
+ return str;
32519
+ }
32017
32520
  function handleChangePoint(newCoord, index) {
32018
32521
  if (typeof newCoord !== "undefined") {
32019
32522
  const newPoints = [...points];
32020
32523
  newPoints[index] = [...newCoord];
32524
+
32525
+ // Update labels to match the new points
32526
+ const oldMidpoint = vec.midpoint(tail, tip);
32527
+ const newMidpoint = vec.midpoint(newPoints[0], newPoints[1]);
32528
+ const offset = vec.sub(newMidpoint, oldMidpoint);
32529
+ const newLabels = labels == null ? void 0 : labels.map(label => _extends({}, label, {
32530
+ coord: vec.add(label.coord, offset)
32531
+ }));
32021
32532
  onChangeProps({
32022
- points: newPoints
32533
+ points: newPoints,
32534
+ labels: newLabels
32023
32535
  });
32024
32536
  }
32025
32537
  }
32026
32538
  function handleColorChange(newColor) {
32027
- onChangeProps({
32539
+ const newProps = {
32540
+ color: newColor
32541
+ };
32542
+
32543
+ // Update the color of the all labels to match the point
32544
+ newProps.labels = labels == null ? void 0 : labels.map(label => _extends({}, label, {
32028
32545
  color: newColor
32546
+ }));
32547
+ onChangeProps(newProps);
32548
+ }
32549
+ function handleLabelChange(updatedLabel, labelIndex) {
32550
+ if (!labels) {
32551
+ return;
32552
+ }
32553
+ const updatedLabels = [...labels];
32554
+ updatedLabels[labelIndex] = _extends({}, labels[labelIndex], updatedLabel);
32555
+ onChangeProps({
32556
+ labels: updatedLabels
32557
+ });
32558
+ }
32559
+ function handleLabelRemove(labelIndex) {
32560
+ if (!labels) {
32561
+ return;
32562
+ }
32563
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
32564
+ onChangeProps({
32565
+ labels: updatedLabels
32029
32566
  });
32030
32567
  }
32031
32568
  return /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
@@ -32074,7 +32611,51 @@ const LockedVectorSettings = props => {
32074
32611
  onChange: newProps => {
32075
32612
  handleChangePoint(newProps, 1);
32076
32613
  }
32077
- })), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
32614
+ })), (flags == null || (_flags$mafs = flags["mafs"]) == null ? void 0 : _flags$mafs["locked-figures-aria"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
32615
+ size: spacing.small_12
32616
+ }), /*#__PURE__*/React.createElement(View, {
32617
+ style: styles$j.horizontalRule
32618
+ }), /*#__PURE__*/React.createElement(LockedFigureAria, {
32619
+ ariaLabel: ariaLabel,
32620
+ prePopulatedAriaLabel: getPrepopulatedAriaLabel(),
32621
+ onChangeProps: newProps => {
32622
+ onChangeProps(newProps);
32623
+ }
32624
+ })), (flags == null || (_flags$mafs2 = flags["mafs"]) == null ? void 0 : _flags$mafs2["locked-vector-labels"]) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
32625
+ size: spacing.xxxSmall_4
32626
+ }), /*#__PURE__*/React.createElement(View, {
32627
+ style: styles$j.horizontalRule
32628
+ }), /*#__PURE__*/React.createElement(Strut, {
32629
+ size: spacing.small_12
32630
+ }), /*#__PURE__*/React.createElement(LabelMedium, null, "Visible labels"), labels == null ? void 0 : labels.map((label, labelIndex) => /*#__PURE__*/React.createElement(LockedLabelSettings, _extends({}, label, {
32631
+ expanded: true,
32632
+ onChangeProps: newLabel => {
32633
+ handleLabelChange(newLabel, labelIndex);
32634
+ },
32635
+ onRemove: () => {
32636
+ handleLabelRemove(labelIndex);
32637
+ },
32638
+ containerStyle: styles$j.labelContainer
32639
+ }))), /*#__PURE__*/React.createElement(Button, {
32640
+ kind: "tertiary",
32641
+ startIcon: plusCircle,
32642
+ onClick: () => {
32643
+ var _labels$length;
32644
+ // Additional vertical offset for each label so
32645
+ // they don't overlap.
32646
+ const offsetPerLabel = [0, -1];
32647
+ const labelLocation = vec.add(vec.scale(offsetPerLabel, (_labels$length = labels == null ? void 0 : labels.length) != null ? _labels$length : 0), vec.midpoint(tail, tip));
32648
+ const newLabel = _extends({}, getDefaultFigureForType("label"), {
32649
+ coord: labelLocation,
32650
+ // Default to the same color as the vector
32651
+ color: lineColor
32652
+ });
32653
+ onChangeProps({
32654
+ labels: [...(labels != null ? labels : []), newLabel]
32655
+ });
32656
+ },
32657
+ style: styles$j.addButton
32658
+ }, "Add visible label")), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
32078
32659
  figureType: props.type,
32079
32660
  onMove: onMove,
32080
32661
  onRemove: onRemove
@@ -32098,6 +32679,16 @@ const styles$j = StyleSheet.create({
32098
32679
  row: {
32099
32680
  flexDirection: "row",
32100
32681
  alignItems: "center"
32682
+ },
32683
+ addButton: {
32684
+ alignSelf: "start"
32685
+ },
32686
+ horizontalRule: {
32687
+ height: 1,
32688
+ backgroundColor: color.offBlack16
32689
+ },
32690
+ labelContainer: {
32691
+ backgroundColor: color.white
32101
32692
  }
32102
32693
  });
32103
32694