@khanacademy/perseus 23.3.0 → 23.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3304,7 +3304,7 @@ const DeprecationMixin$1 = {
3304
3304
  /**
3305
3305
  * Approximate equality on numbers and primitives.
3306
3306
  */
3307
- function eq$2(x, y) {
3307
+ function eq$3(x, y) {
3308
3308
  if (typeof x === "number" && typeof y === "number") {
3309
3309
  return Math.abs(x - y) < 1e-9;
3310
3310
  }
@@ -3331,7 +3331,7 @@ function deepEq$5(x, y) {
3331
3331
  return false;
3332
3332
  }
3333
3333
  if (typeof x === "function" && typeof y === "function") {
3334
- return eq$2(x, y);
3334
+ return eq$3(x, y);
3335
3335
  }
3336
3336
  if (typeof x === "function" || typeof y === "function") {
3337
3337
  return false;
@@ -3348,7 +3348,7 @@ function deepEq$5(x, y) {
3348
3348
  if (typeof x === "object" && !!x || typeof y === "object" && !!y) {
3349
3349
  return false;
3350
3350
  }
3351
- return eq$2(x, y);
3351
+ return eq$3(x, y);
3352
3352
  }
3353
3353
 
3354
3354
  /**
@@ -3647,7 +3647,7 @@ const Util = {
3647
3647
  tickStepFromNumTicks,
3648
3648
  constrainedTickStepsFromTickSteps,
3649
3649
  DeprecationMixin: DeprecationMixin$1,
3650
- eq: eq$2,
3650
+ eq: eq$3,
3651
3651
  deepEq: deepEq$5,
3652
3652
  parseQueryString,
3653
3653
  updateQueryString: updateQueryString$2,
@@ -10885,7 +10885,7 @@ class WrappedLine extends WrappedDrawing {
10885
10885
  * A collection of geomtry-related utility functions
10886
10886
  */
10887
10887
  const {
10888
- eq: eq$1,
10888
+ eq: eq$2,
10889
10889
  deepEq: deepEq$4
10890
10890
  } = Util;
10891
10891
 
@@ -10893,17 +10893,21 @@ const {
10893
10893
 
10894
10894
  // a, b, c
10895
10895
 
10896
+ // Given a number, return whether it is positive (1), negative (-1), or zero (0)
10896
10897
  function sign(val) {
10897
- if (eq$1(val, 0)) {
10898
+ if (eq$2(val, 0)) {
10898
10899
  return 0;
10899
10900
  }
10900
10901
  return val > 0 ? 1 : -1;
10901
10902
  }
10903
+
10904
+ // Determine whether three points are collinear (0), for a clockwise turn (negative),
10905
+ // or counterclockwise turn (positive)
10902
10906
  function ccw(a, b, c) {
10903
10907
  return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);
10904
10908
  }
10905
10909
  function collinear(a, b, c) {
10906
- return eq$1(ccw(a, b, c), 0);
10910
+ return eq$2(ccw(a, b, c), 0);
10907
10911
  }
10908
10912
 
10909
10913
  // Given rect bounding points A and B, whether point C is inside the rect
@@ -11048,7 +11052,7 @@ function similar(coords1, coords2, tolerance) {
11048
11052
  return pair[0] / pair[1];
11049
11053
  });
11050
11054
  const same = ___default["default"].all(factors, function (factor) {
11051
- return eq$1(factors[0], factor);
11055
+ return eq$2(factors[0], factor);
11052
11056
  });
11053
11057
  const congruentEnough = ___default["default"].all(sidePairs, function (pair) {
11054
11058
  return kmath.number.equal(pair[0], pair[1], tolerance);
@@ -11101,7 +11105,7 @@ function rotate(array, n) {
11101
11105
  return array.slice(n).concat(array.slice(0, n));
11102
11106
  }
11103
11107
  function getLineEquation(first, second) {
11104
- if (eq$1(first[0], second[0])) {
11108
+ if (eq$2(first[0], second[0])) {
11105
11109
  return "x = " + first[0].toFixed(3);
11106
11110
  }
11107
11111
  const m = (second[1] - first[1]) / (second[0] - first[0]);
@@ -28943,13 +28947,15 @@ const ItemExtras = [
28943
28947
 
28944
28948
  const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
28945
28949
  const lockedFigureColors = {
28950
+ blue: "#3D7586",
28946
28951
  green: "#447A53",
28947
28952
  grayH: "#3B3D45",
28948
28953
  purple: "#594094",
28949
28954
  pink: "#B25071",
28950
- red: "#D92916"
28955
+ red: "#D92916",
28956
+ orange: "#946700"
28951
28957
  };
28952
- const lockedEllipseFillStyles = {
28958
+ const lockedFigureFillStyles = {
28953
28959
  none: 0,
28954
28960
  solid: 1,
28955
28961
  translucent: 0.4
@@ -28969,7 +28975,7 @@ const LockedEllipse = props => {
28969
28975
  center: center,
28970
28976
  radius: radius,
28971
28977
  angle: angle,
28972
- fillOpacity: lockedEllipseFillStyles[fillStyle],
28978
+ fillOpacity: lockedFigureFillStyles[fillStyle],
28973
28979
  strokeStyle: strokeStyle,
28974
28980
  color: lockedFigureColors[color]
28975
28981
  });
@@ -29228,6 +29234,29 @@ const LockedPoint = props => {
29228
29234
  });
29229
29235
  };
29230
29236
 
29237
+ const LockedPolygon = props => {
29238
+ const {
29239
+ points,
29240
+ color,
29241
+ showVertices,
29242
+ fillStyle,
29243
+ strokeStyle
29244
+ } = props;
29245
+ return /*#__PURE__*/React__namespace.createElement("g", {
29246
+ className: "locked-polygon"
29247
+ }, /*#__PURE__*/React__namespace.createElement(mafs.Polygon, {
29248
+ points: [...points],
29249
+ fillOpacity: lockedFigureFillStyles[fillStyle],
29250
+ strokeStyle: strokeStyle,
29251
+ color: lockedFigureColors[color]
29252
+ }), showVertices && points.map((point, index) => /*#__PURE__*/React__namespace.createElement(mafs.Point, {
29253
+ key: `locked-polygon-point-${index}`,
29254
+ x: point[0],
29255
+ y: point[1],
29256
+ color: lockedFigureColors[color]
29257
+ })));
29258
+ };
29259
+
29231
29260
  const LockedVector = props => {
29232
29261
  const {
29233
29262
  color,
@@ -29258,13 +29287,17 @@ const GraphLockedLayer = props => {
29258
29287
  key: `line-${index}`,
29259
29288
  range: props.range
29260
29289
  }, figure));
29290
+ case "vector":
29291
+ return /*#__PURE__*/React__namespace.createElement(LockedVector, _extends({
29292
+ key: `vector-${index}`
29293
+ }, figure));
29261
29294
  case "ellipse":
29262
29295
  return /*#__PURE__*/React__namespace.createElement(LockedEllipse, _extends({
29263
29296
  key: `ellipse-${index}`
29264
29297
  }, figure));
29265
- case "vector":
29266
- return /*#__PURE__*/React__namespace.createElement(LockedVector, _extends({
29267
- key: `vector-${index}`
29298
+ case "polygon":
29299
+ return /*#__PURE__*/React__namespace.createElement(LockedPolygon, _extends({
29300
+ key: `polygon-${index}`
29268
29301
  }, figure));
29269
29302
  default:
29270
29303
  /**
@@ -29278,6 +29311,13 @@ const GraphLockedLayer = props => {
29278
29311
  }));
29279
29312
  };
29280
29313
 
29314
+ const REINITIALIZE = "reinitialize";
29315
+ function reinitialize(params) {
29316
+ return {
29317
+ type: REINITIALIZE,
29318
+ params
29319
+ };
29320
+ }
29281
29321
  const MOVE_CONTROL_POINT = "move-control-point";
29282
29322
  function moveControlPoint(pointIndex, destination, itemIndex) {
29283
29323
  return {
@@ -29542,6 +29582,7 @@ function useControlPoint(point, color, onMovePoint) {
29542
29582
  });
29543
29583
  const focusableHandle = /*#__PURE__*/React__namespace.createElement("g", {
29544
29584
  "data-testid": "movable-point__focusable-handle",
29585
+ className: "movable-point__focusable-handle",
29545
29586
  tabIndex: 0,
29546
29587
  ref: keyboardHandleRef,
29547
29588
  onFocus: () => setFocused(true),
@@ -29711,7 +29752,6 @@ const LinearSystemGraph = props => {
29711
29752
  const {
29712
29753
  coords: lines
29713
29754
  } = props.graphState;
29714
- const colors = ["var(--movable-line-stroke-color)", "var(--mafs-violet)"];
29715
29755
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, lines?.map((line, i) => /*#__PURE__*/React__namespace.createElement(MovableLine, {
29716
29756
  key: i,
29717
29757
  points: line,
@@ -29723,7 +29763,7 @@ const LinearSystemGraph = props => {
29723
29763
  end: true
29724
29764
  },
29725
29765
  onMovePoint: (endpointIndex, destination) => dispatch(moveControlPoint(endpointIndex, destination, i)),
29726
- color: colors[i]
29766
+ color: "var(--movable-line-stroke-color)"
29727
29767
  })), ";");
29728
29768
  };
29729
29769
 
@@ -29798,7 +29838,8 @@ const Angle = _ref => {
29798
29838
  endPoints,
29799
29839
  range,
29800
29840
  polygonLines,
29801
- showAngles
29841
+ showAngles,
29842
+ snapTo
29802
29843
  } = _ref;
29803
29844
  const [centerX, centerY] = centerPoint;
29804
29845
  const areClockwise = clockwise$1([centerPoint, ...endPoints]);
@@ -29836,7 +29877,9 @@ const Angle = _ref => {
29836
29877
  if (isOutside) {
29837
29878
  angleInDegrees = 360 - angleInDegrees;
29838
29879
  }
29839
- const angleLabelNumber = parseFloat(angleInDegrees.toFixed(1));
29880
+
29881
+ // Only want to show whole numbers when in angles mode
29882
+ const angleLabelNumber = parseFloat(angleInDegrees.toFixed(snapTo === "angles" ? 0 : 1));
29840
29883
  const angleLabel = Number.isInteger(angleLabelNumber) ? angleLabelNumber : "≈ " + angleLabelNumber;
29841
29884
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("filter", {
29842
29885
  id: "background",
@@ -29927,15 +29970,17 @@ const StyledMovablePoint = props => {
29927
29970
  point,
29928
29971
  onMove,
29929
29972
  cursor,
29930
- color = wonderBlocksTokens.color.blue
29973
+ color = wonderBlocksTokens.color.blue,
29974
+ snapTo
29931
29975
  } = props;
29976
+ const snapToValue = snapTo ?? "grid";
29932
29977
  const {
29933
29978
  dragging
29934
29979
  } = mafs.useMovable({
29935
29980
  gestureTarget: elementRef,
29936
29981
  point,
29937
29982
  onMove,
29938
- constrain: p => snap(snapStep, p)
29983
+ constrain: p => ["angles", "sides"].includes(snapToValue) ? p : snap(snapStep, p)
29939
29984
  });
29940
29985
  return /*#__PURE__*/React__namespace.createElement(MovablePointView, {
29941
29986
  ref: elementRef,
@@ -29961,7 +30006,8 @@ const PolygonGraph = props => {
29961
30006
  showAngles,
29962
30007
  showSides,
29963
30008
  range,
29964
- snapStep
30009
+ snapStep,
30010
+ snapTo
29965
30011
  } = props.graphState;
29966
30012
 
29967
30013
  // TODO(benchristel): can the default set of points be removed here? I don't
@@ -29969,6 +30015,7 @@ const PolygonGraph = props => {
29969
30015
  const points = coords ?? [[0, 0]];
29970
30016
  const ref = React__namespace.useRef(null);
29971
30017
  const dragReferencePoint = points[0];
30018
+ const snapToValue = snapTo ?? "grid";
29972
30019
  const {
29973
30020
  dragging
29974
30021
  } = mafs.useMovable({
@@ -29978,7 +30025,7 @@ const PolygonGraph = props => {
29978
30025
  const delta = mafs.vec.sub(newPoint, dragReferencePoint);
29979
30026
  dispatch(moveAll(delta));
29980
30027
  },
29981
- constrain: p => snap(snapStep, p)
30028
+ constrain: p => ["angles", "sides"].includes(snapToValue) ? p : snap(snapStep, p)
29982
30029
  });
29983
30030
  const active = hovered || focused || dragging;
29984
30031
  const lines = getLines(points);
@@ -30001,12 +30048,13 @@ const PolygonGraph = props => {
30001
30048
  active: active,
30002
30049
  range: range,
30003
30050
  polygonLines: lines,
30004
- showAngles: !!showAngles
30051
+ showAngles: !!showAngles,
30052
+ snapTo: snapToValue
30005
30053
  });
30006
30054
  }), showSides && lines.map((_ref, i) => {
30007
30055
  let [start, end] = _ref;
30008
30056
  const [x, y] = mafs.vec.midpoint(start, end);
30009
- const length = parseFloat(mafs.vec.dist(start, end).toFixed(1));
30057
+ const length = parseFloat(mafs.vec.dist(start, end).toFixed(snapTo === "sides" ? 0 : 1));
30010
30058
  return /*#__PURE__*/React__namespace.createElement(TextLabel, {
30011
30059
  key: "side-" + i,
30012
30060
  x: x,
@@ -30030,153 +30078,12 @@ const PolygonGraph = props => {
30030
30078
  }
30031
30079
  }), points.map((point, i) => /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
30032
30080
  key: "point-" + i,
30081
+ snapTo: snapTo,
30033
30082
  point: point,
30034
30083
  onMove: destination => dispatch(movePoint(i, destination))
30035
30084
  })));
30036
30085
  };
30037
30086
 
30038
- function initializeGraphState(params) {
30039
- const {
30040
- graph,
30041
- step,
30042
- snapStep,
30043
- range
30044
- } = params;
30045
- const shared = {
30046
- hasBeenInteractedWith: false,
30047
- range,
30048
- snapStep
30049
- };
30050
- switch (graph.type) {
30051
- case "segment":
30052
- return {
30053
- ...shared,
30054
- type: "segment",
30055
- coords: getSegmentCoords({
30056
- graph,
30057
- step,
30058
- range
30059
- })
30060
- };
30061
- case "linear":
30062
- return {
30063
- ...shared,
30064
- type: graph.type,
30065
- coords: getLineCoords({
30066
- graph,
30067
- range,
30068
- step
30069
- })
30070
- };
30071
- case "ray":
30072
- return {
30073
- ...shared,
30074
- type: graph.type,
30075
- coords: getLineCoords({
30076
- graph,
30077
- range,
30078
- step
30079
- })
30080
- };
30081
- case "linear-system":
30082
- return {
30083
- ...shared,
30084
- type: graph.type,
30085
- coords: getLinearSystemCoords({
30086
- graph,
30087
- range,
30088
- step
30089
- })
30090
- };
30091
- case "polygon":
30092
- return {
30093
- ...shared,
30094
- type: "polygon",
30095
- showAngles: Boolean(graph.showAngles),
30096
- showSides: Boolean(graph.showSides),
30097
- coords: getPolygonCoords({
30098
- graph,
30099
- range,
30100
- step
30101
- })
30102
- };
30103
- case "point":
30104
- return {
30105
- ...shared,
30106
- type: graph.type,
30107
- coords: getDefaultPoints({
30108
- graph,
30109
- step,
30110
- range
30111
- })
30112
- };
30113
- case "circle":
30114
- return {
30115
- ...shared,
30116
- type: graph.type,
30117
- ...getCircleCoords(graph)
30118
- };
30119
- case "quadratic":
30120
- return {
30121
- ...shared,
30122
- type: graph.type,
30123
- coords: getQuadraticCoords(graph, range, step)
30124
- };
30125
- case "sinusoid":
30126
- return {
30127
- ...shared,
30128
- type: graph.type,
30129
- coords: getSinusoidCoords(graph, range, step)
30130
- };
30131
- case "angle":
30132
- throw new Error("Mafs not yet implemented for graph type: " + graph.type);
30133
- default:
30134
- throw new wonderStuffCore.UnreachableCaseError(graph);
30135
- }
30136
- }
30137
- const getDefaultPoints = _ref => {
30138
- let {
30139
- graph,
30140
- range,
30141
- step
30142
- } = _ref;
30143
- const numPoints = graph.numPoints || 1;
30144
- let coords = graph.coords?.slice();
30145
- if (coords) {
30146
- return coords;
30147
- }
30148
- switch (numPoints) {
30149
- case 1:
30150
- // Back in the day, one point's coords were in graph.coord
30151
- coords = [graph.coord || [0, 0]];
30152
- break;
30153
- case 2:
30154
- coords = [[-5, 0], [5, 0]];
30155
- break;
30156
- case 3:
30157
- coords = [[-5, 0], [0, 0], [5, 0]];
30158
- break;
30159
- case 4:
30160
- coords = [[-6, 0], [-2, 0], [2, 0], [6, 0]];
30161
- break;
30162
- case 5:
30163
- coords = [[-6, 0], [-3, 0], [0, 0], [3, 0], [6, 0]];
30164
- break;
30165
- case 6:
30166
- coords = [[-5, 0], [-3, 0], [-1, 0], [1, 0], [3, 0], [5, 0]];
30167
- break;
30168
- default:
30169
- coords = [];
30170
- break;
30171
- }
30172
- // Transform coords from their -10 to 10 space to 0 to 1
30173
- // because of the old graph.coord, and also it's easier.
30174
- const newCoords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
30175
- return normalizePoints(range, step, newCoords);
30176
- };
30177
-
30178
- // TS v4 doesn't narrow return types, while v5 does.
30179
- // Instead of updating to v5, using generic type to relate input and output types.
30180
30087
  function getGradableGraph(state, initialGraph) {
30181
30088
  if (!state.hasBeenInteractedWith) {
30182
30089
  return {
@@ -30240,118 +30147,6 @@ function getGradableGraph(state, initialGraph) {
30240
30147
  }
30241
30148
  throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
30242
30149
  }
30243
- const getSegmentCoords = _ref2 => {
30244
- let {
30245
- graph,
30246
- range,
30247
- step
30248
- } = _ref2;
30249
- if (graph.coords) {
30250
- return graph.coords;
30251
- }
30252
- const ys = n => {
30253
- switch (n) {
30254
- case 2:
30255
- return [5, -5];
30256
- case 3:
30257
- return [5, 0, -5];
30258
- case 4:
30259
- return [6, 2, -2, -6];
30260
- case 5:
30261
- return [6, 3, 0, -3, -6];
30262
- case 6:
30263
- return [5, 3, 1, -1, -3, -5];
30264
- default:
30265
- return [5];
30266
- }
30267
- };
30268
- const defaultRange = [[-10, 10], [-10, 10]];
30269
- return ys(graph.numSegments).map(y => {
30270
- let endpoints = [[-5, y], [5, y]];
30271
- endpoints = normalizeCoords(endpoints, defaultRange);
30272
- endpoints = normalizePoints(range, step, endpoints);
30273
- return endpoints;
30274
- });
30275
- };
30276
- const defaultLinearCoords = [[[0.25, 0.75], [0.75, 0.75]], [[0.25, 0.25], [0.75, 0.25]]];
30277
- const getLineCoords = _ref3 => {
30278
- let {
30279
- graph,
30280
- range,
30281
- step
30282
- } = _ref3;
30283
- if (graph.coords) {
30284
- return graph.coords;
30285
- }
30286
- return normalizePoints(range, step, defaultLinearCoords[0]);
30287
- };
30288
- const getLinearSystemCoords = _ref4 => {
30289
- let {
30290
- graph,
30291
- range,
30292
- step
30293
- } = _ref4;
30294
- if (graph.coords) {
30295
- return graph.coords;
30296
- }
30297
- return defaultLinearCoords.map(points => normalizePoints(range, step, points));
30298
- };
30299
- const getPolygonCoords = _ref5 => {
30300
- let {
30301
- graph,
30302
- range,
30303
- step
30304
- } = _ref5;
30305
- let coords = graph.coords?.slice();
30306
- if (coords) {
30307
- return coords;
30308
- }
30309
- const n = graph.numSides || 3;
30310
- if (n === "unlimited") {
30311
- coords = [];
30312
- } else {
30313
- const angle = 2 * Math.PI / n;
30314
- const offset = (1 / n - 1 / 2) * Math.PI;
30315
-
30316
- // TODO(alex): Generalize this to more than just triangles so that
30317
- // all polygons have whole number side lengths if snapping to sides
30318
- const radius = graph.snapTo === "sides" ? Math.sqrt(3) / 3 * 7 : 4;
30319
-
30320
- // Generate coords of a regular polygon with n sides
30321
- coords = [...Array(n).keys()].map(i => [radius * Math.cos(i * angle + offset), radius * Math.sin(i * angle + offset)]);
30322
- }
30323
- coords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
30324
- const snapToGrid = !["angles", "sides"].includes(graph.snapTo || "");
30325
- coords = normalizePoints(range, step, coords, /* noSnap */!snapToGrid);
30326
- return coords;
30327
- };
30328
- const getSinusoidCoords = (graph, range, step) => {
30329
- if (graph.coords) {
30330
- return [graph.coords[0], graph.coords[1]];
30331
- }
30332
- let coords = [[0.5, 0.5], [0.65, 0.6]];
30333
- coords = normalizePoints(range, step, coords, true);
30334
- return coords;
30335
- };
30336
- const getQuadraticCoords = (graph, range, step) => {
30337
- if (graph.coords) {
30338
- return graph.coords;
30339
- }
30340
- const defaultCoords = [[0.25, 0.75], [0.5, 0.25], [0.75, 0.75]];
30341
- return normalizePoints(range, step, defaultCoords, true);
30342
- };
30343
- const getCircleCoords = (graph, range, step) => {
30344
- if (graph.center != null && graph.radius != null) {
30345
- return {
30346
- center: graph.center,
30347
- radiusPoint: mafs.vec.add(graph.center, [graph.radius, 0])
30348
- };
30349
- }
30350
- return {
30351
- center: [0, 0],
30352
- radiusPoint: [1, 0]
30353
- };
30354
- };
30355
30150
 
30356
30151
  /**
30357
30152
  * determine radius of a circle graph
@@ -30485,38 +30280,16 @@ function QuadraticGraph(props) {
30485
30280
 
30486
30281
  // Calculate the y value based on the current x value
30487
30282
  const y = x => (a * x + b) * x + c;
30488
- const handleOnMove = (destination, elementId) => {
30489
- // If the destination is invalid, we want do not want to move the point
30490
- const validDestination = isValidDestination(destination, elementId, coords);
30491
- if (validDestination === false) {
30492
- return;
30493
- }
30494
- dispatch(movePoint(elementId, destination));
30495
- };
30496
30283
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfX, {
30497
30284
  y: y,
30498
30285
  color: wonderBlocksTokens.color.blue
30499
30286
  }), coords.map((coord, i) => /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
30500
30287
  key: "point-" + i,
30501
30288
  point: coord,
30502
- onMove: destination => handleOnMove(destination, i)
30289
+ onMove: destination => dispatch(movePoint(i, destination))
30503
30290
  })));
30504
30291
  }
30505
30292
 
30506
- // Ensure that we are only snapping to coordinates that result in a valid quadratic equation
30507
- const isValidDestination = (destination, elementId, coords) => {
30508
- // Set up the new coords and check if the quadratic coefficients are valid
30509
- const newCoords = [...coords];
30510
- newCoords[elementId] = destination;
30511
- const QuadraticCoefficients = getQuadraticCoefficients(newCoords);
30512
-
30513
- // If the new destination results in an invalid quadratic equation, we don't want to move the point
30514
- if (QuadraticCoefficients === undefined) {
30515
- return false;
30516
- }
30517
- return true;
30518
- };
30519
-
30520
30293
  // Get the quadratic coefficients from the 3 control points
30521
30294
  // These equations were originally set up in 2013 and may require some
30522
30295
  // additional comments to help clarify the quadratic formula manipulations
@@ -31666,8 +31439,214 @@ const LegacyGrid = _ref => {
31666
31439
  return null;
31667
31440
  };
31668
31441
 
31442
+ function initializeGraphState(params) {
31443
+ const {
31444
+ graph,
31445
+ step,
31446
+ snapStep,
31447
+ range
31448
+ } = params;
31449
+ const shared = {
31450
+ hasBeenInteractedWith: false,
31451
+ range,
31452
+ snapStep
31453
+ };
31454
+ switch (graph.type) {
31455
+ case "segment":
31456
+ return {
31457
+ ...shared,
31458
+ type: "segment",
31459
+ coords: getSegmentCoords(graph, range, step)
31460
+ };
31461
+ case "linear":
31462
+ return {
31463
+ ...shared,
31464
+ type: graph.type,
31465
+ coords: getLineCoords(graph, range, step)
31466
+ };
31467
+ case "ray":
31468
+ return {
31469
+ ...shared,
31470
+ type: graph.type,
31471
+ coords: getLineCoords(graph, range, step)
31472
+ };
31473
+ case "linear-system":
31474
+ return {
31475
+ ...shared,
31476
+ type: graph.type,
31477
+ coords: getLinearSystemCoords(graph, range, step)
31478
+ };
31479
+ case "polygon":
31480
+ return {
31481
+ ...shared,
31482
+ type: "polygon",
31483
+ showAngles: Boolean(graph.showAngles),
31484
+ showSides: Boolean(graph.showSides),
31485
+ coords: getPolygonCoords(graph, range, step),
31486
+ snapTo: graph.snapTo ?? "grid"
31487
+ };
31488
+ case "point":
31489
+ return {
31490
+ ...shared,
31491
+ type: graph.type,
31492
+ coords: getPointCoords(graph, range, step)
31493
+ };
31494
+ case "circle":
31495
+ return {
31496
+ ...shared,
31497
+ type: graph.type,
31498
+ ...getCircleCoords(graph)
31499
+ };
31500
+ case "quadratic":
31501
+ return {
31502
+ ...shared,
31503
+ type: graph.type,
31504
+ coords: getQuadraticCoords(graph, range, step)
31505
+ };
31506
+ case "sinusoid":
31507
+ return {
31508
+ ...shared,
31509
+ type: graph.type,
31510
+ coords: getSinusoidCoords(graph, range, step)
31511
+ };
31512
+ case "angle":
31513
+ throw new Error("Mafs not yet implemented for graph type: " + graph.type);
31514
+ default:
31515
+ throw new wonderStuffCore.UnreachableCaseError(graph);
31516
+ }
31517
+ }
31518
+ function getPointCoords(graph, range, step) {
31519
+ const numPoints = graph.numPoints || 1;
31520
+ let coords = graph.coords?.slice();
31521
+ if (coords) {
31522
+ return coords;
31523
+ }
31524
+ switch (numPoints) {
31525
+ case 1:
31526
+ // Back in the day, one point's coords were in graph.coord
31527
+ coords = [graph.coord || [0, 0]];
31528
+ break;
31529
+ case 2:
31530
+ coords = [[-5, 0], [5, 0]];
31531
+ break;
31532
+ case 3:
31533
+ coords = [[-5, 0], [0, 0], [5, 0]];
31534
+ break;
31535
+ case 4:
31536
+ coords = [[-6, 0], [-2, 0], [2, 0], [6, 0]];
31537
+ break;
31538
+ case 5:
31539
+ coords = [[-6, 0], [-3, 0], [0, 0], [3, 0], [6, 0]];
31540
+ break;
31541
+ case 6:
31542
+ coords = [[-5, 0], [-3, 0], [-1, 0], [1, 0], [3, 0], [5, 0]];
31543
+ break;
31544
+ default:
31545
+ coords = [];
31546
+ break;
31547
+ }
31548
+ // Transform coords from their -10 to 10 space to 0 to 1
31549
+ // because of the old graph.coord, and also it's easier.
31550
+ const newCoords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
31551
+ return normalizePoints(range, step, newCoords);
31552
+ }
31553
+ function getSegmentCoords(graph, range, step) {
31554
+ if (graph.coords) {
31555
+ return graph.coords;
31556
+ }
31557
+ const ys = n => {
31558
+ switch (n) {
31559
+ case 2:
31560
+ return [5, -5];
31561
+ case 3:
31562
+ return [5, 0, -5];
31563
+ case 4:
31564
+ return [6, 2, -2, -6];
31565
+ case 5:
31566
+ return [6, 3, 0, -3, -6];
31567
+ case 6:
31568
+ return [5, 3, 1, -1, -3, -5];
31569
+ default:
31570
+ return [5];
31571
+ }
31572
+ };
31573
+ const defaultRange = [[-10, 10], [-10, 10]];
31574
+ return ys(graph.numSegments).map(y => {
31575
+ let endpoints = [[-5, y], [5, y]];
31576
+ endpoints = normalizeCoords(endpoints, defaultRange);
31577
+ endpoints = normalizePoints(range, step, endpoints);
31578
+ return endpoints;
31579
+ });
31580
+ }
31581
+ const defaultLinearCoords = [[[0.25, 0.75], [0.75, 0.75]], [[0.25, 0.25], [0.75, 0.25]]];
31582
+ function getLineCoords(graph, range, step) {
31583
+ if (graph.coords) {
31584
+ return graph.coords;
31585
+ }
31586
+ return normalizePoints(range, step, defaultLinearCoords[0]);
31587
+ }
31588
+ function getLinearSystemCoords(graph, range, step) {
31589
+ if (graph.coords) {
31590
+ return graph.coords;
31591
+ }
31592
+ return defaultLinearCoords.map(points => normalizePoints(range, step, points));
31593
+ }
31594
+ function getPolygonCoords(graph, range, step) {
31595
+ let coords = graph.coords?.slice();
31596
+ if (coords) {
31597
+ return coords;
31598
+ }
31599
+ const n = graph.numSides || 3;
31600
+ if (n === "unlimited") {
31601
+ coords = [];
31602
+ } else {
31603
+ const angle = 2 * Math.PI / n;
31604
+ const offset = (1 / n - 1 / 2) * Math.PI;
31605
+
31606
+ // TODO(alex): Generalize this to more than just triangles so that
31607
+ // all polygons have whole number side lengths if snapping to sides
31608
+ const radius = graph.snapTo === "sides" ? Math.sqrt(3) / 3 * 7 : 4;
31609
+
31610
+ // Generate coords of a regular polygon with n sides
31611
+ coords = [...Array(n).keys()].map(i => [radius * Math.cos(i * angle + offset), radius * Math.sin(i * angle + offset)]);
31612
+ }
31613
+ coords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
31614
+ const snapToGrid = !["angles", "sides"].includes(graph.snapTo || "");
31615
+ coords = normalizePoints(range, step, coords, /* noSnap */!snapToGrid);
31616
+ return coords;
31617
+ }
31618
+ function getSinusoidCoords(graph, range, step) {
31619
+ if (graph.coords) {
31620
+ return [graph.coords[0], graph.coords[1]];
31621
+ }
31622
+ let coords = [[0.5, 0.5], [0.65, 0.6]];
31623
+ coords = normalizePoints(range, step, coords, true);
31624
+ return coords;
31625
+ }
31626
+ function getQuadraticCoords(graph, range, step) {
31627
+ if (graph.coords) {
31628
+ return graph.coords;
31629
+ }
31630
+ const defaultCoords = [[0.25, 0.75], [0.5, 0.25], [0.75, 0.75]];
31631
+ return normalizePoints(range, step, defaultCoords, true);
31632
+ }
31633
+ function getCircleCoords(graph) {
31634
+ if (graph.center != null && graph.radius != null) {
31635
+ return {
31636
+ center: graph.center,
31637
+ radiusPoint: mafs.vec.add(graph.center, [graph.radius, 0])
31638
+ };
31639
+ }
31640
+ return {
31641
+ center: [0, 0],
31642
+ radiusPoint: [2, 0]
31643
+ };
31644
+ }
31645
+
31669
31646
  function interactiveGraphReducer(state, action) {
31670
31647
  switch (action.type) {
31648
+ case REINITIALIZE:
31649
+ return initializeGraphState(action.params);
31671
31650
  case MOVE_CONTROL_POINT:
31672
31651
  return doMoveControlPoint(state, action);
31673
31652
  case MOVE_LINE:
@@ -31803,11 +31782,20 @@ function doMoveAll(state, action) {
31803
31782
  switch (state.type) {
31804
31783
  case "polygon":
31805
31784
  {
31806
- const change = getChange(state.coords, action.delta, {
31807
- snapStep,
31808
- range
31809
- });
31810
- const newCoords = state.coords.map(point => snap(snapStep, mafs.vec.add(point, change)));
31785
+ let newCoords;
31786
+ if (state.snapTo === "sides" || state.snapTo === "angles") {
31787
+ const change = getChange(state.coords, action.delta, {
31788
+ snapStep: [0, 0],
31789
+ range
31790
+ });
31791
+ newCoords = state.coords.map(point => mafs.vec.add(point, change));
31792
+ } else {
31793
+ const change = getChange(state.coords, action.delta, {
31794
+ snapStep,
31795
+ range
31796
+ });
31797
+ newCoords = state.coords.map(point => snap(snapStep, mafs.vec.add(point, change)));
31798
+ }
31811
31799
  return {
31812
31800
  ...state,
31813
31801
  hasBeenInteractedWith: true,
@@ -31822,10 +31810,18 @@ function doMoveAll(state, action) {
31822
31810
  function doMovePoint(state, action) {
31823
31811
  switch (state.type) {
31824
31812
  case "polygon":
31813
+ let newValue;
31814
+ if (state.snapTo === "sides") {
31815
+ newValue = boundAndSnapToSides(action.destination, state, action.index);
31816
+ } else if (state.snapTo === "angles") {
31817
+ newValue = boundAndSnapToAngle(action.destination, state, action.index);
31818
+ } else {
31819
+ newValue = boundAndSnapToGrid(action.destination, state);
31820
+ }
31825
31821
  const newCoords = setAtIndex({
31826
31822
  array: state.coords,
31827
31823
  index: action.index,
31828
- newValue: boundAndSnapToGrid(action.destination, state)
31824
+ newValue: newValue
31829
31825
  });
31830
31826
 
31831
31827
  // Reject the move if it would cause the sides of the polygon to cross
@@ -31871,6 +31867,15 @@ function doMovePoint(state, action) {
31871
31867
  }
31872
31868
  case "quadratic":
31873
31869
  {
31870
+ // Set up the new coords and check if the quadratic coefficients are valid
31871
+ const newCoords = [...state.coords];
31872
+ newCoords[action.index] = action.destination;
31873
+ const QuadraticCoefficients = getQuadraticCoefficients(newCoords);
31874
+
31875
+ // If the new destination results in an invalid quadratic equation, we don't want to move the point
31876
+ if (QuadraticCoefficients === undefined) {
31877
+ return state;
31878
+ }
31874
31879
  return {
31875
31880
  ...state,
31876
31881
  hasBeenInteractedWith: true,
@@ -31968,8 +31973,17 @@ function doChangeRange(state, action) {
31968
31973
  range: action.range
31969
31974
  };
31970
31975
  }
31971
- const getChange = (coords, delta, constraintOpts) => {
31976
+ const getDeltaVertex = (maxMoves, minMoves, delta) => {
31972
31977
  const [deltaX, deltaY] = delta;
31978
+ const maxXMove = Math.min(...maxMoves.map(move => move[0]));
31979
+ const maxYMove = Math.min(...maxMoves.map(move => move[1]));
31980
+ const minXMove = Math.max(...minMoves.map(move => move[0]));
31981
+ const minYMove = Math.max(...minMoves.map(move => move[1]));
31982
+ const dx = clamp(deltaX, minXMove, maxXMove);
31983
+ const dy = clamp(deltaY, minYMove, maxYMove);
31984
+ return [dx, dy];
31985
+ };
31986
+ const getChange = (coords, delta, constraintOpts) => {
31973
31987
  const maxMoves = coords.map(point => maxMove({
31974
31988
  ...constraintOpts,
31975
31989
  point
@@ -31978,14 +31992,15 @@ const getChange = (coords, delta, constraintOpts) => {
31978
31992
  ...constraintOpts,
31979
31993
  point
31980
31994
  }));
31981
- const maxXMove = Math.min(...maxMoves.map(move => move[0]));
31982
- const maxYMove = Math.min(...maxMoves.map(move => move[1]));
31983
- const minXMove = Math.max(...minMoves.map(move => move[0]));
31984
- const minYMove = Math.max(...minMoves.map(move => move[1]));
31985
- const dx = clamp(deltaX, minXMove, maxXMove);
31986
- const dy = clamp(deltaY, minYMove, maxYMove);
31995
+ const [dx, dy] = getDeltaVertex(maxMoves, minMoves, delta);
31987
31996
  return [dx, dy];
31988
31997
  };
31998
+ const eq$1 = Util.eq;
31999
+
32000
+ // Less than or approximately equal
32001
+ function leq$1(a, b) {
32002
+ return a < b || eq$1(a, b);
32003
+ }
31989
32004
  function boundAndSnapToGrid(point, _ref) {
31990
32005
  let {
31991
32006
  snapStep,
@@ -31997,28 +32012,155 @@ function boundAndSnapToGrid(point, _ref) {
31997
32012
  point
31998
32013
  }));
31999
32014
  }
32015
+ function boundAndSnapToAngle(destinationPoint, _ref2, index) {
32016
+ let {
32017
+ range,
32018
+ coords
32019
+ } = _ref2;
32020
+ const startingPoint = coords[index];
32021
+
32022
+ // Needed to prevent updating the original coords before the checks for
32023
+ // degenerate triangles and overlapping sides
32024
+ const coordsCopy = [...coords];
32025
+
32026
+ // Takes the destination point and makes sure it is within the bounds of the graph
32027
+ // SnapStep is [0, 0] because we don't want to snap to the grid
32028
+ coordsCopy[index] = bound$1({
32029
+ snapStep: [0, 0],
32030
+ range,
32031
+ point: destinationPoint
32032
+ });
32033
+
32034
+ // Gets the radian angles between the coords and maps them to degrees
32035
+ const angles = angleMeasures(coordsCopy).map(angle => angle * 180 / Math.PI);
32036
+
32037
+ // Gets the relative index of a point
32038
+ const rel = j => {
32039
+ return (index + j + coordsCopy.length) % coordsCopy.length;
32040
+ };
32041
+
32042
+ // Round the angles to left and right of the current point
32043
+ ___default["default"].each([-1, 1], function (j) {
32044
+ angles[rel(j)] = Math.round(angles[rel(j)]);
32045
+ });
32046
+ const getAngle = function (a, vertex, b) {
32047
+ const angle = GraphUtils.findAngle(coordsCopy[rel(a)], coordsCopy[rel(b)], coordsCopy[rel(vertex)]);
32048
+ return (angle + 360) % 360;
32049
+ };
32050
+ const innerAngles = [angles[rel(-1)] - getAngle(-2, -1, 1), angles[rel(1)] - getAngle(-1, 1, 2)];
32051
+ innerAngles[2] = 180 - (innerAngles[0] + innerAngles[1]);
32052
+
32053
+ // Avoid degenerate triangles
32054
+ if (innerAngles.some(function (angle) {
32055
+ return leq$1(angle, 1);
32056
+ })) {
32057
+ return startingPoint;
32058
+ }
32059
+ const knownSide = magnitude(
32060
+ // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'.
32061
+ vector(coordsCopy[rel(-1)], coordsCopy[rel(1)]));
32062
+
32063
+ // Returns true if the points form a counter-clockwise turn;
32064
+ // a.k.a if the point is on the left or right of the polygon.
32065
+ // This is used to determine how to adjust the point: if the point is on the left,
32066
+ // we want to add the inner angle to the outer angle, and if it's on the right,
32067
+ // we want to subtract the inner angle from the outer angle. The angle solved
32068
+ // for is then used in the polar function to determine the new point.
32069
+ const onLeft = sign(ccw(coordsCopy[rel(-1)], coordsCopy[rel(1)], coordsCopy[index])) === 1;
32070
+
32071
+ // Solve for side by using the law of sines
32072
+ const side = Math.sin(innerAngles[1] * Math.PI / 180) / Math.sin(innerAngles[2] * Math.PI / 180) * knownSide;
32073
+
32074
+ // Angle at the second vertex of the polygon
32075
+ const outerAngle = GraphUtils.findAngle(coordsCopy[rel(1)], coordsCopy[rel(-1)]);
32076
+
32077
+ // Uses the length of the side of the polygon (radial coordinate)
32078
+ // and the angle between the first and second sides of the
32079
+ // polygon (angular coordinate) to determine how to adjust the point
32080
+ const offset = polar(side, outerAngle + (onLeft ? 1 : -1) * innerAngles[0]);
32081
+ return kmath.vector.add(coordsCopy[rel(-1)], offset);
32082
+ }
32083
+ function boundAndSnapToSides(destinationPoint, _ref3, index) {
32084
+ let {
32085
+ range,
32086
+ coords
32087
+ } = _ref3;
32088
+ const startingPoint = coords[index];
32089
+
32090
+ // Needed to prevent updating the original coords before the checks for
32091
+ // degenerate triangles and overlapping sides
32092
+ const coordsCopy = [...coords];
32093
+
32094
+ // Takes the destination point and makes sure it is within the bounds of the graph
32095
+ // SnapStep is [0, 0] because we don't want to snap to the grid
32096
+ coordsCopy[index] = bound$1({
32097
+ snapStep: [0, 0],
32098
+ range,
32099
+ point: destinationPoint
32100
+ });
32101
+
32102
+ // Gets the relative index of a point
32103
+ const rel = j => {
32104
+ return (index + j + coordsCopy.length) % coordsCopy.length;
32105
+ };
32106
+ const sides = ___default["default"].map([[coordsCopy[rel(-1)], coordsCopy[index]], [coordsCopy[index], coordsCopy[rel(1)]], [coordsCopy[rel(-1)], coordsCopy[rel(1)]]], function (coordsCopy) {
32107
+ // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'. | TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
32108
+ return magnitude(vector(...coordsCopy));
32109
+ });
32110
+
32111
+ // Round the sides to left and right of the current point
32112
+ ___default["default"].each([0, 1], function (j) {
32113
+ sides[j] = Math.round(sides[j]);
32114
+ });
32115
+
32116
+ // Avoid degenerate triangles
32117
+ if (leq$1(sides[1] + sides[2], sides[0]) || leq$1(sides[0] + sides[2], sides[1]) || leq$1(sides[0] + sides[1], sides[2])) {
32118
+ return startingPoint;
32119
+ }
32120
+
32121
+ // Solve for angle by using the law of cosines
32122
+ // Angle at the first vertex of the polygon
32123
+ const innerAngle = lawOfCosines(sides[0], sides[2], sides[1]);
32124
+
32125
+ // Angle at the second vertex of the polygon
32126
+ const outerAngle = GraphUtils.findAngle(coordsCopy[rel(1)], coordsCopy[rel(-1)]);
32127
+
32128
+ // Returns true if the points form a counter-clockwise turn;
32129
+ // a.k.a if the point is on the left or right of the polygon.
32130
+ // This is used to determine how to adjust the point: if the point is on the left,
32131
+ // we want to add the inner angle to the outer angle, and if it's on the right,
32132
+ // we want to subtract the inner angle from the outer angle. The angle solved
32133
+ // for is then used in the polar function to determine the new point.
32134
+ const onLeft = sign(ccw(coordsCopy[rel(-1)], coordsCopy[rel(1)], coordsCopy[index])) === 1;
32135
+
32136
+ // Uses the length of the first side of the polygon (radial coordinate)
32137
+ // and the angle between the first and second sides of the
32138
+ // polygon (angular coordinate) to determine how to adjust the point
32139
+ const offset = polar(sides[0], outerAngle + (onLeft ? 1 : -1) * innerAngle);
32140
+ return kmath.vector.add(coordsCopy[rel(-1)], offset);
32141
+ }
32000
32142
 
32001
32143
  // Returns the closest point to the given `point` that is within the graph
32002
32144
  // bounds given in `state`.
32003
- function bound$1(_ref2) {
32145
+ function bound$1(_ref4) {
32004
32146
  let {
32005
32147
  snapStep,
32006
32148
  range,
32007
32149
  point
32008
- } = _ref2;
32150
+ } = _ref4;
32009
32151
  const [requestedX, requestedY] = point;
32010
32152
  const [snapX, snapY] = snapStep;
32011
32153
  const [[minX, maxX], [minY, maxY]] = range;
32012
32154
  return [clamp(requestedX, minX + snapX, maxX - snapX), clamp(requestedY, minY + snapY, maxY - snapY)];
32013
32155
  }
32014
32156
 
32015
- // Returns the vector from the given point to the top-right corner of the graph
32016
- function maxMove(_ref3) {
32157
+ // Returns the vector from the given point to the top-right corner of the graph when snapped to the grid
32158
+ function maxMove(_ref5) {
32017
32159
  let {
32018
32160
  snapStep,
32019
32161
  range,
32020
32162
  point
32021
- } = _ref3;
32163
+ } = _ref5;
32022
32164
  const topRight = bound$1({
32023
32165
  snapStep,
32024
32166
  range,
@@ -32027,14 +32169,13 @@ function maxMove(_ref3) {
32027
32169
  return mafs.vec.sub(topRight, point);
32028
32170
  }
32029
32171
 
32030
- // Returns the vector from the given point to the bottom-left corner of the
32031
- // graph
32032
- function minMove(_ref4) {
32172
+ // Returns the vector from the given point to the bottom-left corner of the graph when snapped to the grid
32173
+ function minMove(_ref6) {
32033
32174
  let {
32034
32175
  snapStep,
32035
32176
  range,
32036
32177
  point
32037
- } = _ref4;
32178
+ } = _ref6;
32038
32179
  const bottomLeft = bound$1({
32039
32180
  snapStep,
32040
32181
  range,
@@ -32155,11 +32296,12 @@ function mafsStateToInteractiveGraph(state) {
32155
32296
  }
32156
32297
  const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
32157
32298
  const {
32158
- onChange
32299
+ onChange,
32300
+ graph
32159
32301
  } = props;
32160
32302
  const [state, dispatch] = React__namespace.useReducer(interactiveGraphReducer, props, initializeGraphState);
32161
32303
  React.useImperativeHandle(ref, () => ({
32162
- getUserInput: () => getGradableGraph(state, props.graph)
32304
+ getUserInput: () => getGradableGraph(state, graph)
32163
32305
  }));
32164
32306
  const prevState = React.useRef(state);
32165
32307
  React.useEffect(() => {
@@ -32182,6 +32324,18 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
32182
32324
  React.useEffect(() => {
32183
32325
  dispatch(changeRange([[xMinRange, xMaxRange], [yMinRange, yMaxRange]]));
32184
32326
  }, [dispatch, xMinRange, xMaxRange, yMinRange, yMaxRange]);
32327
+ const numSegments = graph.type === "segment" ? graph.numSegments : null;
32328
+ const originalPropsRef = React.useRef(props);
32329
+ const latestPropsRef = wonderBlocksCore.useLatestRef(props);
32330
+ React.useEffect(() => {
32331
+ // This conditional prevents the state from being "reinitialized" right
32332
+ // after the first render. This is an optimization, but also prevents
32333
+ // a bug where the graph would be marked "incorrect" during grading
32334
+ // even if the user never interacted with it.
32335
+ if (latestPropsRef.current !== originalPropsRef.current) {
32336
+ dispatch(reinitialize(latestPropsRef.current));
32337
+ }
32338
+ }, [graph.type, numSegments, latestPropsRef]);
32185
32339
  return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends({}, props, {
32186
32340
  state: state,
32187
32341
  dispatch: dispatch
@@ -44343,7 +44497,7 @@ const init = function (options) {
44343
44497
 
44344
44498
  // This file is processed by a Rollup plugin (replace) to inject the production
44345
44499
  const libName = "@khanacademy/perseus";
44346
- const libVersion = "23.3.0";
44500
+ const libVersion = "23.5.0";
44347
44501
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
44348
44502
 
44349
44503
  const apiVersion = {
@@ -47443,8 +47597,8 @@ exports.itemDataVersion = itemDataVersion;
47443
47597
  exports.itemToTree = itemToTree;
47444
47598
  exports.itemVersion = ItemVersion;
47445
47599
  exports.libVersion = libVersion;
47446
- exports.lockedEllipseFillStyles = lockedEllipseFillStyles;
47447
47600
  exports.lockedFigureColors = lockedFigureColors;
47601
+ exports.lockedFigureFillStyles = lockedFigureFillStyles;
47448
47602
  exports.mediaQueries = mediaQueries;
47449
47603
  exports.parsePerseusItem = parsePerseusItem;
47450
47604
  exports.plotterPlotTypes = plotterPlotTypes;