@khanacademy/perseus 24.3.0 → 25.0.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
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var KAS = require('@khanacademy/kas');
6
6
  var mathInput = require('@khanacademy/math-input');
7
+ var perseusCore = require('@khanacademy/perseus-core');
7
8
  var PerseusLinter = require('@khanacademy/perseus-linter');
8
9
  var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
9
10
  var Tooltip$1 = require('@khanacademy/wonder-blocks-tooltip');
@@ -40,7 +41,6 @@ var Switch = require('@khanacademy/wonder-blocks-switch');
40
41
  var Pill = require('@khanacademy/wonder-blocks-pill');
41
42
  var reactPopper = require('react-popper');
42
43
  var Link = require('@khanacademy/wonder-blocks-link');
43
- var perseusCore = require('@khanacademy/perseus-core');
44
44
 
45
45
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
46
46
 
@@ -803,52 +803,9 @@ var dependencies = /*#__PURE__*/Object.freeze({
803
803
  // TODO(LP-11481): Change the primary API we use for logging in Perseus to use
804
804
  // getDependencies() internally... simplify usage to just using a "singleton"
805
805
  // which get's the injected logger.
806
- /**
807
- * @typedef {Object} Errors utility for referencing the Perseus error taxonomy.
808
- */
809
- const Errors = Object.freeze({
810
- /**
811
- * @property {ErrorKind} Unknown The kind of error is not known.
812
- */
813
- Unknown: "Unknown",
814
- /**
815
- * @property {ErrorKind} Internal The error is internal to the executing code.
816
- */
817
- Internal: "Internal",
818
- /**
819
- * @property {ErrorKind} InvalidInput There was a problem with the provided
820
- * input, such as the wrong format or a null value.
821
- */
822
- InvalidInput: "InvalidInput",
823
- /**
824
- * @property {ErrorKind} NotAllowed There was a problem due to the state of
825
- * the system not matching the requested operation or input. For example,
826
- * trying to create a username that is valid, but is already taken by
827
- * another user. Use {@link InvalidInput} instead when the input isn't
828
- * valid regardless of the state of the system. Use {@link NotFound} when
829
- * the failure is due to not being able to find a resource.
830
- */
831
- NotAllowed: "NotAllowed",
832
- /**
833
- * @property {ErrorKind} TransientService There was a problem when making a
834
- * request to a service.
835
- */
836
- TransientService: "TransientService",
837
- /**
838
- * @property {ErrorKind} Service There was a non-transient problem when
839
- * making a request to service.
840
- */
841
- Service: "Service"
842
- });
843
-
844
- /**
845
- * @type {ErrorKind} The kind of error being reported
846
- */
847
-
848
806
  /**
849
807
  * Provides logging infrastructure for Perseus
850
808
  */
851
-
852
809
  const Log = {
853
810
  // Logs a message
854
811
  log: (message, extra) => {
@@ -860,16 +817,6 @@ const Log = {
860
817
  }
861
818
  };
862
819
 
863
- class PerseusError extends Error {
864
- kind;
865
- metadata;
866
- constructor(message, kind, options) {
867
- super(message);
868
- this.kind = kind;
869
- this.metadata = options?.metadata;
870
- }
871
- }
872
-
873
820
  /**
874
821
  * These are things that widgets should exclude when serializing themselves.
875
822
  *
@@ -973,9 +920,9 @@ const change = function (newPropsOrSinglePropName, propValue, callback) {
973
920
  // string propName
974
921
  propValue, callback);
975
922
  }
976
- throw new PerseusError("Invalid types sent to this.change(): " +
923
+ throw new perseusCore.PerseusError("Invalid types sent to this.change(): " +
977
924
  // eslint-disable-next-line prefer-rest-params
978
- ___default["default"].toArray(arguments).join() + "\n" + USAGE, Errors.Internal);
925
+ ___default["default"].toArray(arguments).join() + "\n" + USAGE, perseusCore.Errors.Internal);
979
926
  };
980
927
  const propTypes = {
981
928
  onChange: PropTypes__default["default"].func.isRequired
@@ -2148,9 +2095,9 @@ const KhanAnswerTypes = {
2148
2095
  parseSolution: function (solutionString, options) {
2149
2096
  let solution = KAS__namespace.parse(solutionString, options);
2150
2097
  if (!solution.parsed) {
2151
- throw new PerseusError("The provided solution (" + solutionString + ") didn't parse.", Errors.InvalidInput);
2098
+ throw new perseusCore.PerseusError("The provided solution (" + solutionString + ") didn't parse.", perseusCore.Errors.InvalidInput);
2152
2099
  } else if (options.simplified && !solution.expr.isSimplified()) {
2153
- throw new PerseusError("The provided solution (" + solutionString + ") isn't fully expanded and simplified.", Errors.InvalidInput);
2100
+ throw new perseusCore.PerseusError("The provided solution (" + solutionString + ") isn't fully expanded and simplified.", perseusCore.Errors.InvalidInput);
2154
2101
  } else {
2155
2102
  solution = solution.expr;
2156
2103
  }
@@ -2341,7 +2288,7 @@ class Expression extends React__namespace.Component {
2341
2288
  // in the function variables list for the expression.
2342
2289
  if (!expression.parsed) {
2343
2290
  /* c8 ignore next */
2344
- Log.error("Unable to parse solution answer for expression", Errors.InvalidInput, {
2291
+ Log.error("Unable to parse solution answer for expression", perseusCore.Errors.InvalidInput, {
2345
2292
  loggedMetadata: {
2346
2293
  rubric: JSON.stringify(rubric)
2347
2294
  }
@@ -3032,7 +2979,7 @@ function combineScores(scoreA, scoreB) {
3032
2979
  * The above checks cover all combinations of score type, so if we get here
3033
2980
  * then something is amiss with our inputs.
3034
2981
  */
3035
- throw new PerseusError("PerseusScore with unknown type encountered", Errors.InvalidInput, {
2982
+ throw new perseusCore.PerseusError("PerseusScore with unknown type encountered", perseusCore.Errors.InvalidInput, {
3036
2983
  metadata: {
3037
2984
  scoreA: JSON.stringify(scoreA),
3038
2985
  scoreB: JSON.stringify(scoreB)
@@ -3062,9 +3009,9 @@ function keScoreFromPerseusScore(score, guess, state) {
3062
3009
  state: state
3063
3010
  };
3064
3011
  }
3065
- throw new PerseusError(
3012
+ throw new perseusCore.PerseusError(
3066
3013
  // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
3067
- "Invalid score type: " + score.type, Errors.InvalidInput, {
3014
+ "Invalid score type: " + score.type, perseusCore.Errors.InvalidInput, {
3068
3015
  metadata: {
3069
3016
  score: JSON.stringify(score),
3070
3017
  guess: JSON.stringify(guess),
@@ -4433,7 +4380,7 @@ const MovableHelperMethods = {
4433
4380
  return memo;
4434
4381
  }
4435
4382
  // Anything else is an error
4436
- throw new PerseusError("Constraint returned invalid result: " + result, Errors.Internal);
4383
+ throw new perseusCore.PerseusError("Constraint returned invalid result: " + result, perseusCore.Errors.Internal);
4437
4384
  }, current, this);
4438
4385
  },
4439
4386
  /**
@@ -4539,7 +4486,7 @@ const FUNCTION_ARRAY_OPTIONS = ["add", "modify", "draw", "remove", "constraints"
4539
4486
  const InteractiveUtil = {
4540
4487
  assert: function (isTrue, message) {
4541
4488
  if (!isTrue) {
4542
- throw new PerseusError("Assertion Error" + (message ? ": " + message : ""), Errors.Internal);
4489
+ throw new perseusCore.PerseusError("Assertion Error" + (message ? ": " + message : ""), perseusCore.Errors.Internal);
4543
4490
  }
4544
4491
  },
4545
4492
  /**
@@ -9120,7 +9067,7 @@ class Graphie$1 {
9120
9067
  // TODO(jeremy): This can be removed once we're confident that callers
9121
9068
  // obey the Typescript types.
9122
9069
  if (options.range == null) {
9123
- throw new PerseusError("range should be specified in graph init", Errors.Internal);
9070
+ throw new perseusCore.PerseusError("range should be specified in graph init", perseusCore.Errors.Internal);
9124
9071
  }
9125
9072
  this.#bounds = new GraphBounds(...options.range);
9126
9073
  this.#drawingTransform = new DrawingTransform(this.raphael, scale, this.bounds());
@@ -13707,7 +13654,7 @@ function MovableAngle(graphie, options) {
13707
13654
 
13708
13655
  // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
13709
13656
  if (!this.points || this.points.length !== 3) {
13710
- throw new PerseusError("MovableAngle requires 3 points", Errors.InvalidInput);
13657
+ throw new perseusCore.PerseusError("MovableAngle requires 3 points", perseusCore.Errors.InvalidInput);
13711
13658
  }
13712
13659
 
13713
13660
  // Handle coordinates that are not MovablePoints (i.e. [2, 4])
@@ -13998,9 +13945,9 @@ function GraphieMovable$1(descriptor) {
13998
13945
  ___default["default"].extend(this, descriptor);
13999
13946
  }
14000
13947
  const abstractMethod = function () {
14001
- throw new PerseusError("Abstract method! Must be implemented by Graphie Movable" +
13948
+ throw new perseusCore.PerseusError("Abstract method! Must be implemented by Graphie Movable" +
14002
13949
  // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
14003
- this.constructor.displayName, Errors.NotAllowed);
13950
+ this.constructor.displayName, perseusCore.Errors.NotAllowed);
14004
13951
  };
14005
13952
  ___default["default"].extend(GraphieMovable$1.prototype, {
14006
13953
  movableProps: [],
@@ -14040,7 +13987,7 @@ const createClass = function (spec) {
14040
13987
  const GraphieClass = function (props) {
14041
13988
  // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
14042
13989
  if (!(this instanceof GraphieClass)) {
14043
- throw new PerseusError("Use createElement or JSX with graphie movables", Errors.NotAllowed);
13990
+ throw new perseusCore.PerseusError("Use createElement or JSX with graphie movables", perseusCore.Errors.NotAllowed);
14044
13991
  }
14045
13992
  // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
14046
13993
  this.props = rewriteProps(props, props.children || []);
@@ -14359,7 +14306,7 @@ class Movable {
14359
14306
  return memo;
14360
14307
  }
14361
14308
  // Anything else is an error
14362
- throw new PerseusError("Constraint returned invalid result: " + result, Errors.Internal);
14309
+ throw new perseusCore.PerseusError("Constraint returned invalid result: " + result, perseusCore.Errors.Internal);
14363
14310
  }, current);
14364
14311
  }
14365
14312
 
@@ -15709,7 +15656,7 @@ class MovablePoint$4 {
15709
15656
  return memo;
15710
15657
  }
15711
15658
  // Anything else is an error
15712
- throw new PerseusError("Constraint returned invalid result: " + result, Errors.Internal);
15659
+ throw new perseusCore.PerseusError("Constraint returned invalid result: " + result, perseusCore.Errors.Internal);
15713
15660
  }, current);
15714
15661
  }
15715
15662
 
@@ -16864,7 +16811,7 @@ class Graphie extends React__namespace.Component {
16864
16811
  // would have horrible performance implications. In order to avoid
16865
16812
  // those, we just warn here.
16866
16813
  if (this.props.setup !== prevProps.setup) {
16867
- Log.error("<Graphie> was given a new setup function. " + "This is a bad idea; please refactor your code to give " + "the same setup function reference to <Graphie> on " + "every render.", Errors.Internal);
16814
+ Log.error("<Graphie> was given a new setup function. " + "This is a bad idea; please refactor your code to give " + "the same setup function reference to <Graphie> on " + "every render.", perseusCore.Errors.Internal);
16868
16815
  }
16869
16816
  if (!deepEq$2(this.props.options, prevProps.options) || !deepEq$2(this.props.box, prevProps.box) || !deepEq$2(this.props.range, prevProps.range)) {
16870
16817
  this._setupGraphie();
@@ -17043,7 +16990,7 @@ class Graphie extends React__namespace.Component {
17043
16990
  // This generally is a bad idea, so warn about it if this
17044
16991
  // is being caused by implicit keys
17045
16992
  if (keyProp == null) {
17046
- Log.error("Replacing a <Graphie> child with a " + "child of a different type. Please add keys " + "to your <Graphie> children", Errors.Internal);
16993
+ Log.error("Replacing a <Graphie> child with a " + "child of a different type. Please add keys " + "to your <Graphie> children", perseusCore.Errors.Internal);
17047
16994
  }
17048
16995
  prevMovable.remove();
17049
16996
  child.add(graphie);
@@ -17320,7 +17267,7 @@ function getLocalizedDataUrl(url) {
17320
17267
  function getUrlHash(url) {
17321
17268
  const match = url.match(hashRegex);
17322
17269
  if (match == null) {
17323
- throw new PerseusError("not a valid URL", Errors.InvalidInput);
17270
+ throw new perseusCore.PerseusError("not a valid URL", perseusCore.Errors.InvalidInput);
17324
17271
  }
17325
17272
  return match && match[1];
17326
17273
  }
@@ -17457,7 +17404,7 @@ class SvgImage extends React__namespace.Component {
17457
17404
  // If there is isn't any localized data, fall back to
17458
17405
  // the original, unlocalized data
17459
17406
  retrieveData(Util.getDataUrl(this.props.src), (x, status, error) => {
17460
- Log.error("Data load failed for svg-image", Errors.Service, {
17407
+ Log.error("Data load failed for svg-image", perseusCore.Errors.Service, {
17461
17408
  cause: error,
17462
17409
  loggedMetadata: {
17463
17410
  dataUrl: Util.getDataUrl(this.props.src),
@@ -17468,7 +17415,7 @@ class SvgImage extends React__namespace.Component {
17468
17415
  });
17469
17416
  } else {
17470
17417
  retrieveData(Util.getDataUrl(this.props.src), (x, status, error) => {
17471
- Log.error("Data load failed for svg-image", Errors.Service, {
17418
+ Log.error("Data load failed for svg-image", perseusCore.Errors.Service, {
17472
17419
  cause: error,
17473
17420
  loggedMetadata: {
17474
17421
  dataUrl: Util.getDataUrl(this.props.src),
@@ -17720,7 +17667,7 @@ class SvgImage extends React__namespace.Component {
17720
17667
  } else if (this.state.imageDimensions) {
17721
17668
  box = [this.state.imageDimensions[0] * this.props.scale, this.state.imageDimensions[1] * this.props.scale];
17722
17669
  } else {
17723
- throw new PerseusError("svg-image has no dimensions", Errors.InvalidInput, {
17670
+ throw new perseusCore.PerseusError("svg-image has no dimensions", perseusCore.Errors.InvalidInput, {
17724
17671
  metadata: {
17725
17672
  src: this.props.src
17726
17673
  }
@@ -18148,7 +18095,7 @@ class ErrorBoundary extends React__namespace.Component {
18148
18095
  // differentiate between the different errors that are thrown, they
18149
18096
  // all end up being grouped as a single Sentry event, which is very
18150
18097
  // unhelpful.
18151
- "Unhandled Perseus error: " + error.message, Errors.Internal, {
18098
+ "Unhandled Perseus error: " + error.message, perseusCore.Errors.Internal, {
18152
18099
  cause: error,
18153
18100
  loggedMetadata: {
18154
18101
  componentStack: !!info && "componentStack" in info ? info.componentStack : "componentStack not provided",
@@ -19201,7 +19148,7 @@ const replaceWidget = (name, replacementName) => {
19201
19148
  // that doesn't exist at all.
19202
19149
  if (!substituteWidget) {
19203
19150
  const errorMsg = `Failed to replace ${name} with ${replacementName}`;
19204
- throw new PerseusError(errorMsg, Errors.Internal);
19151
+ throw new perseusCore.PerseusError(errorMsg, perseusCore.Errors.Internal);
19205
19152
  }
19206
19153
  registerWidget(name, substituteWidget);
19207
19154
  };
@@ -19215,7 +19162,7 @@ const replaceDeprecatedWidgets = () => {
19215
19162
  const registerEditors = editorsToRegister => {
19216
19163
  editorsToRegister.forEach(editor => {
19217
19164
  if (!editor.widgetName) {
19218
- throw new PerseusError(`Editor ${editor.displayName} doesn't have a widgetName property`, Errors.Internal);
19165
+ throw new perseusCore.PerseusError(`Editor ${editor.displayName} doesn't have a widgetName property`, perseusCore.Errors.Internal);
19219
19166
  }
19220
19167
  editors[editor.widgetName] = editor;
19221
19168
  });
@@ -19233,7 +19180,7 @@ const replaceEditor = (name, replacementName) => {
19233
19180
  const substituteEditor = editors[replacementName];
19234
19181
  if (!substituteEditor && Log) {
19235
19182
  const errorMsg = `Failed to replace editor ${name} with ${replacementName}`;
19236
- Log.error(errorMsg, Errors.Internal);
19183
+ Log.error(errorMsg, perseusCore.Errors.Internal);
19237
19184
  return;
19238
19185
  }
19239
19186
  editors[name] = substituteEditor;
@@ -19307,7 +19254,7 @@ const upgradeWidgetInfoToLatestVersion = oldWidgetInfo => {
19307
19254
  // suspect we have legacy data (potentially unpublished) and we should
19308
19255
  // figure that out before depending solely on types.
19309
19256
  if (!___default["default"].isString(type)) {
19310
- throw new PerseusError("widget type must be a string, but was: " + type, Errors.Internal);
19257
+ throw new perseusCore.PerseusError("widget type must be a string, but was: " + type, perseusCore.Errors.Internal);
19311
19258
  }
19312
19259
  const widgetExports = widgets[type];
19313
19260
  if (widgetExports == null) {
@@ -19358,7 +19305,7 @@ const upgradeWidgetInfoToLatestVersion = oldWidgetInfo => {
19358
19305
  // This is a Log.error because it is unlikely to be hit in
19359
19306
  // local testing, and a Log.error is slightly less scary in
19360
19307
  // prod than a `throw new Error`
19361
- Log.error("No upgrade found for widget. Cannot render.", Errors.Internal, {
19308
+ Log.error("No upgrade found for widget. Cannot render.", perseusCore.Errors.Internal, {
19362
19309
  loggedMetadata: {
19363
19310
  type,
19364
19311
  fromMajorVersion: nextVersion - 1,
@@ -19431,7 +19378,7 @@ const getRendererPropsForWidgetInfo = (widgetInfo, strings, problemNum) => {
19431
19378
  };
19432
19379
  const traverseChildWidgets$3 = (widgetInfo, traverseRenderer) => {
19433
19380
  if (!traverseRenderer) {
19434
- throw new PerseusError("traverseRenderer must be provided, but was not", Errors.Internal);
19381
+ throw new perseusCore.PerseusError("traverseRenderer must be provided, but was not", perseusCore.Errors.Internal);
19435
19382
  }
19436
19383
  if (!widgetInfo || !widgetInfo.type || !widgets[widgetInfo.type]) {
19437
19384
  return widgetInfo;
@@ -19500,12 +19447,12 @@ const validAlignments = ["block", "inline-block", "inline", "float-left", "float
19500
19447
  const validateAlignments = () => {
19501
19448
  ___default["default"].each(widgets, function (widgetInfo) {
19502
19449
  if (widgetInfo.defaultAlignment && !___default["default"].contains(validAlignments, widgetInfo.defaultAlignment)) {
19503
- throw new PerseusError("Widget '" + widgetInfo.displayName + "' has an invalid defaultAlignment value: " + widgetInfo.defaultAlignment, Errors.InvalidInput);
19450
+ throw new perseusCore.PerseusError("Widget '" + widgetInfo.displayName + "' has an invalid defaultAlignment value: " + widgetInfo.defaultAlignment, perseusCore.Errors.InvalidInput);
19504
19451
  }
19505
19452
  if (widgetInfo.supportedAlignments) {
19506
19453
  const unknownAlignments = ___default["default"].difference(widgetInfo.supportedAlignments, validAlignments);
19507
19454
  if (unknownAlignments.length) {
19508
- throw new PerseusError("Widget '" + widgetInfo.displayName + "' has an invalid value for supportedAlignments: " + unknownAlignments.join(" "), Errors.InvalidInput);
19455
+ throw new perseusCore.PerseusError("Widget '" + widgetInfo.displayName + "' has an invalid value for supportedAlignments: " + unknownAlignments.join(" "), perseusCore.Errors.InvalidInput);
19509
19456
  }
19510
19457
  }
19511
19458
  });
@@ -20131,7 +20078,7 @@ class Renderer extends React__namespace.Component {
20131
20078
 
20132
20079
  // If the two lists of IDs match (ignoring order)
20133
20080
  if (serializedWidgetIds.length !== widgetPropIds.length || ___default["default"].intersection(serializedWidgetIds, widgetPropIds).length !== serializedWidgetIds.length) {
20134
- Log.error("Refusing to restore bad serialized state:", Errors.Internal, {
20081
+ Log.error("Refusing to restore bad serialized state:", perseusCore.Errors.Internal, {
20135
20082
  loggedMetadata: {
20136
20083
  serializedState: JSON.stringify(serializedState),
20137
20084
  currentProps: JSON.stringify(this.state.widgetProps)
@@ -20289,7 +20236,7 @@ class Renderer extends React__namespace.Component {
20289
20236
  return function (id) {
20290
20237
  let focusPath = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
20291
20238
  if (!___default["default"].isArray(focusPath)) {
20292
- throw new PerseusError("widget props.onFocus focusPath must be an Array, " + "but was" + JSON.stringify(focusPath), Errors.Internal);
20239
+ throw new perseusCore.PerseusError("widget props.onFocus focusPath must be an Array, " + "but was" + JSON.stringify(focusPath), perseusCore.Errors.Internal);
20293
20240
  }
20294
20241
  _this2._setCurrentFocus([id].concat(focusPath));
20295
20242
  };
@@ -20773,7 +20720,7 @@ class Renderer extends React__namespace.Component {
20773
20720
  // object return value.
20774
20721
  // The result of focus was a {path, id} object itself
20775
20722
  path = [id].concat(focusResult.path || []);
20776
- Log.error("Renderer received a focus result of type 'object' " + "instead of the expected type 'boolean'", Errors.Internal, {
20723
+ Log.error("Renderer received a focus result of type 'object' " + "instead of the expected type 'boolean'", perseusCore.Errors.Internal, {
20777
20724
  loggedMetadata: {
20778
20725
  focusResult: JSON.stringify(focusResult),
20779
20726
  currentProps: JSON.stringify(this.state.widgetProps)
@@ -28723,7 +28670,44 @@ function inset(amount, box) {
28723
28670
  return [trim(amount[X], box[X]), trim(amount[Y], box[Y])];
28724
28671
  }
28725
28672
 
28673
+ // [L]inear Int[erp]olation: gets the weighted average of two values `a` and
28674
+ // `b`, with the given `fraction` specifying how much weight `a` and `b` get:
28675
+ // - if `fraction` is 0, `lerp` returns `a`.
28676
+ // - if `fraction` is 0.5, `lerp` returns the average of `a` and `b`.
28677
+ // - if `fraction` is 1, `lerp` returns `b`.
28678
+ function lerp(a, b, fraction) {
28679
+ return (b - a) * clamp(fraction, 0, 1) + a;
28680
+ }
28681
+
28682
+ // Determines whether two line segments have exactly one intersection point.
28683
+ // The segments are treated as "open" - that is, not inclusive of their
28684
+ // endpoints.
28685
+ // Algorithm from https://stackoverflow.com/a/24392281/7347484
28686
+ const segmentsIntersect = (_ref, _ref2) => {
28687
+ let [[a, b], [c, d]] = _ref;
28688
+ let [[p, q], [r, s]] = _ref2;
28689
+ const determinant = (c - a) * (s - q) - (r - p) * (d - b);
28690
+ if (determinant === 0) {
28691
+ return false;
28692
+ } else {
28693
+ const lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / determinant;
28694
+ const gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / determinant;
28695
+ return 0 < lambda && lambda < 1 && 0 < gamma && gamma < 1;
28696
+ }
28697
+ };
28698
+
28726
28699
  // This file contains helper functions for working with angles.
28700
+
28701
+ function convertDegreesToRadians(degrees) {
28702
+ return degrees / 180 * Math.PI;
28703
+ }
28704
+
28705
+ // Returns a value between -180 and 180, inclusive. The angle is measured
28706
+ // between the positive x-axis and the given vector.
28707
+ function calculateAngleInDegrees(_ref) {
28708
+ let [x, y] = _ref;
28709
+ return Math.atan2(y, x) * 180 / Math.PI;
28710
+ }
28727
28711
  function polar(r, th) {
28728
28712
  if (typeof r === "number") {
28729
28713
  r = [r, r];
@@ -29061,52 +29045,6 @@ function Arrowhead(props) {
29061
29045
  })));
29062
29046
  }
29063
29047
 
29064
- function calculateAngleInDegrees(_ref) {
29065
- let [x, y] = _ref;
29066
- return Math.atan2(y, x) * 180 / Math.PI;
29067
- }
29068
-
29069
- /**
29070
- * Given a ray and a rectangular box, find the point where the ray intersects
29071
- * the edge of the box. Assumes the `initialPoint` is inside the box.
29072
- * @param initialPoint - The starting point of the ray.
29073
- * @param throughPoint - A point that the ray passes through. Must be different from initialPoint.
29074
- * @param box - The box with which to intersect the ray, in the form [[xMin, xMax], [yMin, yMax]]
29075
- */
29076
- const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
29077
- const [[xMin, xMax], [yMin, yMax]] = box;
29078
- const [aX, aY] = initialPoint;
29079
- const [bX, bY] = throughPoint;
29080
- const yDiff = bY - aY;
29081
- const xDiff = bX - aX;
29082
- const slope = yDiff / xDiff;
29083
- const inverseSlope = 1 / slope;
29084
- const xExtreme = xDiff < 0 ? xMin : xMax;
29085
- const yExtreme = yDiff < 0 ? yMin : yMax;
29086
- const yAtXExtreme = aY + (xExtreme - aX) * slope;
29087
- const xAtYExtreme = aX + (yExtreme - aY) * inverseSlope;
29088
- switch (true) {
29089
- // does the ray exit the graph bounding box via the left or right edge?
29090
- case isBetween(yAtXExtreme, yMin, yMax):
29091
- return [xExtreme, yAtXExtreme];
29092
-
29093
- // does the ray exit the graph bounding box via the top or bottom edge?
29094
- case isBetween(xAtYExtreme, xMin, xMax):
29095
- return [xAtYExtreme, yExtreme];
29096
- default:
29097
- return [xExtreme, yExtreme];
29098
- }
29099
- };
29100
- const getLines = points => {
29101
- return points.map((point, i) => {
29102
- const next = points[(i + 1) % points.length];
29103
- return [point, next];
29104
- });
29105
- };
29106
- function isBetween(x, low, high) {
29107
- return x >= low && x <= high;
29108
- }
29109
-
29110
29048
  function SVGLine(props) {
29111
29049
  const {
29112
29050
  start,
@@ -29152,6 +29090,41 @@ function Vector(props) {
29152
29090
  }));
29153
29091
  }
29154
29092
 
29093
+ /**
29094
+ * Given a ray and a rectangular box, find the point where the ray intersects
29095
+ * the edge of the box. Assumes the `initialPoint` is inside the box.
29096
+ * @param initialPoint - The starting point of the ray.
29097
+ * @param throughPoint - A point that the ray passes through. Must be different from initialPoint.
29098
+ * @param box - The box with which to intersect the ray, in the form [[xMin, xMax], [yMin, yMax]]
29099
+ */
29100
+ const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
29101
+ const [[xMin, xMax], [yMin, yMax]] = box;
29102
+ const [aX, aY] = initialPoint;
29103
+ const [bX, bY] = throughPoint;
29104
+ const yDiff = bY - aY;
29105
+ const xDiff = bX - aX;
29106
+ const slope = yDiff / xDiff;
29107
+ const inverseSlope = 1 / slope;
29108
+ const xExtreme = xDiff < 0 ? xMin : xMax;
29109
+ const yExtreme = yDiff < 0 ? yMin : yMax;
29110
+ const yAtXExtreme = aY + (xExtreme - aX) * slope;
29111
+ const xAtYExtreme = aX + (yExtreme - aY) * inverseSlope;
29112
+ switch (true) {
29113
+ // does the ray exit the graph bounding box via the left or right edge?
29114
+ case isBetween(yAtXExtreme, yMin, yMax):
29115
+ return [xExtreme, yAtXExtreme];
29116
+
29117
+ // does the ray exit the graph bounding box via the top or bottom edge?
29118
+ case isBetween(xAtYExtreme, xMin, xMax):
29119
+ return [xAtYExtreme, yExtreme];
29120
+ default:
29121
+ return [xExtreme, yExtreme];
29122
+ }
29123
+ };
29124
+ function isBetween(x, low, high) {
29125
+ return x >= low && x <= high;
29126
+ }
29127
+
29155
29128
  const LockedLine = props => {
29156
29129
  const {
29157
29130
  color,
@@ -29611,10 +29584,7 @@ const MovablePointView = /*#__PURE__*/React.forwardRef((props, hitboxRef) => {
29611
29584
  })?.[0] ?? "blue";
29612
29585
  const pointClasses = `movable-point ${dragging ? "movable-point--dragging" : ""} ${focusClass(focusBehavior)}`;
29613
29586
  const [[x, y]] = useTransformVectorsToPixels(point);
29614
-
29615
- // TODO(benchristel): destructure range in one line
29616
- const [xMin, xMax] = range[X];
29617
- const [yMin, yMax] = range[Y];
29587
+ const [[xMin, xMax], [yMin, yMax]] = range;
29618
29588
  const [[verticalStartX]] = useTransformVectorsToPixels([xMin, 0]);
29619
29589
  const [[verticalEndX]] = useTransformVectorsToPixels([xMax, 0]);
29620
29590
  const [[_, horizontalStartY]] = useTransformVectorsToPixels([0, yMin]);
@@ -30201,26 +30171,11 @@ const shouldDrawArcOutside = (midpoint, vertex, range, polygonLines) => {
30201
30171
  // Create a ray from the midpoint (inside angle) to the edge of the range
30202
30172
  const rangeIntersectionPoint = getIntersectionOfRayWithBox(midpoint, vertex, range);
30203
30173
  let lineIntersectionCount = 0;
30204
- polygonLines.forEach(line => linesIntersect([vertex, rangeIntersectionPoint], line) && lineIntersectionCount++);
30174
+ polygonLines.forEach(line => segmentsIntersect([vertex, rangeIntersectionPoint], line) && lineIntersectionCount++);
30205
30175
 
30206
30176
  // If the number of intersections is even, the angle is inside the polygon
30207
30177
  return !isEven(lineIntersectionCount);
30208
30178
  };
30209
-
30210
- // https://stackoverflow.com/a/24392281/7347484
30211
- // The "intersects" function in geometry doesn't seem to work for this use case
30212
- const linesIntersect = (_ref5, _ref6) => {
30213
- let [[a, b], [c, d]] = _ref5;
30214
- let [[p, q], [r, s]] = _ref6;
30215
- const determinant = (c - a) * (s - q) - (r - p) * (d - b);
30216
- if (determinant === 0) {
30217
- return false;
30218
- } else {
30219
- const lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / determinant;
30220
- const gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / determinant;
30221
- return 0 < lambda && lambda < 1 && 0 < gamma && gamma < 1;
30222
- }
30223
- };
30224
30179
  const isEven = n => n % 2 === 0;
30225
30180
 
30226
30181
  // This function calculates the bisector point of an angle formed by two points
@@ -30414,6 +30369,12 @@ const PolygonGraph = props => {
30414
30369
  onMove: destination => dispatch(movePoint(i, destination))
30415
30370
  })));
30416
30371
  };
30372
+ function getLines(points) {
30373
+ return points.map((point, i) => {
30374
+ const next = points[(i + 1) % points.length];
30375
+ return [point, next];
30376
+ });
30377
+ }
30417
30378
 
30418
30379
  function getGradableGraph(state, initialGraph) {
30419
30380
  if (!state.hasBeenInteractedWith) {
@@ -30803,12 +30764,8 @@ const AxisTickLabels = () => {
30803
30764
  tickStep,
30804
30765
  range
30805
30766
  } = graphConfig;
30806
-
30807
- // TODO(benchristel): use destructuring here
30808
- const [xMin, xMax] = range[X];
30809
- const [yMin, yMax] = range[Y];
30810
- const yTickStep = tickStep[Y];
30811
- const xTickStep = tickStep[X];
30767
+ const [[xMin, xMax], [yMin, yMax]] = range;
30768
+ const [xTickStep, yTickStep] = tickStep;
30812
30769
  const yGridTicks = generateTickLocations$1(yTickStep, yMin, yMax);
30813
30770
  const xGridTicks = generateTickLocations$1(xTickStep, xMin, xMax);
30814
30771
  return /*#__PURE__*/React__namespace.createElement("div", {
@@ -31192,12 +31149,8 @@ const AxisTicks = () => {
31192
31149
  width,
31193
31150
  height
31194
31151
  };
31195
-
31196
- // TODO(benchristel): destructure these in one line
31197
- const [xMin, xMax] = range[X];
31198
- const [yMin, yMax] = range[Y];
31199
- const yTickStep = tickStep[Y];
31200
- const xTickStep = tickStep[X];
31152
+ const [[xMin, xMax], [yMin, yMax]] = range;
31153
+ const [xTickStep, yTickStep] = tickStep;
31201
31154
  const yGridTicks = generateTickLocations(yTickStep, yMin, yMax);
31202
31155
  const xGridTicks = generateTickLocations(xTickStep, xMin, xMax);
31203
31156
  return /*#__PURE__*/React__namespace.createElement("g", {
@@ -31734,7 +31687,7 @@ const PropCheckBox = createReactClass__default["default"]({
31734
31687
  return !___default["default"].has(this.DEFAULT_PROPS, localPropName);
31735
31688
  }, this);
31736
31689
  if (!propName) {
31737
- throw new PerseusError("Attempted to create a PropCheckBox with no prop!", Errors.InvalidInput);
31690
+ throw new perseusCore.PerseusError("Attempted to create a PropCheckBox with no prop!", perseusCore.Errors.InvalidInput);
31738
31691
  }
31739
31692
  return propName;
31740
31693
  },
@@ -31927,7 +31880,7 @@ function Protractor() {
31927
31880
  function RotationArrow() {
31928
31881
  const radius = 175;
31929
31882
  const angleDeg = 10;
31930
- const angleRad = degreesToRadians(angleDeg);
31883
+ const angleRad = convertDegreesToRadians(angleDeg);
31931
31884
  const endX = radius * (1 - Math.cos(angleRad));
31932
31885
  const endY = radius * -Math.sin(angleRad);
31933
31886
  const rotationArrow = pathBuilder().move(0, 0).circularArc(radius, endX, endY, {
@@ -32006,17 +31959,135 @@ function useDraggablePx(args) {
32006
31959
  });
32007
31960
  }
32008
31961
 
32009
- // [L]inear Int[erp]olation: gets the weighted average of two values `a` and
32010
- // `b`, with the given `fraction` specifying how much weight `a` and `b` get:
32011
- // - if `fraction` is 0, `lerp` returns `a`.
32012
- // - if `fraction` is 0.5, `lerp` returns the average of `a` and `b`.
32013
- // - if `fraction` is 1, `lerp` returns `b`.
32014
- function lerp(a, b, fraction) {
32015
- return (b - a) * fraction + a;
32016
- }
32017
- function degreesToRadians(degrees) {
32018
- return degrees / 180 * Math.PI;
32019
- }
31962
+ const MafsGraph = props => {
31963
+ const {
31964
+ state,
31965
+ dispatch,
31966
+ labels
31967
+ } = props;
31968
+ const [width, height] = props.box;
31969
+ const tickStep = props.step;
31970
+ return /*#__PURE__*/React__namespace.createElement(GraphConfigContext.Provider, {
31971
+ value: {
31972
+ range: state.range,
31973
+ snapStep: state.snapStep,
31974
+ markings: props.markings,
31975
+ tickStep: tickStep,
31976
+ gridStep: props.gridStep,
31977
+ showTooltips: !!props.showTooltips,
31978
+ graphDimensionsInPixels: props.box,
31979
+ width,
31980
+ height,
31981
+ labels
31982
+ }
31983
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31984
+ className: "mafs-graph",
31985
+ style: {
31986
+ width,
31987
+ height,
31988
+ position: "relative",
31989
+ padding: "25px 25px 0 0",
31990
+ boxSizing: "content-box",
31991
+ marginLeft: "20px",
31992
+ marginBottom: "20px"
31993
+ }
31994
+ }, /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
31995
+ box: props.box,
31996
+ backgroundImage: props.backgroundImage
31997
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31998
+ style: {
31999
+ position: "absolute",
32000
+ bottom: 0,
32001
+ left: 0
32002
+ }
32003
+ }, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisLabels, null), /*#__PURE__*/React__namespace.createElement(AxisTickLabels, null)), /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
32004
+ preserveAspectRatio: false,
32005
+ viewBox: {
32006
+ x: state.range[X],
32007
+ y: state.range[Y],
32008
+ padding: 0
32009
+ },
32010
+ pan: false,
32011
+ zoom: false,
32012
+ width: width,
32013
+ height: height
32014
+ }, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement(Grid, {
32015
+ tickStep: props.step,
32016
+ gridStep: props.gridStep,
32017
+ range: state.range,
32018
+ containerSizeClass: props.containerSizeClass,
32019
+ markings: props.markings
32020
+ }), props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
32021
+ lockedFigures: props.lockedFigures,
32022
+ range: state.range
32023
+ }), "/* Protractor */", props.showProtractor && /*#__PURE__*/React__namespace.createElement(Protractor, null), renderGraph({
32024
+ state,
32025
+ dispatch
32026
+ })))));
32027
+ };
32028
+ const renderGraph = props => {
32029
+ const {
32030
+ state,
32031
+ dispatch
32032
+ } = props;
32033
+ const {
32034
+ type
32035
+ } = state;
32036
+ switch (type) {
32037
+ case "angle":
32038
+ return /*#__PURE__*/React__namespace.createElement(AngleGraph, {
32039
+ graphState: state,
32040
+ dispatch: dispatch
32041
+ });
32042
+ case "segment":
32043
+ return /*#__PURE__*/React__namespace.createElement(SegmentGraph, {
32044
+ graphState: state,
32045
+ dispatch: dispatch
32046
+ });
32047
+ case "linear-system":
32048
+ return /*#__PURE__*/React__namespace.createElement(LinearSystemGraph, {
32049
+ graphState: state,
32050
+ dispatch: dispatch
32051
+ });
32052
+ case "linear":
32053
+ return /*#__PURE__*/React__namespace.createElement(LinearGraph, {
32054
+ graphState: state,
32055
+ dispatch: dispatch
32056
+ });
32057
+ case "ray":
32058
+ return /*#__PURE__*/React__namespace.createElement(RayGraph, {
32059
+ graphState: state,
32060
+ dispatch: dispatch
32061
+ });
32062
+ case "polygon":
32063
+ return /*#__PURE__*/React__namespace.createElement(PolygonGraph, {
32064
+ graphState: state,
32065
+ dispatch: dispatch
32066
+ });
32067
+ case "point":
32068
+ return /*#__PURE__*/React__namespace.createElement(PointGraph, {
32069
+ graphState: state,
32070
+ dispatch: dispatch
32071
+ });
32072
+ case "circle":
32073
+ return /*#__PURE__*/React__namespace.createElement(CircleGraph, {
32074
+ graphState: state,
32075
+ dispatch: dispatch
32076
+ });
32077
+ case "quadratic":
32078
+ return /*#__PURE__*/React__namespace.createElement(QuadraticGraph, {
32079
+ graphState: state,
32080
+ dispatch: dispatch
32081
+ });
32082
+ case "sinusoid":
32083
+ return /*#__PURE__*/React__namespace.createElement(SinusoidGraph, {
32084
+ graphState: state,
32085
+ dispatch: dispatch
32086
+ });
32087
+ default:
32088
+ return new wonderStuffCore.UnreachableCaseError(type);
32089
+ }
32090
+ };
32020
32091
 
32021
32092
  function initializeGraphState(params) {
32022
32093
  const {
@@ -32968,70 +33039,6 @@ function setAtIndex(args) {
32968
33039
  return copy;
32969
33040
  }
32970
33041
 
32971
- const renderGraph = props => {
32972
- const {
32973
- state,
32974
- dispatch
32975
- } = props;
32976
- const {
32977
- type
32978
- } = state;
32979
- switch (type) {
32980
- case "angle":
32981
- return /*#__PURE__*/React__namespace.createElement(AngleGraph, {
32982
- graphState: state,
32983
- dispatch: dispatch
32984
- });
32985
- case "segment":
32986
- return /*#__PURE__*/React__namespace.createElement(SegmentGraph, {
32987
- graphState: state,
32988
- dispatch: dispatch
32989
- });
32990
- case "linear-system":
32991
- return /*#__PURE__*/React__namespace.createElement(LinearSystemGraph, {
32992
- graphState: state,
32993
- dispatch: dispatch
32994
- });
32995
- case "linear":
32996
- return /*#__PURE__*/React__namespace.createElement(LinearGraph, {
32997
- graphState: state,
32998
- dispatch: dispatch
32999
- });
33000
- case "ray":
33001
- return /*#__PURE__*/React__namespace.createElement(RayGraph, {
33002
- graphState: state,
33003
- dispatch: dispatch
33004
- });
33005
- case "polygon":
33006
- return /*#__PURE__*/React__namespace.createElement(PolygonGraph, {
33007
- graphState: state,
33008
- dispatch: dispatch
33009
- });
33010
- case "point":
33011
- return /*#__PURE__*/React__namespace.createElement(PointGraph, {
33012
- graphState: state,
33013
- dispatch: dispatch
33014
- });
33015
- case "circle":
33016
- return /*#__PURE__*/React__namespace.createElement(CircleGraph, {
33017
- graphState: state,
33018
- dispatch: dispatch
33019
- });
33020
- case "quadratic":
33021
- return /*#__PURE__*/React__namespace.createElement(QuadraticGraph, {
33022
- graphState: state,
33023
- dispatch: dispatch
33024
- });
33025
- case "sinusoid":
33026
- return /*#__PURE__*/React__namespace.createElement(SinusoidGraph, {
33027
- graphState: state,
33028
- dispatch: dispatch
33029
- });
33030
- default:
33031
- return new wonderStuffCore.UnreachableCaseError(type);
33032
- }
33033
- };
33034
-
33035
33042
  // Rather than be tightly bound to how data was structured in
33036
33043
  // the legacy interactive graph, this lets us store state
33037
33044
  // however we want and we just transform it before handing it off
@@ -33101,72 +33108,6 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
33101
33108
  dispatch: dispatch
33102
33109
  }));
33103
33110
  });
33104
- const MafsGraph = props => {
33105
- const {
33106
- state,
33107
- dispatch,
33108
- labels
33109
- } = props;
33110
- const [width, height] = props.box;
33111
- const tickStep = props.step;
33112
- return /*#__PURE__*/React__namespace.createElement(GraphConfigContext.Provider, {
33113
- value: {
33114
- range: state.range,
33115
- snapStep: state.snapStep,
33116
- markings: props.markings,
33117
- tickStep: tickStep,
33118
- gridStep: props.gridStep,
33119
- showTooltips: !!props.showTooltips,
33120
- graphDimensionsInPixels: props.box,
33121
- width,
33122
- height,
33123
- labels
33124
- }
33125
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
33126
- className: "mafs-graph",
33127
- style: {
33128
- width,
33129
- height,
33130
- position: "relative",
33131
- padding: "25px 25px 0 0",
33132
- boxSizing: "content-box",
33133
- marginLeft: "20px",
33134
- marginBottom: "20px"
33135
- }
33136
- }, /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
33137
- box: props.box,
33138
- backgroundImage: props.backgroundImage
33139
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
33140
- style: {
33141
- position: "absolute",
33142
- bottom: 0,
33143
- left: 0
33144
- }
33145
- }, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisLabels, null), /*#__PURE__*/React__namespace.createElement(AxisTickLabels, null)), /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
33146
- preserveAspectRatio: false,
33147
- viewBox: {
33148
- x: state.range[X],
33149
- y: state.range[Y],
33150
- padding: 0
33151
- },
33152
- pan: false,
33153
- zoom: false,
33154
- width: width,
33155
- height: height
33156
- }, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement(Grid, {
33157
- tickStep: props.step,
33158
- gridStep: props.gridStep,
33159
- range: state.range,
33160
- containerSizeClass: props.containerSizeClass,
33161
- markings: props.markings
33162
- }), props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
33163
- lockedFigures: props.lockedFigures,
33164
- range: state.range
33165
- }), "/* Protractor */", props.showProtractor && /*#__PURE__*/React__namespace.createElement(Protractor, null), renderGraph({
33166
- state,
33167
- dispatch
33168
- })))));
33169
- };
33170
33111
 
33171
33112
  const {
33172
33113
  DeprecationMixin
@@ -33215,7 +33156,7 @@ const _isClickToAddPoints = props => {
33215
33156
  return props.graph.type === "point" && props.graph.numPoints === UNLIMITED || props.graph.type === "polygon" && props.graph.numSides === UNLIMITED;
33216
33157
  };
33217
33158
  const makeInvalidTypeError = (functionName, graphType) => {
33218
- return new PerseusError(`${functionName} called but current graph type is not a '${graphType}'`, Errors.NotAllowed, {
33159
+ return new perseusCore.PerseusError(`${functionName} called but current graph type is not a '${graphType}'`, perseusCore.Errors.NotAllowed, {
33219
33160
  metadata: {
33220
33161
  graphType
33221
33162
  }
@@ -33314,7 +33255,7 @@ class LegacyInteractiveGraph extends React__namespace.Component {
33314
33255
  // This function should only be called when this.isClickToAddPoints()
33315
33256
  // is true
33316
33257
  if (!this.isClickToAddPoints()) {
33317
- throw new PerseusError("handleAddPointsClick should not be registered" + "when isClickToAddPoints() is false", Errors.NotAllowed);
33258
+ throw new perseusCore.PerseusError("handleAddPointsClick should not be registered" + "when isClickToAddPoints() is false", perseusCore.Errors.NotAllowed);
33318
33259
  }
33319
33260
  if (!this.isCoordInTrash(coord)) {
33320
33261
  let point;
@@ -34452,7 +34393,7 @@ class InteractiveGraph extends React__namespace.Component {
34452
34393
  if (this.legacyGraphRef.current) {
34453
34394
  return this.legacyGraphRef.current.getUserInput();
34454
34395
  }
34455
- throw new PerseusError("Cannot getUserInput from a graph that has never rendered", Errors.NotAllowed);
34396
+ throw new perseusCore.PerseusError("Cannot getUserInput from a graph that has never rendered", perseusCore.Errors.NotAllowed);
34456
34397
  };
34457
34398
  simpleValidate(rubric) {
34458
34399
  return InteractiveGraph.validate(this.getUserInput?.(), rubric, this);
@@ -40178,7 +40119,7 @@ class Card extends React__namespace.Component {
40178
40119
  // Event handlers should be unbound before component unmounting, but
40179
40120
  // just in case...
40180
40121
  if (this.mouseMoveUpBound) {
40181
- Log.error("Removing an element with bound event handlers.", Errors.Internal);
40122
+ Log.error("Removing an element with bound event handlers.", perseusCore.Errors.Internal);
40182
40123
  this.unbindMouseMoveUp();
40183
40124
  Util.resetTouchHandlers();
40184
40125
  }
@@ -40999,7 +40940,7 @@ function deserializeHighlight(serializedHighlight, wordRanges) {
40999
40940
  } = serializedHighlight.range;
41000
40941
  const firstWord = wordRanges[firstWordIndex];
41001
40942
  if (!firstWord) {
41002
- throw new PerseusError(`first word index ${firstWord} is out of bounds: ` + `must be 0–${wordRanges.length - 1} inclusive`, Errors.InvalidInput, {
40943
+ throw new perseusCore.PerseusError(`first word index ${firstWord} is out of bounds: ` + `must be 0–${wordRanges.length - 1} inclusive`, perseusCore.Errors.InvalidInput, {
41003
40944
  metadata: {
41004
40945
  firstWord,
41005
40946
  wordRanges: JSON.stringify(wordRanges)
@@ -41008,7 +40949,7 @@ function deserializeHighlight(serializedHighlight, wordRanges) {
41008
40949
  }
41009
40950
  const lastWord = wordRanges[lastWordIndex];
41010
40951
  if (!lastWord) {
41011
- throw new PerseusError(`last word index ${lastWord} is out of bounds: ` + `must be 0–${wordRanges.length - 1} inclusive`, Errors.InvalidInput, {
40952
+ throw new perseusCore.PerseusError(`last word index ${lastWord} is out of bounds: ` + `must be 0–${wordRanges.length - 1} inclusive`, perseusCore.Errors.InvalidInput, {
41012
40953
  metadata: {
41013
40954
  lastWord,
41014
40955
  wordRanges: JSON.stringify(wordRanges)
@@ -41761,7 +41702,7 @@ class WordIndexer extends React__namespace.PureComponent {
41761
41702
  _getWordRanges() {
41762
41703
  const container = this._container;
41763
41704
  if (!container) {
41764
- throw new PerseusError("invariant violation: `this._container` is not defined, but " + "this method is only called after mount/update", Errors.NotAllowed);
41705
+ throw new perseusCore.PerseusError("invariant violation: `this._container` is not defined, but " + "this method is only called after mount/update", perseusCore.Errors.NotAllowed);
41765
41706
  }
41766
41707
 
41767
41708
  // Create a TreeWalker that visits text nodes and element nodes.
@@ -42227,6 +42168,7 @@ const rules = {
42227
42168
  }, /*#__PURE__*/React__namespace.createElement("span", {
42228
42169
  style: SQUARE_LABEL_STYLE
42229
42170
  }, node.content)), /*#__PURE__*/React__namespace.createElement(AltText, {
42171
+ key: "alt-text",
42230
42172
  id: "questionMarker",
42231
42173
  number: node.content
42232
42174
  }), node.space ? "\u00A0" : null];
@@ -42251,6 +42193,7 @@ const rules = {
42251
42193
  }, /*#__PURE__*/React__namespace.createElement("span", {
42252
42194
  style: CIRCLE_LABEL_STYLE
42253
42195
  }, node.content)), /*#__PURE__*/React__namespace.createElement(AltText, {
42196
+ key: "alt-text",
42254
42197
  id: "circleMarker",
42255
42198
  number: node.content
42256
42199
  }), node.space ? "\u00A0" : null];
@@ -42274,6 +42217,7 @@ const rules = {
42274
42217
  className: "perseus-passage-bracket-label",
42275
42218
  "aria-hidden": "true"
42276
42219
  }, "[", node.content, "]"), /*#__PURE__*/React__namespace.createElement(AltText, {
42220
+ key: "alt-text",
42277
42221
  id: "sentenceMarker",
42278
42222
  number: node.content
42279
42223
  }), node.space ? "\u00A0" : null];
@@ -45283,7 +45227,7 @@ const init = function (options) {
45283
45227
 
45284
45228
  // This file is processed by a Rollup plugin (replace) to inject the production
45285
45229
  const libName = "@khanacademy/perseus";
45286
- const libVersion = "24.3.0";
45230
+ const libVersion = "25.0.0";
45287
45231
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
45288
45232
 
45289
45233
  const apiVersion = {
@@ -46659,9 +46603,9 @@ tree, shape, path, mappers
46659
46603
  // @ts-expect-error - TS2315 - Type 'ArrayNode' is not generic.
46660
46604
  const array = tree;
46661
46605
  if (!Array.isArray(array)) {
46662
- throw new PerseusError(`Invalid object of type "${typeof array}" found at path ` +
46606
+ throw new perseusCore.PerseusError(`Invalid object of type "${typeof array}" found at path ` +
46663
46607
  // @ts-expect-error - TS2769 - No overload matches this call.
46664
- `${["<root>"].concat(path).join(".")}. Expected array.`, Errors.Internal);
46608
+ `${["<root>"].concat(path).join(".")}. Expected array.`, perseusCore.Errors.Internal);
46665
46609
  }
46666
46610
  const elementShape = shape.elementShape;
46667
46611
  // @ts-expect-error - TS2315 - Type 'ArrayNode' is not generic.
@@ -46671,30 +46615,30 @@ tree, shape, path, mappers
46671
46615
  if (shape.type === "object") {
46672
46616
  const object = tree;
46673
46617
  if (object && typeof object !== "object") {
46674
- throw new PerseusError(`Invalid object of type "${typeof object}" found at ` +
46618
+ throw new perseusCore.PerseusError(`Invalid object of type "${typeof object}" found at ` +
46675
46619
  // @ts-expect-error - TS2769 - No overload matches this call.
46676
- `path ${["<root>"].concat(path).join(".")}. Expected ` + `"object" type.`, Errors.InvalidInput);
46620
+ `path ${["<root>"].concat(path).join(".")}. Expected ` + `"object" type.`, perseusCore.Errors.InvalidInput);
46677
46621
  }
46678
46622
  const valueShapes = shape.shape;
46679
46623
  if (!valueShapes) {
46680
- throw new PerseusError(`Unexpected shape ${JSON.stringify(shape)} at path ` +
46624
+ throw new perseusCore.PerseusError(`Unexpected shape ${JSON.stringify(shape)} at path ` +
46681
46625
  // @ts-expect-error - TS2769 - No overload matches this call.
46682
- `${["<root>"].concat(path).join(".")}.`, Errors.InvalidInput);
46626
+ `${["<root>"].concat(path).join(".")}.`, perseusCore.Errors.InvalidInput);
46683
46627
  }
46684
46628
  const newObject = {};
46685
46629
  Object.keys(valueShapes).forEach(key => {
46686
46630
  if (!(key in object)) {
46687
- throw new PerseusError(`Key "${key}" is missing from shape at path ` +
46631
+ throw new perseusCore.PerseusError(`Key "${key}" is missing from shape at path ` +
46688
46632
  // @ts-expect-error - TS2769 - No overload matches this call.
46689
- `${["<root>"].concat(path).join(".")}.`, Errors.InvalidInput);
46633
+ `${["<root>"].concat(path).join(".")}.`, perseusCore.Errors.InvalidInput);
46690
46634
  }
46691
46635
  newObject[key] = mapTree(object[key], valueShapes[key], path.concat(key), mappers);
46692
46636
  });
46693
46637
  return newObject;
46694
46638
  }
46695
- throw new PerseusError(
46639
+ throw new perseusCore.PerseusError(
46696
46640
  // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
46697
- `unexpected shape type ${shape.type}`, Errors.InvalidInput);
46641
+ `unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
46698
46642
  }
46699
46643
 
46700
46644
  /**
@@ -46746,9 +46690,9 @@ function buildEmptyItemTreeForShape(shape) {
46746
46690
  });
46747
46691
  return object;
46748
46692
  }
46749
- throw new PerseusError(
46693
+ throw new perseusCore.PerseusError(
46750
46694
  // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
46751
- `unexpected shape type ${shape.type}`, Errors.InvalidInput);
46695
+ `unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
46752
46696
  }
46753
46697
 
46754
46698
  /**
@@ -46823,7 +46767,7 @@ function inferItemTreeShape(node) {
46823
46767
  });
46824
46768
  return shapes.shape(valueShapes);
46825
46769
  }
46826
- throw new PerseusError(`unexpected multi-item node ${JSON.stringify(node)}`, Errors.InvalidInput);
46770
+ throw new perseusCore.PerseusError(`unexpected multi-item node ${JSON.stringify(node)}`, perseusCore.Errors.InvalidInput);
46827
46771
  }
46828
46772
 
46829
46773
  /**
@@ -46901,7 +46845,7 @@ class MultiRenderer extends React__namespace.Component {
46901
46845
  renderError: null
46902
46846
  };
46903
46847
  } catch (e) {
46904
- Log.error("Error building tree state", Errors.Internal, {
46848
+ Log.error("Error building tree state", perseusCore.Errors.Internal, {
46905
46849
  cause: e
46906
46850
  });
46907
46851
  return {
@@ -47265,9 +47209,9 @@ function buildTreePropTypeForShape(shape) {
47265
47209
  });
47266
47210
  return PropTypes__default["default"].shape(propTypeShape);
47267
47211
  }
47268
- throw new PerseusError(
47212
+ throw new perseusCore.PerseusError(
47269
47213
  // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
47270
- `unexpected shape type ${shape.type}`, Errors.InvalidInput);
47214
+ `unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
47271
47215
  }
47272
47216
 
47273
47217
  /**
@@ -47390,7 +47334,7 @@ const isRendererContentRenderableBy = function (rendererOptions, rendererContent
47390
47334
  };
47391
47335
  const isItemRenderableByVersion = function (itemData, rendererContentVersion) {
47392
47336
  if (itemData == null || rendererContentVersion == null) {
47393
- throw new PerseusError("missing parameter to Perseus.isRenderable.item", Errors.InvalidInput);
47337
+ throw new perseusCore.PerseusError("missing parameter to Perseus.isRenderable.item", perseusCore.Errors.InvalidInput);
47394
47338
  }
47395
47339
  if (itemData._multi) {
47396
47340
  const shape = inferItemShape$1(itemData);
@@ -48311,7 +48255,6 @@ exports.DashPicker = DashPicker;
48311
48255
  exports.Dependencies = dependencies;
48312
48256
  exports.EditorJsonify = EditorJsonify;
48313
48257
  exports.ElementContainer = ElementContainer;
48314
- exports.Errors = Errors;
48315
48258
  exports.Expression = Expression;
48316
48259
  exports.GrapherUtil = util;
48317
48260
  exports.GrapherWidget = Grapher$1;
@@ -48328,7 +48271,6 @@ exports.Log = Log;
48328
48271
  exports.MatrixWidget = Matrix$1;
48329
48272
  exports.MultiItems = MultiItems;
48330
48273
  exports.NumericInput = NumericInput$1;
48331
- exports.PerseusError = PerseusError;
48332
48274
  exports.PerseusExpressionAnswerFormConsidered = PerseusExpressionAnswerFormConsidered;
48333
48275
  exports.PerseusI18nContext = PerseusI18nContext;
48334
48276
  exports.PerseusI18nContextProvider = PerseusI18nContextProvider;