@khanacademy/perseus-editor 14.1.3 → 14.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/components/util.d.ts +0 -14
  2. package/dist/es/index.js +1542 -1450
  3. package/dist/es/index.js.map +1 -1
  4. package/dist/index.js +1375 -1274
  5. package/dist/index.js.map +1 -1
  6. package/dist/{components → widgets/interactive-graph-editor/components}/graph-points-count-selector.d.ts +1 -1
  7. package/dist/{components → widgets/interactive-graph-editor/components}/graph-type-selector.d.ts +1 -0
  8. package/dist/{components → widgets/interactive-graph-editor/components}/interactive-graph-description.d.ts +1 -1
  9. package/dist/widgets/interactive-graph-editor/interactive-graph-editor.d.ts +281 -128
  10. package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-figure-settings-actions.d.ts +1 -1
  11. package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-figure-settings.d.ts +2 -0
  12. package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-figures-section.d.ts +3 -2
  13. package/dist/widgets/interactive-graph-editor/locked-figures/locked-label-settings.d.ts +35 -0
  14. package/dist/widgets/interactive-graph-editor/locked-figures/util.d.ts +9 -0
  15. package/dist/widgets/interactive-graph-editor/start-coords/start-coords-angle.d.ts +9 -0
  16. package/dist/widgets/interactive-graph-editor/start-coords/start-coords-circle.d.ts +12 -0
  17. package/dist/{components → widgets/interactive-graph-editor/start-coords}/start-coords-line.d.ts +2 -2
  18. package/dist/{components → widgets/interactive-graph-editor/start-coords}/start-coords-multiline.d.ts +2 -2
  19. package/dist/{components → widgets/interactive-graph-editor/start-coords}/start-coords-point.d.ts +2 -2
  20. package/dist/{components → widgets/interactive-graph-editor/start-coords}/start-coords-quadratic.d.ts +2 -2
  21. package/dist/{components → widgets/interactive-graph-editor/start-coords}/start-coords-settings.d.ts +2 -1
  22. package/dist/widgets/interactive-graph-editor/start-coords/start-coords-sinusoid.d.ts +9 -0
  23. package/dist/widgets/interactive-graph-editor/start-coords/types.d.ts +24 -0
  24. package/dist/widgets/interactive-graph-editor/start-coords/util.d.ts +8 -0
  25. package/package.json +2 -2
  26. package/dist/components/graph-locked-figures/locked-label-settings.d.ts +0 -17
  27. package/dist/components/start-coords-angle.d.ts +0 -8
  28. package/dist/components/start-coords-circle.d.ts +0 -11
  29. package/dist/components/start-coords-sinusoid.d.ts +0 -8
  30. /package/dist/{components → widgets/interactive-graph-editor/components}/interactive-graph-correct-answer.d.ts +0 -0
  31. /package/dist/{components → widgets/interactive-graph-editor/components}/interactive-graph-settings.d.ts +0 -0
  32. /package/dist/{components → widgets/interactive-graph-editor/components}/segment-count-selector.d.ts +0 -0
  33. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/color-select.d.ts +0 -0
  34. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/color-swatch.d.ts +0 -0
  35. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/defining-point-settings.d.ts +0 -0
  36. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/ellipse-swatch.d.ts +0 -0
  37. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/labeled-row.d.ts +0 -0
  38. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/labeled-switch.d.ts +0 -0
  39. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/line-stroke-select.d.ts +0 -0
  40. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/line-swatch.d.ts +0 -0
  41. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-ellipse-settings.d.ts +0 -0
  42. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-figure-select.d.ts +0 -0
  43. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-function-examples.d.ts +0 -0
  44. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-function-settings.d.ts +0 -0
  45. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-line-settings.d.ts +0 -0
  46. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-point-settings.d.ts +0 -0
  47. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-polygon-settings.d.ts +0 -0
  48. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-vector-settings.d.ts +0 -0
  49. /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/polygon-swatch.d.ts +0 -0
package/dist/index.js CHANGED
@@ -26,6 +26,7 @@ var wonderStuffCore = require('@khanacademy/wonder-stuff-core');
26
26
  var mathInput = require('@khanacademy/math-input');
27
27
  var kmath = require('@khanacademy/kmath');
28
28
  var wonderBlocksDropdown = require('@khanacademy/wonder-blocks-dropdown');
29
+ var Banner = require('@khanacademy/wonder-blocks-banner');
29
30
  var wonderBlocksAccordion = require('@khanacademy/wonder-blocks-accordion');
30
31
  var IconButton = require('@khanacademy/wonder-blocks-icon-button');
31
32
  var caretDoubleDownIcon = require('@phosphor-icons/core/bold/caret-double-down-bold.svg');
@@ -35,13 +36,12 @@ var caretUpIcon = require('@phosphor-icons/core/bold/caret-up-bold.svg');
35
36
  var trashIcon = require('@phosphor-icons/core/bold/trash-bold.svg');
36
37
  var copyIcon = require('@phosphor-icons/core/assets/regular/copy.svg');
37
38
  var autoPasteIcon = require('@phosphor-icons/core/assets/regular/note-pencil.svg');
39
+ var plusCircle = require('@phosphor-icons/core/regular/plus-circle.svg');
38
40
  var arrowFatDown = require('@phosphor-icons/core/regular/arrow-fat-down.svg');
39
41
  var arrowFatLeft = require('@phosphor-icons/core/regular/arrow-fat-left.svg');
40
42
  var arrowFatRight = require('@phosphor-icons/core/regular/arrow-fat-right.svg');
41
43
  var arrowFatUp = require('@phosphor-icons/core/regular/arrow-fat-up.svg');
42
44
  var minusCircle = require('@phosphor-icons/core/regular/minus-circle.svg');
43
- var plusCircle = require('@phosphor-icons/core/regular/plus-circle.svg');
44
- var Banner = require('@khanacademy/wonder-blocks-banner');
45
45
  var arrowCounterClockwise = require('@phosphor-icons/core/bold/arrow-counter-clockwise-bold.svg');
46
46
 
47
47
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -76,6 +76,7 @@ var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
76
76
  var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
77
77
  var KAS__namespace = /*#__PURE__*/_interopNamespace(KAS);
78
78
  var Button__default = /*#__PURE__*/_interopDefaultLegacy(Button);
79
+ var Banner__default = /*#__PURE__*/_interopDefaultLegacy(Banner);
79
80
  var IconButton__default = /*#__PURE__*/_interopDefaultLegacy(IconButton);
80
81
  var caretDoubleDownIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretDoubleDownIcon);
81
82
  var caretDoubleUpIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretDoubleUpIcon);
@@ -84,18 +85,17 @@ var caretUpIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretUpIcon);
84
85
  var trashIcon__default = /*#__PURE__*/_interopDefaultLegacy(trashIcon);
85
86
  var copyIcon__default = /*#__PURE__*/_interopDefaultLegacy(copyIcon);
86
87
  var autoPasteIcon__default = /*#__PURE__*/_interopDefaultLegacy(autoPasteIcon);
88
+ var plusCircle__default = /*#__PURE__*/_interopDefaultLegacy(plusCircle);
87
89
  var arrowFatDown__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatDown);
88
90
  var arrowFatLeft__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatLeft);
89
91
  var arrowFatRight__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatRight);
90
92
  var arrowFatUp__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatUp);
91
93
  var minusCircle__default = /*#__PURE__*/_interopDefaultLegacy(minusCircle);
92
- var plusCircle__default = /*#__PURE__*/_interopDefaultLegacy(plusCircle);
93
- var Banner__default = /*#__PURE__*/_interopDefaultLegacy(Banner);
94
94
  var arrowCounterClockwise__default = /*#__PURE__*/_interopDefaultLegacy(arrowCounterClockwise);
95
95
 
96
96
  // This file is processed by a Rollup plugin (replace) to inject the production
97
97
  const libName = "@khanacademy/perseus-editor";
98
- const libVersion = "14.1.3";
98
+ const libVersion = "14.3.0";
99
99
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
100
100
 
101
101
  function _extends() {
@@ -29585,39 +29585,96 @@ function invariant(condition, message) {
29585
29585
  throw new Error(value);
29586
29586
  }
29587
29587
 
29588
- // Renders the given children in a View laid out horizontally.
29589
- const LabeledRow = props => {
29590
- const {
29591
- children,
29592
- label,
29593
- labelSide = "left",
29594
- style
29595
- } = props;
29596
- return /*#__PURE__*/React__namespace.createElement("label", {
29597
- className: aphrodite.css(styles$J.label)
29598
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29599
- style: [styles$J.row, style]
29600
- }, labelSide === "start" || /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29601
- style: styles$J.spaceEnd
29602
- }, label), children, labelSide === "end" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29603
- style: styles$J.spaceStart
29604
- }, label)));
29588
+ const UNLIMITED = "unlimited";
29589
+ // Parses a string (ostensibly from some UI element that only supports string
29590
+ // types, such as a <select />) into a numeric point count or the special sigil
29591
+ // "unlimited". Note that 0 is a special case, and means "unlimited".
29592
+ const parsePointCount = points => {
29593
+ const parsed = parseInt(points, 10);
29594
+ if (isNaN(parsed)) {
29595
+ return UNLIMITED;
29596
+ }
29597
+ return parsed === 0 ? UNLIMITED : parsed;
29598
+ };
29599
+
29600
+ const GraphPointsCountSelector = _ref => {
29601
+ let {
29602
+ numPoints = 1,
29603
+ onChange
29604
+ } = _ref;
29605
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
29606
+ selectedValue: `${numPoints}`,
29607
+ onChange: newValue => {
29608
+ onChange(parsePointCount(newValue));
29609
+ }
29610
+ // Never uses placeholder, always has value
29611
+ ,
29612
+ placeholder: "",
29613
+ style: styles$J.singleSelectShort
29614
+ }, [...[...Array(7).keys()].map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29615
+ key: n,
29616
+ value: `${n}`,
29617
+ label: `${n} point${n > 1 ? "s" : ""}`
29618
+ })), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29619
+ key: "unlimited",
29620
+ value: UNLIMITED,
29621
+ label: "unlimited"
29622
+ })]);
29605
29623
  };
29606
29624
  const styles$J = aphrodite.StyleSheet.create({
29607
- label: {
29608
- width: "fit-content"
29609
- },
29610
- row: {
29611
- flexDirection: "row",
29612
- marginTop: wonderBlocksTokens.spacing.xSmall_8,
29613
- alignItems: "center",
29614
- width: "fit-content"
29615
- },
29616
- spaceStart: {
29617
- marginInlineStart: wonderBlocksTokens.spacing.xSmall_8
29618
- },
29619
- spaceEnd: {
29620
- marginInlineEnd: wonderBlocksTokens.spacing.xSmall_8
29625
+ singleSelectShort: {
29626
+ // Non-standard spacing, but it's the smallest we can go
29627
+ // without running into styling issues with the dropdown.
29628
+ height: 26
29629
+ }
29630
+ });
29631
+
29632
+ const GraphTypeSelector = props => {
29633
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
29634
+ selectedValue: props.graphType,
29635
+ onChange: props.onChange,
29636
+ placeholder: "Select an answer type",
29637
+ style: styles$I.singleSelectShort
29638
+ }, props.showNoneOption && /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29639
+ value: "none",
29640
+ label: "None"
29641
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29642
+ value: "linear",
29643
+ label: "Linear function"
29644
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29645
+ value: "quadratic",
29646
+ label: "Quadratic function"
29647
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29648
+ value: "sinusoid",
29649
+ label: "Sinusoid function"
29650
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29651
+ value: "circle",
29652
+ label: "Circle"
29653
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29654
+ value: "point",
29655
+ label: "Point(s)"
29656
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29657
+ value: "linear-system",
29658
+ label: "Linear System"
29659
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29660
+ value: "polygon",
29661
+ label: "Polygon"
29662
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29663
+ value: "segment",
29664
+ label: "Line Segment(s)"
29665
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29666
+ value: "ray",
29667
+ label: "Ray"
29668
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
29669
+ value: "angle",
29670
+ label: "Angle"
29671
+ }));
29672
+ };
29673
+ const styles$I = aphrodite.StyleSheet.create({
29674
+ singleSelectShort: {
29675
+ // Non-standard spacing, but it's the smallest we can go
29676
+ // without running into styling issues with the dropdown.
29677
+ height: 26
29621
29678
  }
29622
29679
  });
29623
29680
 
@@ -29629,11 +29686,11 @@ function Heading(_ref) {
29629
29686
  onToggle
29630
29687
  } = _ref;
29631
29688
  return /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
29632
- style: [styles$I.container, !isCollapsible && styles$I.notClickable],
29689
+ style: [styles$H.container, !isCollapsible && styles$H.notClickable],
29633
29690
  disabled: !isCollapsible,
29634
29691
  onClick: () => isCollapsible && onToggle?.(!isOpen)
29635
29692
  }, () => /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29636
- style: styles$I.heading
29693
+ style: styles$H.heading
29637
29694
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
29638
29695
  style: {
29639
29696
  fontSize: 14,
@@ -29643,7 +29700,7 @@ function Heading(_ref) {
29643
29700
  isExpanded: isOpen
29644
29701
  })));
29645
29702
  }
29646
- const styles$I = aphrodite.StyleSheet.create({
29703
+ const styles$H = aphrodite.StyleSheet.create({
29647
29704
  container: {
29648
29705
  marginTop: wonderBlocksTokens.spacing.small_12,
29649
29706
  // NOTE(jeremy): This is the inverse of the @editorPadding CSS
@@ -29667,348 +29724,765 @@ const styles$I = aphrodite.StyleSheet.create({
29667
29724
  }
29668
29725
  });
29669
29726
 
29670
- function focusWithChromeStickyFocusBugWorkaround(element) {
29671
- // NOTE(marksandstrom) Chrome sticky focus bug.
29672
- //
29673
- // There is a bug in Chrome related to sticky positioning and
29674
- // focus: When a child of an element with sticky positioning is
29675
- // focused with the focus() method, the scrollable area
29676
- // containing that element will scroll to the top (even though
29677
- // the element is already visble on the page). For a dropdown
29678
- // this means that the area will be scrolled to the top when
29679
- // the user interacts with the dropdown (since we actively
29680
- // manage dropdown header and option focus for keyboard users).
29681
- //
29682
- // To work around this bug the `preventScroll` focus option is
29683
- // used.
29684
- //
29685
- // Using `focusOptions` is an experimental browser feature
29686
- // "that should not be used in production code". However, since
29687
- // Chrome is the only browser we support that exhibits this
29688
- // buggy behavior and using `focusOptions` works around the
29689
- // bug, it is perfectly reasonable to use the feature in this
29690
- // case. We are not relying on the effect of the
29691
- // `preventScroll` option otherwise.
29692
- //
29693
- // focusOptions documentation:
29694
- //
29695
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
29696
- //
29697
- // Note that there could be cases where we want default focus() behavior.
29698
- // One that comes to mind is a dropdown with a long list of options that
29699
- // might be rendered off screen when opened. With this workaround the
29700
- // selected option would not be scrolled into view if the option is near
29701
- // the end of the list. We're not aware of any uses of the dropdown where
29702
- // this is an issue, however, so there isn't currently a way to out of the
29703
- // `preventScroll` behavior.
29704
-
29705
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element'.
29706
- element.focus({
29707
- preventScroll: true
29708
- });
29709
- }
29710
- const DEFAULT_COLOR = "grayH";
29711
- function getDefaultFigureForType(type) {
29712
- switch (type) {
29713
- case "point":
29714
- return {
29715
- type: "point",
29716
- coord: [0, 0],
29717
- color: DEFAULT_COLOR,
29718
- filled: true
29719
- };
29720
- case "line":
29721
- return {
29722
- type: "line",
29723
- kind: "line",
29724
- points: [getDefaultFigureForType("point"), {
29725
- ...getDefaultFigureForType("point"),
29726
- coord: [2, 2]
29727
- }],
29728
- color: DEFAULT_COLOR,
29729
- lineStyle: "solid",
29730
- showPoint1: false,
29731
- showPoint2: false
29732
- };
29733
- case "vector":
29734
- return {
29735
- type: "vector",
29736
- points: [[0, 0], [2, 2]],
29737
- color: DEFAULT_COLOR
29738
- };
29739
- case "ellipse":
29740
- return {
29741
- type: "ellipse",
29742
- center: [0, 0],
29743
- radius: [1, 1],
29744
- angle: 0,
29745
- color: DEFAULT_COLOR,
29746
- fillStyle: "none",
29747
- strokeStyle: "solid"
29748
- };
29749
- case "polygon":
29750
- return {
29751
- type: "polygon",
29752
- points: [[0, 2], [-1, 0], [1, 0]],
29753
- color: DEFAULT_COLOR,
29754
- showVertices: false,
29755
- fillStyle: "none",
29756
- strokeStyle: "solid"
29757
- };
29758
- case "function":
29759
- return {
29760
- type: "function",
29761
- color: DEFAULT_COLOR,
29762
- strokeStyle: "solid",
29763
- equation: "x^2",
29764
- directionalAxis: "x"
29765
- };
29766
- case "label":
29767
- return {
29768
- type: "label",
29769
- coord: [0, 0],
29770
- text: "",
29771
- color: DEFAULT_COLOR,
29772
- size: "medium"
29773
- };
29774
- default:
29775
- throw new wonderStuffCore.UnreachableCaseError(type);
29776
- }
29777
- }
29778
- function degreeToRadian(degrees) {
29779
- return degrees / 180 * Math.PI;
29780
- }
29781
- function radianToDegree(radians) {
29782
- return radians / Math.PI * 180;
29783
- }
29784
- function getDefaultGraphStartCoords(graph, range, step) {
29785
- switch (graph.type) {
29786
- case "linear":
29787
- case "ray":
29788
- return perseus.getLineCoords({
29789
- ...graph,
29790
- startCoords: undefined
29791
- }, range, step);
29792
- case "segment":
29793
- return perseus.getSegmentCoords({
29794
- ...graph,
29795
- startCoords: undefined
29796
- }, range, step);
29797
- case "linear-system":
29798
- return perseus.getLinearSystemCoords({
29799
- ...graph,
29800
- startCoords: undefined
29801
- }, range, step);
29802
- case "circle":
29803
- const startCoords = perseus.getCircleCoords({
29804
- ...graph,
29805
- startCoords: undefined
29806
- });
29807
- const radius = kmath.vector.length(kmath.vector.subtract(startCoords.radiusPoint, startCoords.center));
29808
- return {
29809
- center: startCoords.center,
29810
- radius
29811
- };
29812
- case "sinusoid":
29813
- return perseus.getSinusoidCoords({
29814
- ...graph,
29815
- startCoords: undefined
29816
- }, range, step);
29817
- case "quadratic":
29818
- return perseus.getQuadraticCoords({
29819
- ...graph,
29820
- startCoords: undefined
29821
- }, range, step);
29822
- case "point":
29823
- return perseus.getPointCoords({
29824
- ...graph,
29825
- startCoords: undefined
29826
- }, range, step);
29827
- case "polygon":
29828
- return perseus.getPolygonCoords({
29829
- ...graph,
29830
- startCoords: undefined
29831
- }, range, step);
29832
- case "angle":
29833
- return perseus.getAngleCoords({
29834
- graph: {
29835
- ...graph,
29836
- startCoords: undefined
29837
- },
29838
- range,
29839
- step
29840
- });
29841
- default:
29842
- return undefined;
29843
- }
29727
+ function InteractiveGraphCorrectAnswer(props) {
29728
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
29729
+ title: "Correct Answer",
29730
+ isOpen: true,
29731
+ isCollapsible: false
29732
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelXSmall, {
29733
+ style: {
29734
+ paddingTop: wonderBlocksTokens.spacing.xxSmall_6,
29735
+ paddingBottom: wonderBlocksTokens.spacing.xxSmall_6,
29736
+ color: wonderBlocksTokens.color.offBlack64
29737
+ }
29738
+ }, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.BodyMonospace, {
29739
+ style: {
29740
+ fontSize: 12,
29741
+ backgroundColor: "#eee",
29742
+ paddingInline: wonderBlocksTokens.spacing.xxSmall_6,
29743
+ borderColor: "#ccc",
29744
+ borderStyle: "solid",
29745
+ borderWidth: 1
29746
+ }
29747
+ }, props.equationString)), props.children));
29844
29748
  }
29845
- const getSinusoidEquation = startCoords => {
29846
- // Get coefficients
29847
- // It's assumed that p1 is the root and p2 is the first peak
29848
- const p1 = startCoords[0];
29849
- const p2 = startCoords[1];
29850
-
29851
- // Resulting coefficients are canonical for this sine curve
29852
- const amplitude = p2[1] - p1[1];
29853
- const angularFrequency = Math.PI / (2 * (p2[0] - p1[0]));
29854
- const phase = p1[0] * angularFrequency;
29855
- const verticalOffset = p1[1];
29856
- return "y = " + amplitude.toFixed(3) + "sin(" + angularFrequency.toFixed(3) + "x - " + phase.toFixed(3) + ") + " + verticalOffset.toFixed(3);
29857
- };
29858
- const getQuadraticEquation = startCoords => {
29859
- const p1 = startCoords[0];
29860
- const p2 = startCoords[1];
29861
- const p3 = startCoords[2];
29862
- const denom = (p1[0] - p2[0]) * (p1[0] - p3[0]) * (p2[0] - p3[0]);
29863
- if (denom === 0) {
29864
- // Many of the callers assume that the return value is always defined.
29865
- return "Division by zero error";
29866
- }
29867
- const a = (p3[0] * (p2[1] - p1[1]) + p2[0] * (p1[1] - p3[1]) + p1[0] * (p3[1] - p2[1])) / denom;
29868
- const b = (p3[0] * p3[0] * (p1[1] - p2[1]) + p2[0] * p2[0] * (p3[1] - p1[1]) + p1[0] * p1[0] * (p2[1] - p3[1])) / denom;
29869
- const c = (p2[0] * p3[0] * (p2[0] - p3[0]) * p1[1] + p3[0] * p1[0] * (p3[0] - p1[0]) * p2[1] + p1[0] * p2[0] * (p1[0] - p2[0]) * p3[1]) / denom;
29870
- return "y = " + a.toFixed(3) + "x^2 + " + b.toFixed(3) + "x + " + c.toFixed(3);
29871
- };
29872
- const findAngle = (point1, point2) => {
29873
- const x = point1[0] - point2[0];
29874
- const y = point1[1] - point2[1];
29875
- return (180 + Math.atan2(-y, -x) * 180 / Math.PI + 360) % 360;
29876
- };
29877
- const getAngleEquation = startCoords => {
29878
- const [point1, vertex, point2] = startCoords;
29879
- const angle = findAngle(point2, vertex) - findAngle(point1, vertex);
29880
- const roundedAngle = angle.toFixed(0);
29881
- return `${roundedAngle}\u00B0 angle at (${vertex[0]}, ${vertex[1]})`;
29882
- };
29883
- const shouldShowStartCoordsUI = (graph, isStatic) => {
29884
- // We don't show the start coords UI for static graphs, since
29885
- // the coords shown for this are determined by the coords on the
29886
- // "correct" graph. The start coords would not be used here.
29887
- if (isStatic) {
29888
- return false;
29889
- }
29890
- if (graph.type === "point" && graph.numPoints === "unlimited") {
29891
- return false;
29892
- }
29893
- if (graph.type === "polygon" && (graph.numSides === "unlimited" || graph.snapTo === "angles" || graph.snapTo === "sides")) {
29894
- return false;
29895
- }
29896
- return true;
29897
- };
29898
29749
 
29899
- /**
29900
- * Dropdown for selecting a locked figure to add to an interactive graph.
29901
- * Locked figures are elements (points, segmeents, etc.) that are not
29902
- * interactive, just present in the graph's background.
29903
- *
29904
- * Used in the interactive graph editor's locked figures section.
29905
- */
29906
- const LockedFigureSelect = props => {
29750
+ function InteractiveGraphDescription(props) {
29907
29751
  const {
29908
- id,
29752
+ ariaLabelValue,
29753
+ ariaDescriptionValue,
29909
29754
  onChange
29910
29755
  } = props;
29911
- const figureTypes = ["point", "line", "vector", "ellipse", "polygon", "function"];
29912
- if (props.showLabelsFlag) {
29913
- figureTypes.push("label");
29914
- }
29915
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29916
- style: styles$H.container
29917
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionMenu, {
29918
- menuText: "Add locked figure",
29919
- style: styles$H.addElementSelect
29920
- }, figureTypes.map(figureType => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
29921
- key: `${id}-${figureType}`,
29922
- label: figureType,
29923
- onClick: () => onChange(figureType)
29756
+ const [isOpen, setIsOpen] = React__namespace.useState(true);
29757
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
29758
+ title: "Description",
29759
+ isCollapsible: true,
29760
+ isOpen: isOpen,
29761
+ onToggle: setIsOpen
29762
+ }), isOpen && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelXSmall, {
29763
+ style: styles$G.caption
29764
+ }, "Use these fields to describe the graph as a whole. These are used by screen readers to describe content to users who are visually impaired."), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
29765
+ tag: "label"
29766
+ }, "Title", /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
29767
+ value: ariaLabelValue,
29768
+ onChange: newValue => onChange({
29769
+ fullGraphAriaLabel: newValue
29770
+ }),
29771
+ style: styles$G.spaceAbove
29772
+ })), /*#__PURE__*/React__namespace.createElement(Strut, {
29773
+ size: wonderBlocksTokens.spacing.small_12
29774
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
29775
+ tag: "label"
29776
+ }, "Description", /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextArea, {
29777
+ rows: 8,
29778
+ resizeType: "vertical",
29779
+ value: ariaDescriptionValue,
29780
+ onChange: newValue => onChange({
29781
+ fullGraphAriaDescription: newValue
29782
+ }),
29783
+ style: styles$G.spaceAbove
29924
29784
  }))));
29925
- };
29926
- const styles$H = aphrodite.StyleSheet.create({
29927
- container: {
29928
- marginTop: wonderBlocksTokens.spacing.xSmall_8
29785
+ }
29786
+ const styles$G = aphrodite.StyleSheet.create({
29787
+ caption: {
29788
+ color: wonderBlocksTokens.color.offBlack64,
29789
+ paddingTop: wonderBlocksTokens.spacing.xxSmall_6,
29790
+ paddingBottom: wonderBlocksTokens.spacing.xxSmall_6
29929
29791
  },
29930
- addElementSelect: {
29931
- backgroundColor: wonderBlocksTokens.color.fadedBlue8,
29932
- borderRadius: wonderBlocksTokens.spacing.xxxSmall_4
29792
+ spaceAbove: {
29793
+ marginTop: wonderBlocksTokens.spacing.xxxSmall_4
29933
29794
  }
29934
29795
  });
29935
29796
 
29936
- /**
29937
- * This is a custom text field of type="number" for use in Perseus Editors.
29938
- *
29939
- * This makes it so that the text field's input number updates on scroll
29940
- * without scrolling the page.
29941
- *
29942
- * NOTE 1: Native HTML number inputs do not update the number value on scroll,
29943
- * they only scroll the page. Inputs in React do NOT work this way (explanation
29944
- * here: https://stackoverflow.com/a/68266494). By default, scrolling on a
29945
- * focused number input in React causes BOTH the input value to change AND
29946
- * the page to scroll. The behavior in this component is an improvement on
29947
- * the React behavior, but it's the opposite of the native HTML behavior.
29948
- *
29949
- * NOTE 2: Firefox seems to have a custom override for this. Even with this
29950
- * stopPropogation, Firefox matches the native HTML behavior.
29951
- */
29952
- const ScrolllessNumberTextField = props => {
29953
- const inputRef = React__namespace.useRef(null);
29954
- React__namespace.useEffect(() => {
29955
- const ref = inputRef.current;
29956
-
29957
- // stopPropogation makes it so that the page scroll event is not
29958
- // triggered when the input is focused and the user scrolls.
29959
- // The input value will still change on scroll.
29960
- const ignoreScroll = e => {
29961
- e.stopPropagation();
29962
- };
29963
- ref?.addEventListener("wheel", ignoreScroll);
29964
- return () => {
29965
- ref?.removeEventListener("wheel", ignoreScroll);
29966
- };
29967
- }, [inputRef]);
29968
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, _extends({
29969
- type: "number"
29970
- }, props, {
29971
- ref: inputRef
29972
- }));
29973
- };
29974
-
29975
- const AngleInput = props => {
29797
+ // Renders the given children in a View laid out horizontally.
29798
+ const LabeledRow = props => {
29976
29799
  const {
29977
- angle,
29978
- onChange
29800
+ children,
29801
+ label,
29802
+ labelSide = "left",
29803
+ style
29979
29804
  } = props;
29980
- const [angleInput, setAngleInput] = React__namespace.useState(radianToDegree(angle).toString());
29981
- function handleAngleChange(newValue) {
29982
- // Update the local state (update the input field value).
29983
- setAngleInput(newValue);
29984
-
29985
- // If the new value is not a number, don't update the props.
29986
- // If it's empty, keep the props the same value instead of setting to 0.
29987
- if (isNaN(+newValue) || newValue === "") {
29988
- return;
29989
- }
29990
-
29991
- // Update the graph.
29992
- onChange(degreeToRadian(newValue));
29993
- }
29994
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
29995
- tag: "label",
29996
- style: styles$G.row
29997
- }, "angle (degrees)", /*#__PURE__*/React__namespace.createElement(Strut, {
29998
- size: wonderBlocksTokens.spacing.xxSmall_6
29999
- }), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
30000
- value: angleInput,
30001
- onChange: handleAngleChange,
30002
- style: styles$G.textField
30003
- }), /*#__PURE__*/React__namespace.createElement(Strut, {
30004
- size: wonderBlocksTokens.spacing.xxSmall_6
30005
- }));
29805
+ return /*#__PURE__*/React__namespace.createElement("label", {
29806
+ className: aphrodite.css(styles$F.label)
29807
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29808
+ style: [styles$F.row, style]
29809
+ }, labelSide === "start" || /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29810
+ style: styles$F.spaceEnd
29811
+ }, label), children, labelSide === "end" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
29812
+ style: styles$F.spaceStart
29813
+ }, label)));
30006
29814
  };
30007
- const styles$G = aphrodite.StyleSheet.create({
29815
+ const styles$F = aphrodite.StyleSheet.create({
29816
+ label: {
29817
+ width: "fit-content"
29818
+ },
30008
29819
  row: {
30009
- display: "flex",
30010
29820
  flexDirection: "row",
30011
- alignItems: "center"
29821
+ marginTop: wonderBlocksTokens.spacing.xSmall_8,
29822
+ alignItems: "center",
29823
+ width: "fit-content"
29824
+ },
29825
+ spaceStart: {
29826
+ marginInlineStart: wonderBlocksTokens.spacing.xSmall_8
29827
+ },
29828
+ spaceEnd: {
29829
+ marginInlineEnd: wonderBlocksTokens.spacing.xSmall_8
29830
+ }
29831
+ });
29832
+
29833
+ /* eslint-disable react/forbid-prop-types, react/no-unsafe */
29834
+ const {
29835
+ ButtonGroup: ButtonGroup$2,
29836
+ InfoTip: InfoTip$d,
29837
+ RangeInput: RangeInput$4
29838
+ } = perseus.components;
29839
+ const defaultBackgroundImage$1 = {
29840
+ url: null,
29841
+ width: 0,
29842
+ height: 0
29843
+ };
29844
+ function numSteps(range, step) {
29845
+ return Math.floor((range[1] - range[0]) / step);
29846
+ }
29847
+ class InteractiveGraphSettings extends React__namespace.Component {
29848
+ _isMounted = false;
29849
+ bgUrlRef = /*#__PURE__*/React__namespace.createRef();
29850
+ labelXRef = /*#__PURE__*/React__namespace.createRef();
29851
+ labelYRef = /*#__PURE__*/React__namespace.createRef();
29852
+ static stateFromProps(props) {
29853
+ return {
29854
+ labelsTextbox: props.labels,
29855
+ gridStepTextbox: props.gridStep,
29856
+ snapStepTextbox: props.snapStep,
29857
+ stepTextbox: props.step,
29858
+ rangeTextbox: props.range,
29859
+ // Shallow-copied clone
29860
+ backgroundImage: {
29861
+ ...props.backgroundImage
29862
+ }
29863
+ };
29864
+ }
29865
+ constructor(props) {
29866
+ super(props);
29867
+ this.state = {
29868
+ isExpanded: true,
29869
+ ...InteractiveGraphSettings.stateFromProps(props)
29870
+ };
29871
+ }
29872
+ static defaultProps = {
29873
+ box: [perseus.interactiveSizes.defaultBoxSizeSmall, perseus.interactiveSizes.defaultBoxSizeSmall],
29874
+ labels: ["x", "y"],
29875
+ range: [[-10, 10], [-10, 10]],
29876
+ step: [1, 1],
29877
+ gridStep: [1, 1],
29878
+ snapStep: [1, 1],
29879
+ valid: true,
29880
+ backgroundImage: defaultBackgroundImage$1,
29881
+ markings: "graph",
29882
+ showProtractor: false,
29883
+ showTooltips: false
29884
+ };
29885
+ componentDidMount() {
29886
+ // TODO(scottgrant): This is a hack to remove the deprecated call to
29887
+ // this.isMounted() but is still considered an anti-pattern.
29888
+ this._isMounted = true;
29889
+ this.changeGraph = ___default["default"].debounce(this.changeGraph, 300);
29890
+ }
29891
+ UNSAFE_componentWillReceiveProps(nextProps) {
29892
+ // Make sure that state updates when switching
29893
+ // between different items in a multi-item editor.
29894
+ if (!___default["default"].isEqual(this.props.labels, nextProps.labels) || !___default["default"].isEqual(this.props.gridStep, nextProps.gridStep) || !___default["default"].isEqual(this.props.snapStep, nextProps.snapStep) || !___default["default"].isEqual(this.props.step, nextProps.step) || !___default["default"].isEqual(this.props.range, nextProps.range) || !___default["default"].isEqual(this.props.backgroundImage, nextProps.backgroundImage)) {
29895
+ this.setState(InteractiveGraphSettings.stateFromProps(nextProps));
29896
+ }
29897
+ }
29898
+ componentWillUnmount() {
29899
+ this._isMounted = false;
29900
+ }
29901
+ change = (() => {
29902
+ var _this = this;
29903
+ return function () {
29904
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
29905
+ args[_key] = arguments[_key];
29906
+ }
29907
+ return perseus.Changeable.change.apply(_this, args);
29908
+ };
29909
+ })();
29910
+ changeBackgroundUrl = e => {
29911
+ // Only continue on blur or "enter"
29912
+ if (e.type === "keypress" && e.key !== "Enter") {
29913
+ return;
29914
+ }
29915
+ const setUrl = (url, width, height) => {
29916
+ // Shallow-copied clone
29917
+ const image = {
29918
+ ...this.props.backgroundImage
29919
+ };
29920
+ image.url = url;
29921
+ image.width = width;
29922
+ image.height = height;
29923
+ this.setState({
29924
+ backgroundImage: image
29925
+ }, this.changeGraph);
29926
+ };
29927
+ const url = this.bgUrlRef.current?.value;
29928
+ if (url) {
29929
+ perseus.Util.getImageSize(url, (width, height) => {
29930
+ if (this._isMounted) {
29931
+ setUrl(url, width, height);
29932
+ }
29933
+ });
29934
+ } else {
29935
+ setUrl(null, 0, 0);
29936
+ }
29937
+ };
29938
+ renderLabelChoices = choices => {
29939
+ return choices.map(nameAndValue => /*#__PURE__*/React__namespace.createElement("option", {
29940
+ key: nameAndValue[1],
29941
+ value: nameAndValue[1]
29942
+ }, nameAndValue[0]));
29943
+ };
29944
+ validRange = range => {
29945
+ const numbers = ___default["default"].every(range, function (num) {
29946
+ return ___default["default"].isFinite(num);
29947
+ });
29948
+ if (!numbers) {
29949
+ return "Range must be a valid number";
29950
+ }
29951
+ if (range[0] >= range[1]) {
29952
+ return "Range must have a higher number on the right";
29953
+ }
29954
+ return true;
29955
+ };
29956
+ validateStepValue = settings => {
29957
+ const {
29958
+ step,
29959
+ range,
29960
+ name,
29961
+ minTicks,
29962
+ maxTicks
29963
+ } = settings;
29964
+ const nSteps = numSteps(range, step);
29965
+ if (nSteps < minTicks) {
29966
+ return name + " is too large, there must be at least " + minTicks + " ticks.";
29967
+ }
29968
+ if (nSteps > maxTicks) {
29969
+ return name + " is too small, there can be at most " + maxTicks + " ticks.";
29970
+ }
29971
+ return true;
29972
+ };
29973
+ validSnapStep = (step, range) => {
29974
+ return this.validateStepValue({
29975
+ step: step,
29976
+ range: range,
29977
+ name: "Snap step",
29978
+ minTicks: 5,
29979
+ maxTicks: 60
29980
+ });
29981
+ };
29982
+ validGridStep = (step, range) => {
29983
+ return this.validateStepValue({
29984
+ step: step,
29985
+ range: range,
29986
+ name: "Grid step",
29987
+ minTicks: 3,
29988
+ maxTicks: 60
29989
+ });
29990
+ };
29991
+ validStep = (step, range) => {
29992
+ return this.validateStepValue({
29993
+ step: step,
29994
+ range: range,
29995
+ name: "Step",
29996
+ minTicks: 3,
29997
+ maxTicks: 20
29998
+ });
29999
+ };
30000
+ validBackgroundImageSize = image => {
30001
+ // Ignore empty images
30002
+ if (!image.url) {
30003
+ return true;
30004
+ }
30005
+ const validSize = image.width <= 450 && image.height <= 450;
30006
+ if (!validSize) {
30007
+ return "Image must be smaller than 450px x 450px.";
30008
+ }
30009
+ return true;
30010
+ };
30011
+ validateGraphSettings = (range, step, gridStep, snapStep, image) => {
30012
+ const self = this;
30013
+ let msg;
30014
+ const goodRange = ___default["default"].every(range, function (range) {
30015
+ msg = self.validRange(range);
30016
+ return msg === true;
30017
+ });
30018
+ if (!goodRange) {
30019
+ return msg;
30020
+ }
30021
+ const goodStep = ___default["default"].every(step, function (step, i) {
30022
+ msg = self.validStep(step, range[i]);
30023
+ return msg === true;
30024
+ });
30025
+ if (!goodStep) {
30026
+ return msg;
30027
+ }
30028
+ const goodGridStep = ___default["default"].every(gridStep, function (gridStep, i) {
30029
+ msg = self.validGridStep(gridStep, range[i]);
30030
+ return msg === true;
30031
+ });
30032
+ if (!goodGridStep) {
30033
+ return msg;
30034
+ }
30035
+ const goodSnapStep = ___default["default"].every(snapStep, function (snapStep, i) {
30036
+ msg = self.validSnapStep(snapStep, range[i]);
30037
+ return msg === true;
30038
+ });
30039
+ if (!goodSnapStep) {
30040
+ return msg;
30041
+ }
30042
+ const goodImageSize = this.validBackgroundImageSize(image);
30043
+ if (goodImageSize !== true) {
30044
+ msg = goodImageSize;
30045
+ return msg;
30046
+ }
30047
+ return true;
30048
+ };
30049
+ changeLabel = (i, e) => {
30050
+ const val = e.target.value;
30051
+ const labels = this.state.labelsTextbox.slice();
30052
+ labels[i] = val;
30053
+ this.setState({
30054
+ labelsTextbox: labels
30055
+ }, this.changeGraph);
30056
+ };
30057
+ changeRange = (i, values) => {
30058
+ const ranges = this.state.rangeTextbox.slice();
30059
+ ranges[i] = values;
30060
+ const step = this.state.stepTextbox.slice();
30061
+ const gridStep = this.state.gridStepTextbox.slice();
30062
+ const snapStep = this.state.snapStepTextbox.slice();
30063
+ const scale = perseus.Util.scaleFromExtent(ranges[i], this.props.box[i]);
30064
+ if (this.validRange(ranges[i]) === true) {
30065
+ step[i] = perseus.Util.tickStepFromExtent(ranges[i], this.props.box[i]);
30066
+ const gridStepValue = perseus.Util.gridStepFromTickStep(step[i], scale);
30067
+ if (gridStepValue) {
30068
+ gridStep[i] = gridStepValue;
30069
+ }
30070
+ snapStep[i] = gridStep[i] / 2;
30071
+ }
30072
+ this.setState({
30073
+ stepTextbox: step,
30074
+ gridStepTextbox: gridStep,
30075
+ snapStepTextbox: snapStep,
30076
+ rangeTextbox: ranges
30077
+ }, this.changeGraph);
30078
+ };
30079
+ changeStep = step => {
30080
+ this.setState({
30081
+ stepTextbox: step
30082
+ }, this.changeGraph);
30083
+ };
30084
+ changeSnapStep = snapStep => {
30085
+ this.setState({
30086
+ snapStepTextbox: snapStep
30087
+ }, this.changeGraph);
30088
+ };
30089
+ changeGridStep = gridStep => {
30090
+ this.setState({
30091
+ gridStepTextbox: gridStep,
30092
+ snapStepTextbox: ___default["default"].map(gridStep, function (step) {
30093
+ return step / 2;
30094
+ })
30095
+ }, this.changeGraph);
30096
+ };
30097
+ changeGraph = () => {
30098
+ const labels = this.state.labelsTextbox;
30099
+ const range = ___default["default"].map(this.state.rangeTextbox, function (range) {
30100
+ return ___default["default"].map(range, Number);
30101
+ });
30102
+ const step = ___default["default"].map(this.state.stepTextbox, Number);
30103
+ const gridStep = this.state.gridStepTextbox;
30104
+ const snapStep = this.state.snapStepTextbox;
30105
+ const image = this.state.backgroundImage;
30106
+
30107
+ // validationResult is either:
30108
+ // true -> the settings are valid
30109
+ // a string -> the settings are invalid, and the explanation
30110
+ // is contained in the string
30111
+ // TODO(aria): Refactor this to not be confusing
30112
+ const validationResult = this.validateGraphSettings(range, step, gridStep, snapStep, image);
30113
+ if (validationResult === true) {
30114
+ // either true or a string
30115
+ this.change({
30116
+ valid: true,
30117
+ labels: labels,
30118
+ range: range,
30119
+ step: step,
30120
+ gridStep: gridStep,
30121
+ snapStep: snapStep,
30122
+ backgroundImage: image
30123
+ });
30124
+ } else {
30125
+ this.change({
30126
+ valid: validationResult // a string message, not false
30127
+ });
30128
+ }
30129
+ };
30130
+
30131
+ render() {
30132
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
30133
+ title: "Common Graph Settings",
30134
+ isOpen: this.state.isExpanded,
30135
+ isCollapsible: true,
30136
+ onToggle: () => this.setState({
30137
+ isExpanded: !this.state.isExpanded
30138
+ })
30139
+ }), this.state.isExpanded && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement("div", {
30140
+ className: "graph-settings"
30141
+ }, /*#__PURE__*/React__namespace.createElement("div", {
30142
+ className: "perseus-widget-row"
30143
+ }, /*#__PURE__*/React__namespace.createElement("div", {
30144
+ className: "perseus-widget-left-col"
30145
+ }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30146
+ label: "x Label"
30147
+ }, /*#__PURE__*/React__namespace.createElement("input", {
30148
+ type: "text",
30149
+ className: "graph-settings-axis-label",
30150
+ ref: this.labelXRef,
30151
+ onChange: e => this.changeLabel(0, e),
30152
+ value: this.state.labelsTextbox[0] || ""
30153
+ }))), /*#__PURE__*/React__namespace.createElement("div", {
30154
+ className: "perseus-widget-right-col"
30155
+ }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30156
+ label: "y Label"
30157
+ }, /*#__PURE__*/React__namespace.createElement("input", {
30158
+ type: "text",
30159
+ className: "graph-settings-axis-label",
30160
+ ref: this.labelYRef,
30161
+ onChange: e => this.changeLabel(1, e),
30162
+ value: this.state.labelsTextbox[1] || ""
30163
+ })))), /*#__PURE__*/React__namespace.createElement("div", {
30164
+ className: "perseus-widget-row"
30165
+ }, /*#__PURE__*/React__namespace.createElement("div", {
30166
+ className: "perseus-widget-left-col"
30167
+ }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30168
+ label: "x Range"
30169
+ }, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
30170
+ value: this.state.rangeTextbox[0],
30171
+ onChange: vals => this.changeRange(0, vals)
30172
+ }))), /*#__PURE__*/React__namespace.createElement("div", {
30173
+ className: "perseus-widget-right-col"
30174
+ }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30175
+ label: "y Range"
30176
+ }, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
30177
+ value: this.state.rangeTextbox[1],
30178
+ onChange: vals => this.changeRange(1, vals)
30179
+ })))), /*#__PURE__*/React__namespace.createElement("div", {
30180
+ className: "perseus-widget-row"
30181
+ }, /*#__PURE__*/React__namespace.createElement("div", {
30182
+ className: "perseus-widget-left-col"
30183
+ }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30184
+ label: "Tick Step"
30185
+ }, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
30186
+ value: this.state.stepTextbox,
30187
+ onChange: this.changeStep
30188
+ }))), /*#__PURE__*/React__namespace.createElement("div", {
30189
+ className: "perseus-widget-right-col"
30190
+ }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30191
+ label: "Grid Step"
30192
+ }, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
30193
+ value: this.state.gridStepTextbox,
30194
+ onChange: this.changeGridStep
30195
+ })))), /*#__PURE__*/React__namespace.createElement("div", {
30196
+ className: "perseus-widget-row"
30197
+ }, /*#__PURE__*/React__namespace.createElement("div", {
30198
+ className: "perseus-widget-left-col"
30199
+ }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30200
+ label: "Snap Step"
30201
+ }, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
30202
+ value: this.state.snapStepTextbox,
30203
+ onChange: this.changeSnapStep
30204
+ })))), /*#__PURE__*/React__namespace.createElement("div", {
30205
+ className: "perseus-widget-row"
30206
+ }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30207
+ label: "Markings:"
30208
+ }, /*#__PURE__*/React__namespace.createElement(ButtonGroup$2, {
30209
+ value: this.props.markings,
30210
+ allowEmpty: false,
30211
+ buttons: [{
30212
+ value: "graph",
30213
+ content: "Graph"
30214
+ }, {
30215
+ value: "grid",
30216
+ content: "Grid"
30217
+ }, {
30218
+ value: "none",
30219
+ content: "None"
30220
+ }],
30221
+ onChange: this.change("markings")
30222
+ }))), /*#__PURE__*/React__namespace.createElement("div", {
30223
+ className: "perseus-widget-left-col"
30224
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
30225
+ label: "Show tooltips",
30226
+ checked: this.props.showTooltips,
30227
+ onChange: value => {
30228
+ this.change({
30229
+ showTooltips: value
30230
+ });
30231
+ }
30232
+ }))), /*#__PURE__*/React__namespace.createElement(LabeledRow, {
30233
+ label: "Background image URL:",
30234
+ style: styles$E.resetSpaceTop
30235
+ }, /*#__PURE__*/React__namespace.createElement("input", {
30236
+ type: "text",
30237
+ className: aphrodite.css(styles$E.backgroundUrlInput),
30238
+ ref: this.bgUrlRef,
30239
+ value: this.state.backgroundImage.url || "",
30240
+ onChange: e => {
30241
+ // Shallow-copied clone
30242
+ const image = {
30243
+ ...this.props.backgroundImage
30244
+ };
30245
+ image.url = e.target.value;
30246
+ this.setState({
30247
+ backgroundImage: image
30248
+ });
30249
+ },
30250
+ onKeyPress: this.changeBackgroundUrl,
30251
+ onBlur: this.changeBackgroundUrl
30252
+ }), /*#__PURE__*/React__namespace.createElement(InfoTip$d, null, /*#__PURE__*/React__namespace.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background."))), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30253
+ style: styles$E.protractorSection
30254
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30255
+ style: styles$E.checkboxRow
30256
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
30257
+ label: "Show protractor",
30258
+ checked: this.props.showProtractor,
30259
+ onChange: value => {
30260
+ this.change({
30261
+ showProtractor: value
30262
+ });
30263
+ },
30264
+ style: styles$E.resetSpaceTop
30265
+ })), this.props.showProtractor && /*#__PURE__*/React__namespace.createElement(Banner__default["default"], {
30266
+ layout: "floating",
30267
+ text: "The protractor is not accessible. Please consider an alternate approach.",
30268
+ kind: "warning"
30269
+ }))));
30270
+ }
30271
+ }
30272
+ const styles$E = aphrodite.StyleSheet.create({
30273
+ resetSpaceTop: {
30274
+ marginTop: 0
30275
+ },
30276
+ backgroundUrlInput: {
30277
+ border: `1px solid ${wonderBlocksTokens.color.offBlack32}`,
30278
+ borderRadius: wonderBlocksTokens.spacing.xxxSmall_4,
30279
+ padding: wonderBlocksTokens.spacing.xxxSmall_4
30280
+ },
30281
+ checkboxRow: {
30282
+ flexDirection: "row",
30283
+ alignItems: "center",
30284
+ justifyContent: "space-between",
30285
+ marginBottom: wonderBlocksTokens.spacing.xSmall_8
30286
+ },
30287
+ protractorSection: {
30288
+ marginTop: wonderBlocksTokens.spacing.xSmall_8,
30289
+ borderTop: `1px solid ${wonderBlocksTokens.color.offBlack16}`,
30290
+ paddingTop: wonderBlocksTokens.spacing.xSmall_8,
30291
+ paddingBottom: wonderBlocksTokens.spacing.xSmall_8,
30292
+ borderBottom: `1px solid ${wonderBlocksTokens.color.offBlack16}`
30293
+ }
30294
+ });
30295
+
30296
+ const SegmentCountSelector = _ref => {
30297
+ let {
30298
+ numSegments = 1,
30299
+ onChange
30300
+ } = _ref;
30301
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30302
+ key: "segment-select",
30303
+ selectedValue: `${numSegments}`
30304
+ // Never uses placeholder, always has value
30305
+ ,
30306
+ placeholder: "",
30307
+ onChange: newValue => {
30308
+ const num = +newValue;
30309
+ onChange(num);
30310
+ },
30311
+ style: styles$D.singleSelectShort
30312
+ }, ___default["default"].range(1, 7).map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
30313
+ key: n,
30314
+ value: `${n}`,
30315
+ label: `${n} segment${n > 1 ? "s" : ""}`
30316
+ })));
30317
+ };
30318
+ const styles$D = aphrodite.StyleSheet.create({
30319
+ singleSelectShort: {
30320
+ // Non-standard spacing, but it's the smallest we can go
30321
+ // without running into styling issues with the dropdown.
30322
+ height: 26
30323
+ }
30324
+ });
30325
+
30326
+ /**
30327
+ * Dropdown for selecting a locked figure to add to an interactive graph.
30328
+ * Locked figures are elements (points, segmeents, etc.) that are not
30329
+ * interactive, just present in the graph's background.
30330
+ *
30331
+ * Used in the interactive graph editor's locked figures section.
30332
+ */
30333
+ const LockedFigureSelect = props => {
30334
+ const {
30335
+ id,
30336
+ onChange
30337
+ } = props;
30338
+ const figureTypes = ["point", "line", "vector", "ellipse", "polygon", "function"];
30339
+ if (props.showLabelsFlag) {
30340
+ figureTypes.push("label");
30341
+ }
30342
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30343
+ style: styles$C.container
30344
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionMenu, {
30345
+ menuText: "Add locked figure",
30346
+ style: styles$C.addElementSelect
30347
+ }, figureTypes.map(figureType => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
30348
+ key: `${id}-${figureType}`,
30349
+ label: figureType,
30350
+ onClick: () => onChange(figureType)
30351
+ }))));
30352
+ };
30353
+ const styles$C = aphrodite.StyleSheet.create({
30354
+ container: {
30355
+ marginTop: wonderBlocksTokens.spacing.xSmall_8
30356
+ },
30357
+ addElementSelect: {
30358
+ backgroundColor: wonderBlocksTokens.color.fadedBlue8,
30359
+ borderRadius: wonderBlocksTokens.spacing.xxxSmall_4
30360
+ }
30361
+ });
30362
+
30363
+ /**
30364
+ * This is a custom text field of type="number" for use in Perseus Editors.
30365
+ *
30366
+ * This makes it so that the text field's input number updates on scroll
30367
+ * without scrolling the page.
30368
+ *
30369
+ * NOTE 1: Native HTML number inputs do not update the number value on scroll,
30370
+ * they only scroll the page. Inputs in React do NOT work this way (explanation
30371
+ * here: https://stackoverflow.com/a/68266494). By default, scrolling on a
30372
+ * focused number input in React causes BOTH the input value to change AND
30373
+ * the page to scroll. The behavior in this component is an improvement on
30374
+ * the React behavior, but it's the opposite of the native HTML behavior.
30375
+ *
30376
+ * NOTE 2: Firefox seems to have a custom override for this. Even with this
30377
+ * stopPropogation, Firefox matches the native HTML behavior.
30378
+ */
30379
+ const ScrolllessNumberTextField = props => {
30380
+ const inputRef = React__namespace.useRef(null);
30381
+ React__namespace.useEffect(() => {
30382
+ const ref = inputRef.current;
30383
+
30384
+ // stopPropogation makes it so that the page scroll event is not
30385
+ // triggered when the input is focused and the user scrolls.
30386
+ // The input value will still change on scroll.
30387
+ const ignoreScroll = e => {
30388
+ e.stopPropagation();
30389
+ };
30390
+ ref?.addEventListener("wheel", ignoreScroll);
30391
+ return () => {
30392
+ ref?.removeEventListener("wheel", ignoreScroll);
30393
+ };
30394
+ }, [inputRef]);
30395
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, _extends({
30396
+ type: "number"
30397
+ }, props, {
30398
+ ref: inputRef
30399
+ }));
30400
+ };
30401
+
30402
+ function focusWithChromeStickyFocusBugWorkaround(element) {
30403
+ // NOTE(marksandstrom) Chrome sticky focus bug.
30404
+ //
30405
+ // There is a bug in Chrome related to sticky positioning and
30406
+ // focus: When a child of an element with sticky positioning is
30407
+ // focused with the focus() method, the scrollable area
30408
+ // containing that element will scroll to the top (even though
30409
+ // the element is already visble on the page). For a dropdown
30410
+ // this means that the area will be scrolled to the top when
30411
+ // the user interacts with the dropdown (since we actively
30412
+ // manage dropdown header and option focus for keyboard users).
30413
+ //
30414
+ // To work around this bug the `preventScroll` focus option is
30415
+ // used.
30416
+ //
30417
+ // Using `focusOptions` is an experimental browser feature
30418
+ // "that should not be used in production code". However, since
30419
+ // Chrome is the only browser we support that exhibits this
30420
+ // buggy behavior and using `focusOptions` works around the
30421
+ // bug, it is perfectly reasonable to use the feature in this
30422
+ // case. We are not relying on the effect of the
30423
+ // `preventScroll` option otherwise.
30424
+ //
30425
+ // focusOptions documentation:
30426
+ //
30427
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
30428
+ //
30429
+ // Note that there could be cases where we want default focus() behavior.
30430
+ // One that comes to mind is a dropdown with a long list of options that
30431
+ // might be rendered off screen when opened. With this workaround the
30432
+ // selected option would not be scrolled into view if the option is near
30433
+ // the end of the list. We're not aware of any uses of the dropdown where
30434
+ // this is an issue, however, so there isn't currently a way to out of the
30435
+ // `preventScroll` behavior.
30436
+
30437
+ // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element'.
30438
+ element.focus({
30439
+ preventScroll: true
30440
+ });
30441
+ }
30442
+ function degreeToRadian(degrees) {
30443
+ return degrees / 180 * Math.PI;
30444
+ }
30445
+ function radianToDegree(radians) {
30446
+ return radians / Math.PI * 180;
30447
+ }
30448
+
30449
+ const AngleInput = props => {
30450
+ const {
30451
+ angle,
30452
+ onChange
30453
+ } = props;
30454
+ const [angleInput, setAngleInput] = React__namespace.useState(radianToDegree(angle).toString());
30455
+ function handleAngleChange(newValue) {
30456
+ // Update the local state (update the input field value).
30457
+ setAngleInput(newValue);
30458
+
30459
+ // If the new value is not a number, don't update the props.
30460
+ // If it's empty, keep the props the same value instead of setting to 0.
30461
+ if (isNaN(+newValue) || newValue === "") {
30462
+ return;
30463
+ }
30464
+
30465
+ // Update the graph.
30466
+ onChange(degreeToRadian(newValue));
30467
+ }
30468
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30469
+ tag: "label",
30470
+ style: styles$B.row
30471
+ }, "angle (degrees)", /*#__PURE__*/React__namespace.createElement(Strut, {
30472
+ size: wonderBlocksTokens.spacing.xxSmall_6
30473
+ }), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
30474
+ value: angleInput,
30475
+ onChange: handleAngleChange,
30476
+ style: styles$B.textField
30477
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
30478
+ size: wonderBlocksTokens.spacing.xxSmall_6
30479
+ }));
30480
+ };
30481
+ const styles$B = aphrodite.StyleSheet.create({
30482
+ row: {
30483
+ display: "flex",
30484
+ flexDirection: "row",
30485
+ alignItems: "center"
30012
30486
  },
30013
30487
  textField: {
30014
30488
  width: wonderBlocksTokens.spacing.xxxLarge_64
@@ -30053,30 +30527,30 @@ const CoordinatePairInput = props => {
30053
30527
  onChange(newCoords);
30054
30528
  }
30055
30529
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30056
- style: [styles$F.row, style]
30530
+ style: [styles$A.row, style]
30057
30531
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30058
30532
  tag: "label",
30059
- style: styles$F.row
30533
+ style: styles$A.row
30060
30534
  }, labels ? labels[0] : "x coord", /*#__PURE__*/React__namespace.createElement(Strut, {
30061
30535
  size: wonderBlocksTokens.spacing.xxSmall_6
30062
30536
  }), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
30063
30537
  value: coordState[0],
30064
30538
  onChange: newValue => handleCoordChange(newValue, 0),
30065
- style: [styles$F.textField, error ? styles$F.errorField : undefined]
30539
+ style: [styles$A.textField, error ? styles$A.errorField : undefined]
30066
30540
  })), /*#__PURE__*/React__namespace.createElement(Strut, {
30067
30541
  size: wonderBlocksTokens.spacing.medium_16
30068
30542
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30069
30543
  tag: "label",
30070
- style: styles$F.row
30544
+ style: styles$A.row
30071
30545
  }, labels ? labels[1] : "y coord", /*#__PURE__*/React__namespace.createElement(Strut, {
30072
30546
  size: wonderBlocksTokens.spacing.xxSmall_6
30073
30547
  }), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
30074
30548
  value: coordState[1],
30075
30549
  onChange: newValue => handleCoordChange(newValue, 1),
30076
- style: [styles$F.textField, error ? styles$F.errorField : undefined]
30550
+ style: [styles$A.textField, error ? styles$A.errorField : undefined]
30077
30551
  })));
30078
30552
  };
30079
- const styles$F = aphrodite.StyleSheet.create({
30553
+ const styles$A = aphrodite.StyleSheet.create({
30080
30554
  row: {
30081
30555
  display: "flex",
30082
30556
  flexDirection: "row",
@@ -30109,14 +30583,14 @@ const PerseusEditorAccordion = props => {
30109
30583
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksAccordion.AccordionSection, {
30110
30584
  expanded: expanded,
30111
30585
  onToggle: onToggle,
30112
- style: [styles$E.container, containerStyle],
30113
- headerStyle: styles$E.accordionHeader,
30586
+ style: [styles$z.container, containerStyle],
30587
+ headerStyle: styles$z.accordionHeader,
30114
30588
  header: header
30115
30589
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30116
- style: [styles$E.accordionPanel, panelStyle]
30590
+ style: [styles$z.accordionPanel, panelStyle]
30117
30591
  }, children)));
30118
30592
  };
30119
- const styles$E = aphrodite.StyleSheet.create({
30593
+ const styles$z = aphrodite.StyleSheet.create({
30120
30594
  container: {
30121
30595
  backgroundColor: wonderBlocksTokens.color.fadedBlue8,
30122
30596
  marginTop: wonderBlocksTokens.spacing.xSmall_8
@@ -30147,13 +30621,13 @@ const ColorSwatch = props => {
30147
30621
  "aria-label":
30148
30622
  // Don't include an aria label for decorative circles.
30149
30623
  !decorative ? `${color}, ${filled ? "filled" : "open"}` : undefined,
30150
- style: [styles$D.colorSwatch, {
30624
+ style: [styles$y.colorSwatch, {
30151
30625
  border: `4px solid ${perseus.lockedFigureColors[color]}`,
30152
30626
  backgroundColor: filled ? perseus.lockedFigureColors[color] : wonderBlocksTokens.color.white
30153
30627
  }]
30154
30628
  });
30155
30629
  };
30156
- const styles$D = aphrodite.StyleSheet.create({
30630
+ const styles$y = aphrodite.StyleSheet.create({
30157
30631
  colorSwatch: {
30158
30632
  // Add a white outline so that the color swatch is visible when
30159
30633
  // the dropdown option is highlighted with its blue background.
@@ -30172,10 +30646,10 @@ const ColorSelect = props => {
30172
30646
  onChange
30173
30647
  } = props;
30174
30648
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30175
- style: [styles$C.row, style]
30649
+ style: [styles$x.row, style]
30176
30650
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30177
30651
  tag: "label",
30178
- style: styles$C.row
30652
+ style: styles$x.row
30179
30653
  }, "color", /*#__PURE__*/React__namespace.createElement(Strut, {
30180
30654
  size: wonderBlocksTokens.spacing.xxSmall_6
30181
30655
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -30194,7 +30668,7 @@ const ColorSelect = props => {
30194
30668
  })
30195
30669
  })))));
30196
30670
  };
30197
- const styles$C = aphrodite.StyleSheet.create({
30671
+ const styles$x = aphrodite.StyleSheet.create({
30198
30672
  row: {
30199
30673
  display: "flex",
30200
30674
  flexDirection: "row",
@@ -30213,17 +30687,17 @@ const EllipseSwatch = props => {
30213
30687
  } = props;
30214
30688
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30215
30689
  "aria-label": `${color}, stroke ${strokeStyle}, fill ${fillStyle}`,
30216
- style: [styles$B.container, {
30690
+ style: [styles$w.container, {
30217
30691
  border: `4px ${strokeStyle} ${perseus.lockedFigureColors[color]}`
30218
30692
  }]
30219
30693
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30220
- style: [styles$B.innerCircle, {
30694
+ style: [styles$w.innerCircle, {
30221
30695
  backgroundColor: perseus.lockedFigureColors[color],
30222
30696
  opacity: fillStyle === "white" ? 0 : perseus.lockedFigureFillStyles[fillStyle]
30223
30697
  }]
30224
30698
  }));
30225
30699
  };
30226
- const styles$B = aphrodite.StyleSheet.create({
30700
+ const styles$w = aphrodite.StyleSheet.create({
30227
30701
  container: {
30228
30702
  // Add a white outline so that the color swatch is visible when
30229
30703
  // the dropdown option is highlighted with its blue background.
@@ -30249,7 +30723,7 @@ const LineStrokeSelect = props => {
30249
30723
  } = props;
30250
30724
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30251
30725
  tag: "label",
30252
- style: styles$A.lineStrokeSelect
30726
+ style: styles$v.lineStrokeSelect
30253
30727
  }, "stroke", /*#__PURE__*/React__namespace.createElement(Strut, {
30254
30728
  size: wonderBlocksTokens.spacing.xxxSmall_4
30255
30729
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -30266,7 +30740,7 @@ const LineStrokeSelect = props => {
30266
30740
  label: "dashed"
30267
30741
  })));
30268
30742
  };
30269
- const styles$A = aphrodite.StyleSheet.create({
30743
+ const styles$v = aphrodite.StyleSheet.create({
30270
30744
  lineStrokeSelect: {
30271
30745
  display: "flex",
30272
30746
  flexDirection: "row",
@@ -30288,40 +30762,40 @@ const LockedFigureSettingsActions = props => {
30288
30762
  onRemove
30289
30763
  } = props;
30290
30764
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30291
- style: styles$z.container
30765
+ style: styles$u.container
30292
30766
  }, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
30293
30767
  startIcon: trashIcon__default["default"],
30294
30768
  "aria-label": `Delete locked ${figureType}`,
30295
30769
  onClick: onRemove,
30296
30770
  kind: "tertiary",
30297
- style: styles$z.deleteButton
30298
- }, "Delete"), /*#__PURE__*/React__namespace.createElement(Spring, null), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30771
+ style: styles$u.deleteButton
30772
+ }, "Delete"), onMove && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Spring, null), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30299
30773
  icon: caretDoubleUpIcon__default["default"],
30300
30774
  size: "small",
30301
30775
  "aria-label": `Move locked ${figureType} to the back`,
30302
30776
  onClick: () => onMove("back"),
30303
- style: styles$z.iconButton
30777
+ style: styles$u.iconButton
30304
30778
  }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30305
30779
  icon: caretUpIcon__default["default"],
30306
30780
  size: "small",
30307
30781
  "aria-label": `Move locked ${figureType} backward`,
30308
30782
  onClick: () => onMove("backward"),
30309
- style: styles$z.iconButton
30783
+ style: styles$u.iconButton
30310
30784
  }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30311
30785
  icon: caretDownIcon__default["default"],
30312
30786
  size: "small",
30313
30787
  "aria-label": `Move locked ${figureType} forward`,
30314
30788
  onClick: () => onMove("forward"),
30315
- style: styles$z.iconButton
30789
+ style: styles$u.iconButton
30316
30790
  }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30317
30791
  icon: caretDoubleDownIcon__default["default"],
30318
30792
  size: "small",
30319
30793
  "aria-label": `Move locked ${figureType} to the front`,
30320
30794
  onClick: () => onMove("front"),
30321
- style: styles$z.iconButton
30322
- }));
30795
+ style: styles$u.iconButton
30796
+ })));
30323
30797
  };
30324
- const styles$z = aphrodite.StyleSheet.create({
30798
+ const styles$u = aphrodite.StyleSheet.create({
30325
30799
  container: {
30326
30800
  width: "100%",
30327
30801
  flexDirection: "row",
@@ -30340,7 +30814,7 @@ const styles$z = aphrodite.StyleSheet.create({
30340
30814
  });
30341
30815
 
30342
30816
  const {
30343
- InfoTip: InfoTip$d
30817
+ InfoTip: InfoTip$c
30344
30818
  } = perseus.components;
30345
30819
  const LockedEllipseSettings = props => {
30346
30820
  const {
@@ -30368,7 +30842,7 @@ const LockedEllipseSettings = props => {
30368
30842
  /*#__PURE__*/
30369
30843
  // Summary: Ellipse, center, radius, color (opacity, dashed)
30370
30844
  React__namespace.createElement(wonderBlocksCore.View, {
30371
- style: styles$y.row
30845
+ style: styles$t.row
30372
30846
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`), /*#__PURE__*/React__namespace.createElement(Strut, {
30373
30847
  size: wonderBlocksTokens.spacing.xSmall_8
30374
30848
  }), /*#__PURE__*/React__namespace.createElement(EllipseSwatch, {
@@ -30377,19 +30851,19 @@ const LockedEllipseSettings = props => {
30377
30851
  strokeStyle: strokeStyle
30378
30852
  }))
30379
30853
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30380
- style: styles$y.row
30854
+ style: styles$t.row
30381
30855
  }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
30382
30856
  coord: center,
30383
- style: styles$y.spaceUnder,
30857
+ style: styles$t.spaceUnder,
30384
30858
  onChange: newCoords => onChangeProps({
30385
30859
  center: newCoords
30386
30860
  })
30387
30861
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30388
- style: styles$y.spaceUnder
30389
- }, /*#__PURE__*/React__namespace.createElement(InfoTip$d, null, "The coordinates for the center of the ellipse."))), /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
30862
+ style: styles$t.spaceUnder
30863
+ }, /*#__PURE__*/React__namespace.createElement(InfoTip$c, null, "The coordinates for the center of the ellipse."))), /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
30390
30864
  coord: radius,
30391
30865
  labels: ["x radius", "y radius"],
30392
- style: styles$y.spaceUnder,
30866
+ style: styles$t.spaceUnder,
30393
30867
  onChange: newCoords => onChangeProps({
30394
30868
  radius: newCoords
30395
30869
  })
@@ -30401,7 +30875,7 @@ const LockedEllipseSettings = props => {
30401
30875
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
30402
30876
  size: wonderBlocksTokens.spacing.xSmall_8
30403
30877
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30404
- style: [styles$y.row, styles$y.spaceUnder]
30878
+ style: [styles$t.row, styles$t.spaceUnder]
30405
30879
  }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30406
30880
  selectedValue: color,
30407
30881
  onChange: handleColorChange
@@ -30409,7 +30883,7 @@ const LockedEllipseSettings = props => {
30409
30883
  size: wonderBlocksTokens.spacing.medium_16
30410
30884
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30411
30885
  tag: "label",
30412
- style: [styles$y.row, styles$y.truncatedWidth]
30886
+ style: [styles$t.row, styles$t.truncatedWidth]
30413
30887
  }, "fill", /*#__PURE__*/React__namespace.createElement(Strut, {
30414
30888
  size: wonderBlocksTokens.spacing.xxSmall_6
30415
30889
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -30435,7 +30909,7 @@ const LockedEllipseSettings = props => {
30435
30909
  onRemove: onRemove
30436
30910
  }));
30437
30911
  };
30438
- const styles$y = aphrodite.StyleSheet.create({
30912
+ const styles$t = aphrodite.StyleSheet.create({
30439
30913
  row: {
30440
30914
  display: "flex",
30441
30915
  flexDirection: "row",
@@ -30456,15 +30930,15 @@ const LineSwatch = props => {
30456
30930
  lineStyle
30457
30931
  } = props;
30458
30932
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30459
- style: styles$x.container
30933
+ style: styles$s.container
30460
30934
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30461
30935
  "aria-label": `${color}, ${lineStyle}`,
30462
- style: [styles$x.lineSwatch, {
30936
+ style: [styles$s.lineSwatch, {
30463
30937
  border: `5px ${lineStyle} ${perseus.lockedFigureColors[color]}`
30464
30938
  }]
30465
30939
  }));
30466
30940
  };
30467
- const styles$x = aphrodite.StyleSheet.create({
30941
+ const styles$s = aphrodite.StyleSheet.create({
30468
30942
  container: {
30469
30943
  backgroundColor: wonderBlocksTokens.color.white,
30470
30944
  justifyContent: "center",
@@ -30549,9 +31023,9 @@ const LockedFunctionSettings = props => {
30549
31023
  expanded: props.expanded,
30550
31024
  onToggle: props.onToggle,
30551
31025
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30552
- style: styles$w.row
31026
+ style: styles$r.row
30553
31027
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
30554
- style: styles$w.accordionHeader
31028
+ style: styles$r.accordionHeader
30555
31029
  }, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
30556
31030
  size: wonderBlocksTokens.spacing.xSmall_8
30557
31031
  }), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
@@ -30559,7 +31033,7 @@ const LockedFunctionSettings = props => {
30559
31033
  lineStyle: strokeStyle
30560
31034
  }))
30561
31035
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30562
- style: [styles$w.row, styles$w.spaceUnder]
31036
+ style: [styles$r.row, styles$r.spaceUnder]
30563
31037
  }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30564
31038
  selectedValue: lineColor,
30565
31039
  onChange: newValue => {
@@ -30573,14 +31047,14 @@ const LockedFunctionSettings = props => {
30573
31047
  handlePropChange("strokeStyle", newValue);
30574
31048
  }
30575
31049
  })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30576
- style: [styles$w.row, styles$w.rowSpace]
31050
+ style: [styles$r.row, styles$r.rowSpace]
30577
31051
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
30578
31052
  selectedValue: directionalAxis,
30579
31053
  onChange: newValue => {
30580
31054
  handlePropChange("directionalAxis", newValue);
30581
31055
  },
30582
31056
  "aria-label": "equation prefix",
30583
- style: [styles$w.dropdownLabel, styles$w.axisMenu]
31057
+ style: [styles$r.dropdownLabel, styles$r.axisMenu]
30584
31058
  // Placeholder is required, but never gets used.
30585
31059
  ,
30586
31060
  placeholder: ""
@@ -30599,17 +31073,17 @@ const LockedFunctionSettings = props => {
30599
31073
  onChange: newValue => {
30600
31074
  handlePropChange("equation", newValue);
30601
31075
  },
30602
- style: [styles$w.textField]
31076
+ style: [styles$r.textField]
30603
31077
  })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30604
- style: [styles$w.row, styles$w.rowSpace]
31078
+ style: [styles$r.row, styles$r.rowSpace]
30605
31079
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30606
31080
  tag: "label",
30607
- style: [styles$w.dropdownLabel, styles$w.domainMin]
31081
+ style: [styles$r.dropdownLabel, styles$r.domainMin]
30608
31082
  }, `${domainRangeText} min`, /*#__PURE__*/React__namespace.createElement(Strut, {
30609
31083
  size: wonderBlocksTokens.spacing.xxSmall_6
30610
31084
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30611
31085
  type: "number",
30612
- style: styles$w.domainMinField,
31086
+ style: styles$r.domainMinField,
30613
31087
  value: domainEntries[0],
30614
31088
  onChange: newValue => {
30615
31089
  handleDomainChange(0, newValue);
@@ -30619,12 +31093,12 @@ const LockedFunctionSettings = props => {
30619
31093
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30620
31094
  tag: "label",
30621
31095
  "aria-label": `${domainRangeText} max`,
30622
- style: [styles$w.dropdownLabel, styles$w.domainMax]
31096
+ style: [styles$r.dropdownLabel, styles$r.domainMax]
30623
31097
  }, "max", /*#__PURE__*/React__namespace.createElement(Strut, {
30624
31098
  size: wonderBlocksTokens.spacing.xxSmall_6
30625
31099
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
30626
31100
  type: "number",
30627
- style: styles$w.domainMaxField,
31101
+ style: styles$r.domainMaxField,
30628
31102
  value: domainEntries[1],
30629
31103
  onChange: newValue => {
30630
31104
  handleDomainChange(1, newValue);
@@ -30632,11 +31106,11 @@ const LockedFunctionSettings = props => {
30632
31106
  }))), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
30633
31107
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Example Functions"),
30634
31108
  expanded: false,
30635
- containerStyle: styles$w.exampleWorkspace,
30636
- panelStyle: styles$w.exampleAccordionPanel
31109
+ containerStyle: styles$r.exampleWorkspace,
31110
+ panelStyle: styles$r.exampleAccordionPanel
30637
31111
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30638
31112
  tag: "label",
30639
- style: styles$w.dropdownLabel
31113
+ style: styles$r.dropdownLabel
30640
31114
  }, "Choose a category", /*#__PURE__*/React__namespace.createElement(Strut, {
30641
31115
  size: wonderBlocksTokens.spacing.xxSmall_6
30642
31116
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -30650,7 +31124,7 @@ const LockedFunctionSettings = props => {
30650
31124
  label: category
30651
31125
  });
30652
31126
  }))), exampleCategorySelected && /*#__PURE__*/React__namespace.createElement("ul", {
30653
- className: aphrodite.css(styles$w.exampleContainer)
31127
+ className: aphrodite.css(styles$r.exampleContainer)
30654
31128
  }, exampleContent.map((example, index) => /*#__PURE__*/React__namespace.createElement(ExampleItem, {
30655
31129
  category: exampleCategory,
30656
31130
  example: example,
@@ -30672,29 +31146,29 @@ const ExampleItem = props => {
30672
31146
  const exampleId = React.useId();
30673
31147
  return /*#__PURE__*/React__namespace.createElement("li", {
30674
31148
  key: `${category}-${index}`,
30675
- className: aphrodite.css(styles$w.exampleRow)
31149
+ className: aphrodite.css(styles$r.exampleRow)
30676
31150
  }, /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30677
31151
  icon: autoPasteIcon__default["default"],
30678
31152
  "aria-label": "paste example",
30679
31153
  "aria-describedby": exampleId,
30680
31154
  onClick: () => pasteEquationFn("equation", example),
30681
31155
  size: "medium",
30682
- style: styles$w.copyPasteButton
31156
+ style: styles$r.copyPasteButton
30683
31157
  }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30684
31158
  icon: copyIcon__default["default"],
30685
31159
  "aria-label": "copy example",
30686
31160
  "aria-describedby": exampleId,
30687
31161
  onClick: () => navigator.clipboard.writeText(example),
30688
31162
  size: "medium",
30689
- style: styles$w.copyPasteButton
31163
+ style: styles$r.copyPasteButton
30690
31164
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
30691
31165
  size: wonderBlocksTokens.spacing.xxxSmall_4
30692
31166
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30693
- style: styles$w.exampleContent,
31167
+ style: styles$r.exampleContent,
30694
31168
  id: exampleId
30695
31169
  }, example));
30696
31170
  };
30697
- const styles$w = aphrodite.StyleSheet.create({
31171
+ const styles$r = aphrodite.StyleSheet.create({
30698
31172
  accordionHeader: {
30699
31173
  textOverflow: "ellipsis",
30700
31174
  // A maximum width needs to be specified in order for the ellipsis to work.
@@ -30812,15 +31286,16 @@ function LockedLabelSettings(props) {
30812
31286
  expanded: expanded,
30813
31287
  onToggle: onToggle,
30814
31288
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30815
- style: [styles$v.row, styles$v.accordionHeaderContainer]
31289
+ style: [styles$q.row, styles$q.accordionHeaderContainer]
30816
31290
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Label (", coord[0], ", ", coord[1], ")"), /*#__PURE__*/React__namespace.createElement(Strut, {
30817
31291
  size: wonderBlocksTokens.spacing.xSmall_8
30818
31292
  }), text !== "" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
30819
31293
  style: [{
30820
31294
  backgroundColor: wonderBlocksTokens.color.white,
30821
31295
  color: perseus.lockedFigureColors[color]
30822
- }, styles$v.accordionHeader]
30823
- }, text))
31296
+ }, styles$q.accordionHeader]
31297
+ }, text)),
31298
+ containerStyle: !onMove && styles$q.innerLabelAccordionPanel
30824
31299
  }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
30825
31300
  coord: coord,
30826
31301
  onChange: newCoords => {
@@ -30828,10 +31303,10 @@ function LockedLabelSettings(props) {
30828
31303
  coord: newCoords
30829
31304
  });
30830
31305
  },
30831
- style: styles$v.spaceUnder
31306
+ style: styles$q.spaceUnder
30832
31307
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30833
31308
  tag: "label",
30834
- style: [styles$v.row, styles$v.spaceUnder]
31309
+ style: [styles$q.row, styles$q.spaceUnder]
30835
31310
  }, "TeX", /*#__PURE__*/React__namespace.createElement(Strut, {
30836
31311
  size: wonderBlocksTokens.spacing.xSmall_8
30837
31312
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
@@ -30841,20 +31316,20 @@ function LockedLabelSettings(props) {
30841
31316
  text: newValue
30842
31317
  })
30843
31318
  })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30844
- style: styles$v.row
30845
- }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31319
+ style: styles$q.row
31320
+ }, onMove && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30846
31321
  selectedValue: color,
30847
31322
  onChange: newColor => {
30848
31323
  onChangeProps({
30849
31324
  color: newColor
30850
31325
  });
30851
31326
  },
30852
- style: styles$v.spaceUnder
31327
+ style: styles$q.spaceUnder
30853
31328
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
30854
31329
  size: wonderBlocksTokens.spacing.medium_16
30855
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31330
+ })), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
30856
31331
  tag: "label",
30857
- style: styles$v.row
31332
+ style: styles$q.row
30858
31333
  }, "size", /*#__PURE__*/React__namespace.createElement(Strut, {
30859
31334
  size: wonderBlocksTokens.spacing.xSmall_8
30860
31335
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -30881,7 +31356,7 @@ function LockedLabelSettings(props) {
30881
31356
  onRemove: onRemove
30882
31357
  }));
30883
31358
  }
30884
- const styles$v = aphrodite.StyleSheet.create({
31359
+ const styles$q = aphrodite.StyleSheet.create({
30885
31360
  accordionHeaderContainer: {
30886
31361
  // Stop the label summary from wrapping.
30887
31362
  whiteSpace: "nowrap"
@@ -30902,6 +31377,9 @@ const styles$v = aphrodite.StyleSheet.create({
30902
31377
  },
30903
31378
  spaceUnder: {
30904
31379
  marginBottom: wonderBlocksTokens.spacing.xSmall_8
31380
+ },
31381
+ innerLabelAccordionPanel: {
31382
+ backgroundColor: wonderBlocksTokens.color.white
30905
31383
  }
30906
31384
  });
30907
31385
 
@@ -30915,7 +31393,7 @@ const LabeledSwitch = props => {
30915
31393
  const ids = wonderBlocksCore.useUniqueIdWithMock();
30916
31394
  const switchId = ids.get("switch");
30917
31395
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30918
- style: [styles$u.row, style]
31396
+ style: [styles$p.row, style]
30919
31397
  }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
30920
31398
  id: switchId,
30921
31399
  checked: checked,
@@ -30927,7 +31405,7 @@ const LabeledSwitch = props => {
30927
31405
  htmlFor: switchId
30928
31406
  }, label));
30929
31407
  };
30930
- const styles$u = aphrodite.StyleSheet.create({
31408
+ const styles$p = aphrodite.StyleSheet.create({
30931
31409
  row: {
30932
31410
  flexDirection: "row",
30933
31411
  alignItems: "center"
@@ -30961,13 +31439,13 @@ const DefiningPointSettings = props => {
30961
31439
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
30962
31440
  expanded: expanded,
30963
31441
  onToggle: onToggle,
30964
- containerStyle: styles$t.container,
30965
- panelStyle: styles$t.accordionPanel,
31442
+ containerStyle: styles$o.container,
31443
+ panelStyle: styles$o.accordionPanel,
30966
31444
  header:
30967
31445
  /*#__PURE__*/
30968
31446
  // Summary: Point, coords, color (filled/open)
30969
31447
  React__namespace.createElement(wonderBlocksCore.View, {
30970
- style: styles$t.row
31448
+ style: styles$o.row
30971
31449
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `${label || "Point"} (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React__namespace.createElement(Strut, {
30972
31450
  size: wonderBlocksTokens.spacing.xSmall_8
30973
31451
  }), showPoint && /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
@@ -30977,7 +31455,7 @@ const DefiningPointSettings = props => {
30977
31455
  }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
30978
31456
  coord: coord,
30979
31457
  error: !!error,
30980
- style: styles$t.spaceUnder,
31458
+ style: styles$o.spaceUnder,
30981
31459
  onChange: newCoords => {
30982
31460
  onChangeProps({
30983
31461
  coord: newCoords
@@ -30986,12 +31464,12 @@ const DefiningPointSettings = props => {
30986
31464
  }), onTogglePoint && /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
30987
31465
  label: "show point on graph",
30988
31466
  checked: !!showPoint,
30989
- style: showPoint && styles$t.spaceUnder,
31467
+ style: showPoint && styles$o.spaceUnder,
30990
31468
  onChange: onTogglePoint
30991
31469
  }), showPoint && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
30992
31470
  selectedValue: pointColor,
30993
31471
  onChange: handleColorChange,
30994
- style: styles$t.spaceUnder
31472
+ style: styles$o.spaceUnder
30995
31473
  }), /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
30996
31474
  label: "open point",
30997
31475
  checked: !filled,
@@ -31002,7 +31480,7 @@ const DefiningPointSettings = props => {
31002
31480
  }
31003
31481
  })));
31004
31482
  };
31005
- const styles$t = aphrodite.StyleSheet.create({
31483
+ const styles$o = aphrodite.StyleSheet.create({
31006
31484
  container: {
31007
31485
  marginTop: wonderBlocksTokens.spacing.xSmall_8,
31008
31486
  marginBottom: 0,
@@ -31070,7 +31548,7 @@ const LockedLineSettings = props => {
31070
31548
  expanded: props.expanded,
31071
31549
  onToggle: props.onToggle,
31072
31550
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31073
- style: styles$s.row
31551
+ style: styles$n.row
31074
31552
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
31075
31553
  size: wonderBlocksTokens.spacing.xSmall_8
31076
31554
  }), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
@@ -31079,7 +31557,7 @@ const LockedLineSettings = props => {
31079
31557
  }))
31080
31558
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31081
31559
  tag: "label",
31082
- style: [styles$s.row, styles$s.spaceUnder]
31560
+ style: [styles$n.row, styles$n.spaceUnder]
31083
31561
  }, "kind", /*#__PURE__*/React__namespace.createElement(Strut, {
31084
31562
  size: wonderBlocksTokens.spacing.xxxSmall_4
31085
31563
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -31100,7 +31578,7 @@ const LockedLineSettings = props => {
31100
31578
  value: "segment",
31101
31579
  label: "segment"
31102
31580
  }))), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31103
- style: styles$s.row
31581
+ style: styles$n.row
31104
31582
  }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31105
31583
  selectedValue: lineColor,
31106
31584
  onChange: handleColorChange
@@ -31112,7 +31590,7 @@ const LockedLineSettings = props => {
31112
31590
  lineStyle: value
31113
31591
  })
31114
31592
  })), isInvalid && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31115
- style: styles$s.errorText
31593
+ style: styles$n.errorText
31116
31594
  }, lengthZeroStr), /*#__PURE__*/React__namespace.createElement(DefiningPointSettings, _extends({
31117
31595
  label: "Point 1",
31118
31596
  showPoint: showPoint1,
@@ -31137,7 +31615,7 @@ const LockedLineSettings = props => {
31137
31615
  onRemove: onRemove
31138
31616
  }));
31139
31617
  };
31140
- const styles$s = aphrodite.StyleSheet.create({
31618
+ const styles$n = aphrodite.StyleSheet.create({
31141
31619
  row: {
31142
31620
  display: "flex",
31143
31621
  flexDirection: "row",
@@ -31151,24 +31629,127 @@ const styles$s = aphrodite.StyleSheet.create({
31151
31629
  }
31152
31630
  });
31153
31631
 
31154
- /**
31155
- * LockedPointSettings is a component that allows the user to edit the
31156
- * settings of specifically a locked point on the graph.
31157
- *
31158
- * Used in the interactive graph editor's locked figures section.
31159
- */
31632
+ const DEFAULT_COLOR = "grayH";
31633
+ function getDefaultFigureForType(type) {
31634
+ switch (type) {
31635
+ case "point":
31636
+ return {
31637
+ type: "point",
31638
+ coord: [0, 0],
31639
+ color: DEFAULT_COLOR,
31640
+ filled: true,
31641
+ labels: []
31642
+ };
31643
+ case "line":
31644
+ return {
31645
+ type: "line",
31646
+ kind: "line",
31647
+ points: [getDefaultFigureForType("point"), {
31648
+ ...getDefaultFigureForType("point"),
31649
+ coord: [2, 2]
31650
+ }],
31651
+ color: DEFAULT_COLOR,
31652
+ lineStyle: "solid",
31653
+ showPoint1: false,
31654
+ showPoint2: false
31655
+ };
31656
+ case "vector":
31657
+ return {
31658
+ type: "vector",
31659
+ points: [[0, 0], [2, 2]],
31660
+ color: DEFAULT_COLOR
31661
+ };
31662
+ case "ellipse":
31663
+ return {
31664
+ type: "ellipse",
31665
+ center: [0, 0],
31666
+ radius: [1, 1],
31667
+ angle: 0,
31668
+ color: DEFAULT_COLOR,
31669
+ fillStyle: "none",
31670
+ strokeStyle: "solid"
31671
+ };
31672
+ case "polygon":
31673
+ return {
31674
+ type: "polygon",
31675
+ points: [[0, 2], [-1, 0], [1, 0]],
31676
+ color: DEFAULT_COLOR,
31677
+ showVertices: false,
31678
+ fillStyle: "none",
31679
+ strokeStyle: "solid"
31680
+ };
31681
+ case "function":
31682
+ return {
31683
+ type: "function",
31684
+ color: DEFAULT_COLOR,
31685
+ strokeStyle: "solid",
31686
+ equation: "x^2",
31687
+ directionalAxis: "x"
31688
+ };
31689
+ case "label":
31690
+ return {
31691
+ type: "label",
31692
+ coord: [0, 0],
31693
+ text: "",
31694
+ color: DEFAULT_COLOR,
31695
+ size: "medium"
31696
+ };
31697
+ default:
31698
+ throw new wonderStuffCore.UnreachableCaseError(type);
31699
+ }
31700
+ }
31701
+
31160
31702
  const LockedPointSettings = props => {
31161
31703
  const {
31704
+ flags,
31162
31705
  coord,
31163
31706
  color: pointColor,
31164
31707
  filled = true,
31708
+ labels,
31165
31709
  onChangeProps,
31166
31710
  onMove,
31167
31711
  onRemove
31168
31712
  } = props;
31169
31713
  function handleColorChange(newValue) {
31170
- onChangeProps({
31714
+ const newProps = {
31715
+ color: newValue
31716
+ };
31717
+
31718
+ // Update the color of the all labels to match the point
31719
+ newProps.labels = labels.map(label => ({
31720
+ ...label,
31171
31721
  color: newValue
31722
+ }));
31723
+ onChangeProps(newProps);
31724
+ }
31725
+ function handleCoordChange(newCoord) {
31726
+ const xOffset = newCoord[0] - coord[0];
31727
+ const yOffset = newCoord[1] - coord[1];
31728
+ const newProps = {
31729
+ coord: newCoord
31730
+ };
31731
+
31732
+ // Update the coord by the same amount as the point for all labels
31733
+ newProps.labels = labels.map(label => ({
31734
+ ...label,
31735
+ coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31736
+ }));
31737
+ onChangeProps(newProps);
31738
+ }
31739
+ function handleLabelChange(updatedLabel, labelIndex) {
31740
+ const updatedLabels = [...labels];
31741
+ updatedLabels[labelIndex] = {
31742
+ ...labels[labelIndex],
31743
+ ...updatedLabel
31744
+ };
31745
+ onChangeProps({
31746
+ labels: updatedLabels
31747
+ });
31748
+ }
31749
+ function handleLabelRemove(labelIndex) {
31750
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31751
+ onChangeProps({
31752
+ labels: updatedLabels
31172
31753
  });
31173
31754
  }
31174
31755
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
@@ -31178,7 +31759,7 @@ const LockedPointSettings = props => {
31178
31759
  /*#__PURE__*/
31179
31760
  // Summary: Point, coords, color (filled/open)
31180
31761
  React__namespace.createElement(wonderBlocksCore.View, {
31181
- style: styles$r.row
31762
+ style: styles$m.row
31182
31763
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Point (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React__namespace.createElement(Strut, {
31183
31764
  size: wonderBlocksTokens.spacing.xSmall_8
31184
31765
  }), /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
@@ -31186,17 +31767,13 @@ const LockedPointSettings = props => {
31186
31767
  filled: filled
31187
31768
  }))
31188
31769
  }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31189
- coord: coord,
31190
- style: styles$r.spaceUnder,
31191
- onChange: newCoord => {
31192
- onChangeProps({
31193
- coord: newCoord
31194
- });
31195
- }
31770
+ coord: coord,
31771
+ style: styles$m.spaceUnder,
31772
+ onChange: handleCoordChange
31196
31773
  }), /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31197
31774
  selectedValue: pointColor,
31198
31775
  onChange: handleColorChange,
31199
- style: styles$r.spaceUnder
31776
+ style: styles$m.spaceUnder
31200
31777
  }), /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
31201
31778
  label: "open point",
31202
31779
  checked: !filled,
@@ -31204,20 +31781,53 @@ const LockedPointSettings = props => {
31204
31781
  onChangeProps({
31205
31782
  filled: !newValue
31206
31783
  });
31784
+ },
31785
+ style: styles$m.spaceUnder
31786
+ }), flags?.["mafs"]?.["locked-point-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, labels.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
31787
+ expanded: true,
31788
+ onChangeProps: newLabel => {
31789
+ handleLabelChange(newLabel, labelIndex);
31790
+ },
31791
+ onRemove: () => {
31792
+ handleLabelRemove(labelIndex);
31207
31793
  }
31208
- }), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31794
+ }))), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
31795
+ kind: "tertiary",
31796
+ startIcon: plusCircle__default["default"],
31797
+ onClick: () => {
31798
+ const newLabel = {
31799
+ ...getDefaultFigureForType("label"),
31800
+ // Place the label at the same position
31801
+ // as the point. Add a small offset to
31802
+ // avoid crowding.
31803
+ coord: [coord[0] + 0.5,
31804
+ // Additional offset for each label so
31805
+ // they don't overlap.
31806
+ coord[1] - 1 * labels?.length],
31807
+ // Default to the same color as the point
31808
+ color: pointColor
31809
+ };
31810
+ onChangeProps({
31811
+ labels: [...labels, newLabel]
31812
+ });
31813
+ },
31814
+ style: styles$m.addButton
31815
+ }, "Add visible label")), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31209
31816
  figureType: props.type,
31210
31817
  onMove: onMove,
31211
31818
  onRemove: onRemove
31212
31819
  }));
31213
31820
  };
31214
- const styles$r = aphrodite.StyleSheet.create({
31821
+ const styles$m = aphrodite.StyleSheet.create({
31215
31822
  row: {
31216
31823
  flexDirection: "row",
31217
31824
  alignItems: "center"
31218
31825
  },
31219
31826
  spaceUnder: {
31220
31827
  marginBottom: wonderBlocksTokens.spacing.xSmall_8
31828
+ },
31829
+ addButton: {
31830
+ alignSelf: "start"
31221
31831
  }
31222
31832
  });
31223
31833
 
@@ -31229,17 +31839,17 @@ const PolygonSwatch = props => {
31229
31839
  } = props;
31230
31840
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31231
31841
  "aria-label": `${color}, stroke ${strokeStyle}, fill ${fillStyle}`,
31232
- style: [styles$q.container, {
31842
+ style: [styles$l.container, {
31233
31843
  border: `4px ${strokeStyle} ${perseus.lockedFigureColors[color]}`
31234
31844
  }]
31235
31845
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31236
- style: [styles$q.innerSquare, {
31846
+ style: [styles$l.innerSquare, {
31237
31847
  backgroundColor: perseus.lockedFigureColors[color],
31238
31848
  opacity: fillStyle === "white" ? 0 : perseus.lockedFigureFillStyles[fillStyle]
31239
31849
  }]
31240
31850
  }));
31241
31851
  };
31242
- const styles$q = aphrodite.StyleSheet.create({
31852
+ const styles$l = aphrodite.StyleSheet.create({
31243
31853
  container: {
31244
31854
  // Add a white outline so that the color swatch is visible when
31245
31855
  // the dropdown option is highlighted with its blue background.
@@ -31317,7 +31927,7 @@ const LockedPolygonSettings = props => {
31317
31927
  /*#__PURE__*/
31318
31928
  // Summary: Polygon, number of sides, style swatch
31319
31929
  React__namespace.createElement(wonderBlocksCore.View, {
31320
- style: styles$p.row
31930
+ style: styles$k.row
31321
31931
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Polygon, ${points.length} sides`), /*#__PURE__*/React__namespace.createElement(Strut, {
31322
31932
  size: wonderBlocksTokens.spacing.xSmall_8
31323
31933
  }), /*#__PURE__*/React__namespace.createElement(PolygonSwatch, {
@@ -31326,7 +31936,7 @@ const LockedPolygonSettings = props => {
31326
31936
  strokeStyle: strokeStyle
31327
31937
  }))
31328
31938
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31329
- style: [styles$p.row, styles$p.spaceUnder]
31939
+ style: [styles$k.row, styles$k.spaceUnder]
31330
31940
  }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31331
31941
  selectedValue: color,
31332
31942
  onChange: handleColorChange
@@ -31334,7 +31944,7 @@ const LockedPolygonSettings = props => {
31334
31944
  size: wonderBlocksTokens.spacing.medium_16
31335
31945
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31336
31946
  tag: "label",
31337
- style: [styles$p.row, styles$p.truncatedWidth]
31947
+ style: [styles$k.row, styles$k.truncatedWidth]
31338
31948
  }, "fill", /*#__PURE__*/React__namespace.createElement(Strut, {
31339
31949
  size: wonderBlocksTokens.spacing.xxSmall_6
31340
31950
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
@@ -31360,17 +31970,17 @@ const LockedPolygonSettings = props => {
31360
31970
  onChange: newValue => onChangeProps({
31361
31971
  showVertices: newValue
31362
31972
  }),
31363
- style: styles$p.spaceUnder
31973
+ style: styles$k.spaceUnder
31364
31974
  }), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31365
31975
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Points"),
31366
31976
  expanded: true,
31367
- containerStyle: styles$p.pointAccordionContainer,
31368
- panelStyle: styles$p.pointAccordionPanel
31977
+ containerStyle: styles$k.pointAccordionContainer,
31978
+ panelStyle: styles$k.pointAccordionPanel
31369
31979
  }, points.map((point, index) => {
31370
31980
  const pointLabel = String.fromCharCode(65 + index);
31371
31981
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31372
31982
  key: `locked-polygon-point-index-${index}`,
31373
- style: [styles$p.row, styles$p.spaceUnder]
31983
+ style: [styles$k.row, styles$k.spaceUnder]
31374
31984
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `${pointLabel}:`), /*#__PURE__*/React__namespace.createElement(Strut, {
31375
31985
  size: wonderBlocksTokens.spacing.medium_16
31376
31986
  }), /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
@@ -31398,10 +32008,10 @@ const LockedPolygonSettings = props => {
31398
32008
  points: newPoints
31399
32009
  });
31400
32010
  },
31401
- style: styles$p.icon
32011
+ style: styles$k.icon
31402
32012
  }));
31403
32013
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31404
- style: [styles$p.row, styles$p.polygonActionsContainer]
32014
+ style: [styles$k.row, styles$k.polygonActionsContainer]
31405
32015
  }, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
31406
32016
  kind: "tertiary",
31407
32017
  startIcon: plusCircle__default["default"],
@@ -31411,30 +32021,30 @@ const LockedPolygonSettings = props => {
31411
32021
  });
31412
32022
  }
31413
32023
  }, "Add point"), /*#__PURE__*/React__namespace.createElement(Spring, null), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31414
- style: styles$p.movementButtonsContainer
32024
+ style: styles$k.movementButtonsContainer
31415
32025
  }, /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
31416
32026
  "aria-label": "Move polygon up",
31417
- style: styles$p.iconButton,
32027
+ style: styles$k.iconButton,
31418
32028
  size: "small",
31419
32029
  icon: arrowFatUp__default["default"],
31420
32030
  onClick: () => handlePolygonMove("up")
31421
32031
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31422
- style: styles$p.row
32032
+ style: styles$k.row
31423
32033
  }, /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
31424
32034
  "aria-label": "Move polygon left",
31425
- style: styles$p.iconButton,
32035
+ style: styles$k.iconButton,
31426
32036
  size: "small",
31427
32037
  icon: arrowFatLeft__default["default"],
31428
32038
  onClick: () => handlePolygonMove("left")
31429
32039
  }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
31430
32040
  "aria-label": "Move polygon down",
31431
- style: styles$p.iconButton,
32041
+ style: styles$k.iconButton,
31432
32042
  size: "small",
31433
32043
  icon: arrowFatDown__default["default"],
31434
32044
  onClick: () => handlePolygonMove("down")
31435
32045
  }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
31436
32046
  "aria-label": "Move polygon right",
31437
- style: styles$p.iconButton,
32047
+ style: styles$k.iconButton,
31438
32048
  size: "small",
31439
32049
  icon: arrowFatRight__default["default"],
31440
32050
  onClick: () => handlePolygonMove("right")
@@ -31444,7 +32054,7 @@ const LockedPolygonSettings = props => {
31444
32054
  onRemove: onRemove
31445
32055
  }));
31446
32056
  };
31447
- const styles$p = aphrodite.StyleSheet.create({
32057
+ const styles$k = aphrodite.StyleSheet.create({
31448
32058
  row: {
31449
32059
  display: "flex",
31450
32060
  flexDirection: "row",
@@ -31518,7 +32128,7 @@ const LockedVectorSettings = props => {
31518
32128
  expanded: props.expanded,
31519
32129
  onToggle: props.onToggle,
31520
32130
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31521
- style: styles$o.row
32131
+ style: styles$j.row
31522
32132
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
31523
32133
  size: wonderBlocksTokens.spacing.xSmall_8
31524
32134
  }), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
@@ -31526,19 +32136,19 @@ const LockedVectorSettings = props => {
31526
32136
  lineStyle: "solid"
31527
32137
  }))
31528
32138
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31529
- style: [styles$o.row, styles$o.spaceUnder]
32139
+ style: [styles$j.row, styles$j.spaceUnder]
31530
32140
  }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31531
32141
  selectedValue: lineColor,
31532
32142
  onChange: handleColorChange
31533
32143
  })), isInvalid && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31534
- style: styles$o.errorText
32144
+ style: styles$j.errorText
31535
32145
  }, lengthErrorMessage), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31536
32146
  expanded: true // Initial state is expanded
31537
32147
  ,
31538
- containerStyle: styles$o.container,
31539
- panelStyle: styles$o.accordionPanel,
32148
+ containerStyle: styles$j.container,
32149
+ panelStyle: styles$j.accordionPanel,
31540
32150
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31541
- style: styles$o.row
32151
+ style: styles$j.row
31542
32152
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Tail (${tail[0]}, ${tail[1]})`))
31543
32153
  }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31544
32154
  coord: tail,
@@ -31549,10 +32159,10 @@ const LockedVectorSettings = props => {
31549
32159
  })), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
31550
32160
  expanded: true // Initial state is expanded
31551
32161
  ,
31552
- containerStyle: styles$o.container,
31553
- panelStyle: styles$o.accordionPanel,
32162
+ containerStyle: styles$j.container,
32163
+ panelStyle: styles$j.accordionPanel,
31554
32164
  header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31555
- style: styles$o.row
32165
+ style: styles$j.row
31556
32166
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Tip (${tip[0]}, ${tip[1]})`))
31557
32167
  }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31558
32168
  coord: tip,
@@ -31566,7 +32176,7 @@ const LockedVectorSettings = props => {
31566
32176
  onRemove: onRemove
31567
32177
  }));
31568
32178
  };
31569
- const styles$o = aphrodite.StyleSheet.create({
32179
+ const styles$j = aphrodite.StyleSheet.create({
31570
32180
  accordionPanel: {
31571
32181
  paddingBottom: wonderBlocksTokens.spacing.medium_16
31572
32182
  },
@@ -31634,783 +32244,264 @@ const LockedFiguresSection = props => {
31634
32244
  const lockedFigures = figures || [];
31635
32245
  const newProps = {
31636
32246
  lockedFigures: [...lockedFigures, getDefaultFigureForType(newFigure)]
31637
- };
31638
- onChange(newProps);
31639
- setExpandedStates([...expandedStates, true]);
31640
- }
31641
- function moveLockedFigure(index, movement) {
31642
- // Don't allow moving the first figure up or the last figure down.
31643
- if (index === 0 && (movement === "back" || movement === "backward")) {
31644
- return;
31645
- }
31646
- if (figures && index === figures.length - 1 && (movement === "front" || movement === "forward")) {
31647
- return;
31648
- }
31649
- const lockedFigures = figures || [];
31650
- const newFigures = [...lockedFigures];
31651
- const newExpandedStates = [...expandedStates];
31652
-
31653
- // First, remove the figure from its current position
31654
- // in the figures array and the expanded states array.
31655
- const [removedFigure] = newFigures.splice(index, 1);
31656
- newExpandedStates.splice(index, 1);
31657
-
31658
- // Then, add it back in the new position. Add "true" to the
31659
- // expanded states array for the new position (it must already
31660
- // be open since the button to move it is being pressed from there).
31661
- switch (movement) {
31662
- case "back":
31663
- newFigures.unshift(removedFigure);
31664
- newExpandedStates.unshift(true);
31665
- break;
31666
- case "backward":
31667
- newFigures.splice(index - 1, 0, removedFigure);
31668
- newExpandedStates.splice(index - 1, 0, true);
31669
- break;
31670
- case "forward":
31671
- newFigures.splice(index + 1, 0, removedFigure);
31672
- newExpandedStates.splice(index + 1, 0, true);
31673
- break;
31674
- case "front":
31675
- newFigures.push(removedFigure);
31676
- newExpandedStates.push(true);
31677
- break;
31678
- }
31679
- onChange({
31680
- lockedFigures: newFigures
31681
- });
31682
- setExpandedStates(newExpandedStates);
31683
- }
31684
- function removeLockedFigure(index) {
31685
- // eslint-disable-next-line no-alert
31686
- if (window.confirm("Are you sure you want to delete this figure?")) {
31687
- const lockedFigures = figures || [];
31688
- onChange({
31689
- lockedFigures: [...lockedFigures.slice(0, index), ...lockedFigures.slice(index + 1)]
31690
- });
31691
-
31692
- // Update expanded states
31693
- const newExpandedStates = [...expandedStates];
31694
- newExpandedStates.splice(index, 1);
31695
- setExpandedStates(newExpandedStates);
31696
- }
31697
- }
31698
- function changeProps(index,
31699
- // Omit the type from the figure props so it doesn't think
31700
- // we're trying to pass in the props for the wrong type.
31701
- figureProps) {
31702
- const lockedFigures = figures || [];
31703
- const newFigures = {
31704
- lockedFigures: [...lockedFigures.slice(0, index), {
31705
- ...lockedFigures[index],
31706
- ...figureProps
31707
- }, ...lockedFigures.slice(index + 1)]
31708
- };
31709
- onChange(newFigures);
31710
- }
31711
- function toggleExpanded(newValue) {
31712
- setExpandedStates(Array(figures?.length).fill(newValue));
31713
- }
31714
- const allCollapsed = expandedStates.every(value => !value);
31715
- const buttonLabel = allCollapsed ? "Expand all" : "Collapse all";
31716
- const showExpandButton = !!figures?.length;
31717
- return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
31718
- title: "Locked Figures",
31719
- isOpen: isExpanded,
31720
- onToggle: () => setIsExpanded(!isExpanded),
31721
- isCollapsible: true
31722
- }), isExpanded && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, figures?.map((figure, index) => {
31723
- return /*#__PURE__*/React__namespace.createElement(LockedFigureSettings, _extends({
31724
- key: `${uniqueId}-locked-${figure}-${index}`,
31725
- showLabelsFlag: props.showLabelsFlag,
31726
- expanded: expandedStates[index],
31727
- onToggle: newValue => {
31728
- const newExpanded = [...expandedStates];
31729
- newExpanded[index] = newValue;
31730
- setExpandedStates(newExpanded);
31731
- }
31732
- }, figure, {
31733
- onChangeProps: newProps => changeProps(index, newProps),
31734
- onMove: movement => moveLockedFigure(index, movement),
31735
- onRemove: () => removeLockedFigure(index)
31736
- }));
31737
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31738
- style: styles$n.buttonContainer
31739
- }, /*#__PURE__*/React__namespace.createElement(LockedFigureSelect, {
31740
- showLabelsFlag: props.showLabelsFlag,
31741
- id: `${uniqueId}-select`,
31742
- onChange: addLockedFigure
31743
- }), /*#__PURE__*/React__namespace.createElement(Strut, {
31744
- size: wonderBlocksTokens.spacing.small_12
31745
- }), showExpandButton && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
31746
- kind: "secondary",
31747
- onClick: () => toggleExpanded(allCollapsed),
31748
- style: styles$n.button
31749
- }, buttonLabel))));
31750
- };
31751
- const styles$n = aphrodite.StyleSheet.create({
31752
- buttonContainer: {
31753
- flexDirection: "row",
31754
- alignItems: "center"
31755
- },
31756
- button: {
31757
- marginTop: wonderBlocksTokens.spacing.xSmall_8,
31758
- flexGrow: 1
31759
- }
31760
- });
31761
-
31762
- const UNLIMITED = "unlimited";
31763
- // Parses a string (ostensibly from some UI element that only supports string
31764
- // types, such as a <select />) into a numeric point count or the special sigil
31765
- // "unlimited". Note that 0 is a special case, and means "unlimited".
31766
- const parsePointCount = points => {
31767
- const parsed = parseInt(points, 10);
31768
- if (isNaN(parsed)) {
31769
- return UNLIMITED;
31770
- }
31771
- return parsed === 0 ? UNLIMITED : parsed;
31772
- };
31773
-
31774
- const GraphPointsCountSelector = _ref => {
31775
- let {
31776
- numPoints = 1,
31777
- onChange
31778
- } = _ref;
31779
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
31780
- selectedValue: `${numPoints}`,
31781
- onChange: newValue => {
31782
- onChange(parsePointCount(newValue));
31783
- }
31784
- // Never uses placeholder, always has value
31785
- ,
31786
- placeholder: "",
31787
- style: styles$m.singleSelectShort
31788
- }, [...[...Array(7).keys()].map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31789
- key: n,
31790
- value: `${n}`,
31791
- label: `${n} point${n > 1 ? "s" : ""}`
31792
- })), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31793
- key: "unlimited",
31794
- value: UNLIMITED,
31795
- label: "unlimited"
31796
- })]);
31797
- };
31798
- const styles$m = aphrodite.StyleSheet.create({
31799
- singleSelectShort: {
31800
- // Non-standard spacing, but it's the smallest we can go
31801
- // without running into styling issues with the dropdown.
31802
- height: 26
31803
- }
31804
- });
31805
-
31806
- const GraphTypeSelector = props => {
31807
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
31808
- selectedValue: props.graphType,
31809
- onChange: props.onChange,
31810
- placeholder: "Select a graph type",
31811
- style: styles$l.singleSelectShort
31812
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31813
- value: "linear",
31814
- label: "Linear function"
31815
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31816
- value: "quadratic",
31817
- label: "Quadratic function"
31818
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31819
- value: "sinusoid",
31820
- label: "Sinusoid function"
31821
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31822
- value: "circle",
31823
- label: "Circle"
31824
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31825
- value: "point",
31826
- label: "Point(s)"
31827
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31828
- value: "linear-system",
31829
- label: "Linear System"
31830
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31831
- value: "polygon",
31832
- label: "Polygon"
31833
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31834
- value: "segment",
31835
- label: "Line Segment(s)"
31836
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31837
- value: "ray",
31838
- label: "Ray"
31839
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31840
- value: "angle",
31841
- label: "Angle"
31842
- }));
31843
- };
31844
- const styles$l = aphrodite.StyleSheet.create({
31845
- singleSelectShort: {
31846
- // Non-standard spacing, but it's the smallest we can go
31847
- // without running into styling issues with the dropdown.
31848
- height: 26
31849
- }
31850
- });
31851
-
31852
- function InteractiveGraphCorrectAnswer(props) {
31853
- return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
31854
- title: "Correct Answer",
31855
- isOpen: true,
31856
- isCollapsible: false
31857
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelXSmall, {
31858
- style: {
31859
- paddingTop: wonderBlocksTokens.spacing.xxSmall_6,
31860
- paddingBottom: wonderBlocksTokens.spacing.xxSmall_6,
31861
- color: wonderBlocksTokens.color.offBlack64
31862
- }
31863
- }, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.BodyMonospace, {
31864
- style: {
31865
- fontSize: 12,
31866
- backgroundColor: "#eee",
31867
- paddingInline: wonderBlocksTokens.spacing.xxSmall_6,
31868
- borderColor: "#ccc",
31869
- borderStyle: "solid",
31870
- borderWidth: 1
31871
- }
31872
- }, props.equationString)), props.children));
31873
- }
31874
-
31875
- function InteractiveGraphDescription(props) {
31876
- const {
31877
- ariaLabelValue,
31878
- ariaDescriptionValue,
31879
- onChange
31880
- } = props;
31881
- const [isOpen, setIsOpen] = React__namespace.useState(true);
31882
- return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
31883
- title: "Description",
31884
- isCollapsible: true,
31885
- isOpen: isOpen,
31886
- onToggle: setIsOpen
31887
- }), isOpen && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelXSmall, {
31888
- style: styles$k.caption
31889
- }, "Use these fields to describe the graph as a whole. These are used by screen readers to describe content to users who are visually impaired."), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
31890
- tag: "label"
31891
- }, "Title", /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
31892
- value: ariaLabelValue,
31893
- onChange: newValue => onChange({
31894
- fullGraphAriaLabel: newValue
31895
- }),
31896
- style: styles$k.spaceAbove
31897
- })), /*#__PURE__*/React__namespace.createElement(Strut, {
31898
- size: wonderBlocksTokens.spacing.small_12
31899
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
31900
- tag: "label"
31901
- }, "Description", /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextArea, {
31902
- rows: 8,
31903
- resizeType: "vertical",
31904
- value: ariaDescriptionValue,
31905
- onChange: newValue => onChange({
31906
- fullGraphAriaDescription: newValue
31907
- }),
31908
- style: styles$k.spaceAbove
31909
- }))));
31910
- }
31911
- const styles$k = aphrodite.StyleSheet.create({
31912
- caption: {
31913
- color: wonderBlocksTokens.color.offBlack64,
31914
- paddingTop: wonderBlocksTokens.spacing.xxSmall_6,
31915
- paddingBottom: wonderBlocksTokens.spacing.xxSmall_6
31916
- },
31917
- spaceAbove: {
31918
- marginTop: wonderBlocksTokens.spacing.xxxSmall_4
31919
- }
31920
- });
31921
-
31922
- /* eslint-disable react/forbid-prop-types, react/no-unsafe */
31923
- const {
31924
- ButtonGroup: ButtonGroup$2,
31925
- InfoTip: InfoTip$c,
31926
- RangeInput: RangeInput$4
31927
- } = perseus.components;
31928
- const defaultBackgroundImage$1 = {
31929
- url: null,
31930
- width: 0,
31931
- height: 0
31932
- };
31933
- function numSteps(range, step) {
31934
- return Math.floor((range[1] - range[0]) / step);
31935
- }
31936
- class InteractiveGraphSettings extends React__namespace.Component {
31937
- _isMounted = false;
31938
- bgUrlRef = /*#__PURE__*/React__namespace.createRef();
31939
- labelXRef = /*#__PURE__*/React__namespace.createRef();
31940
- labelYRef = /*#__PURE__*/React__namespace.createRef();
31941
- static stateFromProps(props) {
31942
- return {
31943
- labelsTextbox: props.labels,
31944
- gridStepTextbox: props.gridStep,
31945
- snapStepTextbox: props.snapStep,
31946
- stepTextbox: props.step,
31947
- rangeTextbox: props.range,
31948
- // Shallow-copied clone
31949
- backgroundImage: {
31950
- ...props.backgroundImage
31951
- }
31952
- };
31953
- }
31954
- constructor(props) {
31955
- super(props);
31956
- this.state = {
31957
- isExpanded: true,
31958
- ...InteractiveGraphSettings.stateFromProps(props)
31959
- };
31960
- }
31961
- static defaultProps = {
31962
- box: [perseus.interactiveSizes.defaultBoxSizeSmall, perseus.interactiveSizes.defaultBoxSizeSmall],
31963
- labels: ["x", "y"],
31964
- range: [[-10, 10], [-10, 10]],
31965
- step: [1, 1],
31966
- gridStep: [1, 1],
31967
- snapStep: [1, 1],
31968
- valid: true,
31969
- backgroundImage: defaultBackgroundImage$1,
31970
- markings: "graph",
31971
- showProtractor: false,
31972
- showTooltips: false
31973
- };
31974
- componentDidMount() {
31975
- // TODO(scottgrant): This is a hack to remove the deprecated call to
31976
- // this.isMounted() but is still considered an anti-pattern.
31977
- this._isMounted = true;
31978
- this.changeGraph = ___default["default"].debounce(this.changeGraph, 300);
31979
- }
31980
- UNSAFE_componentWillReceiveProps(nextProps) {
31981
- // Make sure that state updates when switching
31982
- // between different items in a multi-item editor.
31983
- if (!___default["default"].isEqual(this.props.labels, nextProps.labels) || !___default["default"].isEqual(this.props.gridStep, nextProps.gridStep) || !___default["default"].isEqual(this.props.snapStep, nextProps.snapStep) || !___default["default"].isEqual(this.props.step, nextProps.step) || !___default["default"].isEqual(this.props.range, nextProps.range) || !___default["default"].isEqual(this.props.backgroundImage, nextProps.backgroundImage)) {
31984
- this.setState(InteractiveGraphSettings.stateFromProps(nextProps));
31985
- }
31986
- }
31987
- componentWillUnmount() {
31988
- this._isMounted = false;
31989
- }
31990
- change = (() => {
31991
- var _this = this;
31992
- return function () {
31993
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
31994
- args[_key] = arguments[_key];
31995
- }
31996
- return perseus.Changeable.change.apply(_this, args);
31997
- };
31998
- })();
31999
- changeBackgroundUrl = e => {
32000
- // Only continue on blur or "enter"
32001
- if (e.type === "keypress" && e.key !== "Enter") {
32002
- return;
32003
- }
32004
- const setUrl = (url, width, height) => {
32005
- // Shallow-copied clone
32006
- const image = {
32007
- ...this.props.backgroundImage
32008
- };
32009
- image.url = url;
32010
- image.width = width;
32011
- image.height = height;
32012
- this.setState({
32013
- backgroundImage: image
32014
- }, this.changeGraph);
32015
- };
32016
- const url = this.bgUrlRef.current?.value;
32017
- if (url) {
32018
- perseus.Util.getImageSize(url, (width, height) => {
32019
- if (this._isMounted) {
32020
- setUrl(url, width, height);
32021
- }
32022
- });
32023
- } else {
32024
- setUrl(null, 0, 0);
32025
- }
32026
- };
32027
- renderLabelChoices = choices => {
32028
- return choices.map(nameAndValue => /*#__PURE__*/React__namespace.createElement("option", {
32029
- key: nameAndValue[1],
32030
- value: nameAndValue[1]
32031
- }, nameAndValue[0]));
32032
- };
32033
- validRange = range => {
32034
- const numbers = ___default["default"].every(range, function (num) {
32035
- return ___default["default"].isFinite(num);
32036
- });
32037
- if (!numbers) {
32038
- return "Range must be a valid number";
32039
- }
32040
- if (range[0] >= range[1]) {
32041
- return "Range must have a higher number on the right";
32042
- }
32043
- return true;
32044
- };
32045
- validateStepValue = settings => {
32046
- const {
32047
- step,
32048
- range,
32049
- name,
32050
- minTicks,
32051
- maxTicks
32052
- } = settings;
32053
- const nSteps = numSteps(range, step);
32054
- if (nSteps < minTicks) {
32055
- return name + " is too large, there must be at least " + minTicks + " ticks.";
32056
- }
32057
- if (nSteps > maxTicks) {
32058
- return name + " is too small, there can be at most " + maxTicks + " ticks.";
32059
- }
32060
- return true;
32061
- };
32062
- validSnapStep = (step, range) => {
32063
- return this.validateStepValue({
32064
- step: step,
32065
- range: range,
32066
- name: "Snap step",
32067
- minTicks: 5,
32068
- maxTicks: 60
32069
- });
32070
- };
32071
- validGridStep = (step, range) => {
32072
- return this.validateStepValue({
32073
- step: step,
32074
- range: range,
32075
- name: "Grid step",
32076
- minTicks: 3,
32077
- maxTicks: 60
32078
- });
32079
- };
32080
- validStep = (step, range) => {
32081
- return this.validateStepValue({
32082
- step: step,
32083
- range: range,
32084
- name: "Step",
32085
- minTicks: 3,
32086
- maxTicks: 20
32087
- });
32088
- };
32089
- validBackgroundImageSize = image => {
32090
- // Ignore empty images
32091
- if (!image.url) {
32092
- return true;
32093
- }
32094
- const validSize = image.width <= 450 && image.height <= 450;
32095
- if (!validSize) {
32096
- return "Image must be smaller than 450px x 450px.";
32097
- }
32098
- return true;
32099
- };
32100
- validateGraphSettings = (range, step, gridStep, snapStep, image) => {
32101
- const self = this;
32102
- let msg;
32103
- const goodRange = ___default["default"].every(range, function (range) {
32104
- msg = self.validRange(range);
32105
- return msg === true;
32106
- });
32107
- if (!goodRange) {
32108
- return msg;
32109
- }
32110
- const goodStep = ___default["default"].every(step, function (step, i) {
32111
- msg = self.validStep(step, range[i]);
32112
- return msg === true;
32113
- });
32114
- if (!goodStep) {
32115
- return msg;
32116
- }
32117
- const goodGridStep = ___default["default"].every(gridStep, function (gridStep, i) {
32118
- msg = self.validGridStep(gridStep, range[i]);
32119
- return msg === true;
32120
- });
32121
- if (!goodGridStep) {
32122
- return msg;
32123
- }
32124
- const goodSnapStep = ___default["default"].every(snapStep, function (snapStep, i) {
32125
- msg = self.validSnapStep(snapStep, range[i]);
32126
- return msg === true;
32127
- });
32128
- if (!goodSnapStep) {
32129
- return msg;
32247
+ };
32248
+ onChange(newProps);
32249
+ setExpandedStates([...expandedStates, true]);
32250
+ }
32251
+ function moveLockedFigure(index, movement) {
32252
+ // Don't allow moving the first figure up or the last figure down.
32253
+ if (index === 0 && (movement === "back" || movement === "backward")) {
32254
+ return;
32130
32255
  }
32131
- const goodImageSize = this.validBackgroundImageSize(image);
32132
- if (goodImageSize !== true) {
32133
- msg = goodImageSize;
32134
- return msg;
32256
+ if (figures && index === figures.length - 1 && (movement === "front" || movement === "forward")) {
32257
+ return;
32135
32258
  }
32136
- return true;
32137
- };
32138
- changeLabel = (i, e) => {
32139
- const val = e.target.value;
32140
- const labels = this.state.labelsTextbox.slice();
32141
- labels[i] = val;
32142
- this.setState({
32143
- labelsTextbox: labels
32144
- }, this.changeGraph);
32145
- };
32146
- changeRange = (i, values) => {
32147
- const ranges = this.state.rangeTextbox.slice();
32148
- ranges[i] = values;
32149
- const step = this.state.stepTextbox.slice();
32150
- const gridStep = this.state.gridStepTextbox.slice();
32151
- const snapStep = this.state.snapStepTextbox.slice();
32152
- const scale = perseus.Util.scaleFromExtent(ranges[i], this.props.box[i]);
32153
- if (this.validRange(ranges[i]) === true) {
32154
- step[i] = perseus.Util.tickStepFromExtent(ranges[i], this.props.box[i]);
32155
- const gridStepValue = perseus.Util.gridStepFromTickStep(step[i], scale);
32156
- if (gridStepValue) {
32157
- gridStep[i] = gridStepValue;
32158
- }
32159
- snapStep[i] = gridStep[i] / 2;
32259
+ const lockedFigures = figures || [];
32260
+ const newFigures = [...lockedFigures];
32261
+ const newExpandedStates = [...expandedStates];
32262
+
32263
+ // First, remove the figure from its current position
32264
+ // in the figures array and the expanded states array.
32265
+ const [removedFigure] = newFigures.splice(index, 1);
32266
+ newExpandedStates.splice(index, 1);
32267
+
32268
+ // Then, add it back in the new position. Add "true" to the
32269
+ // expanded states array for the new position (it must already
32270
+ // be open since the button to move it is being pressed from there).
32271
+ switch (movement) {
32272
+ case "back":
32273
+ newFigures.unshift(removedFigure);
32274
+ newExpandedStates.unshift(true);
32275
+ break;
32276
+ case "backward":
32277
+ newFigures.splice(index - 1, 0, removedFigure);
32278
+ newExpandedStates.splice(index - 1, 0, true);
32279
+ break;
32280
+ case "forward":
32281
+ newFigures.splice(index + 1, 0, removedFigure);
32282
+ newExpandedStates.splice(index + 1, 0, true);
32283
+ break;
32284
+ case "front":
32285
+ newFigures.push(removedFigure);
32286
+ newExpandedStates.push(true);
32287
+ break;
32160
32288
  }
32161
- this.setState({
32162
- stepTextbox: step,
32163
- gridStepTextbox: gridStep,
32164
- snapStepTextbox: snapStep,
32165
- rangeTextbox: ranges
32166
- }, this.changeGraph);
32167
- };
32168
- changeStep = step => {
32169
- this.setState({
32170
- stepTextbox: step
32171
- }, this.changeGraph);
32172
- };
32173
- changeSnapStep = snapStep => {
32174
- this.setState({
32175
- snapStepTextbox: snapStep
32176
- }, this.changeGraph);
32177
- };
32178
- changeGridStep = gridStep => {
32179
- this.setState({
32180
- gridStepTextbox: gridStep,
32181
- snapStepTextbox: ___default["default"].map(gridStep, function (step) {
32182
- return step / 2;
32183
- })
32184
- }, this.changeGraph);
32185
- };
32186
- changeGraph = () => {
32187
- const labels = this.state.labelsTextbox;
32188
- const range = ___default["default"].map(this.state.rangeTextbox, function (range) {
32189
- return ___default["default"].map(range, Number);
32289
+ onChange({
32290
+ lockedFigures: newFigures
32190
32291
  });
32191
- const step = ___default["default"].map(this.state.stepTextbox, Number);
32192
- const gridStep = this.state.gridStepTextbox;
32193
- const snapStep = this.state.snapStepTextbox;
32194
- const image = this.state.backgroundImage;
32195
-
32196
- // validationResult is either:
32197
- // true -> the settings are valid
32198
- // a string -> the settings are invalid, and the explanation
32199
- // is contained in the string
32200
- // TODO(aria): Refactor this to not be confusing
32201
- const validationResult = this.validateGraphSettings(range, step, gridStep, snapStep, image);
32202
- if (validationResult === true) {
32203
- // either true or a string
32204
- this.change({
32205
- valid: true,
32206
- labels: labels,
32207
- range: range,
32208
- step: step,
32209
- gridStep: gridStep,
32210
- snapStep: snapStep,
32211
- backgroundImage: image
32212
- });
32213
- } else {
32214
- this.change({
32215
- valid: validationResult // a string message, not false
32292
+ setExpandedStates(newExpandedStates);
32293
+ }
32294
+ function removeLockedFigure(index) {
32295
+ // eslint-disable-next-line no-alert
32296
+ if (window.confirm("Are you sure you want to delete this figure?")) {
32297
+ const lockedFigures = figures || [];
32298
+ onChange({
32299
+ lockedFigures: [...lockedFigures.slice(0, index), ...lockedFigures.slice(index + 1)]
32216
32300
  });
32217
- }
32218
- };
32219
32301
 
32220
- render() {
32221
- return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
32222
- title: "Common Graph Settings",
32223
- isOpen: this.state.isExpanded,
32224
- isCollapsible: true,
32225
- onToggle: () => this.setState({
32226
- isExpanded: !this.state.isExpanded
32227
- })
32228
- }), this.state.isExpanded && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement("div", {
32229
- className: "graph-settings"
32230
- }, /*#__PURE__*/React__namespace.createElement("div", {
32231
- className: "perseus-widget-row"
32232
- }, /*#__PURE__*/React__namespace.createElement("div", {
32233
- className: "perseus-widget-left-col"
32234
- }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
32235
- label: "x Label"
32236
- }, /*#__PURE__*/React__namespace.createElement("input", {
32237
- type: "text",
32238
- className: "graph-settings-axis-label",
32239
- ref: this.labelXRef,
32240
- onChange: e => this.changeLabel(0, e),
32241
- value: this.state.labelsTextbox[0] || ""
32242
- }))), /*#__PURE__*/React__namespace.createElement("div", {
32243
- className: "perseus-widget-right-col"
32244
- }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
32245
- label: "y Label"
32246
- }, /*#__PURE__*/React__namespace.createElement("input", {
32247
- type: "text",
32248
- className: "graph-settings-axis-label",
32249
- ref: this.labelYRef,
32250
- onChange: e => this.changeLabel(1, e),
32251
- value: this.state.labelsTextbox[1] || ""
32252
- })))), /*#__PURE__*/React__namespace.createElement("div", {
32253
- className: "perseus-widget-row"
32254
- }, /*#__PURE__*/React__namespace.createElement("div", {
32255
- className: "perseus-widget-left-col"
32256
- }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
32257
- label: "x Range"
32258
- }, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
32259
- value: this.state.rangeTextbox[0],
32260
- onChange: vals => this.changeRange(0, vals)
32261
- }))), /*#__PURE__*/React__namespace.createElement("div", {
32262
- className: "perseus-widget-right-col"
32263
- }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
32264
- label: "y Range"
32265
- }, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
32266
- value: this.state.rangeTextbox[1],
32267
- onChange: vals => this.changeRange(1, vals)
32268
- })))), /*#__PURE__*/React__namespace.createElement("div", {
32269
- className: "perseus-widget-row"
32270
- }, /*#__PURE__*/React__namespace.createElement("div", {
32271
- className: "perseus-widget-left-col"
32272
- }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
32273
- label: "Tick Step"
32274
- }, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
32275
- value: this.state.stepTextbox,
32276
- onChange: this.changeStep
32277
- }))), /*#__PURE__*/React__namespace.createElement("div", {
32278
- className: "perseus-widget-right-col"
32279
- }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
32280
- label: "Grid Step"
32281
- }, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
32282
- value: this.state.gridStepTextbox,
32283
- onChange: this.changeGridStep
32284
- })))), /*#__PURE__*/React__namespace.createElement("div", {
32285
- className: "perseus-widget-row"
32286
- }, /*#__PURE__*/React__namespace.createElement("div", {
32287
- className: "perseus-widget-left-col"
32288
- }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
32289
- label: "Snap Step"
32290
- }, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
32291
- value: this.state.snapStepTextbox,
32292
- onChange: this.changeSnapStep
32293
- })))), /*#__PURE__*/React__namespace.createElement("div", {
32294
- className: "perseus-widget-row"
32295
- }, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
32296
- label: "Markings:"
32297
- }, /*#__PURE__*/React__namespace.createElement(ButtonGroup$2, {
32298
- value: this.props.markings,
32299
- allowEmpty: false,
32300
- buttons: [{
32301
- value: "graph",
32302
- content: "Graph"
32303
- }, {
32304
- value: "grid",
32305
- content: "Grid"
32306
- }, {
32307
- value: "none",
32308
- content: "None"
32309
- }],
32310
- onChange: this.change("markings")
32311
- }))), /*#__PURE__*/React__namespace.createElement("div", {
32312
- className: "perseus-widget-left-col"
32313
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
32314
- label: "Show tooltips",
32315
- checked: this.props.showTooltips,
32316
- onChange: value => {
32317
- this.change({
32318
- showTooltips: value
32319
- });
32320
- }
32321
- }))), /*#__PURE__*/React__namespace.createElement(LabeledRow, {
32322
- label: "Background image URL:",
32323
- style: styles$j.resetSpaceTop
32324
- }, /*#__PURE__*/React__namespace.createElement("input", {
32325
- type: "text",
32326
- className: aphrodite.css(styles$j.backgroundUrlInput),
32327
- ref: this.bgUrlRef,
32328
- value: this.state.backgroundImage.url || "",
32329
- onChange: e => {
32330
- // Shallow-copied clone
32331
- const image = {
32332
- ...this.props.backgroundImage
32333
- };
32334
- image.url = e.target.value;
32335
- this.setState({
32336
- backgroundImage: image
32337
- });
32338
- },
32339
- onKeyPress: this.changeBackgroundUrl,
32340
- onBlur: this.changeBackgroundUrl
32341
- }), /*#__PURE__*/React__namespace.createElement(InfoTip$c, null, /*#__PURE__*/React__namespace.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background."))), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32342
- style: styles$j.protractorSection
32343
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32344
- style: styles$j.checkboxRow
32345
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
32346
- label: "Show protractor",
32347
- checked: this.props.showProtractor,
32348
- onChange: value => {
32349
- this.change({
32350
- showProtractor: value
32351
- });
32352
- },
32353
- style: styles$j.resetSpaceTop
32354
- })), this.props.showProtractor && /*#__PURE__*/React__namespace.createElement(Banner__default["default"], {
32355
- layout: "floating",
32356
- text: "The protractor is not accessible. Please consider an alternate approach.",
32357
- kind: "warning"
32358
- }))));
32302
+ // Update expanded states
32303
+ const newExpandedStates = [...expandedStates];
32304
+ newExpandedStates.splice(index, 1);
32305
+ setExpandedStates(newExpandedStates);
32306
+ }
32359
32307
  }
32360
- }
32361
- const styles$j = aphrodite.StyleSheet.create({
32362
- resetSpaceTop: {
32363
- marginTop: 0
32364
- },
32365
- backgroundUrlInput: {
32366
- border: `1px solid ${wonderBlocksTokens.color.offBlack32}`,
32367
- borderRadius: wonderBlocksTokens.spacing.xxxSmall_4,
32368
- padding: wonderBlocksTokens.spacing.xxxSmall_4
32369
- },
32370
- checkboxRow: {
32308
+ function changeProps(index,
32309
+ // Omit the type from the figure props so it doesn't think
32310
+ // we're trying to pass in the props for the wrong type.
32311
+ figureProps) {
32312
+ const lockedFigures = figures || [];
32313
+ const newFigures = {
32314
+ lockedFigures: [...lockedFigures.slice(0, index), {
32315
+ ...lockedFigures[index],
32316
+ ...figureProps
32317
+ }, ...lockedFigures.slice(index + 1)]
32318
+ };
32319
+ onChange(newFigures);
32320
+ }
32321
+ function toggleExpanded(newValue) {
32322
+ setExpandedStates(Array(figures?.length).fill(newValue));
32323
+ }
32324
+ const allCollapsed = expandedStates.every(value => !value);
32325
+ const buttonLabel = allCollapsed ? "Expand all" : "Collapse all";
32326
+ const showExpandButton = !!figures?.length;
32327
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
32328
+ title: "Locked Figures",
32329
+ isOpen: isExpanded,
32330
+ onToggle: () => setIsExpanded(!isExpanded),
32331
+ isCollapsible: true
32332
+ }), isExpanded && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, figures?.map((figure, index) => {
32333
+ return /*#__PURE__*/React__namespace.createElement(LockedFigureSettings, _extends({
32334
+ key: `${uniqueId}-locked-${figure}-${index}`,
32335
+ flags: props.flags,
32336
+ showLabelsFlag: props.showLabelsFlag,
32337
+ expanded: expandedStates[index],
32338
+ onToggle: newValue => {
32339
+ const newExpanded = [...expandedStates];
32340
+ newExpanded[index] = newValue;
32341
+ setExpandedStates(newExpanded);
32342
+ }
32343
+ }, figure, {
32344
+ onChangeProps: newProps => changeProps(index, newProps),
32345
+ onMove: movement => moveLockedFigure(index, movement),
32346
+ onRemove: () => removeLockedFigure(index)
32347
+ }));
32348
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32349
+ style: styles$i.buttonContainer
32350
+ }, /*#__PURE__*/React__namespace.createElement(LockedFigureSelect, {
32351
+ showLabelsFlag: props.showLabelsFlag,
32352
+ id: `${uniqueId}-select`,
32353
+ onChange: addLockedFigure
32354
+ }), /*#__PURE__*/React__namespace.createElement(Strut, {
32355
+ size: wonderBlocksTokens.spacing.small_12
32356
+ }), showExpandButton && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
32357
+ kind: "secondary",
32358
+ onClick: () => toggleExpanded(allCollapsed),
32359
+ style: styles$i.button
32360
+ }, buttonLabel))));
32361
+ };
32362
+ const styles$i = aphrodite.StyleSheet.create({
32363
+ buttonContainer: {
32371
32364
  flexDirection: "row",
32372
- alignItems: "center",
32373
- justifyContent: "space-between",
32374
- marginBottom: wonderBlocksTokens.spacing.xSmall_8
32365
+ alignItems: "center"
32375
32366
  },
32376
- protractorSection: {
32367
+ button: {
32377
32368
  marginTop: wonderBlocksTokens.spacing.xSmall_8,
32378
- borderTop: `1px solid ${wonderBlocksTokens.color.offBlack16}`,
32379
- paddingTop: wonderBlocksTokens.spacing.xSmall_8,
32380
- paddingBottom: wonderBlocksTokens.spacing.xSmall_8,
32381
- borderBottom: `1px solid ${wonderBlocksTokens.color.offBlack16}`
32369
+ flexGrow: 1
32382
32370
  }
32383
32371
  });
32384
32372
 
32385
- const SegmentCountSelector = _ref => {
32386
- let {
32387
- numSegments = 1,
32388
- onChange
32389
- } = _ref;
32390
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
32391
- key: "segment-select",
32392
- selectedValue: `${numSegments}`
32393
- // Never uses placeholder, always has value
32394
- ,
32395
- placeholder: "",
32396
- onChange: newValue => {
32397
- const num = +newValue;
32398
- onChange(num);
32399
- },
32400
- style: styles$i.singleSelectShort
32401
- }, ___default["default"].range(1, 7).map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
32402
- key: n,
32403
- value: `${n}`,
32404
- label: `${n} segment${n > 1 ? "s" : ""}`
32405
- })));
32373
+ function getStartCoords(graph) {
32374
+ if ("startCoords" in graph) {
32375
+ return graph.startCoords;
32376
+ }
32377
+ return undefined;
32378
+ }
32379
+ function getDefaultGraphStartCoords(graph, range, step) {
32380
+ switch (graph.type) {
32381
+ case "linear":
32382
+ case "ray":
32383
+ return perseus.getLineCoords({
32384
+ ...graph,
32385
+ startCoords: undefined
32386
+ }, range, step);
32387
+ case "segment":
32388
+ return perseus.getSegmentCoords({
32389
+ ...graph,
32390
+ startCoords: undefined
32391
+ }, range, step);
32392
+ case "linear-system":
32393
+ return perseus.getLinearSystemCoords({
32394
+ ...graph,
32395
+ startCoords: undefined
32396
+ }, range, step);
32397
+ case "circle":
32398
+ const startCoords = perseus.getCircleCoords({
32399
+ ...graph,
32400
+ startCoords: undefined
32401
+ });
32402
+ const radius = kmath.vector.length(kmath.vector.subtract(startCoords.radiusPoint, startCoords.center));
32403
+ return {
32404
+ center: startCoords.center,
32405
+ radius
32406
+ };
32407
+ case "sinusoid":
32408
+ return perseus.getSinusoidCoords({
32409
+ ...graph,
32410
+ startCoords: undefined
32411
+ }, range, step);
32412
+ case "quadratic":
32413
+ return perseus.getQuadraticCoords({
32414
+ ...graph,
32415
+ startCoords: undefined
32416
+ }, range, step);
32417
+ case "point":
32418
+ return perseus.getPointCoords({
32419
+ ...graph,
32420
+ startCoords: undefined
32421
+ }, range, step);
32422
+ case "polygon":
32423
+ return perseus.getPolygonCoords({
32424
+ ...graph,
32425
+ startCoords: undefined
32426
+ }, range, step);
32427
+ case "angle":
32428
+ return perseus.getAngleCoords({
32429
+ graph: {
32430
+ ...graph,
32431
+ startCoords: undefined
32432
+ },
32433
+ range,
32434
+ step
32435
+ });
32436
+ default:
32437
+ return undefined;
32438
+ }
32439
+ }
32440
+ const getSinusoidEquation = startCoords => {
32441
+ // Get coefficients
32442
+ // It's assumed that p1 is the root and p2 is the first peak
32443
+ const p1 = startCoords[0];
32444
+ const p2 = startCoords[1];
32445
+
32446
+ // Resulting coefficients are canonical for this sine curve
32447
+ const amplitude = p2[1] - p1[1];
32448
+ const angularFrequency = Math.PI / (2 * (p2[0] - p1[0]));
32449
+ const phase = p1[0] * angularFrequency;
32450
+ const verticalOffset = p1[1];
32451
+ return "y = " + amplitude.toFixed(3) + "sin(" + angularFrequency.toFixed(3) + "x - " + phase.toFixed(3) + ") + " + verticalOffset.toFixed(3);
32406
32452
  };
32407
- const styles$i = aphrodite.StyleSheet.create({
32408
- singleSelectShort: {
32409
- // Non-standard spacing, but it's the smallest we can go
32410
- // without running into styling issues with the dropdown.
32411
- height: 26
32453
+ const getQuadraticEquation = startCoords => {
32454
+ const p1 = startCoords[0];
32455
+ const p2 = startCoords[1];
32456
+ const p3 = startCoords[2];
32457
+ const denom = (p1[0] - p2[0]) * (p1[0] - p3[0]) * (p2[0] - p3[0]);
32458
+ if (denom === 0) {
32459
+ // Many of the callers assume that the return value is always defined.
32460
+ return "Division by zero error";
32412
32461
  }
32413
- });
32462
+ const a = (p3[0] * (p2[1] - p1[1]) + p2[0] * (p1[1] - p3[1]) + p1[0] * (p3[1] - p2[1])) / denom;
32463
+ const b = (p3[0] * p3[0] * (p1[1] - p2[1]) + p2[0] * p2[0] * (p3[1] - p1[1]) + p1[0] * p1[0] * (p2[1] - p3[1])) / denom;
32464
+ const c = (p2[0] * p3[0] * (p2[0] - p3[0]) * p1[1] + p3[0] * p1[0] * (p3[0] - p1[0]) * p2[1] + p1[0] * p2[0] * (p1[0] - p2[0]) * p3[1]) / denom;
32465
+ return "y = " + a.toFixed(3) + "x^2 + " + b.toFixed(3) + "x + " + c.toFixed(3);
32466
+ };
32467
+ const findAngle = (point1, point2) => {
32468
+ const x = point1[0] - point2[0];
32469
+ const y = point1[1] - point2[1];
32470
+ return (180 + Math.atan2(-y, -x) * 180 / Math.PI + 360) % 360;
32471
+ };
32472
+ const getAngleEquation = startCoords => {
32473
+ const [point1, vertex, point2] = startCoords;
32474
+ const angle = findAngle(point2, vertex) - findAngle(point1, vertex);
32475
+ const roundedAngle = angle.toFixed(0);
32476
+ return `${roundedAngle}\u00B0 angle at (${vertex[0]}, ${vertex[1]})`;
32477
+ };
32478
+ const shouldShowStartCoordsUI = (graph, isStatic) => {
32479
+ // We don't show the start coords UI for static graphs, since
32480
+ // the coords shown for this are determined by the coords on the
32481
+ // "correct" graph. The start coords would not be used here.
32482
+ if (isStatic) {
32483
+ return false;
32484
+ }
32485
+ switch (graph.type) {
32486
+ case "point":
32487
+ return graph.numPoints !== "unlimited";
32488
+ case "polygon":
32489
+ return graph.numSides !== "unlimited" && graph.snapTo !== "angles" && graph.snapTo !== "sides";
32490
+ case "none":
32491
+ return false;
32492
+ case "angle":
32493
+ case "circle":
32494
+ case "linear":
32495
+ case "linear-system":
32496
+ case "quadratic":
32497
+ case "ray":
32498
+ case "segment":
32499
+ case "sinusoid":
32500
+ return true;
32501
+ default:
32502
+ throw new wonderStuffCore.UnreachableCaseError(graph);
32503
+ }
32504
+ };
32414
32505
 
32415
32506
  const StartCoordsAngle = props => {
32416
32507
  const {
@@ -32922,7 +33013,7 @@ class InteractiveGraphEditor extends React__namespace.Component {
32922
33013
  ___default["default"].extend(json, {
32923
33014
  graph: {
32924
33015
  type: correct.type,
32925
- startCoords: this.props.graph?.startCoords
33016
+ startCoords: this.props.graph && getStartCoords(this.props.graph)
32926
33017
  },
32927
33018
  correct: correct
32928
33019
  });
@@ -33017,7 +33108,7 @@ class InteractiveGraphEditor extends React__namespace.Component {
33017
33108
  }, this.props.valid);
33018
33109
  }
33019
33110
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
33020
- label: "Type of Graph:"
33111
+ label: "Answer type:"
33021
33112
  }, /*#__PURE__*/React__namespace.createElement(GraphTypeSelector, {
33022
33113
  graphType: this.props.graph?.type ?? InteractiveGraph.defaultProps.graph.type,
33023
33114
  onChange: type => {
@@ -33029,7 +33120,8 @@ class InteractiveGraphEditor extends React__namespace.Component {
33029
33120
  type
33030
33121
  }
33031
33122
  });
33032
- }
33123
+ },
33124
+ showNoneOption: this.props.apiOptions?.flags?.mafs?.["none"]
33033
33125
  })), this.props.graph && this.props.apiOptions?.flags?.mafs?.[this.props.graph.type] && /*#__PURE__*/React__namespace.createElement(InteractiveGraphDescription, {
33034
33126
  ariaLabelValue: this.props.fullGraphAriaLabel ?? "",
33035
33127
  ariaDescriptionValue: this.props.fullGraphAriaDescription ?? "",
@@ -33266,6 +33358,7 @@ class InteractiveGraphEditor extends React__namespace.Component {
33266
33358
  // Only show the "Add locked figure" dropdown if the graph
33267
33359
  // is using Mafs.
33268
33360
  this.props.graph && this.props.apiOptions?.flags?.mafs?.[this.props.graph.type] && /*#__PURE__*/React__namespace.createElement(LockedFiguresSection, {
33361
+ flags: this.props.apiOptions.flags,
33269
33362
  showLabelsFlag: this.props.apiOptions?.flags?.mafs?.["interactive-graph-locked-features-labels"],
33270
33363
  figures: this.props.lockedFigures,
33271
33364
  onChange: this.props.onChange
@@ -33305,6 +33398,12 @@ function mergeGraphs(a, b) {
33305
33398
  ...a,
33306
33399
  ...b
33307
33400
  };
33401
+ case "none":
33402
+ invariant(b.type === "none");
33403
+ return {
33404
+ ...a,
33405
+ ...b
33406
+ };
33308
33407
  case "point":
33309
33408
  invariant(b.type === "point");
33310
33409
  return {
@@ -37156,14 +37255,6 @@ class TableEditor extends React__namespace.Component {
37156
37255
  });
37157
37256
  };
37158
37257
  render() {
37159
- const tableProps = ___default["default"].pick(this.props, "headers", "answers", "onChange", "apiOptions");
37160
- ___default["default"].extend(tableProps, {
37161
- editableHeaders: true,
37162
- Editor,
37163
- onFocus: () => {},
37164
- onBlur: () => {},
37165
- trackInteraction: () => {}
37166
- });
37167
37258
  return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", {
37168
37259
  className: "perseus-widget-row"
37169
37260
  }, /*#__PURE__*/React__namespace.createElement("label", null, "Number of columns:", " ", /*#__PURE__*/React__namespace.createElement(NumberInput, {
@@ -37188,7 +37279,17 @@ class TableEditor extends React__namespace.Component {
37188
37279
  }
37189
37280
  },
37190
37281
  useArrowKeys: true
37191
- }))), /*#__PURE__*/React__namespace.createElement("div", null, " ", "Table of answers:", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$1, null, /*#__PURE__*/React__namespace.createElement("p", null, "The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(Table, tableProps)));
37282
+ }))), /*#__PURE__*/React__namespace.createElement("div", null, " ", "Table of answers:", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$1, null, /*#__PURE__*/React__namespace.createElement("p", null, "The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."))), /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(Table, {
37283
+ headers: this.props.headers,
37284
+ answers: this.props.answers,
37285
+ onChange: this.props.onChange,
37286
+ apiOptions: this.props.apiOptions,
37287
+ editableHeaders: true,
37288
+ onFocus: () => {},
37289
+ onBlur: () => {},
37290
+ trackInteraction: () => {},
37291
+ Editor: Editor
37292
+ })));
37192
37293
  }
37193
37294
  }
37194
37295