@khanacademy/perseus 45.1.0 → 46.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/es/index.js CHANGED
@@ -2793,12 +2793,6 @@ const rWidgetRule = /^\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/;
2793
2793
  const rTypeFromWidgetId = /^([a-z-]+) ([0-9]+)$/;
2794
2794
  const rWidgetParts = new RegExp(rWidgetRule.source + "$");
2795
2795
  const snowman = "\u2603";
2796
- const noScore = {
2797
- type: "points",
2798
- earned: 0,
2799
- total: 0,
2800
- message: null
2801
- };
2802
2796
  const seededRNG$1 = function seededRNG(seed) {
2803
2797
  let randomSeed = seed;
2804
2798
  return function () {
@@ -2875,97 +2869,6 @@ const split = "x".split(/(.)/g).length ? function (str, r) {
2875
2869
  return output;
2876
2870
  };
2877
2871
 
2878
- /**
2879
- * Combine two score objects.
2880
- *
2881
- * Given two score objects for two different widgets, combine them so that
2882
- * if one is wrong, the total score is wrong, etc.
2883
- */
2884
- function combineScores(scoreA, scoreB) {
2885
- let message;
2886
- if (scoreA.type === "points" && scoreB.type === "points") {
2887
- if (scoreA.message && scoreB.message && scoreA.message !== scoreB.message) {
2888
- // TODO(alpert): Figure out how to combine messages usefully
2889
- message = null;
2890
- } else {
2891
- message = scoreA.message || scoreB.message;
2892
- }
2893
- return {
2894
- type: "points",
2895
- earned: scoreA.earned + scoreB.earned,
2896
- total: scoreA.total + scoreB.total,
2897
- message: message
2898
- };
2899
- }
2900
- if (scoreA.type === "points" && scoreB.type === "invalid") {
2901
- return scoreB;
2902
- }
2903
- if (scoreA.type === "invalid" && scoreB.type === "points") {
2904
- return scoreA;
2905
- }
2906
- if (scoreA.type === "invalid" && scoreB.type === "invalid") {
2907
- if (scoreA.message && scoreB.message && scoreA.message !== scoreB.message) {
2908
- // TODO(alpert): Figure out how to combine messages usefully
2909
- message = null;
2910
- } else {
2911
- message = scoreA.message || scoreB.message;
2912
- }
2913
- return {
2914
- type: "invalid",
2915
- message: message
2916
- };
2917
- }
2918
-
2919
- /**
2920
- * The above checks cover all combinations of score type, so if we get here
2921
- * then something is amiss with our inputs.
2922
- */
2923
- throw new PerseusError("PerseusScore with unknown type encountered", Errors.InvalidInput, {
2924
- metadata: {
2925
- scoreA: JSON.stringify(scoreA),
2926
- scoreB: JSON.stringify(scoreB)
2927
- }
2928
- });
2929
- }
2930
- function flattenScores(widgetScoreMap) {
2931
- return Object.values(widgetScoreMap).reduce(combineScores, noScore);
2932
- }
2933
- function isCorrect(score) {
2934
- return score.type === "points" && score.earned >= score.total;
2935
- }
2936
- function keScoreFromPerseusScore(score,
2937
- // It's weird, but this is what we're passing it
2938
- guess, state) {
2939
- if (score.type === "points") {
2940
- return {
2941
- empty: false,
2942
- correct: isCorrect(score),
2943
- message: score.message,
2944
- guess: guess,
2945
- state: state
2946
- };
2947
- }
2948
- if (score.type === "invalid") {
2949
- return {
2950
- empty: true,
2951
- correct: false,
2952
- message: score.message,
2953
- suppressAlmostThere: score.suppressAlmostThere,
2954
- guess: guess,
2955
- state: state
2956
- };
2957
- }
2958
- throw new PerseusError(
2959
- // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
2960
- "Invalid score type: " + score.type, Errors.InvalidInput, {
2961
- metadata: {
2962
- score: JSON.stringify(score),
2963
- guess: JSON.stringify(guess),
2964
- state: JSON.stringify(state)
2965
- }
2966
- });
2967
- }
2968
-
2969
2872
  /**
2970
2873
  * Return the first valid interpretation of 'text' as a number, in the form
2971
2874
  * {value: 2.3, exact: true}.
@@ -3263,28 +3166,6 @@ function strongEncodeURIComponent(str) {
3263
3166
  .replace(/\*/g, "%2A");
3264
3167
  }
3265
3168
 
3266
- /**
3267
- * If a widget says that it is empty once it is graded.
3268
- * Trying to encapsulate references to the score format.
3269
- */
3270
- function scoreIsEmpty(score) {
3271
- // HACK(benkomalo): ugh. this isn't great; the Perseus score objects
3272
- // overload the type "invalid" for what should probably be three
3273
- // distinct cases:
3274
- // - truly empty or not fully filled out
3275
- // - invalid or malformed inputs
3276
- // - "almost correct" like inputs where the widget wants to give
3277
- // feedback (e.g. a fraction needs to be reduced, or `pi` should
3278
- // be used instead of 3.14)
3279
- //
3280
- // Unfortunately the coercion happens all over the place, as these
3281
- // Perseus style score objects are created *everywhere* (basically
3282
- // in every widget), so it's hard to change now. We assume that
3283
- // anything with a "message" is not truly empty, and one of the
3284
- // latter two cases for now.
3285
- return score.type === "invalid" && (!score.message || score.message.length === 0);
3286
- }
3287
-
3288
3169
  /*
3289
3170
  * The touchHandlers are used to track the current state of the touch
3290
3171
  * event, such as whether or not the user is currently pressed down (either
@@ -3459,13 +3340,9 @@ const Util = {
3459
3340
  rTypeFromWidgetId,
3460
3341
  rWidgetParts,
3461
3342
  snowman,
3462
- noScore,
3463
3343
  seededRNG: seededRNG$1,
3464
3344
  shuffle: shuffle$3,
3465
3345
  split,
3466
- combineScores,
3467
- flattenScores,
3468
- keScoreFromPerseusScore,
3469
3346
  firstNumericalParse: firstNumericalParse$1,
3470
3347
  stringArrayOfSize: stringArrayOfSize$1,
3471
3348
  gridDimensionConfig,
@@ -3481,7 +3358,6 @@ const Util = {
3481
3358
  parseQueryString,
3482
3359
  updateQueryString: updateQueryString$2,
3483
3360
  strongEncodeURIComponent,
3484
- scoreIsEmpty,
3485
3361
  touchHandlers,
3486
3362
  resetTouchHandlers,
3487
3363
  extractPointerLocation,
@@ -18702,6 +18578,126 @@ class QuestionParagraph extends React.Component {
18702
18578
  }
18703
18579
  }
18704
18580
 
18581
+ const noScore = {
18582
+ type: "points",
18583
+ earned: 0,
18584
+ total: 0,
18585
+ message: null
18586
+ };
18587
+
18588
+ /**
18589
+ * If a widget says that it is empty once it is graded.
18590
+ * Trying to encapsulate references to the score format.
18591
+ */
18592
+ function scoreIsEmpty(score) {
18593
+ // HACK(benkomalo): ugh. this isn't great; the Perseus score objects
18594
+ // overload the type "invalid" for what should probably be three
18595
+ // distinct cases:
18596
+ // - truly empty or not fully filled out
18597
+ // - invalid or malformed inputs
18598
+ // - "almost correct" like inputs where the widget wants to give
18599
+ // feedback (e.g. a fraction needs to be reduced, or `pi` should
18600
+ // be used instead of 3.14)
18601
+ //
18602
+ // Unfortunately the coercion happens all over the place, as these
18603
+ // Perseus style score objects are created *everywhere* (basically
18604
+ // in every widget), so it's hard to change now. We assume that
18605
+ // anything with a "message" is not truly empty, and one of the
18606
+ // latter two cases for now.
18607
+ return score.type === "invalid" && (!score.message || score.message.length === 0);
18608
+ }
18609
+
18610
+ /**
18611
+ * Combine two score objects.
18612
+ *
18613
+ * Given two score objects for two different widgets, combine them so that
18614
+ * if one is wrong, the total score is wrong, etc.
18615
+ */
18616
+ function combineScores(scoreA, scoreB) {
18617
+ let message;
18618
+ if (scoreA.type === "points" && scoreB.type === "points") {
18619
+ if (scoreA.message && scoreB.message && scoreA.message !== scoreB.message) {
18620
+ // TODO(alpert): Figure out how to combine messages usefully
18621
+ message = null;
18622
+ } else {
18623
+ message = scoreA.message || scoreB.message;
18624
+ }
18625
+ return {
18626
+ type: "points",
18627
+ earned: scoreA.earned + scoreB.earned,
18628
+ total: scoreA.total + scoreB.total,
18629
+ message: message
18630
+ };
18631
+ }
18632
+ if (scoreA.type === "points" && scoreB.type === "invalid") {
18633
+ return scoreB;
18634
+ }
18635
+ if (scoreA.type === "invalid" && scoreB.type === "points") {
18636
+ return scoreA;
18637
+ }
18638
+ if (scoreA.type === "invalid" && scoreB.type === "invalid") {
18639
+ if (scoreA.message && scoreB.message && scoreA.message !== scoreB.message) {
18640
+ // TODO(alpert): Figure out how to combine messages usefully
18641
+ message = null;
18642
+ } else {
18643
+ message = scoreA.message || scoreB.message;
18644
+ }
18645
+ return {
18646
+ type: "invalid",
18647
+ message: message
18648
+ };
18649
+ }
18650
+
18651
+ /**
18652
+ * The above checks cover all combinations of score type, so if we get here
18653
+ * then something is amiss with our inputs.
18654
+ */
18655
+ throw new PerseusError("PerseusScore with unknown type encountered", Errors.InvalidInput, {
18656
+ metadata: {
18657
+ scoreA: JSON.stringify(scoreA),
18658
+ scoreB: JSON.stringify(scoreB)
18659
+ }
18660
+ });
18661
+ }
18662
+ function flattenScores(widgetScoreMap) {
18663
+ return Object.values(widgetScoreMap).reduce(combineScores, noScore);
18664
+ }
18665
+ function isCorrect(score) {
18666
+ return score.type === "points" && score.earned >= score.total;
18667
+ }
18668
+ function keScoreFromPerseusScore(score,
18669
+ // It's weird, but this is what we're passing it
18670
+ guess, state) {
18671
+ if (score.type === "points") {
18672
+ return {
18673
+ empty: false,
18674
+ correct: isCorrect(score),
18675
+ message: score.message,
18676
+ guess: guess,
18677
+ state: state
18678
+ };
18679
+ }
18680
+ if (score.type === "invalid") {
18681
+ return {
18682
+ empty: true,
18683
+ correct: false,
18684
+ message: score.message,
18685
+ suppressAlmostThere: score.suppressAlmostThere,
18686
+ guess: guess,
18687
+ state: state
18688
+ };
18689
+ }
18690
+ throw new PerseusError(
18691
+ // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
18692
+ "Invalid score type: " + score.type, Errors.InvalidInput, {
18693
+ metadata: {
18694
+ score: JSON.stringify(score),
18695
+ guess: JSON.stringify(guess),
18696
+ state: JSON.stringify(state)
18697
+ }
18698
+ });
18699
+ }
18700
+
18705
18701
  // These are all the current widgets that require user-input and are supported for automatic scoring
18706
18702
  const QUESTION_WIDGETS = ["numeric-input", "input-number", "radio", "interactive-graph", "interactive-number-line", "categorizer", "plotter", "orderer", "protractor", "matcher", "sorter"];
18707
18703
 
@@ -19300,7 +19296,7 @@ widgetIds, userInputMap, strings, locale) {
19300
19296
  const scorer = getWidgetScorer(widget.type);
19301
19297
  const score = scorer == null ? void 0 : scorer(userInputMap[id], widget.options, strings, locale);
19302
19298
  if (score) {
19303
- return Util.scoreIsEmpty(score);
19299
+ return scoreIsEmpty(score);
19304
19300
  }
19305
19301
  });
19306
19302
  }
@@ -19316,7 +19312,7 @@ strings, locale) {
19316
19312
  // so this checks that the widgets are being used before scoring them
19317
19313
  const usedWidgetIds = getWidgetIdsFromContent(perseusRenderData.content);
19318
19314
  const scores = scoreWidgetsFunctional(perseusRenderData.widgets, usedWidgetIds, userInputMap, strings, locale);
19319
- return Util.flattenScores(scores);
19315
+ return flattenScores(scores);
19320
19316
  }
19321
19317
  function scoreWidgetsFunctional(widgets,
19322
19318
  // This is a port of old code, I'm not sure why
@@ -20596,28 +20592,6 @@ class Renderer extends React.Component {
20596
20592
  const totalScore = this.score();
20597
20593
  return [totalGuess, totalScore];
20598
20594
  };
20599
- this.examples = () => {
20600
- const widgetIds = this.widgetIds;
20601
- const examples = widgetIds.map(widgetId => {
20602
- const widget = this.getWidgetInstance(widgetId);
20603
- return widget != null && widget.examples ? widget.examples() : null;
20604
- }).filter(Boolean);
20605
-
20606
- // no widgets with examples
20607
- if (!examples.length) {
20608
- return null;
20609
- }
20610
- const allEqual = _.all(examples, function (example) {
20611
- return _.isEqual(examples[0], example);
20612
- });
20613
-
20614
- // some widgets have different examples
20615
- // TODO(alex): handle this better
20616
- if (!allEqual) {
20617
- return null;
20618
- }
20619
- return examples[0];
20620
- };
20621
20595
  // TranslationLinter callback
20622
20596
  this.handletranslationLintErrors = lintErrors => {
20623
20597
  if (!this._isMounted) {
@@ -20868,7 +20842,7 @@ class Renderer extends React.Component {
20868
20842
  */
20869
20843
  score() {
20870
20844
  const scores = scoreWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.props.strings, this.context.locale);
20871
- const combinedScore = Util.flattenScores(scores);
20845
+ const combinedScore = flattenScores(scores);
20872
20846
  return combinedScore;
20873
20847
  }
20874
20848
  render() {
@@ -21929,15 +21903,6 @@ class InputNumber extends React.Component {
21929
21903
  currentValue: newValue
21930
21904
  }, cb);
21931
21905
  };
21932
- this.examples = () => {
21933
- const {
21934
- strings
21935
- } = this.context;
21936
- const type = this.props.answerType;
21937
- const forms = answerTypes[type].forms.split(/\s*,\s*/);
21938
- const examples = _.map(forms, form => formExamples$1[form](this.props, strings));
21939
- return [strings.yourAnswer].concat(examples);
21940
- };
21941
21906
  }
21942
21907
  static getUserInputFromProps(props) {
21943
21908
  return {
@@ -21950,6 +21915,15 @@ class InputNumber extends React.Component {
21950
21915
  getPromptJSON() {
21951
21916
  return getPromptJSON$s(this.props, this.getUserInput());
21952
21917
  }
21918
+ examples() {
21919
+ const {
21920
+ strings
21921
+ } = this.context;
21922
+ const type = this.props.answerType;
21923
+ const forms = answerTypes[type].forms.split(/\s*,\s*/);
21924
+ const examples = _.map(forms, form => formExamples$1[form](this.props, strings));
21925
+ return [strings.yourAnswer].concat(examples);
21926
+ }
21953
21927
  render() {
21954
21928
  if (this.props.apiOptions.customKeypad) {
21955
21929
  // TODO(charlie): Support "Review Mode".
@@ -22232,31 +22206,13 @@ class NumericInput extends React.Component {
22232
22206
  previousValues: [""],
22233
22207
  isFocused: false
22234
22208
  };
22235
- // TODO(Nicole, Jeremy): This is maybe never used and should be removed
22236
- this.examples = () => {
22237
- var _this$props$answerFor;
22238
- // if the set of specified forms are empty, allow all forms
22239
- const forms = ((_this$props$answerFor = this.props.answerForms) == null ? void 0 : _this$props$answerFor.length) !== 0 ? this.props.answerForms : Object.keys(formExamples).map(name => {
22240
- return {
22241
- name: name,
22242
- simplify: "required"
22243
- };
22244
- });
22245
- let examples = _.map(forms, form => {
22246
- return formExamples[form.name](form, this.context.strings);
22247
- });
22248
- // Ensure no duplicate tooltip text from simplified and unsimplified
22249
- // versions of the same format
22250
- examples = _.uniq(examples);
22251
- return [this.context.strings.yourAnswer].concat(examples);
22252
- };
22253
22209
  this.shouldShowExamples = () => {
22254
- var _this$props$answerFor2, _this$props$answerFor3;
22255
- const noFormsAccepted = ((_this$props$answerFor2 = this.props.answerForms) == null ? void 0 : _this$props$answerFor2.length) === 0;
22210
+ var _this$props$answerFor, _this$props$answerFor2;
22211
+ const noFormsAccepted = ((_this$props$answerFor = this.props.answerForms) == null ? void 0 : _this$props$answerFor.length) === 0;
22256
22212
  // To check if all answer forms are accepted, we must first
22257
22213
  // find the *names* of all accepted forms, and see if they are
22258
22214
  // all present, ignoring duplicates
22259
- const answerFormNames = _.uniq((_this$props$answerFor3 = this.props.answerForms) == null ? void 0 : _this$props$answerFor3.map(form => form.name));
22215
+ const answerFormNames = _.uniq((_this$props$answerFor2 = this.props.answerForms) == null ? void 0 : _this$props$answerFor2.map(form => form.name));
22260
22216
  const allFormsAccepted = answerFormNames.length >= Object.keys(formExamples).length;
22261
22217
  return !noFormsAccepted && !allFormsAccepted;
22262
22218
  };
@@ -22313,6 +22269,27 @@ class NumericInput extends React.Component {
22313
22269
  currentValue: props.currentValue
22314
22270
  };
22315
22271
  }
22272
+ /**
22273
+ * Generates a string that demonstrates how to input the various supported
22274
+ * answer forms.
22275
+ */
22276
+ examples() {
22277
+ var _this$props$answerFor3;
22278
+ // if the set of specified forms are empty, allow all forms
22279
+ const forms = ((_this$props$answerFor3 = this.props.answerForms) == null ? void 0 : _this$props$answerFor3.length) !== 0 ? this.props.answerForms : Object.keys(formExamples).map(name => {
22280
+ return {
22281
+ name: name,
22282
+ simplify: "required"
22283
+ };
22284
+ });
22285
+ let examples = _.map(forms, form => {
22286
+ return formExamples[form.name](form, this.context.strings);
22287
+ });
22288
+ // Ensure no duplicate tooltip text from simplified and unsimplified
22289
+ // versions of the same format
22290
+ examples = _.uniq(examples);
22291
+ return [this.context.strings.yourAnswer].concat(examples);
22292
+ }
22316
22293
  getUserInput() {
22317
22294
  return NumericInput.getUserInputFromProps(this.props);
22318
22295
  }
@@ -29384,7 +29361,7 @@ const getPromptJSON$f = rendererJSON => {
29384
29361
  // it. As such, scoring a group means scoring all widgets it contains.
29385
29362
  function scoreGroup(userInput, options, strings, locale) {
29386
29363
  const scores = scoreWidgetsFunctional(options.widgets, Object.keys(options.widgets), userInput, strings, locale);
29387
- return Util.flattenScores(scores);
29364
+ return flattenScores(scores);
29388
29365
  }
29389
29366
 
29390
29367
  // exports has no 'transform'
@@ -45109,7 +45086,7 @@ const init = function init() {
45109
45086
 
45110
45087
  // This file is processed by a Rollup plugin (replace) to inject the production
45111
45088
  const libName = "@khanacademy/perseus";
45112
- const libVersion = "45.1.0";
45089
+ const libVersion = "46.0.0";
45113
45090
  addLibraryVersionToPerseusDebug(libName, libVersion);
45114
45091
 
45115
45092
  const apiVersion = {
@@ -45884,7 +45861,7 @@ class ServerItemRenderer extends React.Component {
45884
45861
  // TODO(alex): Check whether we rely on the format here for
45885
45862
  // analyzing ProblemLogs. If not, remove this layer.
45886
45863
  const maxCompatGuess = [this.questionRenderer.getUserInput(), []];
45887
- const keScore = Util.keScoreFromPerseusScore(score, maxCompatGuess, this.questionRenderer.getSerializedState());
45864
+ const keScore = keScoreFromPerseusScore(score, maxCompatGuess, this.questionRenderer.getSerializedState());
45888
45865
  const emptyQuestionAreaWidgets = this.questionRenderer.emptyWidgets();
45889
45866
  this.setState({
45890
45867
  questionCompleted: keScore.correct,
@@ -46963,7 +46940,7 @@ class MultiRenderer extends React.Component {
46963
46940
  if (ref.getSerializedState) {
46964
46941
  state = ref.getSerializedState();
46965
46942
  }
46966
- return Util.keScoreFromPerseusScore(score, guess, state);
46943
+ return keScoreFromPerseusScore(score, guess, state);
46967
46944
  }
46968
46945
 
46969
46946
  /**
@@ -46993,8 +46970,8 @@ class MultiRenderer extends React.Component {
46993
46970
  scores.push(data.ref.score());
46994
46971
  return (_data$ref = data.ref) == null ? void 0 : _data$ref.getUserInput();
46995
46972
  });
46996
- const combinedScore = scores.reduce(Util.combineScores);
46997
- return Util.keScoreFromPerseusScore(combinedScore, guess, state);
46973
+ const combinedScore = scores.reduce(combineScores);
46974
+ return keScoreFromPerseusScore(combinedScore, guess, state);
46998
46975
  }
46999
46976
 
47000
46977
  /**
@@ -49837,6 +49814,9 @@ const GrapherUtil = {
49837
49814
  getEquationString,
49838
49815
  typeToButton
49839
49816
  };
49817
+ const ScoringUtil = {
49818
+ keScoreFromPerseusScore
49819
+ };
49840
49820
 
49841
- export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, addWidget, apiVersion, bodyXsmallBold, buildEmptyItemTreeForShape, buildMapper, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getClockwiseAngle, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, makeSafeUrl, mathOnlyParser, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, scorePerseusItem, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
49821
+ export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ScoringUtil, ref as ServerItemRenderer, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, addWidget, apiVersion, bodyXsmallBold, buildEmptyItemTreeForShape, buildMapper, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getClockwiseAngle, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, makeSafeUrl, mathOnlyParser, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, scorePerseusItem, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
49842
49822
  //# sourceMappingURL=index.js.map