@khanacademy/perseus 57.2.2 → 59.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
@@ -27,7 +27,7 @@ import { KeypadContext } from '@khanacademy/keypad-context';
27
27
  import { TextField } from '@khanacademy/wonder-blocks-form';
28
28
  import { entries, UnreachableCaseError, keys } from '@khanacademy/wonder-stuff-core';
29
29
  import { CircularSpinner } from '@khanacademy/wonder-blocks-progress-spinner';
30
- import { point, KhanMath, vector as vector$3, number, line, geometry, angles, coefficients } from '@khanacademy/kmath';
30
+ import { point, KhanMath, number, vector as vector$3, geometry, line, angles, coefficients } from '@khanacademy/kmath';
31
31
  import _classPrivateFieldLooseBase from '@babel/runtime/helpers/classPrivateFieldLooseBase';
32
32
  import _classPrivateFieldLooseKey from '@babel/runtime/helpers/classPrivateFieldLooseKey';
33
33
  import SimpleMarkdown from '@khanacademy/simple-markdown';
@@ -54,6 +54,7 @@ import { addLibraryVersionToPerseusDebug } from '@khanacademy/perseus-utils';
54
54
  * The translated strings that are used to render Perseus.
55
55
  */
56
56
 
57
+
57
58
  /**
58
59
  * Mock strings for the Perseus package, to be used for tests and Storybook.
59
60
  */
@@ -237,8 +238,6 @@ const mockStrings = {
237
238
  // The following strings are used for interactive graph SR descriptions.
238
239
  srGraphInstructions: "Use the Tab key to move through the interactive elements in the graph. When an interactive element has focus, use Control + Shift + Arrows to move it.",
239
240
  srUnlimitedGraphInstructions: "Press Shift + Enter to interact with the graph. Use the Tab key to move through the interactive elements in the graph and access the graph Action Bar. When an interactive element has focus, use Control + Shift + Arrows to move it or use the Delete key to remove it from the graph. Use the buttons in the Action Bar to add or adjust elements within the graph.",
240
- xAxis: "X-axis",
241
- yAxis: "Y-axis",
242
241
  graphKeyboardPrompt: "Press Shift + Enter to interact with the graph",
243
242
  addPoint: "Add Point",
244
243
  removePoint: "Remove Point",
@@ -755,6 +754,7 @@ class InnerMathInput extends React.Component {
755
754
  const translator = getKeyTranslator(locale, this.context.strings)[key];
756
755
  const mathField = this.mathField();
757
756
  if (mathField) {
757
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
758
758
  if (translator) {
759
759
  translator(mathField, key);
760
760
  }
@@ -1040,9 +1040,9 @@ const useDependencies = () => {
1040
1040
 
1041
1041
  var dependencies = /*#__PURE__*/Object.freeze({
1042
1042
  __proto__: null,
1043
- setDependencies: setDependencies,
1044
- getDependencies: getDependencies,
1045
1043
  DependenciesContext: DependenciesContext,
1044
+ getDependencies: getDependencies,
1045
+ setDependencies: setDependencies,
1046
1046
  useDependencies: useDependencies
1047
1047
  });
1048
1048
 
@@ -1073,6 +1073,15 @@ const denylist = [
1073
1073
  "onBlur", "onFocus", "trackInteraction", "keypadElement"];
1074
1074
 
1075
1075
  /* eslint-disable @babel/no-invalid-this */
1076
+ /**
1077
+ * Changeable
1078
+ *
1079
+ * Adds a this.change() function to a component
1080
+ *
1081
+ * This.change takes prop changes as parameters, and calls
1082
+ * this.props.onChange with the modified props.
1083
+ */
1084
+
1076
1085
  const USAGE = "Usage:\n" + " this.change({propName: 5}, callback);\n" + ' this.change("propName", 5, callback);\n' + ' this.change("propName")';
1077
1086
 
1078
1087
  /**
@@ -1153,6 +1162,7 @@ var changeable = /*#__PURE__*/Object.freeze({
1153
1162
  });
1154
1163
 
1155
1164
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
1165
+ /* eslint-disable @babel/no-invalid-this, react/forbid-prop-types, react/no-unsafe */
1156
1166
  const textWidthCache = {};
1157
1167
  function getTextWidth(text) {
1158
1168
  if (!textWidthCache[text]) {
@@ -1531,6 +1541,7 @@ class Expression extends React.Component {
1531
1541
  // HACK: imperatively add an ID onto the Mathquill input
1532
1542
  // (which in mobile is a span; desktop a textarea)
1533
1543
  // in order to associate a visual label with it
1544
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
1534
1545
  if (this.refs.input) {
1535
1546
  const isMobile = this.props.apiOptions.customKeypad;
1536
1547
  const container = ReactDOM__default.findDOMNode(this.refs.input);
@@ -1573,6 +1584,7 @@ class Expression extends React.Component {
1573
1584
  this.parse = (value, props) => {
1574
1585
  // TODO(jack): Disable icu for content creators here, or
1575
1586
  // make it so that solution answers with ','s or '.'s work
1587
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
1576
1588
  const options = _.pick(props || this.props, "functions");
1577
1589
  _.extend(options, {
1578
1590
  decimal_separator: getDecimalSeparator(this.context.locale)
@@ -1800,6 +1812,7 @@ var Expression$1 = {
1800
1812
  // TODO(LEMS-2656): remove TS suppression
1801
1813
  // @ts-expect-error: Type 'Rubric' is not assignable to type 'PerseusExpressionRubric'.
1802
1814
  getOneCorrectAnswerFromRubric(rubric) {
1815
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
1803
1816
  const correctAnswers = (rubric.answerForms || []).filter(answerForm => answerForm.considered === "correct");
1804
1817
  if (correctAnswers.length === 0) {
1805
1818
  return;
@@ -1990,6 +2003,7 @@ TextInput.defaultProps = {
1990
2003
  * loaded. This is used to know when SvgImage and (Zoomable)TeX are finished
1991
2004
  * renderering.
1992
2005
  */
2006
+
1993
2007
  const defaultContext$2 = {
1994
2008
  assetStatuses: {},
1995
2009
  setAssetStatus: (assetKey, loaded) => {}
@@ -2083,6 +2097,7 @@ const snowman = "\u2603";
2083
2097
  * Drop this custom split thing.
2084
2098
  */
2085
2099
  // In IE8, split doesn't work right. Implement it ourselves.
2100
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
2086
2101
  const split = "x".split(/(.)/g).length ? function (str, r) {
2087
2102
  return str.split(r);
2088
2103
  } : function (str, r) {
@@ -2614,6 +2629,7 @@ function getUrlHash(url) {
2614
2629
  if (match == null) {
2615
2630
  throw new PerseusError("not a valid URL", Errors.InvalidInput);
2616
2631
  }
2632
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
2617
2633
  return match && match[1];
2618
2634
  }
2619
2635
 
@@ -2722,6 +2738,8 @@ function loadGraphie(url, onDataLoaded) {
2722
2738
  }
2723
2739
 
2724
2740
  // Derived from the MIT-licensed:
2741
+ // https://github.com/fat/zoom.js/blob/fd4f3e43153da7596da0bade198e99f98b47791e/js/zoom.js
2742
+
2725
2743
 
2726
2744
  /*jshint browser:true, node:true */
2727
2745
 
@@ -2979,6 +2997,7 @@ Zoom._OFFSET = 80;
2979
2997
  Zoom._MAX_WIDTH = 2560;
2980
2998
  Zoom._MAX_HEIGHT = 4096;
2981
2999
  Zoom.getOffset = function (zoomToFitOnMobile) {
3000
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
2982
3001
  return zoomToFitOnMobile ? 0 : Zoom._OFFSET;
2983
3002
  };
2984
3003
  Zoom.prototype.getOffset = function () {
@@ -3229,39 +3248,39 @@ const articleMaxWidthTableInPx = 512;
3229
3248
 
3230
3249
  var constants = /*#__PURE__*/Object.freeze({
3231
3250
  __proto__: null,
3251
+ articleMaxWidthInPx: articleMaxWidthInPx,
3252
+ articleMaxWidthTableInPx: articleMaxWidthTableInPx,
3232
3253
  baseFontFamily: baseFontFamily,
3254
+ baseUnitPx: baseUnitPx,
3233
3255
  boldFontFamily: boldFontFamily,
3234
- kaGreen: kaGreen,
3235
- white: white,
3236
- gray97: gray97,
3237
- gray85: gray85,
3238
- gray76: gray76,
3239
- gray68: gray68,
3256
+ checkedColor: checkedColor$1,
3257
+ circleSize: circleSize$1,
3240
3258
  gray17: gray17,
3241
- pureSmMin: pureSmMin$1,
3242
- pureMdMin: pureMdMin$1,
3259
+ gray68: gray68,
3260
+ gray76: gray76,
3261
+ gray85: gray85,
3262
+ gray97: gray97,
3263
+ hintBorderWidth: hintBorderWidth,
3264
+ interactiveSizes: interactiveSizes$1,
3265
+ kaGreen: kaGreen,
3266
+ negativePhoneMargin: negativePhoneMargin,
3267
+ phoneMargin: phoneMargin,
3268
+ publishBlockingErrorColor: publishBlockingErrorColor,
3269
+ pureLgMax: pureLgMax$1,
3243
3270
  pureLgMin: pureLgMin$1,
3271
+ pureMdMax: pureMdMax$1,
3272
+ pureMdMin: pureMdMin$1,
3273
+ pureSmMax: pureSmMax$1,
3274
+ pureSmMin: pureSmMin$1,
3244
3275
  pureXlMin: pureXlMin$1,
3245
3276
  pureXsMax: pureXsMax$1,
3246
- pureSmMax: pureSmMax$1,
3247
- pureMdMax: pureMdMax$1,
3248
- pureLgMax: pureLgMax$1,
3249
- tableBackgroundAccent: tableBackgroundAccent,
3250
- phoneMargin: phoneMargin,
3251
- negativePhoneMargin: negativePhoneMargin,
3252
- hintBorderWidth: hintBorderWidth,
3253
- baseUnitPx: baseUnitPx,
3254
- interactiveSizes: interactiveSizes$1,
3255
- circleSize: circleSize$1,
3277
+ radioBorderColor: radioBorderColor$1,
3256
3278
  radioMarginWidth: radioMarginWidth$1,
3279
+ tableBackgroundAccent: tableBackgroundAccent,
3257
3280
  warningColor: warningColor,
3258
- warningColorHover: warningColorHover,
3259
3281
  warningColorActive: warningColorActive,
3260
- publishBlockingErrorColor: publishBlockingErrorColor,
3261
- radioBorderColor: radioBorderColor$1,
3262
- checkedColor: checkedColor$1,
3263
- articleMaxWidthInPx: articleMaxWidthInPx,
3264
- articleMaxWidthTableInPx: articleMaxWidthTableInPx
3282
+ warningColorHover: warningColorHover,
3283
+ white: white
3265
3284
  });
3266
3285
 
3267
3286
  /**
@@ -3368,6 +3387,8 @@ class FixedToResponsive extends React.Component {
3368
3387
  style: style
3369
3388
  }, spacer, this.props.children);
3370
3389
  const shouldFullBleed = this.props.allowFullBleed && this.state.viewportWidth && width >= this.state.viewportWidth;
3390
+
3391
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
3371
3392
  if (shouldFullBleed) {
3372
3393
  return /*#__PURE__*/React.createElement("div", {
3373
3394
  style: {
@@ -3595,6 +3616,7 @@ const InteractiveUtil = {
3595
3616
  getPrefixedTransform: function () {
3596
3617
  // Cache result to avoid re-computation
3597
3618
  // @ts-expect-error - TS2322 - Type 'string | null | undefined' is not assignable to type 'null'.
3619
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
3598
3620
  prefixedTransform = prefixedTransform || computePrefixedTransform();
3599
3621
  return prefixedTransform;
3600
3622
  },
@@ -7979,24 +8001,42 @@ class GraphBounds {
7979
8001
  }
7980
8002
  }
7981
8003
 
7982
- var createRoot;
8004
+ var client = {};
7983
8005
 
7984
- var m = ReactDOM__default;
7985
- if (process.env.NODE_ENV === 'production') {
7986
- createRoot = m.createRoot;
7987
- m.hydrateRoot;
7988
- } else {
7989
- var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
7990
- createRoot = function(c, o) {
7991
- i.usingClientEntryPoint = true;
7992
- try {
7993
- return m.createRoot(c, o);
7994
- } finally {
7995
- i.usingClientEntryPoint = false;
7996
- }
7997
- };
8006
+ var hasRequiredClient;
8007
+
8008
+ function requireClient () {
8009
+ if (hasRequiredClient) return client;
8010
+ hasRequiredClient = 1;
8011
+
8012
+ var m = ReactDOM__default;
8013
+ if (process.env.NODE_ENV === 'production') {
8014
+ client.createRoot = m.createRoot;
8015
+ client.hydrateRoot = m.hydrateRoot;
8016
+ } else {
8017
+ var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
8018
+ client.createRoot = function(c, o) {
8019
+ i.usingClientEntryPoint = true;
8020
+ try {
8021
+ return m.createRoot(c, o);
8022
+ } finally {
8023
+ i.usingClientEntryPoint = false;
8024
+ }
8025
+ };
8026
+ client.hydrateRoot = function(c, h, o) {
8027
+ i.usingClientEntryPoint = true;
8028
+ try {
8029
+ return m.hydrateRoot(c, h, o);
8030
+ } finally {
8031
+ i.usingClientEntryPoint = false;
8032
+ }
8033
+ };
8034
+ }
8035
+ return client;
7998
8036
  }
7999
8037
 
8038
+ var clientExports = requireClient();
8039
+
8000
8040
  // We keep a cache of elements that have already had createRoot() called on
8001
8041
  // them. If we don't do this, React 18 warns every subsequent call:
8002
8042
  // > You are calling ReactDOMClient.createRoot() on a container that has
@@ -8026,7 +8066,7 @@ function render(element, container) {
8026
8066
  }, element);
8027
8067
  let root = reactRootCache.get(container);
8028
8068
  if (root == null) {
8029
- root = createRoot(container);
8069
+ root = clientExports.createRoot(container);
8030
8070
  reactRootCache.set(container, root);
8031
8071
  }
8032
8072
  root.render(children);
@@ -8105,7 +8145,7 @@ function polar$2(r, th) {
8105
8145
  }
8106
8146
  var _bounds = /*#__PURE__*/_classPrivateFieldLooseKey("bounds");
8107
8147
  var _drawingTransform = /*#__PURE__*/_classPrivateFieldLooseKey("drawingTransform");
8108
- class Graphie$1 {
8148
+ let Graphie$1 = class Graphie {
8109
8149
  constructor(el) {
8110
8150
  this.el = void 0;
8111
8151
  Object.defineProperty(this, _bounds, {
@@ -8301,6 +8341,7 @@ class Graphie$1 {
8301
8341
  }
8302
8342
  init(options) {
8303
8343
  var _options$isMobile;
8344
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8304
8345
  let scale = options.scale || [40, 40];
8305
8346
  scale = typeof scale === "number" ? [scale, scale] : scale;
8306
8347
 
@@ -8340,6 +8381,7 @@ class Graphie$1 {
8340
8381
  // - yLabelFormat: fn to format label string for y-axis
8341
8382
  // - xLabelFormat: fn to format label string for x-axis
8342
8383
  graphInit(options) {
8384
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8343
8385
  options = options || {};
8344
8386
  for (const [prop, val] of entries(options)) {
8345
8387
  // allow options to be specified by a single number for shorthand if
@@ -8355,22 +8397,28 @@ class Graphie$1 {
8355
8397
  }
8356
8398
  const range = normalizeRange(options.range || [[-10, 10], [-10, 10]]);
8357
8399
  const gridRange = normalizeRange(options.gridRange || range);
8400
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8358
8401
  const scale = options.scale || [20, 20];
8359
8402
  const grid = options.grid != null ? options.grid : true;
8360
8403
  const gridOpacity = options.gridOpacity || 0.1;
8404
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8361
8405
  const gridStep = toPair(options.gridStep || [1, 1]);
8362
8406
  const axes = options.axes != null ? options.axes : true;
8407
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8363
8408
  const axisArrows = options.axisArrows || "";
8364
8409
  const axisOpacity = options.axisOpacity || 1.0;
8365
8410
  const axisCenter = options.axisCenter || [Math.min(Math.max(range[0][0], 0), range[0][1]), Math.min(Math.max(range[1][0], 0), range[1][1])];
8366
8411
  const axisLabels = options.axisLabels != null ? options.axisLabels : false;
8367
8412
  const ticks = options.ticks != null ? options.ticks : true;
8413
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8368
8414
  const tickStep = options.tickStep || [2, 2];
8415
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8369
8416
  const tickLen = options.tickLen || [5, 5];
8370
8417
  const tickOpacity = options.tickOpacity || 1.0;
8371
8418
  const labels = options.labels || options.labelStep || false;
8372
8419
  const labelStep = options.labelStep || [1, 1];
8373
8420
  const labelOpacity = options.labelOpacity || 1.0;
8421
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8374
8422
  let unityLabels = options.unityLabels || false;
8375
8423
  const labelFormat = options.labelFormat || function (a) {
8376
8424
  return a;
@@ -8439,6 +8487,8 @@ class Graphie$1 {
8439
8487
  thisGraphie.path([[axisCenter[0], gridRange[1][0]], [axisCenter[0], gridRange[1][1]]]);
8440
8488
  });
8441
8489
  }
8490
+
8491
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8442
8492
  if (axisLabels && axisLabels.length === 2) {
8443
8493
  this.label([gridRange[0][1], axisCenter[1]], axisLabels[0], "right");
8444
8494
  this.label([axisCenter[0], gridRange[1][1]], axisLabels[1], "above");
@@ -8461,11 +8511,13 @@ class Graphie$1 {
8461
8511
  let stop = gridRange[0][1];
8462
8512
  if (range[1][0] < 0 && range[1][1] > 0) {
8463
8513
  for (let x = step + axisCenter[0]; x <= stop; x += step) {
8514
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8464
8515
  if (x < stop || !axisArrows) {
8465
8516
  thisGraphie.line([x, -len + axisCenter[1]], [x, halfWidthTicks ? 0 : len + axisCenter[1]]);
8466
8517
  }
8467
8518
  }
8468
8519
  for (let x = -step + axisCenter[0]; x >= start; x -= step) {
8520
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8469
8521
  if (x > start || !axisArrows) {
8470
8522
  thisGraphie.line([x, -len + axisCenter[1]], [x, halfWidthTicks ? 0 : len + axisCenter[1]]);
8471
8523
  }
@@ -8479,11 +8531,13 @@ class Graphie$1 {
8479
8531
  stop = gridRange[1][1];
8480
8532
  if (range[0][0] < 0 && range[0][1] > 0) {
8481
8533
  for (let y = step + axisCenter[1]; y <= stop; y += step) {
8534
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8482
8535
  if (y < stop || !axisArrows) {
8483
8536
  this.line([-len + axisCenter[0], y], [halfWidthTicks ? 0 : len + axisCenter[0], y]);
8484
8537
  }
8485
8538
  }
8486
8539
  for (let y = -step + axisCenter[1]; y >= start; y -= step) {
8540
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8487
8541
  if (y > start || !axisArrows) {
8488
8542
  this.line([-len + axisCenter[0], y], [halfWidthTicks ? 0 : len + axisCenter[0], y]);
8489
8543
  }
@@ -8493,6 +8547,7 @@ class Graphie$1 {
8493
8547
  }
8494
8548
 
8495
8549
  // draw axis labels
8550
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8496
8551
  if (labels) {
8497
8552
  const thisGraphie = this;
8498
8553
  this.style({
@@ -8513,6 +8568,7 @@ class Graphie$1 {
8513
8568
 
8514
8569
  // positive x-axis
8515
8570
  for (let x = (xShowZero ? 0 : step) + axisCenter[0]; x <= stop; x += step) {
8571
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8516
8572
  if (x < stop || !axisArrows) {
8517
8573
  thisGraphie.label([x, axisCenter[1]], xLabelFormat(x), xAxisPosition);
8518
8574
  }
@@ -8520,6 +8576,7 @@ class Graphie$1 {
8520
8576
 
8521
8577
  // negative x-axis
8522
8578
  for (let x = -step * (showUnityX ? 1 : 2) + axisCenter[0]; x >= start; x -= step) {
8579
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8523
8580
  if (x > start || !axisArrows) {
8524
8581
  thisGraphie.label([x, axisCenter[1]], xLabelFormat(x), xAxisPosition);
8525
8582
  }
@@ -8530,6 +8587,7 @@ class Graphie$1 {
8530
8587
 
8531
8588
  // positive y-axis
8532
8589
  for (let y = (yShowZero ? 0 : step) + axisCenter[1]; y <= stop; y += step) {
8590
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8533
8591
  if (y < stop || !axisArrows) {
8534
8592
  thisGraphie.label([axisCenter[0], y], yLabelFormat(y), yAxisPosition);
8535
8593
  }
@@ -8537,6 +8595,7 @@ class Graphie$1 {
8537
8595
 
8538
8596
  // negative y-axis
8539
8597
  for (let y = -step * (showUnityY ? 1 : 2) + axisCenter[1]; y >= start; y -= step) {
8598
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8540
8599
  if (y > start || !axisArrows) {
8541
8600
  thisGraphie.label([axisCenter[0], y], yLabelFormat(y), yAxisPosition);
8542
8601
  }
@@ -8675,6 +8734,7 @@ class Graphie$1 {
8675
8734
  fixedPath(points, center, createPath) {
8676
8735
  points = points.map(this.scalePoint);
8677
8736
  center = center ? this.scalePoint(center) : null;
8737
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8678
8738
  createPath = createPath || this.svgPath;
8679
8739
 
8680
8740
  // Compute bounding box
@@ -8805,7 +8865,7 @@ class Graphie$1 {
8805
8865
  // write these functions the way we do to handle undefined.
8806
8866
  const clip = xy => {
8807
8867
  if (Math.abs(xy[1]) > 500000) {
8808
- return [xy[0], Math.min(Math.max(xy[1], -500000), 500000)];
8868
+ return [xy[0], Math.min(Math.max(xy[1], -5e5), 500000)];
8809
8869
  }
8810
8870
  return xy;
8811
8871
  };
@@ -9085,17 +9145,17 @@ class Graphie$1 {
9085
9145
  getMouseCoord(event) {
9086
9146
  return this.unscalePoint(this.getMousePx(event));
9087
9147
  }
9088
- }
9148
+ };
9089
9149
  const labelDirections = {
9090
9150
  center: [-0.5, -0.5],
9091
- above: [-0.5, -1.0],
9092
- "above right": [0.0, -1.0],
9151
+ above: [-0.5, -1],
9152
+ "above right": [0.0, -1],
9093
9153
  right: [0.0, -0.5],
9094
9154
  "below right": [0.0, 0.0],
9095
9155
  below: [-0.5, 0.0],
9096
- "below left": [-1.0, 0.0],
9097
- left: [-1.0, -0.5],
9098
- "above left": [-1.0, -1.0]
9156
+ "below left": [-1, 0.0],
9157
+ left: [-1, -0.5],
9158
+ "above left": [-1, -1]
9099
9159
  };
9100
9160
 
9101
9161
  // A range for a Graphie can be specified in one of three forms:
@@ -9272,6 +9332,7 @@ const GraphUtils = {
9272
9332
  if (vertex === undefined) {
9273
9333
  const x = point1[0] - point2[0];
9274
9334
  const y = point1[1] - point2[1];
9335
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
9275
9336
  if (!x && !y) {
9276
9337
  return 0;
9277
9338
  }
@@ -9283,6 +9344,13 @@ const GraphUtils = {
9283
9344
  };
9284
9345
 
9285
9346
  /* eslint-disable */
9347
+ /*
9348
+ * jQuery Mobile Framework : "mouse" plugin
9349
+ * Copyright (c) jQuery Project
9350
+ * Dual licensed under the MIT or GPL Version 2 licenses.
9351
+ * http://jquery.org/license
9352
+ */
9353
+
9286
9354
  (function ($, window, document, undefined$1) {
9287
9355
  if (typeof $ === "undefined") {
9288
9356
  return;
@@ -9730,6 +9798,7 @@ const getClipPoint = function getClipPoint(graph, coord, angle) {
9730
9798
  * Default methods for a wrapped movable.
9731
9799
  */
9732
9800
 
9801
+
9733
9802
  /*
9734
9803
  * attr() and animate() simply pass the
9735
9804
  * arguments to the underlying Raphael object.
@@ -9820,14 +9889,14 @@ class WrappedPath extends WrappedDrawing {
9820
9889
  }
9821
9890
  }
9822
9891
 
9823
- class Arrowhead$1 extends WrappedPath {
9892
+ let Arrowhead$1 = class Arrowhead extends WrappedPath {
9824
9893
  constructor(graphie, style) {
9825
9894
  // Points that define the arrowhead
9826
9895
  const center = [0.75, 0];
9827
9896
  const points = [[-3, 4], [-2.75, 2.5], [0, 0.25], center, [0, -0.25], [-2.75, -2.5], [-3, -4]].map(point => {
9828
9897
  // Scale points by `Arrowhead.scale` around `center`
9829
9898
  const pv = vector$3.subtract(point, center);
9830
- const pvScaled = vector$3.scale(pv, Arrowhead$1.scale);
9899
+ const pvScaled = vector$3.scale(pv, Arrowhead.scale);
9831
9900
  return vector$3.add(center, pvScaled);
9832
9901
  });
9833
9902
  const unscaledPoints = points.map(graphie.unscalePoint);
@@ -9845,9 +9914,9 @@ class Arrowhead$1 extends WrappedPath {
9845
9914
  }
9846
9915
  toCoordAtAngle(coord, angle) {
9847
9916
  const clipPoint = this.graphie.scalePoint(getClipPoint(this.graphie, coord, angle));
9848
- this.transform("translateX(" + (clipPoint[0] + Arrowhead$1.scale * this.center[0]) + "px) " + "translateY(" + (clipPoint[1] + Arrowhead$1.scale * this.center[1]) + "px) " + "translateZ(0) " + "rotate(" + (360 - KhanMath.bound(angle)) + "deg)");
9917
+ this.transform("translateX(" + (clipPoint[0] + Arrowhead.scale * this.center[0]) + "px) " + "translateY(" + (clipPoint[1] + Arrowhead.scale * this.center[1]) + "px) " + "translateZ(0) " + "rotate(" + (360 - KhanMath.bound(angle)) + "deg)");
9849
9918
  }
9850
- }
9919
+ };
9851
9920
 
9852
9921
  // We can't just pass in a path to `graph.fixedPath` as we need to modify
9853
9922
  // the points in some way, so instead we provide a function for creating
@@ -9982,6 +10051,13 @@ class WrappedLine extends WrappedDrawing {
9982
10051
  }
9983
10052
 
9984
10053
  /* eslint-disable @babel/no-invalid-this */
10054
+ /**
10055
+ * Interactive graphie utilities.
10056
+ *
10057
+ * This file exposes a couple functions, but mostly it adds functions to the
10058
+ * `Graphie` prototype for dealing with interactive graphie elements.
10059
+ */
10060
+
9985
10061
  const {
9986
10062
  clockwise: clockwise$2,
9987
10063
  reverseVector: reverseVector$1
@@ -11658,7 +11734,7 @@ _.extend(GraphUtils.Graphie.prototype, {
11658
11734
  // and maximum angle values bounding a circle sector, and
11659
11735
  // the third column refers to the cursor name that will be
11660
11736
  // applied if the mouse position falls inside the given sector.
11661
- const cursorAxes = [[Math.PI * -1.0, Math.PI * -0.875, "ew-resize"], [Math.PI * -0.875, Math.PI * -0.625, "nesw-resize"], [Math.PI * -0.625, Math.PI * -0.375, "ns-resize"], [Math.PI * -0.375, Math.PI * -0.125, "nwse-resize"], [Math.PI * -0.125, Math.PI * 0.125, "ew-resize"], [Math.PI * 0.125, Math.PI * 0.375, "nesw-resize"], [Math.PI * 0.375, Math.PI * 0.625, "ns-resize"], [Math.PI * 0.625, Math.PI * 0.875, "nwse-resize"], [Math.PI * 0.875, Math.PI * 1.0, "ew-resize"]];
11737
+ const cursorAxes = [[Math.PI * -1, Math.PI * -0.875, "ew-resize"], [Math.PI * -0.875, Math.PI * -0.625, "nesw-resize"], [Math.PI * -0.625, Math.PI * -0.375, "ns-resize"], [Math.PI * -0.375, Math.PI * -0.125, "nwse-resize"], [Math.PI * -0.125, Math.PI * 0.125, "ew-resize"], [Math.PI * 0.125, Math.PI * 0.375, "nesw-resize"], [Math.PI * 0.375, Math.PI * 0.625, "ns-resize"], [Math.PI * 0.625, Math.PI * 0.875, "nwse-resize"], [Math.PI * 0.875, Math.PI * 1.0, "ew-resize"]];
11662
11738
 
11663
11739
  // When the mouse moves along the circle's perimeter, we
11664
11740
  // dynamically set a CSS rule to show the correct
@@ -11959,6 +12035,7 @@ _.extend(GraphUtils.Graphie.prototype, {
11959
12035
  return isHovering;
11960
12036
  };
11961
12037
  const styles = _.map([0, 1], function (isHighlight) {
12038
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
11962
12039
  const baseStyle = isHighlight ? options.highlightStyle : options.normalStyle;
11963
12040
  return _.map([0, 1], function (opacity) {
11964
12041
  return _.defaults({
@@ -11968,6 +12045,7 @@ _.extend(GraphUtils.Graphie.prototype, {
11968
12045
  });
11969
12046
  const getStyle = function getStyle(isRight) {
11970
12047
  if (isFlipped) {
12048
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
11971
12049
  isRight = !isRight;
11972
12050
  }
11973
12051
  return styles[+isHighlight()][+isRight];
@@ -12316,7 +12394,7 @@ function Ruler(graphie, options) {
12316
12394
  });
12317
12395
  const width = options.units * options.pixelsPerUnit;
12318
12396
  const height = 50;
12319
- const leftBottom = graphie.unscalePoint(vector$3.subtract(graphie.scalePoint(options.center), vector$3.scale([width, -height], 0.5)));
12397
+ const leftBottom = graphie.unscalePoint(vector$3.subtract(graphie.scalePoint(options.center), vector$3.scale([width, -50], 0.5)));
12320
12398
  const graphieUnitsPerUnit = options.pixelsPerUnit / graphie.scale[0];
12321
12399
  const graphieUnitsHeight = height / graphie.scale[0];
12322
12400
  const rightTop = vector$3.add(leftBottom, [options.units * graphieUnitsPerUnit, graphieUnitsHeight]);
@@ -12831,6 +12909,7 @@ _.extend(MovableAngle.prototype, {
12831
12909
  });
12832
12910
 
12833
12911
  /* eslint-disable @babel/no-invalid-this */
12912
+
12834
12913
  const nestedMap$1 = Util.nestedMap;
12835
12914
 
12836
12915
  /**
@@ -13016,6 +13095,7 @@ class Movable {
13016
13095
  // the invisible shape in front of the point that gets mouse events
13017
13096
  if (state.mouseTarget && !prevState.mouseTarget) {
13018
13097
  let $mouseTarget;
13098
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
13019
13099
  if (state.mouseTarget.getMouseTarget) {
13020
13100
  $mouseTarget = $(state.mouseTarget.getMouseTarget());
13021
13101
  } else {
@@ -13063,6 +13143,7 @@ class Movable {
13063
13143
  }
13064
13144
  if (state.mouseTarget && state.cursor !== undefined) {
13065
13145
  let $mouseTarget;
13146
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
13066
13147
  if (state.mouseTarget.getMouseTarget) {
13067
13148
  $mouseTarget = $(state.mouseTarget.getMouseTarget());
13068
13149
  } else {
@@ -13070,6 +13151,7 @@ class Movable {
13070
13151
  }
13071
13152
 
13072
13153
  // "" removes the css cursor if state.cursor is null
13154
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
13073
13155
  $mouseTarget.css("cursor", state.cursor || "");
13074
13156
  }
13075
13157
 
@@ -13214,12 +13296,15 @@ class Movable {
13214
13296
  * (state, prevState)]
13215
13297
  */
13216
13298
  listen(eventName, id, func) {
13299
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
13217
13300
  this._listenerMap = this._listenerMap || {};
13218
13301
 
13219
13302
  // If there's an existing handler, replace it by using its index in
13220
13303
  // `this.state[eventName]`; otherwise, add this handler to the end
13221
13304
  const key = getKey$1(eventName, id);
13222
- const index = this._listenerMap[key] = this._listenerMap[key] || this.state[eventName].length;
13305
+ const index = this._listenerMap[key] =
13306
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
13307
+ this._listenerMap[key] || this.state[eventName].length;
13223
13308
  this.state[eventName][index] = func;
13224
13309
  }
13225
13310
 
@@ -13230,6 +13315,7 @@ class Movable {
13230
13315
  * If the given id has not been registered already, this is a no-op
13231
13316
  */
13232
13317
  unlisten(eventName, id) {
13318
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
13233
13319
  this._listenerMap = this._listenerMap || {};
13234
13320
  const key = getKey$1(eventName, id);
13235
13321
  const index = this._listenerMap[key];
@@ -13283,6 +13369,9 @@ function getEventName$1(key) {
13283
13369
  }
13284
13370
 
13285
13371
  /* eslint-disable @babel/no-invalid-this */
13372
+ /**
13373
+ * A library of options to pass to add/draw/remove/constraints
13374
+ */
13286
13375
  /**
13287
13376
  * Helper functions
13288
13377
  */
@@ -13853,6 +13942,9 @@ const iconMinus = {
13853
13942
  };
13854
13943
 
13855
13944
  /* eslint-disable @babel/no-invalid-this */
13945
+ /**
13946
+ * A library of options to pass to add/draw/remove/constraints
13947
+ */
13856
13948
  const add$1 = {
13857
13949
  constrain: function () {
13858
13950
  this.constrain();
@@ -13994,10 +14086,14 @@ const constraints$1 = {
13994
14086
  let upper = graphie.unscalePoint([
13995
14087
  // @ts-expect-error - 'graphie.ypixels' is possibly 'undefined'.
13996
14088
  graphie.xpixels - paddingPx, paddingPx]);
14089
+
14090
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
13997
14091
  if (snap) {
13998
14092
  lower = point.ceilTo(lower, snap);
13999
14093
  upper = point.floorTo(upper, snap);
14000
14094
  }
14095
+
14096
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
14001
14097
  if (!!options && !!options.onOutOfBounds) {
14002
14098
  if (coord[0] > upper[0] || coord[0] < lower[0] || coord[1] > upper[1] || coord[1] < lower[1]) {
14003
14099
  options.onSkipRemaining();
@@ -14069,7 +14165,7 @@ const DEFAULT_STATE$1 = {
14069
14165
  // TODO(benchristel): this is a memory leak. We add items to
14070
14166
  // tooltipResetFunctions, but never remove them.
14071
14167
  const tooltipResetFunctions = [];
14072
- class MovablePoint$5 {
14168
+ let MovablePoint$5 = class MovablePoint {
14073
14169
  constructor(graphie, movable, options) {
14074
14170
  this.graphie = void 0;
14075
14171
  this.movable = void 0;
@@ -14438,12 +14534,15 @@ class MovablePoint$5 {
14438
14534
  */
14439
14535
  // TODO(benchristel): listen() is duplicated in movable.ts
14440
14536
  listen(eventName, id, func) {
14537
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
14441
14538
  this._listenerMap = this._listenerMap || {};
14442
14539
 
14443
14540
  // If there's an existing handler, replace it by using its index in
14444
14541
  // `this.state[eventName]`; otherwise, add this handler to the end
14445
14542
  const key = getKey(eventName, id);
14446
- const index = this._listenerMap[key] = this._listenerMap[key] || this.state[eventName].length;
14543
+ const index = this._listenerMap[key] =
14544
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
14545
+ this._listenerMap[key] || this.state[eventName].length;
14447
14546
  this.state[eventName][index] = func;
14448
14547
  }
14449
14548
 
@@ -14456,6 +14555,7 @@ class MovablePoint$5 {
14456
14555
  // TODO(benchristel): I don't think unlisten is used. Delete it?
14457
14556
  // TODO(benchristel): unlisten is duplicated in movable.ts
14458
14557
  unlisten(eventName, id) {
14558
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
14459
14559
  this._listenerMap = this._listenerMap || {};
14460
14560
  const key = getKey(eventName, id);
14461
14561
  const index = this._listenerMap[key];
@@ -14514,6 +14614,7 @@ class MovablePoint$5 {
14514
14614
  remove() {
14515
14615
  this.state.added = false;
14516
14616
  this._fireEvent(this.state.remove);
14617
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
14517
14618
  if (this.movable) {
14518
14619
  this.movable.remove();
14519
14620
  }
@@ -14574,6 +14675,7 @@ class MovablePoint$5 {
14574
14675
  // Change z-order to back
14575
14676
  toBack() {
14576
14677
  this.movable.toBack();
14678
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
14577
14679
  if (this.state.visibleShape) {
14578
14680
  this.state.visibleShape.toBack();
14579
14681
  }
@@ -14581,12 +14683,13 @@ class MovablePoint$5 {
14581
14683
 
14582
14684
  // Change z-order to front
14583
14685
  toFront() {
14686
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
14584
14687
  if (this.state.visibleShape) {
14585
14688
  this.state.visibleShape.toFront();
14586
14689
  }
14587
14690
  this.movable.toFront();
14588
14691
  }
14589
- }
14692
+ };
14590
14693
  MovablePoint$5.add = MovablePointOptions.add;
14591
14694
  MovablePoint$5.modify = MovablePointOptions.modify;
14592
14695
  MovablePoint$5.draw = MovablePointOptions.draw;
@@ -14604,6 +14707,10 @@ function getEventName(key) {
14604
14707
  }
14605
14708
 
14606
14709
  /* eslint-disable @babel/no-invalid-this */
14710
+ /**
14711
+ * A library of options to pass to add/draw/remove/constraints
14712
+ */
14713
+
14607
14714
  function sum(array) {
14608
14715
  return _.reduce(array, function (memo, arg) {
14609
14716
  return memo + arg;
@@ -15632,6 +15739,7 @@ class Graphie extends React.Component {
15632
15739
  // corresponding with those descriptors.
15633
15740
  renderChildren(child);
15634
15741
  const prevMovable = oldMovables[key];
15742
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
15635
15743
  if (!prevMovable) {
15636
15744
  // We're creating a new child
15637
15745
  child.add(graphie);
@@ -15866,6 +15974,7 @@ class ImageLoader extends React.Component {
15866
15974
  case Status.LOADED:
15867
15975
  return this.renderImg();
15868
15976
  case Status.FAILED:
15977
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
15869
15978
  if (this.props.children) {
15870
15979
  return this.props.children;
15871
15980
  }
@@ -16083,6 +16192,7 @@ class SvgImage extends React.Component {
16083
16192
  }
16084
16193
  loadResources() {
16085
16194
  loadGraphie(this.props.src, (data, localized) => {
16195
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
16086
16196
  if (this._isMounted && data.labels && data.range) {
16087
16197
  const labelsRendered = {};
16088
16198
  data.labels.forEach(label => {
@@ -16112,6 +16222,7 @@ class SvgImage extends React.Component {
16112
16222
  return null;
16113
16223
  }
16114
16224
  // parseFloat() ignores trailing non-numerical characters.
16225
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
16115
16226
  return parseFloat(value) || null;
16116
16227
  }
16117
16228
  render() {
@@ -16147,6 +16258,7 @@ class SvgImage extends React.Component {
16147
16258
  // is tricky because web+graphie doesn't support labels on non-graphie
16148
16259
  // images.
16149
16260
  let extraGraphie;
16261
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
16150
16262
  if (this.props.extraGraphie && this.props.extraGraphie.labels.length) {
16151
16263
  extraGraphie = /*#__PURE__*/React.createElement(Graphie, {
16152
16264
  box: this.props.extraGraphie.box,
@@ -16163,12 +16275,15 @@ class SvgImage extends React.Component {
16163
16275
  // If preloader is undefined, we use the default. If it's
16164
16276
  // null, there will be no preloader in use.
16165
16277
  const preloaderBaseFunc = this.props.preloader === undefined ? defaultPreloader : this.props.preloader;
16278
+
16279
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
16166
16280
  const preloader = preloaderBaseFunc ? () => preloaderBaseFunc(dimensions) : null;
16167
16281
 
16168
16282
  // Just use a normal image if a normal image is provided
16169
16283
  if (!Util.isLabeledSVG(imageSrc)) {
16170
16284
  if (responsive) {
16171
16285
  const wrapperClasses = classNames$1({
16286
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
16172
16287
  zoomable: (width || 0) > ZOOMABLE_THRESHOLD,
16173
16288
  "svg-image": true
16174
16289
  });
@@ -16372,6 +16487,7 @@ class Zoomable extends React.Component {
16372
16487
  }
16373
16488
  componentWillUnmount() {
16374
16489
  window.removeEventListener("resize", this.reset);
16490
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
16375
16491
  if (this._observer) {
16376
16492
  this._observer.disconnect();
16377
16493
  }
@@ -16396,6 +16512,8 @@ class Zoomable extends React.Component {
16396
16512
  // TODO(jeff, CP-3128): Use Wonder Blocks Timing API
16397
16513
  // eslint-disable-next-line no-restricted-syntax
16398
16514
  setTimeout(() => this.measureAndScaleChildToFit(false), 0);
16515
+
16516
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
16399
16517
  if (window.MutationObserver) {
16400
16518
  this._observer = new MutationObserver(mutations => {
16401
16519
  if (this._isMounted) {
@@ -16553,6 +16671,7 @@ Zoomable.defaultProps = {
16553
16671
  * TeX we run into issues of measuring at the incorrect time resulting in bad
16554
16672
  * measurements.
16555
16673
  */
16674
+
16556
16675
  const computeMathBounds = (parentNode, parentBounds) => {
16557
16676
  const textElement = parentNode.querySelector(".MathJax");
16558
16677
  const textBounds = {
@@ -16602,6 +16721,7 @@ class ZoomableTeX extends React.Component {
16602
16721
  /**
16603
16722
  * A React context for ensuring there is one and only one definition showing at a time
16604
16723
  */
16724
+
16605
16725
  const defaultContext$1 = {
16606
16726
  activeDefinitionId: null,
16607
16727
  setActiveDefinitionId: () => {}
@@ -16746,6 +16866,7 @@ class InteractionTracker {
16746
16866
  /**
16747
16867
  * Paragraph parsing/splitting for article jipt i18n
16748
16868
  */
16869
+
16749
16870
  const arrayRules = {
16750
16871
  fence: {
16751
16872
  match: SimpleMarkdown.defaultRules.fence.match,
@@ -17448,6 +17569,8 @@ const getContent = ast => {
17448
17569
  // arbitrarily nested lists that are direct properties.
17449
17570
  // 2) Only AST nodes have a 'type' property.
17450
17571
  const children = _.chain(ast).values().flatten().filter(object => object != null && _.has(object, "type")).value();
17572
+
17573
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17451
17574
  if (!children.length) {
17452
17575
  return [];
17453
17576
  }
@@ -17584,6 +17707,7 @@ class TranslationLinter {
17584
17707
  applyLintErrors(parsedMarkdown, translationLintErrors) {
17585
17708
  // These lint errors do not have position data associated with
17586
17709
  // them, so we just plop them at the top.
17710
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17587
17711
  if (translationLintErrors.length) {
17588
17712
  const errorText = translationLintErrors.join("\n\n");
17589
17713
  parsedMarkdown.unshift({
@@ -17634,6 +17758,7 @@ const containerSizeClass = {
17634
17758
  XLARGE: "xlarge"
17635
17759
  };
17636
17760
  const getClassFromWidth = width => {
17761
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17637
17762
  if (!width) {
17638
17763
  return containerSizeClass.MEDIUM;
17639
17764
  }
@@ -17684,6 +17809,7 @@ const replaceWidget = (name, replacementName) => {
17684
17809
  // If the replacement widget isn't found, we need to throw. Otherwise after
17685
17810
  // removing the deprecated widget, we'll have data asking for a widget type
17686
17811
  // that doesn't exist at all.
17812
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17687
17813
  if (!substituteWidget) {
17688
17814
  const errorMsg = `Failed to replace ${name} with ${replacementName}`;
17689
17815
  throw new PerseusError(errorMsg, Errors.Internal);
@@ -17717,6 +17843,8 @@ const registerEditors = editorsToRegister => {
17717
17843
  */
17718
17844
  const replaceEditor = (name, replacementName) => {
17719
17845
  const substituteEditor = editors[replacementName];
17846
+
17847
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17720
17848
  if (!substituteEditor && Log) {
17721
17849
  const errorMsg = `Failed to replace editor ${name} with ${replacementName}`;
17722
17850
  Log.error(errorMsg, Errors.Internal);
@@ -17759,6 +17887,7 @@ const getTransform = name => {
17759
17887
  };
17760
17888
  const getVersion = name => {
17761
17889
  const widgetInfo = widgets[name];
17890
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17762
17891
  if (widgetInfo) {
17763
17892
  return widgets[name].version || {
17764
17893
  major: 0,
@@ -17820,11 +17949,15 @@ const traverseChildWidgets$3 = (widgetInfo, traverseRenderer) => {
17820
17949
  if (!traverseRenderer) {
17821
17950
  throw new PerseusError("traverseRenderer must be provided, but was not", Errors.Internal);
17822
17951
  }
17952
+
17953
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17823
17954
  if (!widgetInfo || !widgetInfo.type || !widgets[widgetInfo.type]) {
17824
17955
  return widgetInfo;
17825
17956
  }
17826
17957
  const widgetExports = widgets[widgetInfo.type];
17827
17958
  const props = widgetInfo.options;
17959
+
17960
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17828
17961
  if (widgetExports.traverseChildWidgets && props) {
17829
17962
  const newProps = widgetExports.traverseChildWidgets(props, traverseRenderer);
17830
17963
  return _.extend({}, widgetInfo, {
@@ -17845,6 +17978,7 @@ const traverseChildWidgets$3 = (widgetInfo, traverseRenderer) => {
17845
17978
  */
17846
17979
  const supportsStaticMode = type => {
17847
17980
  const widgetInfo = widgets[type];
17981
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17848
17982
  return widgetInfo && widgetInfo.staticTransform != null;
17849
17983
  };
17850
17984
 
@@ -17854,6 +17988,7 @@ const supportsStaticMode = type => {
17854
17988
  */
17855
17989
  const getStaticTransform = type => {
17856
17990
  const widgetInfo = widgets[type];
17991
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17857
17992
  return widgetInfo && widgetInfo.staticTransform;
17858
17993
  };
17859
17994
 
@@ -17864,6 +17999,7 @@ const getStaticTransform = type => {
17864
17999
  */
17865
18000
  const getTracking = type => {
17866
18001
  const widgetExport = widgets[type];
18002
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17867
18003
  return widgetExport && widgetExport.tracking || DEFAULT_TRACKING;
17868
18004
  };
17869
18005
 
@@ -17873,33 +18009,34 @@ const getTracking = type => {
17873
18009
  */
17874
18010
  const isLintable = type => {
17875
18011
  const widgetExports = widgets[type];
18012
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
17876
18013
  return widgetExports && widgetExports.isLintable || DEFAULT_LINTABLE;
17877
18014
  };
17878
18015
 
17879
18016
  var widgets$1 = /*#__PURE__*/Object.freeze({
17880
18017
  __proto__: null,
17881
- registerWidget: registerWidget,
17882
- registerWidgets: registerWidgets,
17883
- replaceWidget: replaceWidget,
17884
- replaceDeprecatedWidgets: replaceDeprecatedWidgets,
17885
- registerEditors: registerEditors,
17886
- replaceEditor: replaceEditor,
17887
- replaceDeprecatedEditors: replaceDeprecatedEditors,
17888
- getWidget: getWidget,
17889
- getWidgetExport: getWidgetExport,
18018
+ getAllWidgetTypes: getAllWidgetTypes,
17890
18019
  getEditor: getEditor,
18020
+ getPublicWidgets: getPublicWidgets,
18021
+ getRendererPropsForWidgetInfo: getRendererPropsForWidgetInfo,
18022
+ getStaticTransform: getStaticTransform,
18023
+ getTracking: getTracking,
17891
18024
  getTransform: getTransform,
17892
18025
  getVersion: getVersion,
17893
18026
  getVersionVector: getVersionVector,
17894
- getPublicWidgets: getPublicWidgets,
18027
+ getWidget: getWidget,
18028
+ getWidgetExport: getWidgetExport,
17895
18029
  isAccessible: isAccessible,
17896
- getAllWidgetTypes: getAllWidgetTypes,
17897
- getRendererPropsForWidgetInfo: getRendererPropsForWidgetInfo,
17898
- traverseChildWidgets: traverseChildWidgets$3,
18030
+ isLintable: isLintable,
18031
+ registerEditors: registerEditors,
18032
+ registerWidget: registerWidget,
18033
+ registerWidgets: registerWidgets,
18034
+ replaceDeprecatedEditors: replaceDeprecatedEditors,
18035
+ replaceDeprecatedWidgets: replaceDeprecatedWidgets,
18036
+ replaceEditor: replaceEditor,
18037
+ replaceWidget: replaceWidget,
17899
18038
  supportsStaticMode: supportsStaticMode,
17900
- getStaticTransform: getStaticTransform,
17901
- getTracking: getTracking,
17902
- isLintable: isLintable
18039
+ traverseChildWidgets: traverseChildWidgets$3
17903
18040
  });
17904
18041
 
17905
18042
  class WidgetContainer extends React.Component {
@@ -18549,6 +18686,8 @@ class Renderer extends React.Component {
18549
18686
  const imagePlaceholder = apiOptions.imagePlaceholder;
18550
18687
  if (node.type === "widget") {
18551
18688
  const widgetPlaceholder = apiOptions.widgetPlaceholder;
18689
+
18690
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
18552
18691
  if (widgetPlaceholder) {
18553
18692
  return widgetPlaceholder;
18554
18693
  }
@@ -18607,8 +18746,8 @@ class Renderer extends React.Component {
18607
18746
  // TODO(kevinb) automatically determine the margin size
18608
18747
  const margin = 16;
18609
18748
  const outerStyle = {
18610
- marginLeft: -margin,
18611
- marginRight: -margin
18749
+ marginLeft: -16,
18750
+ marginRight: -16
18612
18751
  };
18613
18752
  const horizontalPadding = {
18614
18753
  paddingLeft: margin,
@@ -18656,6 +18795,7 @@ class Renderer extends React.Component {
18656
18795
  }, tex)), /*#__PURE__*/React.createElement("span", null)));
18657
18796
  }
18658
18797
  if (node.type === "image") {
18798
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
18659
18799
  if (imagePlaceholder) {
18660
18800
  return imagePlaceholder;
18661
18801
  }
@@ -18709,6 +18849,7 @@ class Renderer extends React.Component {
18709
18849
  // Used by the translator portal to replace image URLs with
18710
18850
  // placeholders, see preprocessWidgets in manticore-utils.js
18711
18851
  // for more details.
18852
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
18712
18853
  if (imagePlaceholder && rImageURL.test(node.content)) {
18713
18854
  return imagePlaceholder;
18714
18855
  }
@@ -18722,10 +18863,9 @@ class Renderer extends React.Component {
18722
18863
  if (!apiOptions.isMobile) {
18723
18864
  return output;
18724
18865
  }
18725
- const margin = 16;
18726
18866
  const outerStyle = {
18727
- marginLeft: -margin,
18728
- marginRight: -margin
18867
+ marginLeft: -16,
18868
+ marginRight: -16
18729
18869
  };
18730
18870
  const innerStyle = {
18731
18871
  paddingLeft: 0,
@@ -18802,6 +18942,7 @@ class Renderer extends React.Component {
18802
18942
  const widgetId = this.widgetIds[i];
18803
18943
  const widget = this.getWidgetInstance(widgetId);
18804
18944
  const widgetFocusResult = widget == null || widget.focus == null ? void 0 : widget.focus();
18945
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
18805
18946
  if (widgetFocusResult) {
18806
18947
  id = widgetId;
18807
18948
  focusResult = widgetFocusResult;
@@ -18954,6 +19095,7 @@ class Renderer extends React.Component {
18954
19095
  // TODO(jeff, CP-3128): Use Wonder Blocks Timing API
18955
19096
  // eslint-disable-next-line no-restricted-syntax
18956
19097
  setTimeout(() => {
19098
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
18957
19099
  const cbResult = cb && cb();
18958
19100
  if (!silent) {
18959
19101
  this.props.onInteractWithWidget(id);
@@ -19145,10 +19287,13 @@ class Renderer extends React.Component {
19145
19287
  // mode (which is really just part of its widget info).
19146
19288
  const widgetInfo = this.state.widgetInfo[widgetId];
19147
19289
  const reviewModeRubric = this.props.reviewMode && widgetInfo ? widgetInfo.options : null;
19290
+
19291
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
19148
19292
  if (!this._interactionTrackers) {
19149
19293
  this._interactionTrackers = {};
19150
19294
  }
19151
19295
  let interactionTracker = this._interactionTrackers[widgetId];
19296
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
19152
19297
  if (!interactionTracker) {
19153
19298
  interactionTracker = this._interactionTrackers[widgetId] = new InteractionTracker(apiOptions.trackInteraction, widgetInfo && widgetInfo.type, widgetId, getTracking(widgetInfo && widgetInfo.type));
19154
19299
  }
@@ -19269,6 +19414,7 @@ class Renderer extends React.Component {
19269
19414
  // before jipt has a chance to replace its contents, so this check
19270
19415
  // will keep us from adding the component to the registry a second
19271
19416
  // time.
19417
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
19272
19418
  if (!this.translationIndex) {
19273
19419
  this.translationIndex = getDependencies().rendererTranslationComponents.addComponent(this);
19274
19420
  }
@@ -20026,6 +20172,7 @@ var NumericInput$1 = {
20026
20172
  };
20027
20173
 
20028
20174
  const getPromptJSON$q = (renderProps, userInput) => {
20175
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
20029
20176
  const choices = renderProps.choices || [];
20030
20177
  const options = choices.map(choice => {
20031
20178
  return {
@@ -20303,6 +20450,7 @@ function findFirstAndLastWordIndexes(selectionRange, wordRanges) {
20303
20450
  /**
20304
20451
  * Utility functions for manipulating highlights.
20305
20452
  */
20453
+
20306
20454
  /**
20307
20455
  * Given a list of DOMHighlights, return a new list that also includes the
20308
20456
  * given DOMRange as a new DOMHighlight. If the DOMHighlight intersects
@@ -20429,6 +20577,7 @@ function deserializeHighlight(serializedHighlight, wordRanges) {
20429
20577
  lastWordIndex
20430
20578
  } = serializedHighlight.range;
20431
20579
  const firstWord = wordRanges[firstWordIndex];
20580
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
20432
20581
  if (!firstWord) {
20433
20582
  throw new PerseusError(`first word index ${firstWord} is out of bounds: ` + `must be 0–${wordRanges.length - 1} inclusive`, Errors.InvalidInput, {
20434
20583
  metadata: {
@@ -20438,6 +20587,7 @@ function deserializeHighlight(serializedHighlight, wordRanges) {
20438
20587
  });
20439
20588
  }
20440
20589
  const lastWord = wordRanges[lastWordIndex];
20590
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
20441
20591
  if (!lastWord) {
20442
20592
  throw new PerseusError(`last word index ${lastWord} is out of bounds: ` + `must be 0–${wordRanges.length - 1} inclusive`, Errors.InvalidInput, {
20443
20593
  metadata: {
@@ -20611,6 +20761,17 @@ function addClientRectsForText(textNode, textRange, mutableRects) {
20611
20761
  }
20612
20762
 
20613
20763
  /* eslint-disable react/no-unsafe */
20764
+ /**
20765
+ * This component, given a single DOMHighlight, draws highlight rectangles in
20766
+ * the same absolute position as the highlighted content, as computed via
20767
+ * `getClientRects`.
20768
+ *
20769
+ * TODO(mdr): Many things can affect the correct positioning of highlighting,
20770
+ * and this component does not attempt to anticipate them. If we start
20771
+ * using this highlighting library on content with a more dynamic layout,
20772
+ * we should add a hook to allow the parent to `forceUpdate` the
20773
+ * `HighlightRenderer`.
20774
+ */
20614
20775
  class HighlightRenderer extends React.PureComponent {
20615
20776
  constructor(...args) {
20616
20777
  super(...args);
@@ -20766,6 +20927,7 @@ class HighlightTooltip extends React.PureComponent {
20766
20927
  // but let's catch that case and bail out.
20767
20928
  // TODO(mdr): Instead, we should somehow walk back the range until we
20768
20929
  // find an appropriate position for the tooltip. Sounds tricky!
20930
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
20769
20931
  if (!focusRect) {
20770
20932
  Log.log("[Highlighting] Known bug: Could not determine the focus " + 'position, so did not show an "Add Highlight" tooltip. ' + "https://app.asana.com/0/329800276300868/413878480039713 " + "(see also /r/asana-links)");
20771
20933
  return null;
@@ -20840,6 +21002,14 @@ const styles$x = StyleSheet.create({
20840
21002
  });
20841
21003
 
20842
21004
  /* eslint-disable react/no-unsafe */
21005
+ /**
21006
+ * Render a set of highlights. See HighlightRenderer for more details about how
21007
+ * each highlight is rendered.
21008
+ *
21009
+ * This component manages the state of the "Remove highlight" tooltip. To
21010
+ * determine the currently-hovered highlight, it calls the `isHovered` method
21011
+ * on each HighlightRenderer.
21012
+ */
20843
21013
  class HighlightSetRenderer extends React.PureComponent {
20844
21014
  constructor(...args) {
20845
21015
  super(...args);
@@ -20919,7 +21089,10 @@ class HighlightSetRenderer extends React.PureComponent {
20919
21089
  const highlightKeys = Object.keys(this.props.highlights);
20920
21090
  return highlightKeys.find(key => {
20921
21091
  const highlightRenderer = this._highlightRenderers[key];
20922
- return highlightRenderer && highlightRenderer.isHovered(mouseClientPosition);
21092
+ return (
21093
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
21094
+ highlightRenderer && highlightRenderer.isHovered(mouseClientPosition)
21095
+ );
20923
21096
  });
20924
21097
  }
20925
21098
  _renderTooltip() {
@@ -20964,6 +21137,10 @@ class HighlightSetRenderer extends React.PureComponent {
20964
21137
  HighlightSetRenderer.contextType = PerseusI18nContext;
20965
21138
 
20966
21139
  /* eslint-disable react/no-unsafe */
21140
+ /**
21141
+ * Tracks the user's current selection, and exposes it to the subtree using the
21142
+ * function-as-children pattern.
21143
+ */
20967
21144
  class SelectionTracker extends React.PureComponent {
20968
21145
  constructor(...args) {
20969
21146
  super(...args);
@@ -21185,6 +21362,7 @@ HighlightingUI.contextType = PerseusI18nContext;
21185
21362
  * The words yielded by WordIndexer are sorted in document order, which makes
21186
21363
  * them amenable to binary search - see `findBoundaryWordIndex` in ranges.js.
21187
21364
  */
21365
+
21188
21366
  class WordIndexer extends React.PureComponent {
21189
21367
  constructor(...args) {
21190
21368
  super(...args);
@@ -21253,6 +21431,7 @@ class WordIndexer extends React.PureComponent {
21253
21431
  const startOffset = wordMatch.index;
21254
21432
  const endOffset = wordMatch.index + wordMatch[0].length;
21255
21433
  let range;
21434
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
21256
21435
  if (startOffset === 0 && trailingWordRange) {
21257
21436
  // This word is at the start of this text node, and
21258
21437
  // there's a trailing word from the previous text node,
@@ -21815,6 +21994,7 @@ var PassageMarkdown = {
21815
21994
  getInitialParseState
21816
21995
  };
21817
21996
 
21997
+ /* eslint-disable @typescript-eslint/strict-boolean-expressions */
21818
21998
  // A fake paragraph to measure the line height of the passage,
21819
21999
  // so we can adapt to browser zoom
21820
22000
  class LineHeightMeasurer extends React.Component {
@@ -21999,6 +22179,7 @@ class Passage extends React.Component {
21999
22179
  _getStartRefLineNumber(referenceNumber) {
22000
22180
  const refRef = PassageMarkdown.START_REF_PREFIX + referenceNumber;
22001
22181
  const ref = this.refs[refRef];
22182
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
22002
22183
  if (!ref) {
22003
22184
  return null;
22004
22185
  }
@@ -22020,6 +22201,7 @@ class Passage extends React.Component {
22020
22201
  _getEndRefLineNumber(referenceNumber) {
22021
22202
  const refRef = PassageMarkdown.END_REF_PREFIX + referenceNumber;
22022
22203
  const ref = this.refs[refRef];
22204
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
22023
22205
  if (!ref) {
22024
22206
  return null;
22025
22207
  }
@@ -22060,6 +22242,7 @@ class Passage extends React.Component {
22060
22242
  _getRefContent(referenceNumber) {
22061
22243
  const refRef = PassageMarkdown.START_REF_PREFIX + referenceNumber;
22062
22244
  const ref = this.refs[refRef];
22245
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
22063
22246
  if (!ref) {
22064
22247
  return null;
22065
22248
  }
@@ -22379,6 +22562,7 @@ var PassageRef$1 = {
22379
22562
  * },
22380
22563
  * });
22381
22564
  */
22565
+
22382
22566
  const {
22383
22567
  pureXsMax,
22384
22568
  pureSmMin,
@@ -22410,6 +22594,7 @@ var mediaQueries = {
22410
22594
  */
22411
22595
 
22412
22596
  // Polyfill scrollTo if it doesn't exist
22597
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
22413
22598
  if (typeof HTMLElement !== "undefined" && !HTMLElement.prototype.scrollTo) {
22414
22599
  // @ts-expect-error - TS2322 - Type '(left: number, top: any) => void' is not assignable to type '{ (options?: ScrollToOptions | undefined): void; (x: number, y: number): void; }'.
22415
22600
  HTMLElement.prototype.scrollTo = function (left, top) {
@@ -22469,7 +22654,6 @@ const scrollElementToOffset = (elementOrWindow, offset, duration = 0, callback)
22469
22654
  // TODO(jeff, WEB-1378): Use Wonder Blocks Timing API
22470
22655
  // eslint-disable-next-line no-restricted-syntax
22471
22656
  clearInterval(scrollInterval);
22472
- callback == null || callback();
22473
22657
  }
22474
22658
  }, tickLength);
22475
22659
  };
@@ -22528,11 +22712,12 @@ const scrollElementIntoView = (element, callback) => {
22528
22712
  const distanceToScroll = childBounds.top - containerBounds.top;
22529
22713
  offset = currentScrollTop + distanceToScroll;
22530
22714
  }
22531
- scrollElementToOffset(scrollContainer, offset, SCROLL_ANIMATION_DURATION, callback);
22715
+ scrollElementToOffset(scrollContainer, offset, SCROLL_ANIMATION_DURATION);
22532
22716
  }, 0);
22533
22717
  };
22534
22718
 
22535
22719
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
22720
+
22536
22721
  // WARNING: This determines the *viewport* width and height, so a change here
22537
22722
  // requires scaling the values of every SVG path passed in as a string
22538
22723
  // without corresponding `width` and `height` values.
@@ -22692,6 +22877,7 @@ function getA11yText(letter, checked, correct, crossedOut, showCorrectness, stri
22692
22877
  /**
22693
22878
  * Renders a circular selection ring around the child.
22694
22879
  */
22880
+
22695
22881
  const FocusRing = function FocusRing({
22696
22882
  visible = true,
22697
22883
  color = kaGreen,
@@ -22746,6 +22932,7 @@ const styles$t = StyleSheet.create({
22746
22932
 
22747
22933
  /* Component for rendering a letter icon in radio choice */
22748
22934
 
22935
+
22749
22936
  // The "cross-out line" SVG is a bit bigger than the choice icon, to provide
22750
22937
  // extra space for the cute rounded line cap.
22751
22938
  const CROSS_OUT_LINE_PADDING = 2;
@@ -22949,6 +23136,7 @@ const styles$r = StyleSheet.create({
22949
23136
  * ChoiceIcon visualizations but is meant to make the distinctions
22950
23137
  * between the states more immediately clear to users.
22951
23138
  */
23139
+
22952
23140
  function renderText(checked, correct, crossedOut, strings) {
22953
23141
  if (correct) {
22954
23142
  // For correct answers, we surface checked _or_ crossedOut state,
@@ -23300,6 +23488,7 @@ function getInstructionsText(multipleSelect, countChoices, numCorrect, strings)
23300
23488
  if (multipleSelect) {
23301
23489
  // using usesNumCorrect to make sure this logic stays in sync
23302
23490
  // with getRadioPublicWidgetOptions logic
23491
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
23303
23492
  if (usesNumCorrect(multipleSelect, !!countChoices, numCorrect)) {
23304
23493
  return strings.chooseNumAnswers({
23305
23494
  numCorrect: String(numCorrect)
@@ -23344,7 +23533,9 @@ const BaseRadio = function BaseRadio({
23344
23533
  // the most recently used widget (because, if the user has since
23345
23534
  // touched something else, they're probably not trying to keep their
23346
23535
  // eye on this widget anymore).
23347
- if (apiOptions.canScrollPage && isLastUsedWidget && reviewModeRubric && !prevReviewModeRubric.current) {
23536
+ if (apiOptions.canScrollPage && isLastUsedWidget && reviewModeRubric &&
23537
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
23538
+ !prevReviewModeRubric.current) {
23348
23539
  const checkedIndex = choices.findIndex(c => c.checked);
23349
23540
  if (checkedIndex >= 0) {
23350
23541
  const ref = choiceRefs.current[checkedIndex];
@@ -23473,7 +23664,9 @@ const BaseRadio = function BaseRadio({
23473
23664
  });
23474
23665
  }
23475
23666
  const nextChoice = choices[i + 1];
23476
- const nextChoiceHighlighted = !!nextChoice && nextChoice.highlighted;
23667
+ const nextChoiceHighlighted =
23668
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
23669
+ !!nextChoice && nextChoice.highlighted;
23477
23670
  const aphroditeClassName = checked => {
23478
23671
  // Whether or not to show correctness borders
23479
23672
  // for this choice and the next choice.
@@ -23637,7 +23830,7 @@ const styles$o = StyleSheet.create({
23637
23830
 
23638
23831
  // RenderProps is the return type for radio.jsx#transform
23639
23832
 
23640
- class Radio$1 extends React.Component {
23833
+ let Radio$1 = class Radio extends React.Component {
23641
23834
  constructor(...args) {
23642
23835
  super(...args);
23643
23836
  // @ts-expect-error - TS2564 - Property 'focusFunction' has no initializer and is not definitely assigned in the constructor.
@@ -23834,6 +24027,7 @@ class Radio$1 extends React.Component {
23834
24027
  // adding hints when editing.
23835
24028
  // See: https://github.com/Khan/perseus/blame/e18582b4b69959270b90e237ef1813899711ddfa/src/widgets/radio.js#L169
23836
24029
  focus(choiceIndex) {
24030
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
23837
24031
  if (this.focusFunction) {
23838
24032
  return this.focusFunction(choiceIndex);
23839
24033
  }
@@ -23846,10 +24040,10 @@ class Radio$1 extends React.Component {
23846
24040
  this.focusFunction = fun;
23847
24041
  }
23848
24042
  getUserInput() {
23849
- return Radio$1.getUserInputFromProps(this.props);
24043
+ return Radio.getUserInputFromProps(this.props);
23850
24044
  }
23851
24045
  getPromptJSON() {
23852
- const userInput = Radio$1.getUserInputFromProps(this.props, false);
24046
+ const userInput = Radio.getUserInputFromProps(this.props, false);
23853
24047
  return getPromptJSON$q(this.props, userInput);
23854
24048
  }
23855
24049
  render() {
@@ -23963,7 +24157,7 @@ class Radio$1 extends React.Component {
23963
24157
  registerFocusFunction: i => this.registerFocusFunction(i)
23964
24158
  });
23965
24159
  }
23966
- }
24160
+ };
23967
24161
  Radio$1.contextType = PerseusI18nContext;
23968
24162
  Radio$1.defaultProps = {
23969
24163
  choices: [],
@@ -23998,6 +24192,7 @@ const _choiceTransform = (widgetOptions, strings, problemNum) => {
23998
24192
  });
23999
24193
 
24000
24194
  // Place the "None of the above" options last
24195
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
24001
24196
  if (noneOfTheAbove) {
24002
24197
  newChoices.push(noneOfTheAbove);
24003
24198
  }
@@ -24066,6 +24261,8 @@ var Radio = {
24066
24261
  };
24067
24262
 
24068
24263
  /* eslint-disable import/no-named-as-default */
24264
+ // As new widgets get added here, please also make sure they get added in
24265
+ // content_internal/perseus_traversal.py so they can be properly translated.
24069
24266
  var basicWidgets = [Radio, InputNumber$1, NumericInput$1, Expression$1];
24070
24267
 
24071
24268
  const {
@@ -24286,7 +24483,6 @@ Categorizer.defaultProps = {
24286
24483
  values: [],
24287
24484
  linterContext: linterContextDefault
24288
24485
  };
24289
- const pageMargin = 16;
24290
24486
 
24291
24487
  // Stylesheets aren't directly testable
24292
24488
  /* c8 ignore next */
@@ -24298,8 +24494,8 @@ const styles$n = StyleSheet.create({
24298
24494
  },
24299
24495
  fullBleedContainer: {
24300
24496
  [mediaQueries.mdOrSmaller]: {
24301
- marginLeft: -pageMargin,
24302
- marginRight: -pageMargin,
24497
+ marginLeft: -16,
24498
+ marginRight: -16,
24303
24499
  overflowX: "auto"
24304
24500
  }
24305
24501
  },
@@ -24373,6 +24569,7 @@ const location = () => {
24373
24569
  * We cache the result to ensure that on subsequent requests we always get
24374
24570
  * the first URL that was used to initially render the page.
24375
24571
  */
24572
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
24376
24573
  if (!_cachedClientLocation) {
24377
24574
  // eslint-disable-next-line no-restricted-syntax
24378
24575
  _cachedClientLocation = window.location;
@@ -24410,6 +24607,7 @@ const getPromptJSON$m = () => {
24410
24607
  /**
24411
24608
  * This widget is for embedding Khan Academy CS programs.
24412
24609
  */
24610
+
24413
24611
  const {
24414
24612
  updateQueryString: updateQueryString$1
24415
24613
  } = Util;
@@ -24503,6 +24701,7 @@ class CSProgram extends React.Component {
24503
24701
  }
24504
24702
 
24505
24703
  // Turn array of [{name: "", value: ""}] into object
24704
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
24506
24705
  if (this.props.settings) {
24507
24706
  const settings = {};
24508
24707
  _.each(this.props.settings, function (setting) {
@@ -24900,7 +25099,7 @@ const styles$k = StyleSheet.create({
24900
25099
  borderLeftWidth: "5px",
24901
25100
  gridTemplateColumns: "1fr",
24902
25101
  gridTemplateRows: "1fr",
24903
- marginLeft: -leftBorderSpacing,
25102
+ marginLeft: -23,
24904
25103
  minWidth: "100%",
24905
25104
  paddingLeft: leftBorderSpacing,
24906
25105
  paddingBottom: verticalContentPadding,
@@ -25489,6 +25688,8 @@ class GradedGroupSet extends React.Component {
25489
25688
  }));
25490
25689
  }
25491
25690
  const currentGroup = this.props.gradedGroups[this.state.currentGroup];
25691
+
25692
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
25492
25693
  if (!currentGroup) {
25493
25694
  return /*#__PURE__*/React.createElement("span", null, "No current group...");
25494
25695
  }
@@ -25650,7 +25851,9 @@ class ButtonGroup extends React.Component {
25650
25851
  key: "" + i,
25651
25852
  className: css(styles$g.buttonStyle, button.value === value && styles$g.selectedStyle),
25652
25853
  onClick: () => this.toggleSelect(button.value)
25653
- }, button.content || "" + button.value);
25854
+ },
25855
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
25856
+ button.content || "" + button.value);
25654
25857
  });
25655
25858
  const outerStyle = {
25656
25859
  display: "inline-block"
@@ -25907,10 +26110,11 @@ class FunctionGrapher extends React.Component {
25907
26110
  const model = this.props.model;
25908
26111
  const graph = this.props.graph;
25909
26112
  const asymptote = this._asymptote();
26113
+ const showAsymptote = (asymptote == null ? void 0 : asymptote.length) > 0;
25910
26114
  const dashed = {
25911
26115
  strokeDasharray: "- "
25912
26116
  };
25913
- return asymptote && /*#__PURE__*/React.createElement(MovableLine$2, {
26117
+ return showAsymptote && /*#__PURE__*/React.createElement(MovableLine$2, {
25914
26118
  onMove: (newCoord, oldCoord) => {
25915
26119
  // Calculate and apply displacement
25916
26120
  const delta = vector$3.subtract(newCoord, oldCoord);
@@ -26429,6 +26633,7 @@ const getPromptJSON$e = () => {
26429
26633
  * It's particularly well suited for embedding our ProcessingJS programs,
26430
26634
  * but could also be used for embedding viz's hosted elsewhere.
26431
26635
  */
26636
+
26432
26637
  const {
26433
26638
  updateQueryString
26434
26639
  } = Util;
@@ -26493,6 +26698,7 @@ class Iframe extends React.Component {
26493
26698
  let url = this.props.url;
26494
26699
 
26495
26700
  // If the URL doesnt start with http, it must be a program ID
26701
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
26496
26702
  if (url && url.length && url.indexOf("http") !== 0) {
26497
26703
  url = "https://www.khanacademy.org/computer-programming/program/" + url + "/embedded?buttons=no&embed=yes&editor=no&author=no";
26498
26704
  url = updateQueryString(url, "width", this.props.width);
@@ -26738,6 +26944,7 @@ var Image$1 = {
26738
26944
  // has a background but no alt text, it is not accessible
26739
26945
  accessible: widgetOptions => {
26740
26946
  const bgImage = widgetOptions.backgroundImage;
26947
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
26741
26948
  return !(bgImage && bgImage.url && !widgetOptions.alt);
26742
26949
  },
26743
26950
  displayName: "Image",
@@ -26750,6 +26957,7 @@ const getPromptJSON$c = () => {
26750
26957
  };
26751
26958
 
26752
26959
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
26960
+ /* eslint-disable @babel/no-invalid-this, react/no-unsafe */
26753
26961
  // @ts-expect-error - TS2339 - Property 'Label' does not exist on type 'typeof Graphie'.
26754
26962
  const Label = Graphie.Label;
26755
26963
  // @ts-expect-error - TS2339 - Property 'Line' does not exist on type 'typeof Graphie'.
@@ -27919,9 +28127,6 @@ function AxisLabels({
27919
28127
  height,
27920
28128
  labelLocation
27921
28129
  } = useGraphConfig();
27922
- const {
27923
- strings
27924
- } = i18n;
27925
28130
  const graphInfo = {
27926
28131
  range,
27927
28132
  width,
@@ -27941,7 +28146,11 @@ function AxisLabels({
27941
28146
  TeX
27942
28147
  } = getDependencies();
27943
28148
  return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("span", {
27944
- "aria-label": strings.xAxis,
28149
+ // Reading the axis labels by themselves is mostly unhelpful
28150
+ // for screen reader users, so we should hide them to avoid
28151
+ // confusion. Instead, the axis labels should be included as
28152
+ // part of the graph description by content authors.
28153
+ "aria-hidden": true,
27945
28154
  style: {
27946
28155
  position: "absolute",
27947
28156
  left: xAxisLabelLocation[X],
@@ -27950,7 +28159,11 @@ function AxisLabels({
27950
28159
  transform: xLabelTransform
27951
28160
  }
27952
28161
  }, /*#__PURE__*/React__default.createElement(TeX, null, replaceOutsideTeX(xAxisLabelText))), /*#__PURE__*/React__default.createElement("span", {
27953
- "aria-label": strings.yAxis,
28162
+ // Reading the axis labels by themselves is mostly unhelpful
28163
+ // for screen reader users, so we should hide them to avoid
28164
+ // confusion. Instead, the axis labels should be included as
28165
+ // part of the graph description by content authors.
28166
+ "aria-hidden": true,
27954
28167
  style: {
27955
28168
  position: "absolute",
27956
28169
  left: yAxisLabelLocation[X],
@@ -27986,8 +28199,8 @@ const getLabelPosition = (graphInfo, labelLocation) => {
27986
28199
  // the labels do not overlap with the axis tick if they are out of the graph bounds.
27987
28200
  const xAxisLabelOffset = graphInfo.range[Y][MIN] >= 0 ? [0, fontSize * 3] // Move the label down by 3 font sizes if the y-axis min is positive
27988
28201
  : [0, fontSize]; // Move the label down by 1 font size if the y-axis min is negative
27989
- const yAxisLabelOffset = graphInfo.range[X][MIN] >= 0 ? [-fontSize * 3, -fontSize] // Move the label left by 3 font sizes if the x-axis min is positive
27990
- : [-fontSize, -fontSize]; // Move the label left by 1 font size if the x-axis min is negative
28202
+ const yAxisLabelOffset = graphInfo.range[X][MIN] >= 0 ? [-14 * 3, -14] // Move the label left by 3 font sizes if the x-axis min is positive
28203
+ : [-14, -14]; // Move the label left by 1 font size if the x-axis min is negative
27991
28204
 
27992
28205
  // Calculate the location of the labels to be halfway between the min and max values of the axes
27993
28206
  const xAxisLabelLocation = [(graphInfo.range[X][MIN] + graphInfo.range[X][MAX]) / 2, graphInfo.range[Y][MIN]];
@@ -28003,7 +28216,7 @@ const getLabelPosition = (graphInfo, labelLocation) => {
28003
28216
  // place them at the end of the axis, which is the maximum value of the axis.
28004
28217
  const xLabelInitial = [graphInfo.range[X][MAX], 0];
28005
28218
  const yLabelInitial = [0, graphInfo.range[Y][MAX]];
28006
- const yLabelOffset = [0, -fontSize * 2]; // Move the y-axis label up by 2 font sizes
28219
+ const yLabelOffset = [0, -14 * 2]; // Move the y-axis label up by 2 font sizes
28007
28220
 
28008
28221
  const xLabel = pointToPixel(xLabelInitial, graphInfo);
28009
28222
  const yLabel = vec.add(pointToPixel(yLabelInitial, graphInfo), yLabelOffset);
@@ -28046,7 +28259,7 @@ const YGridTick = ({
28046
28259
 
28047
28260
  // Adjust the y position of the x-axis labels based on
28048
28261
  // whether the x-axis is above, within, or below the graph
28049
- const xAdjustment = range[X][MAX] <= 0 ? tickLabelSize * 1.5 : -tickLabelSize * 1.1;
28262
+ const xAdjustment = range[X][MAX] <= 0 ? tickLabelSize * 1.5 : -14 * 1.1;
28050
28263
  const xPositionText = xPosition + xAdjustment;
28051
28264
  const yPositionText = yPosition + tickLabelSize * 0.25; // Center the text vertically on the tick
28052
28265
 
@@ -28105,7 +28318,7 @@ const XGridTick = ({
28105
28318
 
28106
28319
  // Adjust the Y position of the x-axis labels based on
28107
28320
  // whether the x-axis is above, within, or below the graph
28108
- const yAdjustment = range[Y][MAX] < 0 ? -tickLabelSize : tickLabelSize * 1.75;
28321
+ const yAdjustment = range[Y][MAX] < 0 ? -14 : tickLabelSize * 1.75;
28109
28322
 
28110
28323
  // Adjust the X position of the x-axis labels based on
28111
28324
  // whether the label is positive or negative, in order to
@@ -28425,6 +28638,7 @@ const styles$e = StyleSheet.create({
28425
28638
  * (RCSS generates classnames with a randomSuffix, which ensures that any
28426
28639
  * two sets of generated classnames will not match.)
28427
28640
  */
28641
+
28428
28642
  class InfoTip extends React.Component {
28429
28643
  constructor(...args) {
28430
28644
  super(...args);
@@ -29342,6 +29556,7 @@ function getAngleFromPoints(points, i) {
29342
29556
  const point = points.at(i);
29343
29557
  const pt1 = points.at(i - 1);
29344
29558
  const pt2 = points[(i + 1) % points.length];
29559
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
29345
29560
  if (!point || !pt1 || !pt2) {
29346
29561
  return null;
29347
29562
  }
@@ -30261,6 +30476,8 @@ function useDraggable(args) {
30261
30476
  shiftKey
30262
30477
  } = state;
30263
30478
  const direction = [yDownDirection[X], -yDownDirection[Y]];
30479
+
30480
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
30264
30481
  const span = Math.abs(direction[X]) ? xSpan : ySpan;
30265
30482
  let divisions = 50;
30266
30483
  if (altKey || metaKey) {
@@ -31808,6 +32025,7 @@ function initializeGraphState(params) {
31808
32025
  case "polygon":
31809
32026
  return _extends({}, shared, {
31810
32027
  type: "polygon",
32028
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
31811
32029
  numSides: graph.numSides || 0,
31812
32030
  showAngles: Boolean(graph.showAngles),
31813
32031
  showSides: Boolean(graph.showSides),
@@ -31823,6 +32041,7 @@ function initializeGraphState(params) {
31823
32041
  return _extends({}, shared, {
31824
32042
  type: graph.type,
31825
32043
  coords: getPointCoords(graph, range, step),
32044
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
31826
32045
  numPoints: graph.numPoints || 0,
31827
32046
  focusedPointIndex: null,
31828
32047
  showRemovePointButton: false,
@@ -31866,6 +32085,7 @@ function initializeGraphState(params) {
31866
32085
  }
31867
32086
  function getPointCoords(graph, range, step) {
31868
32087
  var _graph$coords, _graph$startCoords;
32088
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
31869
32089
  const numPoints = graph.numPoints || 1;
31870
32090
  let coords = (_graph$coords = graph.coords) == null ? void 0 : _graph$coords.slice();
31871
32091
  if (coords) {
@@ -31964,6 +32184,8 @@ function getPolygonCoords(graph, range, step) {
31964
32184
  if (startCoords) {
31965
32185
  return startCoords;
31966
32186
  }
32187
+
32188
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
31967
32189
  const n = graph.numSides || 3;
31968
32190
  if (n === "unlimited") {
31969
32191
  coords = [];
@@ -32012,6 +32234,8 @@ function getCircleCoords(graph) {
32012
32234
  radiusPoint: vec.add(graph.center, [graph.radius, 0])
32013
32235
  };
32014
32236
  }
32237
+
32238
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
32015
32239
  if ((_graph$startCoords3 = graph.startCoords) != null && _graph$startCoords3.center && graph.startCoords.radius) {
32016
32240
  return {
32017
32241
  center: graph.startCoords.center,
@@ -32278,6 +32502,7 @@ function doMoveLine(state, action) {
32278
32502
  throw new Error("Please provide index of line to move");
32279
32503
  }
32280
32504
  const currentLine = state.coords[action.itemIndex];
32505
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
32281
32506
  if (!currentLine) {
32282
32507
  throw new Error("No line to move");
32283
32508
  }
@@ -33070,6 +33295,7 @@ const LimitedPolygonGraph = statefulProps => {
33070
33295
  }), points.map((point, i) => {
33071
33296
  const pt1 = points.at(i - 1);
33072
33297
  const pt2 = points[(i + 1) % points.length];
33298
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
33073
33299
  if (!pt1 || !pt2) {
33074
33300
  return null;
33075
33301
  }
@@ -34409,7 +34635,9 @@ const MafsGraph = props => {
34409
34635
  handleKeyboardEvent(event, state, dispatch);
34410
34636
  },
34411
34637
  "aria-label": fullGraphAriaLabel,
34412
- "aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId, interactiveElementsDescription && interactiveElementsDescriptionId, isUnlimitedGraphState(state) && unlimitedGraphKeyboardPromptId, state.type !== "none" && !disableInteraction && instructionsId),
34638
+ "aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId,
34639
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
34640
+ interactiveElementsDescription && interactiveElementsDescriptionId, isUnlimitedGraphState(state) && unlimitedGraphKeyboardPromptId, state.type !== "none" && !disableInteraction && instructionsId),
34413
34641
  ref: graphRef,
34414
34642
  tabIndex: 0,
34415
34643
  onFocus: event => {
@@ -35067,6 +35295,7 @@ class InteractiveGraph extends React.Component {
35067
35295
  * @param {object} props of an InteractiveGraph instance
35068
35296
  */
35069
35297
  static getPointCoords(graph, props) {
35298
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
35070
35299
  const numPoints = graph.numPoints || 1;
35071
35300
  let coords = graph.coords;
35072
35301
  if (coords) {
@@ -35131,6 +35360,8 @@ class InteractiveGraph extends React.Component {
35131
35360
  if (coords) {
35132
35361
  return coords;
35133
35362
  }
35363
+
35364
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
35134
35365
  const n = graph.numSides || 3;
35135
35366
  if (n === UNLIMITED) {
35136
35367
  coords = [];
@@ -35599,6 +35830,7 @@ function shouldReduceMotion() {
35599
35830
  return true;
35600
35831
  }
35601
35832
  const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
35833
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
35602
35834
  return !mediaQuery || mediaQuery.matches;
35603
35835
  }
35604
35836
  const MARKER_SIZE = 24;
@@ -36109,6 +36341,7 @@ class LabelImage extends React.Component {
36109
36341
  // Compile the user selected answer choices.
36110
36342
  const selected = choices.filter((_, index) => selection[index]);
36111
36343
  this.handleMarkerChange(index, _extends({}, markers[index], {
36344
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
36112
36345
  selected: selected.length ? selected : undefined
36113
36346
  }));
36114
36347
  }
@@ -36577,6 +36810,8 @@ class Draggable extends React.Component {
36577
36810
  if (this.isMouseMoveUpBound) {
36578
36811
  this.unbindMouseMoveUp();
36579
36812
  }
36813
+
36814
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
36580
36815
  if (this.animationFrameRequest) {
36581
36816
  // TODO(jeff, CP-3128): Use Wonder Blocks Timing API.
36582
36817
  // eslint-disable-next-line no-restricted-syntax
@@ -36692,7 +36927,13 @@ class Sortable extends React.Component {
36692
36927
  }
36693
36928
  componentDidUpdate() {
36694
36929
  // Measure items if their dimensions have been reset
36695
- if (this.state.items.length && !this.state.items[0].width && !this.state.items[0].height) {
36930
+ if (
36931
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
36932
+ this.state.items.length &&
36933
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
36934
+ !this.state.items[0].width &&
36935
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
36936
+ !this.state.items[0].height) {
36696
36937
  // Measure on the next frame to allow items size to settle.
36697
36938
  // TODO(jeff, CP-3128): Use Wonder Blocks Timing API.
36698
36939
  // eslint-disable-next-line no-restricted-syntax
@@ -36811,6 +37052,7 @@ class Sortable extends React.Component {
36811
37052
  const item = _.findWhere(this.state.items, {
36812
37053
  key: key
36813
37054
  });
37055
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
36814
37056
  const margin = this.props.margin || 0;
36815
37057
  // @ts-expect-error - TS2345 - Argument of type 'SortableItem | undefined' is not assignable to parameter of type 'SortableItem'.
36816
37058
  const currentIndex = _.indexOf(items, item);
@@ -37446,6 +37688,8 @@ class Matrix extends React.Component {
37446
37688
  // @ts-expect-error - TS2322 - Type '0' is not assignable to type 'null'.
37447
37689
  enterTheMatrix = 0;
37448
37690
  }
37691
+
37692
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
37449
37693
  if (nextPath) {
37450
37694
  // Prevent the cursor from jumping again inside the next input
37451
37695
  e.preventDefault();
@@ -37478,6 +37722,7 @@ class Matrix extends React.Component {
37478
37722
  };
37479
37723
  this.onValueChange = (row, column, value, cb) => {
37480
37724
  const answers = this.props.answers.map(answer => [...answer]);
37725
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
37481
37726
  if (!answers[row]) {
37482
37727
  answers[row] = [];
37483
37728
  }
@@ -37565,6 +37810,7 @@ class Matrix extends React.Component {
37565
37810
  const inputProps = {
37566
37811
  className: outside ? "outside" : "inside",
37567
37812
  ref: getRefForPath$1(getInputPath$1(row, col)),
37813
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
37568
37814
  value: rowVals ? rowVals[col] : null,
37569
37815
  style: {
37570
37816
  height: INPUT_HEIGHT,
@@ -38014,7 +38260,7 @@ const bondLength = 30;
38014
38260
  function polarAdd(origin, angle, length) {
38015
38261
  const x = origin[0];
38016
38262
  const y = origin[1];
38017
- return [x + Math.cos(angle * 2 * Math.PI / 360) * length, y + -1.0 * Math.sin(angle * 2 * Math.PI / 360) * length];
38263
+ return [x + Math.cos(angle * 2 * Math.PI / 360) * length, y + -1 * Math.sin(angle * 2 * Math.PI / 360) * length];
38018
38264
  }
38019
38265
 
38020
38266
  /**
@@ -38298,14 +38544,7 @@ function layout$1(tree, rotationAngle) {
38298
38544
  return bondLayoutHelper(outputs, atoms, bonds);
38299
38545
  }
38300
38546
  var MoleculeLayout = {
38301
- layout: layout$1,
38302
- // The remainder are exported for testing and are not intended for external
38303
- // use.
38304
- _atomLayout: atomLayout,
38305
- _bondLayout: bondLayout,
38306
- _bondLength: bondLength,
38307
- _convertTree: convertTree
38308
- };
38547
+ layout: layout$1};
38309
38548
 
38310
38549
  // Regexp defining characters that are valid SMILES characters that this parser
38311
38550
  // can parse. In addition to serving as a sort of validation, this also keeps
@@ -38892,6 +39131,7 @@ class NumberLine extends React.Component {
38892
39131
  numDivisions = numDivisions < 0 ? numDivisions * -1 : numDivisions;
38893
39132
 
38894
39133
  // If the number of divisions isn't blank, update the number line
39134
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
38895
39135
  if (numDivisions) {
38896
39136
  const nextProps = _.extend({}, this.props, {
38897
39137
  tickStep: width / numDivisions
@@ -39182,7 +39422,9 @@ class NumberLine extends React.Component {
39182
39422
  // eslint-disable-next-line react/no-string-refs
39183
39423
  , {
39184
39424
  ref: "tick-ctrl",
39185
- value: this.state.numDivisionsEmpty ? null : this.props.numDivisions || divisionRange[0],
39425
+ value: this.state.numDivisionsEmpty ? null :
39426
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
39427
+ this.props.numDivisions || divisionRange[0],
39186
39428
  checkValidity: val => val >= divisionRange[0] && val <= divisionRange[1],
39187
39429
  onChange: this.onNumDivisionsChange,
39188
39430
  onFocus: this._handleTickCtrlFocus,
@@ -39886,6 +40128,7 @@ const getPromptJSON$4 = () => {
39886
40128
  * This is a PhET simulation widget. It is used for rendering simulations
39887
40129
  * from https://phet.colorado.edu/.
39888
40130
  */
40131
+
39889
40132
  // This renders the PhET sim
39890
40133
  class PhetSimulation extends React.Component {
39891
40134
  constructor(props) {
@@ -39962,6 +40205,7 @@ class PhetSimulation extends React.Component {
39962
40205
  }
39963
40206
  async showLocaleWarning(url) {
39964
40207
  // Do not show a locale warning on an invalid URL
40208
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
39965
40209
  if (!url) {
39966
40210
  return false;
39967
40211
  }
@@ -40103,6 +40347,7 @@ class Plotter extends React.Component {
40103
40347
  this.hairlineRange = void 0;
40104
40348
  this.graphie = void 0;
40105
40349
  this.state = {
40350
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
40106
40351
  values: this.props.starting || [1],
40107
40352
  // The measured rendered height of category strings. Used to calculate
40108
40353
  // bottom padding of plot, to prevent categories from overlapping the
@@ -40199,6 +40444,8 @@ class Plotter extends React.Component {
40199
40444
  // TODO(michaelpolyak): Handle other plot types: Dot, Histogram, Line.
40200
40445
  if (isMobile && (isBar || isTiledPlot)) {
40201
40446
  const maxCategoryHeight = Math.max(0, ...Object.values(self.state.categoryHeights));
40447
+
40448
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
40202
40449
  if (maxCategoryHeight) {
40203
40450
  // Account for bottom label position, height.
40204
40451
  let offsetY = 25;
@@ -41283,6 +41530,7 @@ const getPromptJSON = () => {
41283
41530
  /**
41284
41531
  * This is a component that adds a link to the transcript for embedded videos in articles.
41285
41532
  */
41533
+
41286
41534
  const IS_URL$1 = /^https?:\/\//;
41287
41535
  const getYoutubeId = url => {
41288
41536
  const regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
@@ -41349,6 +41597,7 @@ const styles$3 = StyleSheet.create({
41349
41597
  /**
41350
41598
  * This is a video widget for embedding videos in articles.
41351
41599
  */
41600
+
41352
41601
  // Current default is 720p, based on the typical videos we upload currently
41353
41602
  const DEFAULT_WIDTH = 1280;
41354
41603
  const DEFAULT_HEIGHT = 720;
@@ -41437,6 +41686,9 @@ var Video$1 = {
41437
41686
  };
41438
41687
 
41439
41688
  /* eslint-disable import/no-named-as-default */
41689
+ // As new widgets get added here, please also make sure they get added in
41690
+ // content_internal/perseus_traversal.py so they can be properly translated.
41691
+
41440
41692
  var extraWidgets = [Categorizer$1, CSProgram$1, Dropdown$1, Explanation$1, Definition$1, Grapher$1, GradedGroup$1, GradedGroupSet$1, Group$1, Iframe$1, Image$1, Interactive, InteractiveGraph$1, LabelImage$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, PhetSimulation$1, Plotter$1, PythonProgram$1, Sorter$1, Table$1, Video$1, DeprecatedStandin$1];
41441
41693
 
41442
41694
  /**
@@ -41451,8 +41703,11 @@ const init = function init() {
41451
41703
  };
41452
41704
 
41453
41705
  // This file is processed by a Rollup plugin (replace) to inject the production
41706
+ // version number during the release build.
41707
+ // In dev, you'll never see the version number.
41708
+
41454
41709
  const libName = "@khanacademy/perseus";
41455
- const libVersion = "57.2.2";
41710
+ const libVersion = "59.0.0";
41456
41711
  addLibraryVersionToPerseusDebug(libName, libVersion);
41457
41712
 
41458
41713
  const apiVersion = {
@@ -41515,7 +41770,9 @@ class ArticleRenderer extends React.Component {
41515
41770
  // Wait for the keypad to mount before getting the height
41516
41771
  setTimeout(() => {
41517
41772
  const keypadDomNode = keypadElement == null ? void 0 : keypadElement.getDOMNode();
41518
- const keypadHeight = keypadDomNode && didFocusInput ? keypadDomNode.getBoundingClientRect().height : 0;
41773
+ const keypadHeight =
41774
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
41775
+ keypadDomNode && didFocusInput ? keypadDomNode.getBoundingClientRect().height : 0;
41519
41776
  onFocusChange(this._currentFocus, prevFocusPath, keypadHeight, didFocusInput ? focusedInput : null);
41520
41777
  }, 0);
41521
41778
  }
@@ -41792,6 +42049,7 @@ class HintsRenderer extends React.Component {
41792
42049
  let numCallbacks = 1;
41793
42050
  const fireCallback = () => {
41794
42051
  --numCallbacks;
42052
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
41795
42053
  if (callback && numCallbacks === 0) {
41796
42054
  callback();
41797
42055
  }
@@ -41804,6 +42062,7 @@ class HintsRenderer extends React.Component {
41804
42062
  // the state to an unmounted renderer, so...
41805
42063
  // If you want to restore state to hints, make sure to
41806
42064
  // have the appropriate number of hints visible already.
42065
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
41807
42066
  if (hintRenderer) {
41808
42067
  ++numCallbacks;
41809
42068
  // @ts-expect-error - TS2339 - Property 'restoreSerializedState' does not exist on type 'ReactInstance'.
@@ -41892,6 +42151,7 @@ class HintsRenderer extends React.Component {
41892
42151
  onClick: evt => {
41893
42152
  evt.preventDefault();
41894
42153
  evt.stopPropagation();
42154
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
41895
42155
  if (getAnotherHint) {
41896
42156
  getAnotherHint();
41897
42157
  }
@@ -42116,7 +42376,9 @@ class ServerItemRenderer extends React.Component {
42116
42376
  setTimeout(() => {
42117
42377
  // First, calculate the current keypad height
42118
42378
  const keypadDomNode = keypadElement == null ? void 0 : keypadElement.getDOMNode();
42119
- const keypadHeight = keypadDomNode && didFocusInput ? keypadDomNode.getBoundingClientRect().height : 0;
42379
+ const keypadHeight =
42380
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
42381
+ keypadDomNode && didFocusInput ? keypadDomNode.getBoundingClientRect().height : 0;
42120
42382
 
42121
42383
  // Then call the callback
42122
42384
  onFocusChange(this._currentFocus, prevFocus, keypadHeight,
@@ -42368,6 +42630,7 @@ guess, state) {
42368
42630
  * from that. We might eventually expose this, but I'd like to be
42369
42631
  * more confident in the interface provided first.
42370
42632
  */
42633
+
42371
42634
  const noop = function noop() {};
42372
42635
  const deepCallbackFor = function deepCallbackFor(contentCallback, widgetCallback, optionsCallback) {
42373
42636
  const deepCallback = function deepCallback(widgetInfo, widgetId) {
@@ -42456,6 +42719,7 @@ const traverse = function traverse(rendererOptions, contentCallback, widgetCallb
42456
42719
  * This supports widgets that contain renderers, such as the
42457
42720
  * group or sequence widgets.
42458
42721
  */
42722
+
42459
42723
  const isUpgradedWidgetInfoRenderableBy = function isUpgradedWidgetInfoRenderableBy(widgetInfo, widgetRendererVersion) {
42460
42724
  if (widgetRendererVersion == null) {
42461
42725
  // If the widget does not exist in this version, this will
@@ -42509,6 +42773,7 @@ const isItemRenderableByVersion = function isItemRenderableByVersion(itemData, r
42509
42773
  * or screen, based on the widgets it contains.
42510
42774
  */
42511
42775
 
42776
+
42512
42777
  // Iterate over a single Perseus renderer, mutating `widgets` by appending
42513
42778
  // violating widget types discovered in this item.
42514
42779
  function traverseRenderer(itemData, widgets) {
@@ -43019,6 +43284,8 @@ function getAnswersFromWidgets(widgets) {
43019
43284
  keys(widgets).forEach(widgetID => {
43020
43285
  var _options$choices, _categorizer$options, _categorizer$options2, _categorizer$options3, _dropdown$options, _numericInput$options, _inputNumber$options, _expression$options, _gradedGroup$options, _plotter$options, _plotter$options2, _grapher$options, _orderer$options, _sorter$options, _labelImage$options, _numberLine$options, _matrix$options, _matcher$options, _matcher$options2;
43021
43286
  const widget = widgets[widgetID];
43287
+
43288
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43022
43289
  if (!widget.options) {
43023
43290
  return;
43024
43291
  }
@@ -43027,6 +43294,7 @@ function getAnswersFromWidgets(widgets) {
43027
43294
  const radio = widget;
43028
43295
  const options = radio.options;
43029
43296
  // Answer is the content of the correct choice
43297
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43030
43298
  if (options != null && (_options$choices = options.choices) != null && _options$choices.length) {
43031
43299
  for (const choice of options.choices) {
43032
43300
  if (choice != null && choice.correct) {
@@ -43039,7 +43307,11 @@ function getAnswersFromWidgets(widgets) {
43039
43307
  // Answer is a list of items mapped to their category
43040
43308
  // e.g. ['item 1: category 1', 'item 2: category 2']
43041
43309
  const categorizer = widget;
43042
- if ((_categorizer$options = categorizer.options) != null && _categorizer$options.categories && (_categorizer$options2 = categorizer.options) != null && _categorizer$options2.items && (_categorizer$options3 = categorizer.options) != null && _categorizer$options3.values) {
43310
+ if (
43311
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43312
+ (_categorizer$options = categorizer.options) != null && _categorizer$options.categories && // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43313
+ (_categorizer$options2 = categorizer.options) != null && _categorizer$options2.items && // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43314
+ (_categorizer$options3 = categorizer.options) != null && _categorizer$options3.values) {
43043
43315
  var _categorizer$options4, _categorizer$options5, _categorizer$options6;
43044
43316
  const categories = (_categorizer$options4 = categorizer.options) == null ? void 0 : _categorizer$options4.categories;
43045
43317
  const items = (_categorizer$options5 = categorizer.options) == null ? void 0 : _categorizer$options5.items;
@@ -43050,6 +43322,7 @@ function getAnswersFromWidgets(widgets) {
43050
43322
  case "dropdown":
43051
43323
  // Answer is the content of correct dropdown option
43052
43324
  const dropdown = widget;
43325
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43053
43326
  if ((_dropdown$options = dropdown.options) != null && _dropdown$options.choices) {
43054
43327
  for (const choice of dropdown.options.choices) {
43055
43328
  if (choice.correct) {
@@ -43061,6 +43334,7 @@ function getAnswersFromWidgets(widgets) {
43061
43334
  case "numeric-input":
43062
43335
  // Answer is the numeric value cast to a string
43063
43336
  const numericInput = widget;
43337
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43064
43338
  if ((_numericInput$options = numericInput.options) != null && _numericInput$options.answers) {
43065
43339
  for (const ans of numericInput.options.answers) {
43066
43340
  if (ans.status === "correct" && ans.value != null) {
@@ -43072,6 +43346,7 @@ function getAnswersFromWidgets(widgets) {
43072
43346
  case "input-number":
43073
43347
  // Answer is the correct value
43074
43348
  const inputNumber = widget;
43349
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43075
43350
  if ((_inputNumber$options = inputNumber.options) != null && _inputNumber$options.value) {
43076
43351
  answers.push(inputNumber.options.value.toString());
43077
43352
  }
@@ -43080,6 +43355,7 @@ function getAnswersFromWidgets(widgets) {
43080
43355
  // Answer is a list of potential correct expressions,
43081
43356
  // since there can be multiple correct forms of the expression
43082
43357
  const expression = widget;
43358
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43083
43359
  if ((_expression$options = expression.options) != null && _expression$options.answerForms) {
43084
43360
  answers.push(...expression.options.answerForms.map(answer => answer.value));
43085
43361
  }
@@ -43090,6 +43366,7 @@ function getAnswersFromWidgets(widgets) {
43090
43366
  // call this function to get the nested answers from the
43091
43367
  // group's widgets
43092
43368
  const gradedGroup = widget;
43369
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43093
43370
  if ((_gradedGroup$options = gradedGroup.options) != null && _gradedGroup$options.widgets) {
43094
43371
  answers.push(...getAnswersFromWidgets(gradedGroup.options.widgets));
43095
43372
  }
@@ -43099,7 +43376,10 @@ function getAnswersFromWidgets(widgets) {
43099
43376
  // e.g. '{Soccer: 35, Basketball: 20, Golf: 45, Volleyball: 15,
43100
43377
  // Tennis: 30}'
43101
43378
  const plotter = widget;
43102
- if ((_plotter$options = plotter.options) != null && _plotter$options.categories && (_plotter$options2 = plotter.options) != null && _plotter$options2.correct && plotter.options.categories.length === plotter.options.correct.length) {
43379
+ if (
43380
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43381
+ (_plotter$options = plotter.options) != null && _plotter$options.categories && // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43382
+ (_plotter$options2 = plotter.options) != null && _plotter$options2.correct && plotter.options.categories.length === plotter.options.correct.length) {
43103
43383
  const {
43104
43384
  categories,
43105
43385
  correct
@@ -43125,6 +43405,7 @@ function getAnswersFromWidgets(widgets) {
43125
43405
  // in the correct order on newlines
43126
43406
  // E.g. 'item 1\nitem 2\nitem 3'
43127
43407
  const orderer = widget;
43408
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43128
43409
  if ((_orderer$options = orderer.options) != null && _orderer$options.correctOptions) {
43129
43410
  answers.push(joinOptionContents(orderer.options.correctOptions));
43130
43411
  }
@@ -43134,6 +43415,7 @@ function getAnswersFromWidgets(widgets) {
43134
43415
  // separated by commas
43135
43416
  // E.g. 'item 1, item 2, item 3'
43136
43417
  const sorter = widget;
43418
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43137
43419
  if ((_sorter$options = sorter.options) != null && _sorter$options.correct) {
43138
43420
  answers.push(sorter.options.correct.join(", "));
43139
43421
  }
@@ -43142,6 +43424,7 @@ function getAnswersFromWidgets(widgets) {
43142
43424
  // Answer is a list of labels, their positions, and their answer
43143
43425
  // E.g. '{label: "label 1", position: {x: 0.5, y: 0.5}, answer: "answer 1"}'
43144
43426
  const labelImage = widget;
43427
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43145
43428
  if ((_labelImage$options = labelImage.options) != null && _labelImage$options.markers) {
43146
43429
  answers.push(...labelImage.options.markers.map(m => `{label: "${m.label}", position: {${m.x},${m.y}}, answer: "${m.answers.join(", ")}"}`));
43147
43430
  }
@@ -43158,6 +43441,7 @@ function getAnswersFromWidgets(widgets) {
43158
43441
  // Answer is a list of rows representing the matrix
43159
43442
  // E.g. '[[1, 2], [3, 4]]'
43160
43443
  const matrix = widget;
43444
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43161
43445
  if ((_matrix$options = matrix.options) != null && _matrix$options.answers) {
43162
43446
  answers.push(`[${matrix.options.answers.join("], [")}]`);
43163
43447
  }
@@ -43166,6 +43450,7 @@ function getAnswersFromWidgets(widgets) {
43166
43450
  // Answer is a table of the left and right items
43167
43451
  // E.g. '| Left | Right |\n| --- | --- |\n| left item 1 | right item 1 |\n| left item 2 | right item 2 |'
43168
43452
  const matcher = widget;
43453
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43169
43454
  if ((_matcher$options = matcher.options) != null && _matcher$options.left && (_matcher$options2 = matcher.options) != null && _matcher$options2.right) {
43170
43455
  const {
43171
43456
  left,
@@ -43224,6 +43509,7 @@ function injectWidgets(content, widgets, widgetProps) {
43224
43509
  if (!content) {
43225
43510
  return "";
43226
43511
  }
43512
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43227
43513
  if (!widgets) {
43228
43514
  return content;
43229
43515
  }
@@ -43231,6 +43517,8 @@ function injectWidgets(content, widgets, widgetProps) {
43231
43517
  keys(widgets).forEach(widgetID => {
43232
43518
  var _radio$options, _image$options, _labelImage$options2, _explanation$options, _passage$options, _passage$options2, _group$options, _gradedGroup$options2, _categorizer$options7, _dropdown$options2, _definition$options, _orderer$options2, _sorter$options2, _interactiveGraph$opt, _numberLine$options2, _numberLine$options3, _numberLine$options4, _matrix$options2, _matcher$options3, _matcher$options4;
43233
43519
  const widget = widgets[widgetID];
43520
+
43521
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43234
43522
  if (!widget.options) {
43235
43523
  return;
43236
43524
  }
@@ -43243,6 +43531,7 @@ function injectWidgets(content, widgets, widgetProps) {
43243
43531
  // 'Option A: choice 1\nOption B: choice 2\nOption C: choice 3'
43244
43532
  const radio = widget;
43245
43533
  const radioProps = widgetProps == null ? void 0 : widgetProps[widgetID];
43534
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43246
43535
  if ((_radio$options = radio.options) != null && (_radio$options = _radio$options.choices) != null && _radio$options.length) {
43247
43536
  var _radio$options2;
43248
43537
  let radioContext = joinOptionContents(radioProps ? radioProps.choices.map(({
@@ -43300,6 +43589,7 @@ function injectWidgets(content, widgets, widgetProps) {
43300
43589
  // '[[☃ Group 1]]' -> 'Nested question\n[[☃ Radio 1]]'
43301
43590
  // -> 'Nested question\noption 1\noption 2\noption 3'
43302
43591
  const group = widget;
43592
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43303
43593
  if ((_group$options = group.options) != null && _group$options.widgets && group.options.content) {
43304
43594
  context = context.replace(`[[☃ ${widgetID}]]`, injectWidgets(group.options.content, group.options.widgets));
43305
43595
  }
@@ -43309,9 +43599,11 @@ function injectWidgets(content, widgets, widgetProps) {
43309
43599
  // '[[☃ Graded Group Set 1]]'
43310
43600
  // -> 'Nested question 1\noption 1\noption 2\noption 3\nNested question 2\noption 1\noption 2\noption 3'
43311
43601
  const gradedGroup = widget;
43602
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43312
43603
  if ((_gradedGroup$options2 = gradedGroup.options) != null && _gradedGroup$options2.gradedGroups) {
43313
43604
  const gradedGroups = gradedGroup.options.gradedGroups;
43314
43605
  const gradedGroupsContent = gradedGroups.reduce((acc, group) => {
43606
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43315
43607
  if (group.widgets && group.content) {
43316
43608
  acc += injectWidgets(group.content, group.widgets) + "\n";
43317
43609
  }
@@ -43329,7 +43621,11 @@ function injectWidgets(content, widgets, widgetProps) {
43329
43621
  // item 2
43330
43622
  // '''
43331
43623
  const categorizer = widget;
43332
- if ((_categorizer$options7 = categorizer.options) != null && _categorizer$options7.categories && categorizer.options.items) {
43624
+ if (
43625
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43626
+ (_categorizer$options7 = categorizer.options) != null && _categorizer$options7.categories &&
43627
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43628
+ categorizer.options.items) {
43333
43629
  const categories = categorizer.options.categories;
43334
43630
  const items = categorizer.options.items;
43335
43631
  context = context.replace(`[[☃ ${widgetID}]]`, `For each item, select the correct category. Categories: ${categories.join(", ")}.\nItems:\n${items.join("\n")}\n`);
@@ -43339,6 +43635,7 @@ function injectWidgets(content, widgets, widgetProps) {
43339
43635
  // Replace dropdown with the dropdown options
43340
43636
  // '[[☃ Dropdown 1]]' -> '[option 1 | option 2 | option 3]'
43341
43637
  const dropdown = widget;
43638
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43342
43639
  if ((_dropdown$options2 = dropdown.options) != null && _dropdown$options2.choices) {
43343
43640
  const choices = dropdown.options.choices.map(choice => choice.content);
43344
43641
  context = context.replace(`[[☃ ${widgetID}]]`, `[${choices.join(" | ")}]`);
@@ -43358,6 +43655,7 @@ function injectWidgets(content, widgets, widgetProps) {
43358
43655
  // Replace orderer with the orderer options
43359
43656
  // '[[☃ Orderer 1]]' -> 'option 1\noption 2\noption 3'
43360
43657
  const orderer = widget;
43658
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43361
43659
  if ((_orderer$options2 = orderer.options) != null && _orderer$options2.options) {
43362
43660
  context = context.replace(`[[☃ ${widgetID}]]`, joinOptionContents(orderer.options.options));
43363
43661
  }
@@ -43367,6 +43665,7 @@ function injectWidgets(content, widgets, widgetProps) {
43367
43665
  // NOTE(chase): These are already in the correct order
43368
43666
  // '[[☃ Sorter 1]]' -> '[option 1 | option 2 | option 3]'
43369
43667
  const sorter = widget;
43668
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43370
43669
  if ((_sorter$options2 = sorter.options) != null && _sorter$options2.correct) {
43371
43670
  const choices = sorter.options.correct;
43372
43671
  context = context.replace(`[[☃ ${widgetID}]]`, `[${choices.join(" | ")}]`);
@@ -43405,6 +43704,7 @@ function injectWidgets(content, widgets, widgetProps) {
43405
43704
  // Replace matcher with a table representing the left and right columns
43406
43705
  // '[[☃ Matcher 1]]' -> '| Left Column | Right Column |\n| --- | --- |\n| option 1 | option 2 |\n| option 3 | option 4 |'
43407
43706
  const matcher = widget;
43707
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43408
43708
  if ((_matcher$options3 = matcher.options) != null && _matcher$options3.left && (_matcher$options4 = matcher.options) != null && _matcher$options4.right) {
43409
43709
  const {
43410
43710
  left,
@@ -43447,12 +43747,14 @@ function injectWidgets(content, widgets, widgetProps) {
43447
43747
  * @returns a stringified list of {widgetId, imageUrl} for imgs that don't have alt text
43448
43748
  */
43449
43749
  function getImagesWithoutAltData(perseusRenderer) {
43750
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43450
43751
  if (!perseusRenderer.widgets) {
43451
43752
  return "";
43452
43753
  }
43453
43754
  const imgsWithoutAltData = [];
43454
43755
  Object.entries(perseusRenderer.widgets).forEach(([widgetId, widget]) => {
43455
43756
  var _widget$options$backg;
43757
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
43456
43758
  if (!widget.options) {
43457
43759
  return;
43458
43760
  }
@@ -43727,6 +44029,7 @@ const EditorJsonify = {
43727
44029
  /**
43728
44030
  * Main entry point
43729
44031
  */
44032
+
43730
44033
  const GrapherUtil = {
43731
44034
  DEFAULT_GRAPHER_PROPS,
43732
44035
  chooseType,