@khanacademy/perseus 37.0.0 → 38.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.
Files changed (55) hide show
  1. package/dist/all-widgets.d.ts +1 -0
  2. package/dist/basic-widgets.d.ts +1 -0
  3. package/dist/es/index.js +134 -114
  4. package/dist/es/index.js.map +1 -1
  5. package/dist/extra-widgets.d.ts +1 -0
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.js +131 -112
  8. package/dist/index.js.map +1 -1
  9. package/dist/multi-items/item-types.d.ts +4 -3
  10. package/dist/perseus-api.d.ts +7 -6
  11. package/dist/perseus-types.d.ts +31 -30
  12. package/dist/server-item-renderer.d.ts +8 -9
  13. package/dist/types.d.ts +3 -5
  14. package/dist/util/extract-perseus-data.d.ts +1 -1
  15. package/dist/validation.types.d.ts +4 -11
  16. package/dist/widgets/categorizer/categorizer.d.ts +1 -0
  17. package/dist/widgets/cs-program/cs-program.d.ts +1 -0
  18. package/dist/widgets/definition/definition.d.ts +1 -0
  19. package/dist/widgets/deprecated-standin/deprecated-standin.d.ts +1 -0
  20. package/dist/widgets/dropdown/dropdown.d.ts +1 -0
  21. package/dist/widgets/explanation/explanation.d.ts +1 -0
  22. package/dist/widgets/expression/expression.d.ts +43 -37
  23. package/dist/widgets/graded-group/graded-group.d.ts +1 -0
  24. package/dist/widgets/graded-group-set/graded-group-set.d.ts +1 -0
  25. package/dist/widgets/grapher/grapher-types.d.ts +58 -0
  26. package/dist/widgets/grapher/grapher-validator.d.ts +1 -1
  27. package/dist/widgets/grapher/grapher.d.ts +1 -0
  28. package/dist/widgets/grapher/util.d.ts +16 -3
  29. package/dist/widgets/group/group.d.ts +1 -0
  30. package/dist/widgets/iframe/iframe.d.ts +1 -0
  31. package/dist/widgets/image/image.d.ts +1 -0
  32. package/dist/widgets/input-number/input-number.d.ts +1 -1
  33. package/dist/widgets/interaction/interaction.d.ts +1 -0
  34. package/dist/widgets/interactive-graph.d.ts +1 -0
  35. package/dist/widgets/interactive-graphs/mafs-supported-graph-types.d.ts +1 -1
  36. package/dist/widgets/label-image/label-image.d.ts +15 -12
  37. package/dist/widgets/matcher/matcher.d.ts +1 -0
  38. package/dist/widgets/matrix/matrix.d.ts +1 -0
  39. package/dist/widgets/measurer/measurer.d.ts +1 -0
  40. package/dist/widgets/molecule/molecule.d.ts +1 -0
  41. package/dist/widgets/number-line/number-line.d.ts +1 -0
  42. package/dist/widgets/numeric-input/numeric-input.d.ts +1 -1
  43. package/dist/widgets/orderer/orderer.d.ts +1 -0
  44. package/dist/widgets/passage/passage.d.ts +1 -0
  45. package/dist/widgets/passage-ref/passage-ref.d.ts +1 -0
  46. package/dist/widgets/passage-ref-target/passage-ref-target.d.ts +1 -0
  47. package/dist/widgets/phet-simulation/phet-simulation.d.ts +1 -0
  48. package/dist/widgets/plotter/plotter.d.ts +1 -0
  49. package/dist/widgets/python-program/python-program.d.ts +1 -0
  50. package/dist/widgets/radio/radio.d.ts +1 -0
  51. package/dist/widgets/sorter/sorter.d.ts +1 -0
  52. package/dist/widgets/table/table.d.ts +1 -0
  53. package/dist/widgets/video/video.d.ts +1 -0
  54. package/dist/widgets.d.ts +1 -0
  55. package/package.json +1 -1
@@ -16,6 +16,7 @@ declare const _default: readonly Readonly<{
16
16
  transform?: import("./types").WidgetTransform | undefined;
17
17
  staticTransform?: import("./types").WidgetTransform | undefined;
18
18
  validator?: import("./types").WidgetValidatorFunction | undefined;
19
+ getOneCorrectAnswerFromRubric?: ((rubric: import("./validation.types").Rubric) => string | null | undefined) | undefined;
19
20
  propUpgrades?: {
20
21
  [key: string]: (arg1: any) => any;
21
22
  } | undefined;
@@ -16,6 +16,7 @@ declare const _default: readonly Readonly<{
16
16
  transform?: import("./types").WidgetTransform | undefined;
17
17
  staticTransform?: import("./types").WidgetTransform | undefined;
18
18
  validator?: import("./types").WidgetValidatorFunction | undefined;
19
+ getOneCorrectAnswerFromRubric?: ((rubric: import("./validation.types").Rubric) => string | null | undefined) | undefined;
19
20
  propUpgrades?: {
20
21
  [key: string]: (arg1: any) => any;
21
22
  } | undefined;
package/dist/es/index.js CHANGED
@@ -2376,15 +2376,6 @@ class Expression extends React.Component {
2376
2376
  static getUserInputFromProps(props) {
2377
2377
  return normalizeTex(props.value);
2378
2378
  }
2379
- static getOneCorrectAnswerFromRubric(rubric) {
2380
- const correctAnswers = (rubric.answerForms || []).filter(answerForm => answerForm.considered === "correct");
2381
- if (correctAnswers.length === 0) {
2382
- return;
2383
- }
2384
- return correctAnswers[0].value;
2385
- }
2386
- //#endregion
2387
-
2388
2379
  getUserInput() {
2389
2380
  return Expression.getUserInputFromProps(this.props);
2390
2381
  }
@@ -2612,11 +2603,7 @@ const ExpressionWithDependencies = /*#__PURE__*/React.forwardRef((props, ref) =>
2612
2603
  // methods and instead adjust Perseus to provide these facilities through
2613
2604
  // instance methods on our Renderers.
2614
2605
  // @ts-expect-error - TS2339 - Property 'validate' does not exist on type
2615
- ExpressionWithDependencies.validate = expressionValidator;
2616
- // @ts-expect-error - TS2339 - Property 'validate' does not exist on type
2617
2606
  ExpressionWithDependencies.getUserInputFromProps = Expression.getUserInputFromProps;
2618
- // @ts-expect-error - TS2339 - Property 'validate' does not exist on type
2619
- ExpressionWithDependencies.getOneCorrectAnswerFromRubric = Expression.getOneCorrectAnswerFromRubric;
2620
2607
  var Expression$1 = {
2621
2608
  name: "expression",
2622
2609
  displayName: "Expression / Equation",
@@ -2649,7 +2636,14 @@ var Expression$1 = {
2649
2636
  propUpgrades: propUpgrades$2,
2650
2637
  // For use by the editor
2651
2638
  isLintable: true,
2652
- validator: expressionValidator
2639
+ validator: expressionValidator,
2640
+ getOneCorrectAnswerFromRubric(rubric) {
2641
+ const correctAnswers = (rubric.answerForms || []).filter(answerForm => answerForm.considered === "correct");
2642
+ if (correctAnswers.length === 0) {
2643
+ return;
2644
+ }
2645
+ return correctAnswers[0].value;
2646
+ }
2653
2647
  };
2654
2648
 
2655
2649
  /**
@@ -9973,9 +9967,6 @@ const setLabelMargins = function setLabelMargins(span, size) {
9973
9967
  // Inherited line-height values can really mess up placement.
9974
9968
  $container.css("line-height", "normal");
9975
9969
 
9976
- // TODO: Verify that this change doesn't impact other graphies
9977
- // Check the full list of consuming widgets.
9978
-
9979
9970
  // If the change in line-height affected the height of the element,
9980
9971
  // then the height used for calculations should be updated.
9981
9972
  // This can happen when the first label in the container calls this method,
@@ -18893,9 +18884,13 @@ const getWidget = name => {
18893
18884
  }
18894
18885
  return widgets[name].widget;
18895
18886
  };
18887
+ const getWidgetExport = name => {
18888
+ var _widgets$name3;
18889
+ return (_widgets$name3 = widgets[name]) != null ? _widgets$name3 : null;
18890
+ };
18896
18891
  const getWidgetValidator = name => {
18897
- var _widgets$name$validat, _widgets$name3;
18898
- return (_widgets$name$validat = (_widgets$name3 = widgets[name]) == null ? void 0 : _widgets$name3.validator) != null ? _widgets$name$validat : null;
18892
+ var _widgets$name$validat, _widgets$name4;
18893
+ return (_widgets$name$validat = (_widgets$name4 = widgets[name]) == null ? void 0 : _widgets$name4.validator) != null ? _widgets$name$validat : null;
18899
18894
  };
18900
18895
  const getEditor = name => {
18901
18896
  return _.has(editors, name) ? editors[name] : null;
@@ -19199,6 +19194,7 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
19199
19194
  replaceEditor: replaceEditor,
19200
19195
  replaceDeprecatedEditors: replaceDeprecatedEditors,
19201
19196
  getWidget: getWidget,
19197
+ getWidgetExport: getWidgetExport,
19202
19198
  getWidgetValidator: getWidgetValidator,
19203
19199
  getEditor: getEditor,
19204
19200
  getTransform: getTransform,
@@ -21817,16 +21813,6 @@ class InputNumber extends React.Component {
21817
21813
  currentValue: props.currentValue
21818
21814
  };
21819
21815
  }
21820
- static getOneCorrectAnswerFromRubric(rubric) {
21821
- if (rubric.value == null) {
21822
- return;
21823
- }
21824
- let answerString = String(rubric.value);
21825
- if (rubric.inexact && rubric.maxError) {
21826
- answerString += " \u00B1 " + rubric.maxError;
21827
- }
21828
- return answerString;
21829
- }
21830
21816
  getUserInput() {
21831
21817
  return InputNumber.getUserInputFromProps(this.props);
21832
21818
  }
@@ -21935,7 +21921,17 @@ var InputNumber$1 = {
21935
21921
  widget: InputNumber,
21936
21922
  transform: propTransform$3,
21937
21923
  isLintable: true,
21938
- validator: inputNumberValidator
21924
+ validator: inputNumberValidator,
21925
+ getOneCorrectAnswerFromRubric(rubric) {
21926
+ if (rubric.value == null) {
21927
+ return;
21928
+ }
21929
+ let answerString = String(rubric.value);
21930
+ if (rubric.inexact && rubric.maxError) {
21931
+ answerString += " \u00B1 " + rubric.maxError;
21932
+ }
21933
+ return answerString;
21934
+ }
21939
21935
  };
21940
21936
 
21941
21937
  const ParseTex = TexWrangler.parseTex;
@@ -22181,34 +22177,6 @@ class NumericInput extends React.Component {
22181
22177
  currentValue: props.currentValue
22182
22178
  };
22183
22179
  }
22184
- static getOneCorrectAnswerFromRubric(rubric) {
22185
- const correctAnswers = rubric.answers.filter(answer => answer.status === "correct");
22186
- const answerStrings = correctAnswers.map(answer => {
22187
- // Figure out how this answer is supposed to be
22188
- // displayed
22189
- let format = "decimal";
22190
- if (answer.answerForms && answer.answerForms[0]) {
22191
- // NOTE(johnsullivan): This isn't exactly ideal, but
22192
- // it does behave well for all the currently known
22193
- // problems. See D14742 for some discussion on
22194
- // alternate strategies.
22195
- format = answer.answerForms[0];
22196
- }
22197
-
22198
- // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
22199
- let answerString = KhanMath.toNumericString(answer.value, format);
22200
- if (answer.maxError) {
22201
- answerString += " \u00B1 " +
22202
- // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
22203
- KhanMath.toNumericString(answer.maxError, format);
22204
- }
22205
- return answerString;
22206
- });
22207
- if (answerStrings.length === 0) {
22208
- return;
22209
- }
22210
- return answerStrings[0];
22211
- }
22212
22180
  getUserInput() {
22213
22181
  return NumericInput.getUserInputFromProps(this.props);
22214
22182
  }
@@ -22336,7 +22304,35 @@ var NumericInput$1 = {
22336
22304
  widget: NumericInput,
22337
22305
  transform: propsTransform,
22338
22306
  isLintable: true,
22339
- validator: numericInputValidator
22307
+ validator: numericInputValidator,
22308
+ getOneCorrectAnswerFromRubric(rubric) {
22309
+ const correctAnswers = rubric.answers.filter(answer => answer.status === "correct");
22310
+ const answerStrings = correctAnswers.map(answer => {
22311
+ // Figure out how this answer is supposed to be
22312
+ // displayed
22313
+ let format = "decimal";
22314
+ if (answer.answerForms && answer.answerForms[0]) {
22315
+ // NOTE(johnsullivan): This isn't exactly ideal, but
22316
+ // it does behave well for all the currently known
22317
+ // problems. See D14742 for some discussion on
22318
+ // alternate strategies.
22319
+ format = answer.answerForms[0];
22320
+ }
22321
+
22322
+ // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
22323
+ let answerString = KhanMath.toNumericString(answer.value, format);
22324
+ if (answer.maxError) {
22325
+ answerString += " \u00B1 " +
22326
+ // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
22327
+ KhanMath.toNumericString(answer.maxError, format);
22328
+ }
22329
+ return answerString;
22330
+ });
22331
+ if (answerStrings.length === 0) {
22332
+ return;
22333
+ }
22334
+ return answerStrings[0];
22335
+ }
22340
22336
  };
22341
22337
 
22342
22338
  /**
@@ -28276,7 +28272,7 @@ const Exponential = _.extend({}, PlotDefaults, {
28276
28272
  * coordinate, and `false` uses oldCoord as the resulting coordinate.
28277
28273
  */
28278
28274
  extraCoordConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
28279
- const y = _.head(asymptote)[1];
28275
+ const y = asymptote[0][1];
28280
28276
  return _.all(coords, coord => coord[1] !== y);
28281
28277
  },
28282
28278
  extraAsymptoteConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
@@ -28300,7 +28296,7 @@ const Exponential = _.extend({}, PlotDefaults, {
28300
28296
  getCoefficients: function (coords, asymptote) {
28301
28297
  const p1 = coords[0];
28302
28298
  const p2 = coords[1];
28303
- const c = _.head(asymptote)[1];
28299
+ const c = asymptote[0][1];
28304
28300
  const b = Math.log((p1[1] - c) / (p2[1] - c)) / (p1[0] - p2[0]);
28305
28301
  const a = (p1[1] - c) / Math.exp(b * p1[0]);
28306
28302
  return [a, b, c];
@@ -28327,7 +28323,7 @@ const Logarithm = _.extend({}, PlotDefaults, {
28327
28323
  defaultCoords: [[0.55, 0.5], [0.75, 0.75]],
28328
28324
  defaultAsymptote: [[0.5, 0], [0.5, 1.0]],
28329
28325
  extraCoordConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
28330
- const x = _.head(asymptote)[0];
28326
+ const x = asymptote[0][0];
28331
28327
  return _.all(coords, coord => coord[0] !== x) && coords[0][1] !== coords[1][1];
28332
28328
  },
28333
28329
  extraAsymptoteConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
@@ -28355,10 +28351,12 @@ const Logarithm = _.extend({}, PlotDefaults, {
28355
28351
  // logic between the two 'models'.
28356
28352
  const flip = coord => [coord[1], coord[0]];
28357
28353
  const inverseCoeffs = Exponential.getCoefficients(_.map(coords, flip), _.map(asymptote, flip));
28358
- const c = -inverseCoeffs[2] / inverseCoeffs[0];
28359
- const b = 1 / inverseCoeffs[0];
28360
- const a = 1 / inverseCoeffs[1];
28361
- return [a, b, c];
28354
+ if (inverseCoeffs) {
28355
+ const c = -inverseCoeffs[2] / inverseCoeffs[0];
28356
+ const b = 1 / inverseCoeffs[0];
28357
+ const a = 1 / inverseCoeffs[1];
28358
+ return [a, b, c];
28359
+ }
28362
28360
  },
28363
28361
  getFunctionForCoeffs: function (coeffs, x, asymptote) {
28364
28362
  const a = coeffs[0],
@@ -28422,11 +28420,9 @@ const functionTypeMapping = {
28422
28420
  absolute_value: AbsoluteValue
28423
28421
  };
28424
28422
  const allTypes = _.keys(functionTypeMapping);
28425
- function functionForType(
28426
- // TODO(jeremy): Actually `$Keys<typeof functionTypeMapping>` but that
28427
- // triggers TypeScript to require all of our Plot types to be fully typed which
28428
- // is a big amount of work/change.
28429
- type) {
28423
+ function functionForType(type) {
28424
+ // @ts-expect-error: TypeScript doesn't know how to use deal with generics
28425
+ // and conditional types in this way.
28430
28426
  return functionTypeMapping[type];
28431
28427
  }
28432
28428
  const getEquationString = props => {
@@ -28491,12 +28487,13 @@ const defaultPlotProps = (type, graph) => {
28491
28487
  // widget before even reading the question; you can't lose, but you
28492
28488
  // might get a free win.
28493
28489
  const model = functionForType(type);
28490
+ const defaultAsymptote = "defaultAsymptote" in model ? model.defaultAsymptote : null;
28494
28491
  const gridStep = [1, 1];
28495
28492
  // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[number, number]'.
28496
28493
  const snapStep = Util.snapStepFromGridStep(gridStep);
28497
28494
  return {
28498
28495
  type,
28499
- asymptote: maybePointsFromNormalized(model.defaultAsymptote, graph.range, graph.step, snapStep),
28496
+ asymptote: maybePointsFromNormalized(defaultAsymptote, graph.range, graph.step, snapStep),
28500
28497
  coords: null
28501
28498
  };
28502
28499
  };
@@ -28556,8 +28553,19 @@ var util = /*#__PURE__*/Object.freeze({
28556
28553
  typeToButton: typeToButton
28557
28554
  });
28558
28555
 
28559
- function grapherValidator(state, rubric) {
28560
- if (state.type !== rubric.correct.type) {
28556
+ function getCoefficientsByType(data) {
28557
+ if (data.type === "exponential" || data.type === "logarithm") {
28558
+ const grader = functionForType(data.type);
28559
+ return grader.getCoefficients(data.coords, data.asymptote);
28560
+ } else if (data.type === "linear" || data.type === "quadratic" || data.type === "absolute_value" || data.type === "sinusoid" || data.type === "tangent") {
28561
+ const grader = functionForType(data.type);
28562
+ return grader.getCoefficients(data.coords);
28563
+ } else {
28564
+ throw new PerseusError("Invalid grapher type", Errors.InvalidInput);
28565
+ }
28566
+ }
28567
+ function grapherValidator(userInput, rubric) {
28568
+ if (userInput.type !== rubric.correct.type) {
28561
28569
  return {
28562
28570
  type: "points",
28563
28571
  earned: 0,
@@ -28567,7 +28575,7 @@ function grapherValidator(state, rubric) {
28567
28575
  }
28568
28576
 
28569
28577
  // We haven't moved the coords
28570
- if (state.coords == null) {
28578
+ if (userInput.coords == null) {
28571
28579
  return {
28572
28580
  type: "invalid",
28573
28581
  message: null
@@ -28575,11 +28583,9 @@ function grapherValidator(state, rubric) {
28575
28583
  }
28576
28584
 
28577
28585
  // Get new function handler for grading
28578
- const grader = functionForType(state.type);
28579
- const guessCoeffs = grader.getCoefficients(state.coords, state.asymptote);
28580
- const correctCoeffs = grader.getCoefficients(rubric.correct.coords,
28581
- // @ts-expect-error - TS(2339) - Property 'asymptote' does not exist on type '{ type: "absolute_value"; coords: [Coord, Coord]; }'
28582
- rubric.correct.asymptote);
28586
+ const grader = functionForType(userInput.type);
28587
+ const guessCoeffs = getCoefficientsByType(userInput);
28588
+ const correctCoeffs = getCoefficientsByType(rubric.correct);
28583
28589
  if (guessCoeffs == null || correctCoeffs == null) {
28584
28590
  return {
28585
28591
  type: "invalid",
@@ -37599,7 +37605,7 @@ function shouldUseMafs(mafsFlags, graph) {
37599
37605
  // TODO(benchristel): add a feature flag for the "unlimited"
37600
37606
  // case once we've implemented polygon graphs with unlimited
37601
37607
  // sides
37602
- return false;
37608
+ return Boolean(mafsFlags["unlimited-polygon"]);
37603
37609
  }
37604
37610
  return Boolean(mafsFlags["polygon"]);
37605
37611
  default:
@@ -42061,17 +42067,23 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
42061
42067
  const results = [];
42062
42068
 
42063
42069
  // For convenience, extract some props into separate variables
42064
- const range = props.range;
42065
- const labelRange = props.labelRange;
42070
+ const {
42071
+ range,
42072
+ labelRange,
42073
+ labelStyle,
42074
+ labelTicks,
42075
+ tickStep,
42076
+ numDivisions
42077
+ } = props;
42066
42078
  const leftLabel = labelRange[0] == null ? range[0] : labelRange[0];
42067
42079
  const rightLabel = labelRange[1] == null ? range[1] : labelRange[1];
42068
42080
 
42069
42081
  // Find base via GCD for non-reduced fractions
42070
42082
  let base;
42071
- if (props.labelStyle === "non-reduced") {
42083
+ if (labelStyle === "non-reduced") {
42072
42084
  const fractions = [leftLabel, rightLabel];
42073
- for (let i = 0; i <= props.numDivisions; i++) {
42074
- const x = range[0] + i * props.tickStep;
42085
+ for (let i = 0; i <= numDivisions; i++) {
42086
+ const x = range[0] + i * tickStep;
42075
42087
  fractions.push(x);
42076
42088
  }
42077
42089
  const getDenom = x => number.toFraction(x)[1];
@@ -42080,30 +42092,40 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
42080
42092
  } else {
42081
42093
  base = undefined;
42082
42094
  }
42083
-
42084
- // Draw and save the tick marks and tick labels
42085
- for (let i = 0; i <= props.numDivisions; i++) {
42086
- const x = range[0] + i * props.tickStep;
42087
- results.push(graphie.line([x, -0.2], [x, 0.2]));
42088
- const labelTicks = props.labelTicks;
42089
- if (labelTicks || props.labelStyle === "decimal ticks") {
42090
- if (x === leftLabel || x === rightLabel) {
42091
- results.push(graphie.style({
42092
- color: KhanColors.BLUE
42093
- }, () => _label(graphie, props.labelStyle, x, x, base)));
42094
- } else {
42095
- results.push(_label(graphie, props.labelStyle, x, x, base));
42096
- }
42097
- }
42098
- }
42099
-
42100
- // Render the labels' lines
42101
- graphie.style({
42095
+ const highlightedLineStyle = {
42102
42096
  stroke: KhanColors.BLUE,
42103
42097
  strokeWidth: 3.5
42104
- }, () => {
42105
- results.push(graphie.line([leftLabel, -0.2], [leftLabel, 0.2]));
42106
- results.push(graphie.line([rightLabel, -0.2], [rightLabel, 0.2]));
42098
+ };
42099
+ const highlightedTextStyle = {
42100
+ color: KhanColors.BLUE
42101
+ };
42102
+
42103
+ // Generate an array of tick numbers:
42104
+ // `Array(props.numDivisions)` makes an array of null values - one for every division marker
42105
+ // `.keys()` gets the index values for each marker placeholder
42106
+ // `.map()` converts the index values into actual tick numbers
42107
+ const initialTicks = [...Array(numDivisions).keys()].map(index => range[0] + index * tickStep);
42108
+
42109
+ // .sort() comparator
42110
+ const byNumericAscending = (a, b) => a - b;
42111
+
42112
+ // Ensure that any label markers and range endpoints are included in the array
42113
+ // Using `Set()` prevents duplication of tick numbers (and is quite performant)
42114
+ const allTicks = [...new Set([...initialTicks, leftLabel, rightLabel, ...range])].sort(byNumericAscending);
42115
+
42116
+ // Cycle through each tick number and add a tick line, and a label (if needed)
42117
+ allTicks.forEach(tick => {
42118
+ const tickIsHighlighted = tick === leftLabel || tick === rightLabel;
42119
+ const lineStyle = tickIsHighlighted ? highlightedLineStyle : null;
42120
+ const textStyle = tickIsHighlighted ? highlightedTextStyle : null;
42121
+ graphie.style(lineStyle, () => {
42122
+ results.push(graphie.line([tick, -0.2], [tick, 0.2]));
42123
+ });
42124
+ if (labelTicks || tickIsHighlighted || labelStyle === "decimal ticks") {
42125
+ graphie.style(textStyle, () => {
42126
+ results.push(_label(graphie, labelStyle, tick, tick, base));
42127
+ });
42128
+ }
42107
42129
  });
42108
42130
  return results;
42109
42131
  });
@@ -42782,7 +42804,7 @@ class Orderer extends React.Component {
42782
42804
  list.splice(index, 0, newCard);
42783
42805
  }
42784
42806
  this.props.onChange({
42785
- // @ts-expect-error - TS2345 - Argument of type '{ current: any[]; }' is not assignable to parameter of type '{ hints?: readonly Hint[] | undefined; replace?: boolean | undefined; content?: string | undefined; widgets?: WidgetDict | undefined; images?: ImageDict | undefined; ... 13 more ...; plot?: any; }'.
42807
+ // @ts-expect-error - TS2345 - Argument of type '{ current: any[]; }' is not assignable to parameter of type '{ hints?: readonly Hint[] | undefined; replace?: boolean | undefined; content?: string | undefined; widgets?: PerseusWidgetsMap | undefined; images?: ImageDict | undefined; ... 13 more ...; plot?: any; }'.
42786
42808
  current: list
42787
42809
  });
42788
42810
  this.setState({
@@ -42944,7 +42966,7 @@ class Orderer extends React.Component {
42944
42966
  };
42945
42967
  });
42946
42968
  this.props.onChange({
42947
- // @ts-expect-error - TS2345 - Argument of type '{ current: { content: string; }[]; }' is not assignable to parameter of type '{ hints?: readonly Hint[] | undefined; replace?: boolean | undefined; content?: string | undefined; widgets?: WidgetDict | undefined; images?: ImageDict | undefined; ... 13 more ...; plot?: any; }'.
42969
+ // @ts-expect-error - TS2345 - Argument of type '{ current: { content: string; }[]; }' is not assignable to parameter of type '{ hints?: readonly Hint[] | undefined; replace?: boolean | undefined; content?: string | undefined; widgets?: PerseusWidgetsMap | undefined; images?: ImageDict | undefined; ... 13 more ...; plot?: any; }'.
42948
42970
  current: list
42949
42971
  });
42950
42972
  this.setState({
@@ -44805,7 +44827,7 @@ const init = function init(options) {
44805
44827
 
44806
44828
  // This file is processed by a Rollup plugin (replace) to inject the production
44807
44829
  const libName = "@khanacademy/perseus";
44808
- const libVersion = "37.0.0";
44830
+ const libVersion = "38.0.0";
44809
44831
  addLibraryVersionToPerseusDebug(libName, libVersion);
44810
44832
 
44811
44833
  const apiVersion = {
@@ -48053,9 +48075,7 @@ const getCorrectAnswerForWidgetId = (widgetId, itemData) => {
48053
48075
  const rubric = itemData.question.widgets[widgetId].options;
48054
48076
  const widgetMap = getWidgetsMapFromItemData(itemData);
48055
48077
  const widgetType = getWidgetTypeByWidgetId(widgetId, widgetMap);
48056
- const widget = getWidget(widgetType);
48057
-
48058
- // @ts-expect-error - TS2339 - Property 'getOneCorrectAnswerFromRubric' does not exist on type 'ComponentType<any>'.
48078
+ const widget = getWidgetExport(widgetType);
48059
48079
  return widget == null || widget.getOneCorrectAnswerFromRubric == null ? void 0 : widget.getOneCorrectAnswerFromRubric(rubric);
48060
48080
  };
48061
48081