@khanacademy/perseus 19.1.9 → 19.2.1

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
@@ -244,7 +244,7 @@ class MathInput extends React.Component {
244
244
  className = className + " " + this.props.className;
245
245
  }
246
246
  return /*#__PURE__*/React.createElement(View, {
247
- style: [styles$B.outerWrapper, this.state.focused && styles$B.wrapperFocused, this.props.hasError && styles$B.wrapperError]
247
+ style: [styles$C.outerWrapper, this.state.focused && styles$C.wrapperFocused, this.props.hasError && styles$C.wrapperError]
248
248
  }, /*#__PURE__*/React.createElement("div", {
249
249
  style: {
250
250
  display: "flex",
@@ -277,7 +277,7 @@ class MathInput extends React.Component {
277
277
  var _this$props$keypadBut, _this$props;
278
278
  return /*#__PURE__*/React.createElement(PopoverContentCore, {
279
279
  closeButtonVisible: true,
280
- style: styles$B.popoverContent
280
+ style: styles$C.popoverContent
281
281
  }, /*#__PURE__*/React.createElement(DesktopKeypad, _extends({
282
282
  onAnalyticsEvent: this.props.analytics.onAnalyticsEvent,
283
283
  extraKeys: this.props.extraKeys,
@@ -321,9 +321,9 @@ const MathInputIcon = ({
321
321
  color = Color.offBlack;
322
322
  break;
323
323
  }
324
- const dynamicClass = active || focused ? styles$B.iconActive : styles$B.iconInactive;
324
+ const dynamicClass = active || focused ? styles$C.iconActive : styles$C.iconInactive;
325
325
  return /*#__PURE__*/React.createElement(View, {
326
- style: [styles$B.iconContainer, dynamicClass]
326
+ style: [styles$C.iconContainer, dynamicClass]
327
327
  }, /*#__PURE__*/React.createElement("svg", {
328
328
  xmlns: "http://www.w3.org/2000/svg",
329
329
  width: "16",
@@ -368,7 +368,7 @@ const inputFocused = {
368
368
  borderColor: Color.blue,
369
369
  margin: -1
370
370
  };
371
- const styles$B = StyleSheet.create({
371
+ const styles$C = StyleSheet.create({
372
372
  iconContainer: {
373
373
  display: "flex",
374
374
  justifyContent: "center",
@@ -2394,6 +2394,7 @@ ExpressionWithDependencies.getOneCorrectAnswerFromRubric = Expression.getOneCorr
2394
2394
  var Expression$1 = {
2395
2395
  name: "expression",
2396
2396
  displayName: "Expression / Equation",
2397
+ accessible: true,
2397
2398
  defaultAlignment: "inline-block",
2398
2399
  widget: ExpressionWithDependencies,
2399
2400
  transform: widgetOptions => {
@@ -10202,89 +10203,49 @@ const GraphUtils = {
10202
10203
  }
10203
10204
  })($, window, document);
10204
10205
 
10205
- /**
10206
- * A work-in-progress of _ methods for objects.
10207
- * That is, they take an object as a parameter,
10208
- * and return an object instead of an array.
10209
- *
10210
- * TODO(aria): Move this out of interactive2
10211
- */
10212
-
10213
- /**
10214
- * Does a pluck on keys inside objects in an object
10215
- *
10216
- * Ex:
10217
- * tools = {
10218
- * translation: {
10219
- * enabled: true
10220
- * },
10221
- * rotation: {
10222
- * enabled: false
10223
- * }
10224
- * };
10225
- * pluckObject(tools, "enabled") returns {
10226
- * translation: true
10227
- * rotation: false
10228
- * }
10229
- */
10230
- const pluck = function pluck(table, subKey) {
10231
- return _.object(_.map(table, function (value, key) {
10232
- return [key, value[subKey]];
10233
- }));
10234
- };
10235
-
10236
- /**
10237
- * Maps an object to an object
10238
- *
10239
- * > mapObject({a: '1', b: '2'}, (value, key) => {
10240
- * return value + 1;
10241
- * });
10242
- * {a: 2, b: 3}
10243
- */
10244
- const mapObject$2 = function mapObject(obj, lambda) {
10245
- const result = {};
10246
- _.each(_.keys(obj), function (key) {
10247
- // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'K'.
10248
- result[key] = lambda(obj[key], key);
10249
- });
10250
- return result;
10251
- };
10206
+ // Given `coord` and `angle`, find the point where a line extended
10207
+ // from `coord` in the direction of `angle` would be clipped by the
10208
+ // edge of the graphie canvas.
10209
+ const getClipPoint = function getClipPoint(graph, coord, angle) {
10210
+ // Actually put the arrowheads 4px from the edge so they have
10211
+ // a bit of room
10212
+ const xExtent = graph.range[0][1] - graph.range[0][0];
10213
+ const yExtent = graph.range[1][1] - graph.range[1][0];
10252
10214
 
10253
- /**
10254
- * Maps an array to an object
10255
- *
10256
- * > mapObjectFromArray(['a', 'b'], function(elem) {
10257
- * return elem + elem;
10258
- * });
10259
- * {a: 'aa', b: 'bb'}
10260
- */
10261
- const mapObjectFromArray$1 = function mapObjectFromArray(arr, lambda) {
10262
- const result = {};
10263
- _.each(arr, function (elem) {
10264
- result[elem] = lambda(elem);
10265
- });
10266
- return result;
10267
- };
10268
- var objective_ = {
10269
- pluck: pluck,
10270
- mapObject: mapObject$2,
10271
- mapObjectFromArray: mapObjectFromArray$1
10215
+ // shoot a point off into the distance ...
10216
+ const distance = xExtent + yExtent;
10217
+ // we need to scale the point according to the scale of the axes
10218
+ const angleVec = graph.unscaleVector(vector$1.cartFromPolarDeg(1, angle));
10219
+ const distVec = vector$1.scale(vector$1.normalize(angleVec), distance);
10220
+ const farCoord = vector$1.add(coord, distVec);
10221
+ const scaledAngle = vector$1.polarDegFromCart(angleVec)[1];
10222
+ // ... and then bring it back
10223
+ const clipPoint = graph.constrainToBoundsOnAngle(farCoord, 4, scaledAngle * Math.PI / 180);
10224
+ return clipPoint;
10272
10225
  };
10273
10226
 
10274
10227
  /* eslint-disable @babel/no-invalid-this */
10275
10228
 
10276
10229
  /*
10277
- * These functions, when called on the wrapped object, simply pass the
10230
+ * attr() and animate() simply pass the
10278
10231
  * arguments to the underlying Raphael object.
10279
10232
  */
10280
- const PASS_TO_RAPHAEL = ["attr", "animate"];
10281
- const WrappedDefaults = _.extend({
10282
- transform: function (transformation) {
10233
+
10234
+ class WrappedDrawing {
10235
+ constructor(graphie, initialPoint) {
10236
+ this.graphie = void 0;
10237
+ this.wrapper = void 0;
10238
+ this.visibleShape = void 0;
10239
+ this.initialPoint = void 0;
10240
+ this.graphie = graphie;
10241
+ this.initialPoint = initialPoint;
10242
+ }
10243
+ transform(transformation) {
10283
10244
  const prefixedTransform = InteractiveUtil.getPrefixedTransform();
10284
10245
  // @ts-expect-error - TS2538 - Type 'null' cannot be used as an index type. | TS2538 - Type 'undefined' cannot be used as an index type.
10285
10246
  this.wrapper.style[prefixedTransform] = transformation;
10286
- },
10287
- toFront: function () {
10247
+ }
10248
+ toFront() {
10288
10249
  const parentNode = this.wrapper.parentNode;
10289
10250
  // TODO(emily): Sometimes, we call `.remove()` but then hold a
10290
10251
  // reference to this object, and sometimes call `.toFront` on it.
@@ -10293,152 +10254,214 @@ const WrappedDefaults = _.extend({
10293
10254
  if (parentNode) {
10294
10255
  parentNode.appendChild(this.wrapper);
10295
10256
  }
10296
- },
10297
- toBack: function () {
10257
+ }
10258
+ toBack() {
10298
10259
  const parentNode = this.wrapper.parentNode;
10299
- if (parentNode.firstChild !== this.wrapper) {
10260
+ if (parentNode != null && parentNode.firstChild !== this.wrapper) {
10300
10261
  parentNode.insertBefore(this.wrapper, parentNode.firstChild);
10301
10262
  }
10302
- },
10303
- remove: function () {
10263
+ }
10264
+ remove() {
10304
10265
  this.visibleShape.remove();
10305
10266
  $(this.wrapper).remove();
10306
- },
10307
- getMouseTarget: function () {
10267
+ }
10268
+ getMouseTarget() {
10308
10269
  return this.visibleShape[0];
10309
- },
10310
- moveTo: function (point) {
10270
+ }
10271
+ moveTo(point) {
10311
10272
  const delta = vector$1.subtract(this.graphie.scalePoint(point), this.graphie.scalePoint(this.initialPoint));
10312
10273
  const do3dTransform = InteractiveUtil.getCanUse3dTransform();
10313
10274
  const transformation = "translateX(" + delta[0] + "px) " + "translateY(" + delta[1] + "px)" + (do3dTransform ? " translateZ(0)" : "");
10314
10275
  this.transform(transformation);
10315
- },
10316
- hide: function () {
10276
+ }
10277
+ hide() {
10317
10278
  this.visibleShape.hide();
10318
- },
10319
- show: function () {
10279
+ }
10280
+ show() {
10320
10281
  this.visibleShape.show();
10321
10282
  }
10322
- }, objective_.mapObjectFromArray(PASS_TO_RAPHAEL, function (attribute) {
10323
- return function (...args) {
10324
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10325
- this.visibleShape[attribute](...args);
10326
- };
10327
- }));
10283
+ attr(...args) {
10284
+ this.visibleShape.attr(...args);
10285
+ }
10286
+ animate(...args) {
10287
+ this.visibleShape.animate(...args);
10288
+ }
10289
+ }
10328
10290
 
10329
10291
  const DEFAULT_OPTIONS$2 = {
10330
- maxScale: 1,
10331
- mouselayer: false,
10332
- shadow: false,
10333
- disableMouseEventsOnWrapper: false
10292
+ center: null,
10293
+ // gets ignored in `graphie.fixedPath` if `null`
10294
+ createPath: null,
10295
+ // gets defaulted in `graphie.fixedPath` if `null`
10296
+ mouselayer: false
10334
10297
  };
10335
- const WrappedEllipse = function WrappedEllipse(graphie, center, radii, options) {
10336
- options = _.extend({}, DEFAULT_OPTIONS$2, options);
10337
-
10338
- // Add `wrapper`, `visibleShape`, and remaining properties.
10339
- const fixedEllipse = graphie.fixedEllipse(center, radii, options.maxScale, options.padding);
10340
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10341
- _.extend(this, fixedEllipse, {
10342
- graphie: graphie,
10343
- initialPoint: center
10344
- });
10345
- if (options.interactiveKindForTesting) {
10346
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10347
- this.wrapper.setAttribute("data-interactive-kind-for-testing", options.interactiveKindForTesting);
10298
+ class WrappedPath extends WrappedDrawing {
10299
+ constructor(graphie, points, options) {
10300
+ const initialPoint = graphie.scalePoint(_.head(points));
10301
+ super(graphie, initialPoint);
10302
+ this.wrapper = void 0;
10303
+ this.visibleShape = void 0;
10304
+ options = _.extend({}, DEFAULT_OPTIONS$2, options);
10305
+ const fixedPath = graphie.fixedPath(points, options.center, options.createPath);
10306
+ this.wrapper = fixedPath.wrapper;
10307
+ this.visibleShape = fixedPath.visibleShape;
10308
+
10309
+ // Add to appropriate graphie layer
10310
+ if (options.mouselayer) {
10311
+ // Disable browser handling of all panning and zooming gestures on the
10312
+ // movable wrapper so that when moved the browser does not scroll page
10313
+ this.wrapper.style.touchAction = "none";
10314
+ this.graphie.addToMouseLayerWrapper(this.wrapper);
10315
+ } else {
10316
+ this.graphie.addToVisibleLayerWrapper(this.wrapper);
10317
+ }
10348
10318
  }
10319
+ }
10349
10320
 
10350
- // Add to appropriate graphie layer
10351
- if (options.mouselayer) {
10352
- // Disable browser handling of all panning and zooming gestures on the
10353
- // movable wrapper so that when moved the browser does not scroll page
10354
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10355
- this.wrapper.style.touchAction = "none";
10356
-
10357
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10358
- this.graphie.addToMouseLayerWrapper(this.wrapper);
10359
- } else {
10360
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10361
- this.graphie.addToVisibleLayerWrapper(this.wrapper);
10321
+ class Arrowhead extends WrappedPath {
10322
+ constructor(graphie, style) {
10323
+ // Points that define the arrowhead
10324
+ const center = [0.75, 0];
10325
+ const points = [[-3, 4], [-2.75, 2.5], [0, 0.25], center, [0, -0.25], [-2.75, -2.5], [-3, -4]].map(point => {
10326
+ // Scale points by `Arrowhead.scale` around `center`
10327
+ const pv = vector$1.subtract(point, center);
10328
+ const pvScaled = vector$1.scale(pv, Arrowhead.scale);
10329
+ return vector$1.add(center, pvScaled);
10330
+ });
10331
+ const unscaledPoints = points.map(graphie.unscalePoint);
10332
+ super(graphie, unscaledPoints, {
10333
+ center: graphie.unscalePoint(center),
10334
+ createPath: createCubicPath
10335
+ });
10336
+ this.center = void 0;
10337
+ this.center = center;
10338
+ this.attr(_.extend({
10339
+ "stroke-linejoin": "round",
10340
+ "stroke-linecap": "round",
10341
+ "stroke-dasharray": ""
10342
+ }, style));
10362
10343
  }
10363
- if (options.shadow) {
10364
- const filter = "drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.5))";
10365
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10366
- const wrapper = this.wrapper;
10367
- wrapper.style.filter = filter;
10368
-
10369
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10370
- this.moveTo = function (point) {
10371
- const delta = vector$1.subtract(this.graphie.scalePoint(point), this.graphie.scalePoint(this.initialPoint));
10372
- const do3dTransform = InteractiveUtil.getCanUse3dTransform();
10373
- const transform = "translateX(" + Math.round(delta[0]) + "px) " + "translateY(" + Math.round(delta[1]) + "px)" + (do3dTransform ? " translateZ(0)" : "");
10374
- this.transform(transform);
10375
- };
10344
+ toCoordAtAngle(coord, angle) {
10345
+ const clipPoint = this.graphie.scalePoint(getClipPoint(this.graphie, coord, angle));
10346
+ 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)");
10376
10347
  }
10377
- if (options.disableMouseEventsOnWrapper) {
10378
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10379
- this.wrapper.style.pointerEvents = "none";
10380
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10381
- this.visibleShape.node.style.pointerEvents = "auto";
10348
+ }
10349
+
10350
+ // We can't just pass in a path to `graph.fixedPath` as we need to modify
10351
+ // the points in some way, so instead we provide a function for creating
10352
+ // the path once the points have been transformed
10353
+ Arrowhead.scale = 1.4;
10354
+ const createCubicPath = function createCubicPath(points) {
10355
+ let path = "M" + points[0][0] + " " + points[0][1];
10356
+ for (let i = 1; i < points.length; i += 3) {
10357
+ path += "C" + points[i][0] + " " + points[i][1] + " " + points[i + 1][0] + " " + points[i + 1][1] + " " + points[i + 2][0] + " " + points[i + 2][1];
10382
10358
  }
10359
+ return path;
10383
10360
  };
10384
- _.extend(WrappedEllipse.prototype, WrappedDefaults);
10385
10361
 
10386
10362
  const DEFAULT_OPTIONS$1 = {
10387
- thickness: 2,
10388
- mouselayer: false
10363
+ maxScale: 1,
10364
+ mouselayer: false,
10365
+ shadow: false,
10366
+ disableMouseEventsOnWrapper: false
10389
10367
  };
10390
- const WrappedLine = function WrappedLine(graphie, start, end, options) {
10391
- options = _.extend({}, DEFAULT_OPTIONS$1, options);
10392
-
10393
- // Always make the line as large as possible and horizontal; this
10394
- // simplifies a lot of the transforms, e.g., we can rotate by exactly the
10395
- // angle of the argument points in `moveTo`.
10396
- const initialStart = [graphie.range[0][0], 0];
10397
- const initialEnd = [graphie.range[0][1], 0];
10368
+ class WrappedEllipse extends WrappedDrawing {
10369
+ constructor(graphie, center, radii, options) {
10370
+ super(graphie, center);
10371
+ this.initialPoint = void 0;
10372
+ this.wrapper = void 0;
10373
+ this.visibleShape = void 0;
10374
+ options = _.extend({}, DEFAULT_OPTIONS$1, options);
10375
+
10376
+ // Add `wrapper`, `visibleShape`, and remaining properties.
10377
+ const fixedEllipse = graphie.fixedEllipse(center, radii, options.maxScale, options.padding);
10378
+ this.visibleShape = fixedEllipse.visibleShape;
10379
+ this.wrapper = fixedEllipse.wrapper;
10380
+ this.graphie = graphie;
10381
+ this.initialPoint = center;
10382
+ if (options.interactiveKindForTesting) {
10383
+ this.wrapper.setAttribute("data-interactive-kind-for-testing", options.interactiveKindForTesting);
10384
+ }
10398
10385
 
10399
- // Add `wrapper` and `visibleShape`
10400
- _.extend(
10401
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10402
- this, graphie.fixedLine(initialStart, initialEnd, options.thickness));
10403
- if (options.interactiveKindForTesting) {
10404
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10405
- this.wrapper.setAttribute("data-interactive-kind-for-testing", options.interactiveKindForTesting);
10386
+ // Add to appropriate graphie layer
10387
+ if (options.mouselayer) {
10388
+ // Disable browser handling of all panning and zooming gestures on the
10389
+ // movable wrapper so that when moved the browser does not scroll page
10390
+ this.wrapper.style.touchAction = "none";
10391
+ this.graphie.addToMouseLayerWrapper(this.wrapper);
10392
+ } else {
10393
+ this.graphie.addToVisibleLayerWrapper(this.wrapper);
10394
+ }
10395
+ if (options.shadow) {
10396
+ const filter = "drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.5))";
10397
+ const wrapper = this.wrapper;
10398
+ wrapper.style.filter = filter;
10399
+ this.moveTo = function (point) {
10400
+ const delta = vector$1.subtract(this.graphie.scalePoint(point), this.graphie.scalePoint(this.initialPoint));
10401
+ const do3dTransform = InteractiveUtil.getCanUse3dTransform();
10402
+ const transform = "translateX(" + Math.round(delta[0]) + "px) " + "translateY(" + Math.round(delta[1]) + "px)" + (do3dTransform ? " translateZ(0)" : "");
10403
+ this.transform(transform);
10404
+ };
10405
+ }
10406
+ if (options.disableMouseEventsOnWrapper) {
10407
+ this.wrapper.style.pointerEvents = "none";
10408
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10409
+ this.visibleShape.node.style.pointerEvents = "auto";
10410
+ }
10406
10411
  }
10412
+ }
10407
10413
 
10408
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10409
- this.visibleShape.attr(options.normalStyle);
10410
-
10411
- // Save properties for computing transformations
10412
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10413
- _.extend(this, {
10414
- graphie: graphie,
10415
- initialPoint: graphie.scalePoint(initialStart),
10416
- initialLength: point.distanceToPoint(graphie.scalePoint(initialStart), graphie.scalePoint(initialEnd))
10417
- });
10418
-
10419
- // Add to appropriate graphie layer
10420
- if (options.mouselayer) {
10421
- // Disable browser handling of all panning and zooming gestures on the
10422
- // movable wrapper so that when moved the browser does not scroll page
10423
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10424
- this.wrapper.style.touchAction = "none";
10414
+ const DEFAULT_OPTIONS = {
10415
+ thickness: 2,
10416
+ mouselayer: false
10417
+ };
10418
+ class WrappedLine extends WrappedDrawing {
10419
+ constructor(graphie, start, end, options) {
10420
+ // Always make the line as large as possible and horizontal; this
10421
+ // simplifies a lot of the transforms, e.g., we can rotate by exactly the
10422
+ // angle of the argument points in `moveTo`.
10423
+ const initialStart = [graphie.range[0][0], 0];
10424
+ const initialEnd = [graphie.range[0][1], 0];
10425
+ const initialPoint = graphie.scalePoint(initialStart);
10426
+ super(graphie, initialPoint);
10427
+ this.initialLength = void 0;
10428
+ this.wrapper = void 0;
10429
+ this.visibleShape = void 0;
10430
+ options = _.extend({}, DEFAULT_OPTIONS, options);
10431
+ const fixedLine = graphie.fixedLine(initialStart, initialEnd, options.thickness);
10432
+ this.wrapper = fixedLine.wrapper;
10433
+ this.visibleShape = fixedLine.visibleShape;
10434
+ if (options.interactiveKindForTesting) {
10435
+ this.wrapper.setAttribute("data-interactive-kind-for-testing", options.interactiveKindForTesting);
10436
+ }
10437
+ this.visibleShape.attr(options.normalStyle);
10438
+
10439
+ // Save properties for computing transformations
10440
+ this.initialPoint = initialPoint;
10441
+ this.initialLength = point.distanceToPoint(graphie.scalePoint(initialStart), graphie.scalePoint(initialEnd));
10442
+
10443
+ // Add to appropriate graphie layer
10444
+ if (options.mouselayer) {
10445
+ // Disable browser handling of all panning and zooming gestures on the
10446
+ // movable wrapper so that when moved the browser does not scroll page
10447
+ this.wrapper.style.touchAction = "none";
10448
+ this.graphie.addToMouseLayerWrapper(this.wrapper);
10449
+ } else {
10450
+ this.graphie.addToVisibleLayerWrapper(this.wrapper);
10451
+ }
10425
10452
 
10426
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10427
- this.graphie.addToMouseLayerWrapper(this.wrapper);
10428
- } else {
10429
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10430
- this.graphie.addToVisibleLayerWrapper(this.wrapper);
10453
+ // Move line to initial points
10454
+ this.moveTo(start, end);
10431
10455
  }
10432
-
10433
- // Move to argument points
10434
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10435
- this.moveTo(start, end);
10436
- };
10437
- _.extend(WrappedLine.prototype, WrappedDefaults, {
10438
- getMouseTarget: function () {
10456
+ getMouseTarget() {
10439
10457
  return this.wrapper;
10440
- },
10441
- moveTo: function (start, end) {
10458
+ }
10459
+
10460
+ // TODO(benchristel): we need to suppress a type error here because moveTo
10461
+ // takes 2 parameters here, but only 1 parameter in the superclass's
10462
+ // definition. Rename this method after confirming it's safe to do so
10463
+ // @ts-expect-error - TS2416: Property 'moveTo' in type 'WrappedLine' is not assignable to the same property in base type 'WrappedDefaults'.
10464
+ moveTo(start, end) {
10442
10465
  const scaledStart = this.graphie.scalePoint(start);
10443
10466
  const scaledEnd = this.graphie.scalePoint(end);
10444
10467
 
@@ -10454,45 +10477,7 @@ _.extend(WrappedLine.prototype, WrappedDefaults, {
10454
10477
  const transformation = "translateX(" + delta[0] + "px) " + "translateY(" + delta[1] + "px) " + (do3dTransform ? " translateZ(0)" : "") + "rotate(" + angle + "deg) " + "scaleX(" + scale + ") scaleY(1)";
10455
10478
  this.transform(transformation);
10456
10479
  }
10457
- });
10458
-
10459
- const DEFAULT_OPTIONS = {
10460
- center: null,
10461
- // gets ignored in `graphie.fixedPath` if `null`
10462
- createPath: null,
10463
- // gets defaulted in `graphie.fixedPath` if `null`
10464
- mouselayer: false
10465
- };
10466
- const WrappedPath = function WrappedPath(graphie, points, options) {
10467
- options = _.extend({}, DEFAULT_OPTIONS, options);
10468
-
10469
- // Add `wrapper` and `visibleShape`
10470
- _.extend(
10471
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10472
- this, graphie.fixedPath(points, options.center, options.createPath));
10473
-
10474
- // Add remaining properties
10475
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10476
- _.extend(this, {
10477
- graphie: graphie,
10478
- initialPoint: graphie.scalePoint(_.head(points))
10479
- });
10480
-
10481
- // Add to appropriate graphie layer
10482
- if (options.mouselayer) {
10483
- // Disable browser handling of all panning and zooming gestures on the
10484
- // movable wrapper so that when moved the browser does not scroll page
10485
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10486
- this.wrapper.style.touchAction = "none";
10487
-
10488
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10489
- this.graphie.addToMouseLayerWrapper(this.wrapper);
10490
- } else {
10491
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10492
- this.graphie.addToVisibleLayerWrapper(this.wrapper);
10493
- }
10494
- };
10495
- _.extend(WrappedPath.prototype, WrappedDefaults);
10480
+ }
10496
10481
 
10497
10482
  /**
10498
10483
  * A collection of geomtry-related utility functions
@@ -10717,9 +10702,6 @@ firstPoints, secondPoints) {
10717
10702
  }
10718
10703
 
10719
10704
  /* eslint-disable @babel/no-invalid-this */
10720
- const {
10721
- getCanUse3dTransform
10722
- } = InteractiveUtil;
10723
10705
  function scaledDistanceFromAngle(angle) {
10724
10706
  const a = 3.51470560176242 * 20;
10725
10707
  const b = 0.5687298702748785 * 20;
@@ -11603,52 +11585,15 @@ _.extend(GraphUtils.Graphie.prototype, {
11603
11585
  _.each(elements, function (element) {
11604
11586
  element.moveTo(start, end);
11605
11587
  });
11606
- const createArrow = function createArrow(graph, style) {
11607
- const center = [0.75, 0];
11608
- let points = [[-3, 4], [-2.75, 2.5], [0, 0.25], center, [0, -0.25], [-2.75, -2.5], [-3, -4]];
11609
- const scale = 1.4;
11610
- points = _.map(points, function (point) {
11611
- const pv = vector$1.subtract(point, center);
11612
- const pvScaled = vector$1.scale(pv, scale);
11613
- return vector$1.add(center, pvScaled);
11614
- });
11615
- const createCubicPath = function createCubicPath(points) {
11616
- let path = "M" + points[0][0] + " " + points[0][1];
11617
- for (let i = 1; i < points.length; i += 3) {
11618
- path += "C" + points[i][0] + " " + points[i][1] + " " + points[i + 1][0] + " " + points[i + 1][1] + " " + points[i + 2][0] + " " + points[i + 2][1];
11619
- }
11620
- return path;
11621
- };
11622
- const unscaledPoints = _.map(points, graph.unscalePoint);
11623
- const options = {
11624
- center: graph.unscalePoint(center),
11625
- createPath: createCubicPath
11626
- };
11627
- const arrowHead = new WrappedPath(graph, unscaledPoints, options);
11628
- arrowHead.attr(_.extend({
11629
- "stroke-linejoin": "round",
11630
- "stroke-linecap": "round",
11631
- "stroke-dasharray": ""
11632
- }, style));
11633
-
11634
- // Add custom function for transforming arrowheads that
11635
- // accounts for center, scaling, etc.
11636
- arrowHead.toCoordAtAngle = function (coord, angle) {
11637
- const clipPoint = graph.scalePoint(getClipPoint(graph, coord, angle));
11638
- const do3dTransform = getCanUse3dTransform();
11639
- arrowHead.transform("translateX(" + (clipPoint[0] + scale * center[0]) + "px) " + "translateY(" + (clipPoint[1] + scale * center[1]) + "px) " + (do3dTransform ? "translateZ(0) " : "") + "rotate(" + (360 - KhanMath.bound(angle)) + "deg)");
11640
- };
11641
- return arrowHead;
11642
- };
11643
11588
 
11644
11589
  // Add arrows
11645
11590
  if (this._arrows == null) {
11646
11591
  this._arrows = [];
11647
11592
  if (this.extendLine) {
11648
- this._arrows.push(createArrow(graph, this.normalStyle));
11649
- this._arrows.push(createArrow(graph, this.normalStyle));
11593
+ this._arrows.push(new Arrowhead(graph, this.normalStyle));
11594
+ this._arrows.push(new Arrowhead(graph, this.normalStyle));
11650
11595
  } else if (this.extendRay) {
11651
- this._arrows.push(createArrow(graph, this.normalStyle));
11596
+ this._arrows.push(new Arrowhead(graph, this.normalStyle));
11652
11597
  }
11653
11598
  }
11654
11599
  const coordForArrow = [this.coordA, this.coordZ];
@@ -14067,78 +14012,6 @@ const getScaledAngle = function getScaledAngle(line) {
14067
14012
  return vector$1.polarDegFromCart(vector$1.subtract(scaledZ, scaledA))[1];
14068
14013
  };
14069
14014
 
14070
- // Given `coord` and `angle`, find the point where a line extended
14071
- // from `coord` in the direction of `angle` would be clipped by the
14072
- // edge of the graphie canvas. Then draw an arrowhead at that point
14073
- // pointing in the direction of `angle`.
14074
- const getClipPoint = function getClipPoint(graph, coord, angle) {
14075
- // Actually put the arrowheads 4px from the edge so they have
14076
- // a bit of room
14077
- const xExtent = graph.range[0][1] - graph.range[0][0];
14078
- const yExtent = graph.range[1][1] - graph.range[1][0];
14079
-
14080
- // shoot a point off into the distance ...
14081
- const distance = xExtent + yExtent;
14082
- // we need to scale the point according to the scale of the axes
14083
- const angleVec = graph.unscaleVector(vector$1.cartFromPolarDeg(1, angle));
14084
- const distVec = vector$1.scale(vector$1.normalize(angleVec), distance);
14085
- const farCoord = vector$1.add(coord, distVec);
14086
- const scaledAngle = vector$1.polarDegFromCart(angleVec)[1];
14087
- // ... and then bring it back
14088
- const clipPoint = graph.constrainToBoundsOnAngle(farCoord, 4, scaledAngle * Math.PI / 180);
14089
- return clipPoint;
14090
- };
14091
-
14092
- // Given `coord` and `angle`, find the point where a line extended
14093
- // from `coord` in the direction of `angle` would be clipped by the
14094
- // edge of the graphie canvas. Then draw an arrowhead at that point
14095
- // pointing in the direction of `angle`.
14096
- const createArrow = function createArrow(graph, style) {
14097
- // Points that define the arrowhead
14098
- const center = [0.75, 0];
14099
- let points = [[-3, 4], [-2.75, 2.5], [0, 0.25], center, [0, -0.25], [-2.75, -2.5], [-3, -4]];
14100
-
14101
- // Scale points by 1.4 around (0.75, 0)
14102
- const scale = 1.4;
14103
- points = _.map(points, function (point) {
14104
- const pv = vector$1.subtract(point, center);
14105
- const pvScaled = vector$1.scale(pv, scale);
14106
- return vector$1.add(center, pvScaled);
14107
- });
14108
-
14109
- // We can't just pass in a path to `graph.fixedPath` as we need to modify
14110
- // the points in some way, so instead we provide a function for creating
14111
- // the path once the points have been transformed
14112
- const createCubicPath = function createCubicPath(points) {
14113
- let path = "M" + points[0][0] + " " + points[0][1];
14114
- for (let i = 1; i < points.length; i += 3) {
14115
- path += "C" + points[i][0] + " " + points[i][1] + " " + points[i + 1][0] + " " + points[i + 1][1] + " " + points[i + 2][0] + " " + points[i + 2][1];
14116
- }
14117
- return path;
14118
- };
14119
-
14120
- // Create arrowhead
14121
- const unscaledPoints = _.map(points, graph.unscalePoint);
14122
- const options = {
14123
- center: graph.unscalePoint(center),
14124
- createPath: createCubicPath
14125
- };
14126
- const arrowHead = new WrappedPath(graph, unscaledPoints, options);
14127
- arrowHead.attr(_.extend({
14128
- "stroke-linejoin": "round",
14129
- "stroke-linecap": "round",
14130
- "stroke-dasharray": ""
14131
- }, style));
14132
-
14133
- // Add custom function for transforming arrowheads that accounts for
14134
- // center, scaling, etc.
14135
- arrowHead.toCoordAtAngle = function (coord, angle) {
14136
- const clipPoint = graph.scalePoint(getClipPoint(graph, coord, angle));
14137
- arrowHead.transform("translateX(" + (clipPoint[0] + scale * center[0]) + "px) " + "translateY(" + (clipPoint[1] + scale * center[1]) + "px) " + "translateZ(0) " + "rotate(" + (360 - KhanMath.bound(angle)) + "deg)");
14138
- };
14139
- return arrowHead;
14140
- };
14141
-
14142
14015
  /**
14143
14016
  * MovableLine option functions
14144
14017
  */
@@ -14225,16 +14098,16 @@ const draw$3 = {
14225
14098
  // @ts-expect-error - TS2551 - Property '_arrows' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. Did you mean 'arrows'?
14226
14099
  this._arrows.push(
14227
14100
  // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. | TS2339 - Property 'normalStyle' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'.
14228
- createArrow(this.graphie, this.normalStyle()));
14101
+ new Arrowhead(this.graphie, this.normalStyle()));
14229
14102
  // @ts-expect-error - TS2551 - Property '_arrows' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. Did you mean 'arrows'?
14230
14103
  this._arrows.push(
14231
14104
  // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. | TS2339 - Property 'normalStyle' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'.
14232
- createArrow(this.graphie, this.normalStyle()));
14105
+ new Arrowhead(this.graphie, this.normalStyle()));
14233
14106
  } else if (state.extendRay) {
14234
14107
  // @ts-expect-error - TS2551 - Property '_arrows' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. Did you mean 'arrows'?
14235
14108
  this._arrows.push(
14236
14109
  // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. | TS2339 - Property 'normalStyle' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'.
14237
- createArrow(this.graphie, this.normalStyle()));
14110
+ new Arrowhead(this.graphie, this.normalStyle()));
14238
14111
  }
14239
14112
  }
14240
14113
 
@@ -14380,6 +14253,75 @@ var MovableLineOptions = {
14380
14253
  }
14381
14254
  };
14382
14255
 
14256
+ /**
14257
+ * A work-in-progress of _ methods for objects.
14258
+ * That is, they take an object as a parameter,
14259
+ * and return an object instead of an array.
14260
+ *
14261
+ * TODO(aria): Move this out of interactive2
14262
+ */
14263
+
14264
+ /**
14265
+ * Does a pluck on keys inside objects in an object
14266
+ *
14267
+ * Ex:
14268
+ * tools = {
14269
+ * translation: {
14270
+ * enabled: true
14271
+ * },
14272
+ * rotation: {
14273
+ * enabled: false
14274
+ * }
14275
+ * };
14276
+ * pluckObject(tools, "enabled") returns {
14277
+ * translation: true
14278
+ * rotation: false
14279
+ * }
14280
+ */
14281
+ const pluck = function pluck(table, subKey) {
14282
+ return _.object(_.map(table, function (value, key) {
14283
+ return [key, value[subKey]];
14284
+ }));
14285
+ };
14286
+
14287
+ /**
14288
+ * Maps an object to an object
14289
+ *
14290
+ * > mapObject({a: '1', b: '2'}, (value, key) => {
14291
+ * return value + 1;
14292
+ * });
14293
+ * {a: 2, b: 3}
14294
+ */
14295
+ const mapObject$2 = function mapObject(obj, lambda) {
14296
+ const result = {};
14297
+ _.each(_.keys(obj), function (key) {
14298
+ // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'K'.
14299
+ result[key] = lambda(obj[key], key);
14300
+ });
14301
+ return result;
14302
+ };
14303
+
14304
+ /**
14305
+ * Maps an array to an object
14306
+ *
14307
+ * > mapObjectFromArray(['a', 'b'], function(elem) {
14308
+ * return elem + elem;
14309
+ * });
14310
+ * {a: 'aa', b: 'bb'}
14311
+ */
14312
+ const mapObjectFromArray$1 = function mapObjectFromArray(arr, lambda) {
14313
+ const result = {};
14314
+ _.each(arr, function (elem) {
14315
+ result[elem] = lambda(elem);
14316
+ });
14317
+ return result;
14318
+ };
14319
+ var objective_ = {
14320
+ pluck: pluck,
14321
+ mapObject: mapObject$2,
14322
+ mapObjectFromArray: mapObjectFromArray$1
14323
+ };
14324
+
14383
14325
  /**
14384
14326
  * MovableLine
14385
14327
  */
@@ -17907,33 +17849,33 @@ class Lint extends React.Component {
17907
17849
  let warningText;
17908
17850
  let warningTextStyle;
17909
17851
  if (this.props.severity === Severity.Error) {
17910
- severityStyle = styles$A.indicatorError;
17852
+ severityStyle = styles$B.indicatorError;
17911
17853
  warningText = "Error";
17912
- warningTextStyle = styles$A.publishBlockingError;
17854
+ warningTextStyle = styles$B.publishBlockingError;
17913
17855
  } else if (this.props.severity === Severity.Warning) {
17914
- severityStyle = styles$A.indicatorWarning;
17856
+ severityStyle = styles$B.indicatorWarning;
17915
17857
  warningText = "Warning";
17916
- warningTextStyle = styles$A.warning;
17858
+ warningTextStyle = styles$B.warning;
17917
17859
  } else {
17918
- severityStyle = styles$A.indicatorGuideline;
17860
+ severityStyle = styles$B.indicatorGuideline;
17919
17861
  warningText = "Recommendation";
17920
- warningTextStyle = styles$A.warning;
17862
+ warningTextStyle = styles$B.warning;
17921
17863
  }
17922
17864
  return /*#__PURE__*/React.createElement("a", {
17923
17865
  href: `https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,
17924
17866
  target: "lint-help-window",
17925
17867
  className: css(style)
17926
17868
  }, /*#__PURE__*/React.createElement("span", {
17927
- className: css(styles$A.indicator, severityStyle)
17869
+ className: css(styles$B.indicator, severityStyle)
17928
17870
  }, this.props.severity === 1 && /*#__PURE__*/React.createElement(InlineIcon, exclamationIcon)), /*#__PURE__*/React.createElement("div", {
17929
- className: css(styles$A.tooltip, tooltipAbove && styles$A.tooltipAbove)
17871
+ className: css(styles$B.tooltip, tooltipAbove && styles$B.tooltipAbove)
17930
17872
  }, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React.createElement("p", {
17931
17873
  key: i,
17932
- className: css(styles$A.tooltipParagraph)
17874
+ className: css(styles$B.tooltipParagraph)
17933
17875
  }, /*#__PURE__*/React.createElement("span", {
17934
17876
  className: css(warningTextStyle)
17935
17877
  }, warningText, ":", " "), m)), /*#__PURE__*/React.createElement("div", {
17936
- className: css(styles$A.tail, tooltipAbove && styles$A.tailAbove)
17878
+ className: css(styles$B.tail, tooltipAbove && styles$B.tailAbove)
17937
17879
  })));
17938
17880
  };
17939
17881
  }
@@ -17971,20 +17913,20 @@ class Lint extends React.Component {
17971
17913
  }
17972
17914
  if (blockHighlight) {
17973
17915
  return /*#__PURE__*/React.createElement("span", {
17974
- className: css(styles$A.lintContainer, styles$A.lintContainerBlock)
17975
- }, this.renderLink(styles$A.radioWidgetHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
17916
+ className: css(styles$B.lintContainer, styles$B.lintContainerBlock)
17917
+ }, this.renderLink(styles$B.radioWidgetHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
17976
17918
  }
17977
17919
  if (inline) {
17978
17920
  return /*#__PURE__*/React.createElement("span", {
17979
- className: css(styles$A.lintContainer)
17980
- }, this.renderLink(styles$A.inlineHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
17921
+ className: css(styles$B.lintContainer)
17922
+ }, this.renderLink(styles$B.inlineHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
17981
17923
  }
17982
17924
  return /*#__PURE__*/React.createElement("div", {
17983
- className: css(styles$A.lintContainer)
17984
- }, this.renderLink(styles$A.hoverTarget), /*#__PURE__*/React.createElement("div", null, children));
17925
+ className: css(styles$B.lintContainer)
17926
+ }, this.renderLink(styles$B.hoverTarget), /*#__PURE__*/React.createElement("div", null, children));
17985
17927
  }
17986
17928
  }
17987
- const styles$A = StyleSheet.create({
17929
+ const styles$B = StyleSheet.create({
17988
17930
  // This is the class of the outermost element.
17989
17931
  // We use relative positioning so that the lint indicator can be
17990
17932
  // positioned absolutely relative to the position of the linty container.
@@ -19887,7 +19829,7 @@ class Renderer extends React.Component {
19887
19829
  paddingLeft: margin,
19888
19830
  paddingRight: margin
19889
19831
  };
19890
- const mobileInnerStyle = _extends({}, innerStyle, styles$z.mobileZoomableParentFix);
19832
+ const mobileInnerStyle = _extends({}, innerStyle, styles$A.mobileZoomableParentFix);
19891
19833
  return /*#__PURE__*/React.createElement("div", {
19892
19834
  key: state.key,
19893
19835
  className: "perseus-block-math",
@@ -20008,7 +19950,7 @@ class Renderer extends React.Component {
20008
19950
  paddingLeft: 0,
20009
19951
  paddingRight: 0
20010
19952
  };
20011
- const mobileInnerStyle = _extends({}, innerStyle, styles$z.mobileZoomableParentFix);
19953
+ const mobileInnerStyle = _extends({}, innerStyle, styles$A.mobileZoomableParentFix);
20012
19954
  const wrappedOutput = /*#__PURE__*/React.createElement("div", {
20013
19955
  style: _extends({}, mobileInnerStyle, {
20014
19956
  overflowX: "auto"
@@ -20655,7 +20597,7 @@ Renderer.defaultProps = {
20655
20597
  onSerializedStateUpdated: () => {},
20656
20598
  linterContext: PerseusLinter.linterContextDefault
20657
20599
  };
20658
- const styles$z = {
20600
+ const styles$A = {
20659
20601
  mobileZoomableParentFix: {
20660
20602
  // NOTE(abdul): There is an issue where transform animations will
20661
20603
  // cause the Zoomable component to disappear when running on the
@@ -21672,10 +21614,10 @@ class InputNumber extends React.Component {
21672
21614
  // Note: This is _very_ similar to what `numeric-input.jsx` does. If
21673
21615
  // you modify this, double-check if you also need to modify that
21674
21616
  // component.
21675
- const inputStyles = [styles$y.default, this.props.size === "small" ? styles$y.small : null, this.props.rightAlign ? styles$y.rightAlign : styles$y.leftAlign];
21617
+ const inputStyles = [styles$z.default, this.props.size === "small" ? styles$z.small : null, this.props.rightAlign ? styles$z.rightAlign : styles$z.leftAlign];
21676
21618
  // Unanswered
21677
21619
  if (rubric && !this.props.currentValue) {
21678
- inputStyles.push(styles$y.answerStateUnanswered);
21620
+ inputStyles.push(styles$z.answerStateUnanswered);
21679
21621
  }
21680
21622
  return /*#__PURE__*/React.createElement(InputWithExamples
21681
21623
  // eslint-disable-next-line react/no-string-refs
@@ -21760,7 +21702,7 @@ InputNumber.defaultProps = {
21760
21702
  apiOptions: ApiOptions.defaults,
21761
21703
  linterContext: linterContextDefault
21762
21704
  };
21763
- const styles$y = StyleSheet.create({
21705
+ const styles$z = StyleSheet.create({
21764
21706
  default: {
21765
21707
  width: 80,
21766
21708
  height: "auto"
@@ -22761,7 +22703,7 @@ const FocusRing = function FocusRing(props) {
22761
22703
  };
22762
22704
  return /*#__PURE__*/React.createElement("span", {
22763
22705
  "data-test-id": "focus-ring",
22764
- className: css(styles$x.ring),
22706
+ className: css(styles$y.ring),
22765
22707
  style: style
22766
22708
  }, children);
22767
22709
  };
@@ -22770,7 +22712,7 @@ FocusRing.defaultProps = {
22770
22712
  color: kaGreen$1,
22771
22713
  multipleSelect: false
22772
22714
  };
22773
- const styles$x = StyleSheet.create({
22715
+ const styles$y = StyleSheet.create({
22774
22716
  ring: {
22775
22717
  margin: "auto",
22776
22718
  display: "inline-block",
@@ -22807,7 +22749,7 @@ function getChoiceLetter(pos) {
22807
22749
  }
22808
22750
 
22809
22751
  const CHOICE_ICON_SIZE = 24;
22810
- const styles$w = StyleSheet.create({
22752
+ const styles$x = StyleSheet.create({
22811
22753
  iconWrapper: {
22812
22754
  display: "inline-block",
22813
22755
  position: "relative"
@@ -22830,7 +22772,7 @@ const CrossOutLine = function CrossOutLine(props) {
22830
22772
  width: CROSS_OUT_LINE_SIZE,
22831
22773
  height: CROSS_OUT_LINE_SIZE,
22832
22774
  viewBox: `0 0 ${CROSS_OUT_LINE_SIZE} ${CROSS_OUT_LINE_SIZE}`,
22833
- className: css(styles$v.crossOutLine),
22775
+ className: css(styles$w.crossOutLine),
22834
22776
  "data-test-id": "choice-icon__cross-out-line"
22835
22777
  }, /*#__PURE__*/React.createElement("line", {
22836
22778
  // The line stretches from the bottom-left to top-right.
@@ -22845,7 +22787,7 @@ const CrossOutLine = function CrossOutLine(props) {
22845
22787
  strokeLinecap: "round"
22846
22788
  }));
22847
22789
  };
22848
- const styles$v = StyleSheet.create({
22790
+ const styles$w = StyleSheet.create({
22849
22791
  crossOutLine: {
22850
22792
  // Center the icon within the container.
22851
22793
  position: "absolute",
@@ -22926,7 +22868,7 @@ const ChoiceIcon = function ChoiceIcon(props) {
22926
22868
  } = props;
22927
22869
  const dynamicStyles = getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, correct);
22928
22870
  return /*#__PURE__*/React.createElement("div", {
22929
- className: css(styles$w.iconWrapper)
22871
+ className: css(styles$x.iconWrapper)
22930
22872
  }, /*#__PURE__*/React.createElement(FocusRing, {
22931
22873
  color: Color.blue,
22932
22874
  visible: focused || hovered,
@@ -22935,13 +22877,13 @@ const ChoiceIcon = function ChoiceIcon(props) {
22935
22877
  // @ts-expect-error - TS2322 - Type '{ backgroundColor: string | null | undefined; borderColor: string; color: string; borderRadius: number; }' is not assignable to type 'Properties<string | number, string & {}>'.
22936
22878
  style: dynamicStyles,
22937
22879
  "data-test-id": "choice-icon__library-choice-icon",
22938
- className: css(styles$u.circle, showCorrectness && correct && styles$u.circleCorrect, showCorrectness && !correct && styles$u.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$u.circleIncorrectAnswered)
22880
+ className: css(styles$v.circle, showCorrectness && correct && styles$v.circleCorrect, showCorrectness && !correct && styles$v.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$v.circleIncorrectAnswered)
22939
22881
  // used in BaseRadio editMode to check
22940
22882
  // if we actually clicked on the radio icon
22941
22883
  ,
22942
22884
  "data-is-radio-icon": true
22943
22885
  }, /*#__PURE__*/React.createElement("div", {
22944
- className: css(styles$u.innerWrapper)
22886
+ className: css(styles$v.innerWrapper)
22945
22887
  }, /*#__PURE__*/React.createElement(ChoiceInner, {
22946
22888
  pos: pos,
22947
22889
  showCorrectness: showCorrectness,
@@ -22950,7 +22892,7 @@ const ChoiceIcon = function ChoiceIcon(props) {
22950
22892
  color: dynamicStyles.borderColor
22951
22893
  }));
22952
22894
  };
22953
- const styles$u = StyleSheet.create({
22895
+ const styles$v = StyleSheet.create({
22954
22896
  innerWrapper: {
22955
22897
  width: CHOICE_ICON_SIZE,
22956
22898
  height: CHOICE_ICON_SIZE,
@@ -23042,19 +22984,19 @@ const OptionStatus = function OptionStatus(props) {
23042
22984
  }
23043
22985
  let textStyle;
23044
22986
  if (correct) {
23045
- textStyle = styles$t.correct;
22987
+ textStyle = styles$u.correct;
23046
22988
  } else {
23047
22989
  if (checked || previouslyAnswered) {
23048
- textStyle = styles$t.incorrectAnswered;
22990
+ textStyle = styles$u.incorrectAnswered;
23049
22991
  } else {
23050
- textStyle = styles$t.incorrect;
22992
+ textStyle = styles$u.incorrect;
23051
22993
  }
23052
22994
  }
23053
22995
  return /*#__PURE__*/React.createElement("div", {
23054
- className: css(styles$t.text, textStyle)
22996
+ className: css(styles$u.text, textStyle)
23055
22997
  }, renderText(checked, correct, crossedOut));
23056
22998
  };
23057
- const styles$t = StyleSheet.create({
22999
+ const styles$u = StyleSheet.create({
23058
23000
  text: {
23059
23001
  alignItems: "center",
23060
23002
  display: "flex",
@@ -23129,8 +23071,8 @@ const Choice = function Choice(props) {
23129
23071
  crossedOut: updatedCrossedOut
23130
23072
  });
23131
23073
  }
23132
- const descriptionClassName = classNames("description", css(styles$s.description));
23133
- const rationaleClassName = classNames("perseus-radio-rationale-content", css(styles$s.rationale));
23074
+ const descriptionClassName = classNames("description", css(styles$t.description));
23075
+ const rationaleClassName = classNames("perseus-radio-rationale-content", css(styles$t.rationale));
23134
23076
 
23135
23077
  // We want to show the choices as dimmed out when the choices are disabled.
23136
23078
  // However, we don't want to do this when we're in review mode in the
@@ -23294,7 +23236,7 @@ const Choice = function Choice(props) {
23294
23236
  "data-test-id": `perseus-radio-rationale-content-${pos}`
23295
23237
  }, rationale));
23296
23238
  };
23297
- const styles$s = StyleSheet.create({
23239
+ const styles$t = StyleSheet.create({
23298
23240
  description: {
23299
23241
  display: "inline-block",
23300
23242
  width: "100%"
@@ -23486,10 +23428,10 @@ const BaseRadio = function BaseRadio(props) {
23486
23428
  const isMobile = apiOptions.isMobile;
23487
23429
  const firstChoiceHighlighted = choices[0].highlighted;
23488
23430
  const lastChoiceHighlighted = choices[choices.length - 1].highlighted;
23489
- const className = classNames("perseus-widget-radio", !editMode && "perseus-rendered-radio", css(styles$r.radio, styles$r.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$r.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$r.radioContainerLastHighlighted));
23490
- const instructionsClassName = classNames("instructions", css(styles$r.instructions, isMobile && styles$r.instructionsMobile));
23431
+ const className = classNames("perseus-widget-radio", !editMode && "perseus-rendered-radio", css(styles$s.radio, styles$s.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$s.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$s.radioContainerLastHighlighted));
23432
+ const instructionsClassName = classNames("instructions", css(styles$s.instructions, isMobile && styles$s.instructionsMobile));
23491
23433
  const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect);
23492
- const responsiveClassName = css(styles$r.responsiveFieldset);
23434
+ const responsiveClassName = css(styles$s.responsiveFieldset);
23493
23435
  const fieldset = /*#__PURE__*/React.createElement("fieldset", {
23494
23436
  className: `perseus-widget-radio-fieldset ${responsiveClassName}`
23495
23437
  }, /*#__PURE__*/React.createElement("legend", {
@@ -23540,7 +23482,7 @@ const BaseRadio = function BaseRadio(props) {
23540
23482
  const aphroditeClassName = checked => {
23541
23483
  // Whether or not to show correctness borders
23542
23484
  // for this choice and the next choice.
23543
- return css(sharedStyles.aboveScratchpad, styles$r.item, styles$r.responsiveItem, checked && styles$r.selectedItem, checked && choice.highlighted && styles$r.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$r.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$r.nextHighlighted);
23485
+ return css(sharedStyles.aboveScratchpad, styles$s.item, styles$s.responsiveItem, checked && styles$s.selectedItem, checked && choice.highlighted && styles$s.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$s.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$s.nextHighlighted);
23544
23486
  };
23545
23487
 
23546
23488
  // HACK(abdulrahman): Preloads the selection-state
@@ -23614,14 +23556,14 @@ const BaseRadio = function BaseRadio(props) {
23614
23556
  // Allow for horizontal scrolling if content is too wide, which may be
23615
23557
  // an issue especially on phones.
23616
23558
  return /*#__PURE__*/React.createElement("div", {
23617
- className: css(styles$r.responsiveContainer)
23559
+ className: css(styles$s.responsiveContainer)
23618
23560
  }, fieldset);
23619
23561
  };
23620
23562
  BaseRadio.defaultProps = {
23621
23563
  editMode: false,
23622
23564
  multipleSelect: false
23623
23565
  };
23624
- const styles$r = StyleSheet.create({
23566
+ const styles$s = StyleSheet.create({
23625
23567
  instructions: {
23626
23568
  display: "block",
23627
23569
  color: gray17,
@@ -24269,9 +24211,9 @@ class Categorizer extends React.Component {
24269
24211
  indexedItems = Util.shuffle(indexedItems, this.props.problemNum);
24270
24212
  }
24271
24213
  const table = /*#__PURE__*/React.createElement("table", {
24272
- className: "categorizer-table " + css(styles$q.mobileTable)
24214
+ className: "categorizer-table " + css(styles$r.mobileTable)
24273
24215
  }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
24274
- className: css(styles$q.emptyHeaderCell)
24216
+ className: css(styles$r.emptyHeaderCell)
24275
24217
  }), this.props.categories.map((category, i) => {
24276
24218
  // Array index is the correct key here, as that's
24277
24219
  // how category grading actually works -- no way
@@ -24279,7 +24221,7 @@ class Categorizer extends React.Component {
24279
24221
  // middle. (If we later add that, this should be
24280
24222
  // fixed.)
24281
24223
  return /*#__PURE__*/React.createElement("th", {
24282
- className: css(styles$q.header),
24224
+ className: css(styles$r.header),
24283
24225
  key: i
24284
24226
  }, /*#__PURE__*/React.createElement(Renderer, {
24285
24227
  content: category,
@@ -24299,7 +24241,7 @@ class Categorizer extends React.Component {
24299
24241
  })), self.props.categories.map((catName, catNum) => {
24300
24242
  const selected = self.props.values[itemNum] === catNum;
24301
24243
  return /*#__PURE__*/React.createElement("td", {
24302
- className: "category " + css(styles$q.cell),
24244
+ className: "category " + css(styles$r.cell),
24303
24245
  key: catNum
24304
24246
  }, /*#__PURE__*/React.createElement("div", {
24305
24247
  className: ClassNames.INTERACTIVE,
@@ -24318,7 +24260,7 @@ class Categorizer extends React.Component {
24318
24260
  onChange: this.onChange.bind(this, itemNum, catNum),
24319
24261
  onClick: e => e.stopPropagation()
24320
24262
  }), !isMobile && /*#__PURE__*/React.createElement("span", {
24321
- className: css(styles$q.radioSpan, selected && styles$q.checkedRadioSpan, this.props.static && selected && styles$q.staticCheckedRadioSpan)
24263
+ className: css(styles$r.radioSpan, selected && styles$r.checkedRadioSpan, this.props.static && selected && styles$r.staticCheckedRadioSpan)
24322
24264
  }, selected ? /*#__PURE__*/React.createElement(InlineIcon, iconCircle) : /*#__PURE__*/React.createElement(InlineIcon, iconCircleThin))));
24323
24265
  }));
24324
24266
  /* eslint-enable max-len */
@@ -24330,7 +24272,7 @@ class Categorizer extends React.Component {
24330
24272
  "categorizer-container": true,
24331
24273
  "static-mode": this.props.static
24332
24274
  });
24333
- const inlineStyles = this.props.apiOptions.isMobile ? [styles$q.fullBleedContainer] : [];
24275
+ const inlineStyles = this.props.apiOptions.isMobile ? [styles$r.fullBleedContainer] : [];
24334
24276
  return /*#__PURE__*/React.createElement("div", {
24335
24277
  className: extraClassNames + " " + css(...inlineStyles)
24336
24278
  }, table);
@@ -24375,7 +24317,7 @@ const pageMargin = 16;
24375
24317
 
24376
24318
  // Stylesheets aren't directly testable
24377
24319
  /* c8 ignore next */
24378
- const styles$q = StyleSheet.create({
24320
+ const styles$r = StyleSheet.create({
24379
24321
  mobileTable: {
24380
24322
  [mediaQueries.smOrSmaller]: {
24381
24323
  minWidth: "auto"
@@ -24482,7 +24424,7 @@ const toAbsoluteUrl = url => parseUrl(url).href;
24482
24424
  const {
24483
24425
  updateQueryString: updateQueryString$1
24484
24426
  } = Util;
24485
- function getUrlFromProgramID(programID) {
24427
+ function getUrlFromProgramID$1(programID) {
24486
24428
  const {
24487
24429
  InitialRequestUrl
24488
24430
  } = getDependencies();
@@ -24567,7 +24509,7 @@ class CSProgram extends React.Component {
24567
24509
  return /*#__PURE__*/React.createElement("div", null);
24568
24510
  }
24569
24511
  let styleContainer = false;
24570
- let url = getUrlFromProgramID(this.props.programID);
24512
+ let url = getUrlFromProgramID$1(this.props.programID);
24571
24513
  let className;
24572
24514
  const style = {
24573
24515
  height: this.props.height,
@@ -24611,7 +24553,7 @@ class CSProgram extends React.Component {
24611
24553
  // creator "went wild".
24612
24554
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
24613
24555
  return /*#__PURE__*/React.createElement("div", {
24614
- className: css(styles$p.widthOverride, styleContainer && styles$p.container)
24556
+ className: css(styles$q.widthOverride, styleContainer && styles$q.container)
24615
24557
  }, /*#__PURE__*/React.createElement("iframe", {
24616
24558
  sandbox: sandboxOptions,
24617
24559
  src: url,
@@ -24640,7 +24582,7 @@ CSProgram.defaultProps = {
24640
24582
  // optional message
24641
24583
  message: null
24642
24584
  };
24643
- const styles$p = StyleSheet.create({
24585
+ const styles$q = StyleSheet.create({
24644
24586
  // Override the inherited width from the perseus paragraph class
24645
24587
  // 820 is minimum width for 420px editor and 400px canvas
24646
24588
  widthOverride: {
@@ -24685,7 +24627,7 @@ class Definition extends React.Component {
24685
24627
  }) => /*#__PURE__*/React.createElement(Popover, {
24686
24628
  content: /*#__PURE__*/React.createElement(PopoverContentCore, {
24687
24629
  color: "white",
24688
- style: styles$o.tooltipBody,
24630
+ style: styles$p.tooltipBody,
24689
24631
  closeButtonVisible: true
24690
24632
  }, /*#__PURE__*/React.createElement(Renderer, {
24691
24633
  apiOptions: this.props.apiOptions,
@@ -24716,7 +24658,7 @@ Definition.defaultProps = {
24716
24658
  togglePrompt: "define me",
24717
24659
  definition: "definition goes here"
24718
24660
  };
24719
- const styles$o = {
24661
+ const styles$p = {
24720
24662
  tooltipBody: {
24721
24663
  color: Color.offBlack,
24722
24664
  fontSize: 20,
@@ -24922,15 +24864,15 @@ class Explanation extends React.Component {
24922
24864
  const onClick = this._onClick;
24923
24865
  if (isMobile) {
24924
24866
  linkContainer = /*#__PURE__*/React.createElement("div", {
24925
- className: css(styles$n.linkContainer)
24867
+ className: css(styles$o.linkContainer)
24926
24868
  }, /*#__PURE__*/React.createElement("a", {
24927
- className: css(styles$n.mobileExplanationLink),
24869
+ className: css(styles$o.mobileExplanationLink),
24928
24870
  href: href,
24929
24871
  onClick: onClick,
24930
24872
  role: "button",
24931
24873
  "aria-expanded": this.state.expanded
24932
24874
  }, linkAnchor), this.state.expanded && /*#__PURE__*/React.createElement("svg", {
24933
- className: css(styles$n.disclosureArrow)
24875
+ className: css(styles$o.disclosureArrow)
24934
24876
  }, /*#__PURE__*/React.createElement("polygon", {
24935
24877
  style: {
24936
24878
  fill: backgroundColor
@@ -24943,13 +24885,13 @@ class Explanation extends React.Component {
24943
24885
  // an anchor tag (if rendered in a modal) or a Wonder Blocks
24944
24886
  // link component in lesson page, see: `article-page.jsx`.
24945
24887
  linkContainer = /*#__PURE__*/React.createElement("div", {
24946
- className: css(styles$n.linkContainer, styles$n.articleLink)
24888
+ className: css(styles$o.linkContainer, styles$o.articleLink)
24947
24889
  }, /*#__PURE__*/React.createElement(Link, {
24948
- className: css(styles$n.explanationLink)
24890
+ className: css(styles$o.explanationLink)
24949
24891
  // HACK(michaelpolyak): WB Link doesn't passthrough
24950
24892
  // class name.
24951
24893
  ,
24952
- style: styles$n.explanationLink,
24894
+ style: styles$o.explanationLink,
24953
24895
  href: href,
24954
24896
  onClick: onClick,
24955
24897
  role: "button",
@@ -24959,9 +24901,9 @@ class Explanation extends React.Component {
24959
24901
  // NOTE: For exercises, the baseElements `Link` is an
24960
24902
  // anchor tag, see: `perseus-api.jsx`.
24961
24903
  linkContainer = /*#__PURE__*/React.createElement("div", {
24962
- className: css(styles$n.linkContainer, styles$n.exerciseLink)
24904
+ className: css(styles$o.linkContainer, styles$o.exerciseLink)
24963
24905
  }, /*#__PURE__*/React.createElement(Link, {
24964
- className: css(styles$n.explanationLink),
24906
+ className: css(styles$o.explanationLink),
24965
24907
  href: href,
24966
24908
  onClick: onClick,
24967
24909
  role: "button",
@@ -24969,11 +24911,11 @@ class Explanation extends React.Component {
24969
24911
  }, `[${linkAnchor}]`));
24970
24912
  }
24971
24913
  }
24972
- const expandedStyle = isMobile ? styles$n.contentExpandedMobile : styles$n.contentExpanded;
24914
+ const expandedStyle = isMobile ? styles$o.contentExpandedMobile : styles$o.contentExpanded;
24973
24915
  return /*#__PURE__*/React.createElement("div", {
24974
- className: css(styles$n.container)
24916
+ className: css(styles$o.container)
24975
24917
  }, linkContainer, this.state.expanded && /*#__PURE__*/React.createElement("div", {
24976
- className: css(styles$n.content, isMobile && styles$n.contentMobile, this.state.expanded && expandedStyle)
24918
+ className: css(styles$o.content, isMobile && styles$o.contentMobile, this.state.expanded && expandedStyle)
24977
24919
  // eslint-disable-next-line react/no-string-refs
24978
24920
  ,
24979
24921
  ref: "content"
@@ -24997,7 +24939,7 @@ const verticalContentPadding = 10;
24997
24939
  const arrowWidth = 30;
24998
24940
  const arrowHeight = 14;
24999
24941
  const backgroundColor = gray95;
25000
- const styles$n = StyleSheet.create({
24942
+ const styles$o = StyleSheet.create({
25001
24943
  container: {
25002
24944
  display: "inline",
25003
24945
  position: "relative"
@@ -25102,15 +25044,15 @@ class GradedGroupAnswerBar extends React.Component {
25102
25044
  onCheckAnswer,
25103
25045
  onNextQuestion
25104
25046
  } = this.props;
25105
- const answerBarStyle = _extends({}, styles$m.answerBar, {
25047
+ const answerBarStyle = _extends({}, styles$n.answerBar, {
25106
25048
  backgroundColor: answerBarState === "CORRECT" ? Color.offWhite : "white",
25107
25049
  // Center the "Correct!" message only when there's no next question
25108
25050
  justifyContent: answerBarState === "CORRECT" && !onNextQuestion ? "center" : "space-between"
25109
25051
  });
25110
25052
  const message = answerBarState === "INCORRECT" ? /*#__PURE__*/React.createElement("span", {
25111
- style: styles$m.text
25053
+ style: styles$n.text
25112
25054
  }, /*#__PURE__*/React.createElement("span", {
25113
- style: styles$m.tryAgainIcon
25055
+ style: styles$n.tryAgainIcon
25114
25056
  }, /*#__PURE__*/React.createElement(InlineIcon, iconTryAgain)), /*#__PURE__*/React.createElement("span", {
25115
25057
  style: {
25116
25058
  marginLeft: 8
@@ -25129,7 +25071,7 @@ class GradedGroupAnswerBar extends React.Component {
25129
25071
  return /*#__PURE__*/React.createElement("div", {
25130
25072
  style: answerBarStyle
25131
25073
  }, /*#__PURE__*/React.createElement("span", {
25132
- style: styles$m.text
25074
+ style: styles$n.text
25133
25075
  }, /*#__PURE__*/React.createElement("span", {
25134
25076
  style: {
25135
25077
  fontSize: 28,
@@ -25151,7 +25093,7 @@ class GradedGroupAnswerBar extends React.Component {
25151
25093
  }
25152
25094
  }
25153
25095
  const fontSize = 17;
25154
- const styles$m = {
25096
+ const styles$n = {
25155
25097
  answerBar: {
25156
25098
  display: "flex",
25157
25099
  alignItems: "center",
@@ -25337,7 +25279,7 @@ class GradedGroup extends React.Component {
25337
25279
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
25338
25280
  gradeStatus = i18n._("Incorrect");
25339
25281
  }
25340
- const mobileClass = this.props.inGradedGroupSet ? css(styles$l.gradedGroupInSet) : css(styles$l.gradedGroup);
25282
+ const mobileClass = this.props.inGradedGroupSet ? css(styles$m.gradedGroupInSet) : css(styles$m.gradedGroup);
25341
25283
  const classes = classNames({
25342
25284
  [mobileClass]: apiOptions.isMobile,
25343
25285
  "perseus-graded-group": true,
@@ -25356,7 +25298,7 @@ class GradedGroup extends React.Component {
25356
25298
  return /*#__PURE__*/React.createElement("div", {
25357
25299
  className: classes
25358
25300
  }, !!this.props.title && /*#__PURE__*/React.createElement("div", {
25359
- className: css(styles$l.title)
25301
+ className: css(styles$m.title)
25360
25302
  }, this.props.title), /*#__PURE__*/React.createElement(Renderer, _extends({}, this.props, {
25361
25303
  // eslint-disable-next-line react/no-string-refs
25362
25304
  ref: "renderer",
@@ -25388,7 +25330,7 @@ class GradedGroup extends React.Component {
25388
25330
  }, i18n._("Next question")), this.props.hint && this.props.hint.content && (this.state.showHint ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("button", {
25389
25331
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
25390
25332
  tabIndex: "0",
25391
- className: css(styles$l.explanationTitle),
25333
+ className: css(styles$m.explanationTitle),
25392
25334
  onClick: () => this.setState({
25393
25335
  showHint: false
25394
25336
  }),
@@ -25420,7 +25362,7 @@ class GradedGroup extends React.Component {
25420
25362
  showHint: true
25421
25363
  });
25422
25364
  },
25423
- className: css(styles$l.showHintLink)
25365
+ className: css(styles$m.showHintLink)
25424
25366
  }, i18n._("Explain"))), apiOptions.isMobile && answerBarState !== "HIDDEN" && /*#__PURE__*/React.createElement(GradedGroupAnswerBar, {
25425
25367
  apiOptions: apiOptions,
25426
25368
  answerBarState: answerBarState,
@@ -25441,7 +25383,7 @@ GradedGroup.defaultProps = {
25441
25383
  const traverseChildWidgets$3 = function traverseChildWidgets(props, traverseRenderer) {
25442
25384
  return _.extend({}, props, traverseRenderer(props));
25443
25385
  };
25444
- const styles$l = StyleSheet.create({
25386
+ const styles$m = StyleSheet.create({
25445
25387
  gradedGroupInSet: {
25446
25388
  // Reset a few desktop-only styles that come from graded-group.less
25447
25389
  marginLeft: 0,
@@ -25514,18 +25456,18 @@ class Indicators extends React.Component {
25514
25456
  return /*#__PURE__*/React.createElement("ul", {
25515
25457
  // reduntantly add class name for use in .less files--
25516
25458
  // the styles object key gets hashed
25517
- className: classNames(css(styles$k.indicatorContainer), "indicatorContainer")
25459
+ className: classNames(css(styles$l.indicatorContainer), "indicatorContainer")
25518
25460
  }, this.props.gradedGroups.map(({
25519
25461
  title
25520
25462
  }, i) => /*#__PURE__*/React.createElement("li", {
25521
- className: css(styles$k.indicator),
25463
+ className: css(styles$l.indicator),
25522
25464
  key: title
25523
25465
  }, /*#__PURE__*/React.createElement(Clickable, {
25524
25466
  role: "button",
25525
25467
  "aria-label": i18n._("Skip to %(title)s", {
25526
25468
  title
25527
25469
  }),
25528
- style: styles$k.indicatorButton,
25470
+ style: styles$l.indicatorButton,
25529
25471
  onClick: () => this.props.onChangeCurrentGroup(i),
25530
25472
  onKeyDown: e => this.handleKeyDown(e, i)
25531
25473
  }, ({
@@ -25533,9 +25475,9 @@ class Indicators extends React.Component {
25533
25475
  focused,
25534
25476
  pressed
25535
25477
  }) => /*#__PURE__*/React.createElement(View, {
25536
- style: [styles$k.indicatorDot, (hovered || focused || pressed) && styles$k.indicatorDotFocused]
25478
+ style: [styles$l.indicatorDot, (hovered || focused || pressed) && styles$l.indicatorDotFocused]
25537
25479
  }, i === this.props.currentGroup && /*#__PURE__*/React.createElement(View, {
25538
- style: styles$k.indicatorDotActive
25480
+ style: styles$l.indicatorDotActive
25539
25481
  }, /*#__PURE__*/React.createElement("span", {
25540
25482
  className: css(a11y.srOnly)
25541
25483
  }, i18n._("Current"))))))));
@@ -25601,7 +25543,7 @@ class GradedGroupSet extends React.Component {
25601
25543
  } = getDependencies();
25602
25544
  if (JIPT.useJIPT && this.props.gradedGroups.length > 1) {
25603
25545
  return /*#__PURE__*/React.createElement("div", {
25604
- className: css(styles$k.container)
25546
+ className: css(styles$l.container)
25605
25547
  }, this.props.gradedGroups.map((gradedGroup, i) => {
25606
25548
  return (
25607
25549
  /*#__PURE__*/
@@ -25624,13 +25566,13 @@ class GradedGroupSet extends React.Component {
25624
25566
  const numGroups = this.props.gradedGroups.length;
25625
25567
  const handleNextQuestion = this.state.currentGroup < numGroups - 1 ? this.handleNextQuestion : null;
25626
25568
  return /*#__PURE__*/React.createElement("div", {
25627
- className: css(styles$k.container)
25569
+ className: css(styles$l.container)
25628
25570
  }, /*#__PURE__*/React.createElement("div", {
25629
- className: css(styles$k.top)
25571
+ className: css(styles$l.top)
25630
25572
  }, /*#__PURE__*/React.createElement("div", {
25631
- className: css(styles$k.title)
25573
+ className: css(styles$l.title)
25632
25574
  }, currentGroup.title), /*#__PURE__*/React.createElement("div", {
25633
- className: css(styles$k.spacer)
25575
+ className: css(styles$l.spacer)
25634
25576
  }), /*#__PURE__*/React.createElement(Indicators, {
25635
25577
  currentGroup: this.state.currentGroup,
25636
25578
  gradedGroups: this.props.gradedGroups,
@@ -25672,7 +25614,7 @@ var GradedGroupSet$1 = {
25672
25614
  tracking: "all",
25673
25615
  isLintable: true
25674
25616
  };
25675
- const styles$k = StyleSheet.create({
25617
+ const styles$l = StyleSheet.create({
25676
25618
  top: {
25677
25619
  display: "flex",
25678
25620
  flexDirection: "row"
@@ -25777,7 +25719,7 @@ class ButtonGroup extends React.Component {
25777
25719
  id: "" + i,
25778
25720
  ref: "button" + i,
25779
25721
  key: "" + i,
25780
- className: css(styles$j.buttonStyle, button.value === value && styles$j.selectedStyle),
25722
+ className: css(styles$k.buttonStyle, button.value === value && styles$k.selectedStyle),
25781
25723
  onClick: () => this.toggleSelect(button.value)
25782
25724
  }, button.content || "" + button.value);
25783
25725
  });
@@ -25794,7 +25736,7 @@ ButtonGroup.defaultProps = {
25794
25736
  value: null,
25795
25737
  allowEmpty: true
25796
25738
  };
25797
- const styles$j = StyleSheet.create({
25739
+ const styles$k = StyleSheet.create({
25798
25740
  buttonStyle: {
25799
25741
  backgroundColor: "white",
25800
25742
  border: "1px solid #ccc",
@@ -31078,7 +31020,7 @@ const HideAnswersToggle = props => {
31078
31020
  const switchId = idFactory.get("hide-answers-toggle");
31079
31021
  const labelId = idFactory.get("hide-answers-label");
31080
31022
  return /*#__PURE__*/React.createElement(View, {
31081
- style: styles$i.switchWrapper
31023
+ style: styles$j.switchWrapper
31082
31024
  }, /*#__PURE__*/React.createElement(Switch, {
31083
31025
  id: switchId,
31084
31026
  checked: props.areAnswersHidden,
@@ -31090,7 +31032,7 @@ const HideAnswersToggle = props => {
31090
31032
  tag: "label"
31091
31033
  }, strings.hideAnswersToggleLabel));
31092
31034
  };
31093
- const styles$i = StyleSheet.create({
31035
+ const styles$j = StyleSheet.create({
31094
31036
  switchWrapper: {
31095
31037
  display: "flex",
31096
31038
  flexDirection: "row",
@@ -31143,13 +31085,13 @@ const AnswerPill = props => {
31143
31085
  id: idFactory.get("perseus-label-image-widget-answer-pill"),
31144
31086
  onClick: correct ? undefined : onClick,
31145
31087
  ref: ref,
31146
- style: [style, popperStyle, styles$h.pill, correct && styles$h.correct, incorrect && styles$h.incorrect, (focused || hovered) && BringToFront]
31088
+ style: [style, popperStyle, styles$i.pill, correct && styles$i.correct, incorrect && styles$i.incorrect, (focused || hovered) && BringToFront]
31147
31089
  }, /*#__PURE__*/React.createElement(Renderer, {
31148
31090
  content: answerString,
31149
31091
  inline: true
31150
31092
  })));
31151
31093
  };
31152
- const styles$h = StyleSheet.create({
31094
+ const styles$i = StyleSheet.create({
31153
31095
  correct: {
31154
31096
  // WB green darkened by 18%
31155
31097
  backgroundColor: "#00880b"
@@ -31202,23 +31144,23 @@ class Marker extends React.Component {
31202
31144
  icon: iconNull
31203
31145
  };
31204
31146
  if (showCorrectness) {
31205
- iconStyles = [styles$g.markerGraded, showCorrectness === "correct" ? styles$g.markerCorrect : styles$g.markerIncorrect, isOpen && styles$g.markerSelected];
31147
+ iconStyles = [styles$h.markerGraded, showCorrectness === "correct" ? styles$h.markerCorrect : styles$h.markerIncorrect, isOpen && styles$h.markerSelected];
31206
31148
  args = _extends({}, args, {
31207
31149
  icon: showCorrectness === "correct" ? iconCheck : iconMinus
31208
31150
  });
31209
31151
  } else if (selectedAnswers && selectedAnswers.length > 0) {
31210
- iconStyles = [styles$g.markerFilled, isOpen && styles$g.markerSelected];
31152
+ iconStyles = [styles$h.markerFilled, isOpen && styles$h.markerSelected];
31211
31153
  } else if (isOpen) {
31212
- iconStyles = [styles$g.markerSelected];
31154
+ iconStyles = [styles$h.markerSelected];
31213
31155
  args = _extends({}, args, {
31214
31156
  icon: iconChevronDown,
31215
31157
  size: 8
31216
31158
  });
31217
31159
  } else if (showPulsate) {
31218
- iconStyles = [styles$g.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$g.markerUnfilledPulsateOnce : showPulsate && styles$g.markerUnfilledPulsateInfinite];
31160
+ iconStyles = [styles$h.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$h.markerUnfilledPulsateOnce : showPulsate && styles$h.markerUnfilledPulsateInfinite];
31219
31161
  }
31220
31162
  return /*#__PURE__*/React.createElement(View, {
31221
- style: [styles$g.markerIcon, iconStyles],
31163
+ style: [styles$h.markerIcon, iconStyles],
31222
31164
  ref: node => this._icon = node
31223
31165
  }, /*#__PURE__*/React.createElement(Icon, args));
31224
31166
  }
@@ -31240,7 +31182,7 @@ class Marker extends React.Component {
31240
31182
  const markerDisabled = showCorrectness === "correct";
31241
31183
  const active = hovered || focused;
31242
31184
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, {
31243
- style: [styles$g.marker, active && !markerDisabled && styles$g.markerActive]
31185
+ style: [styles$h.marker, active && !markerDisabled && styles$h.markerActive]
31244
31186
  // already translated in: /widgets/graded-group.tsx
31245
31187
  ,
31246
31188
  "aria-label": markerDisabled ? i18n._("Correct!") : label
@@ -31258,7 +31200,7 @@ class Marker extends React.Component {
31258
31200
  Marker.defaultProps = {
31259
31201
  selected: []
31260
31202
  };
31261
- const styles$g = StyleSheet.create({
31203
+ const styles$h = StyleSheet.create({
31262
31204
  marker: {
31263
31205
  position: "absolute",
31264
31206
  backgroundColor: Color.white,
@@ -31828,13 +31770,13 @@ class LabelImage extends React.Component {
31828
31770
  const promptString = isMobile ? multipleAnswers ? i18n._("Tap each dot on the image to select all answers that apply.") : i18n._("Tap each dot on the image to select an answer.") : multipleAnswers ? i18n._("Click each dot on the image to select all answers that apply.") : i18n._("Click each dot on the image to select an answer.");
31829
31771
  const choicesString = i18n._("Choices:");
31830
31772
  return /*#__PURE__*/React.createElement("div", {
31831
- className: classNames("perseus-label-image-widget-instructions", css(styles$f.instructions))
31773
+ className: classNames("perseus-label-image-widget-instructions", css(styles$g.instructions))
31832
31774
  }, /*#__PURE__*/React.createElement("div", {
31833
- className: css(styles$f.instructionsCaption)
31775
+ className: css(styles$g.instructionsCaption)
31834
31776
  }, promptString, " ", !hideChoices && choicesString), !hideChoices && /*#__PURE__*/React.createElement("div", {
31835
- className: css(styles$f.instructionsChoices)
31777
+ className: css(styles$g.instructionsChoices)
31836
31778
  }, choices.map((choice, index) => /*#__PURE__*/React.createElement("div", {
31837
- className: css(styles$f.instructionsChoice),
31779
+ className: css(styles$g.instructionsChoice),
31838
31780
  key: index
31839
31781
  }, /*#__PURE__*/React.createElement(Renderer, {
31840
31782
  content: choice
@@ -31851,20 +31793,20 @@ class LabelImage extends React.Component {
31851
31793
  activeMarkerIndex
31852
31794
  } = this.state;
31853
31795
  return /*#__PURE__*/React.createElement("div", null, this.renderInstructions(), /*#__PURE__*/React.createElement("div", {
31854
- className: css(styles$f.markersCanvas),
31796
+ className: css(styles$g.markersCanvas),
31855
31797
  style: {
31856
31798
  maxWidth: imageWidth,
31857
31799
  maxHeight: imageHeight
31858
31800
  }
31859
31801
  }, /*#__PURE__*/React.createElement("div", {
31860
- className: css(styles$f.imageContainer,
31802
+ className: css(styles$g.imageContainer,
31861
31803
  // Ensure image interaction is disabled while answer
31862
31804
  // choices popup is visible. This addresses specific
31863
31805
  // case where user may click on question image to
31864
31806
  // dismiss the popup. If the image is larger in size
31865
31807
  // than its rendered in the widget, this would
31866
31808
  // result in a zoom of the image.
31867
- activeMarkerIndex !== -1 && styles$f.imageInteractionDisabled)
31809
+ activeMarkerIndex !== -1 && styles$g.imageInteractionDisabled)
31868
31810
  }, /*#__PURE__*/React.createElement(context$1.Consumer, null, ({
31869
31811
  setAssetStatus
31870
31812
  }) => /*#__PURE__*/React.createElement(SvgImage, {
@@ -31888,7 +31830,7 @@ class LabelImage extends React.Component {
31888
31830
  }));
31889
31831
  }
31890
31832
  }
31891
- const styles$f = StyleSheet.create({
31833
+ const styles$g = StyleSheet.create({
31892
31834
  instructions: {
31893
31835
  paddingBottom: 16
31894
31836
  },
@@ -32245,7 +32187,7 @@ class Placeholder extends React.Component {
32245
32187
  const {
32246
32188
  layout
32247
32189
  } = this.props;
32248
- const className = css(styles$e.card, styles$e.placeholder, layout === Layout.HORIZONTAL && styles$e.horizontalCard);
32190
+ const className = css(styles$f.card, styles$f.placeholder, layout === Layout.HORIZONTAL && styles$f.horizontalCard);
32249
32191
  const style = {
32250
32192
  width: this.props.width,
32251
32193
  height: this.props.height
@@ -32428,7 +32370,7 @@ class Draggable extends React.Component {
32428
32370
  // We need to keep backwards compatbility with rules specified directly
32429
32371
  // in CSS. Hence the hacky tacking on of manual classNames.
32430
32372
  // See sortable.less for details.
32431
- let className = css(styles$e.card, styles$e.draggable, layout === Layout.HORIZONTAL && styles$e.horizontalCard, layout === Layout.VERTICAL && styles$e.verticalCard, type === ItemState.DRAGGING && styles$e.dragging, type === ItemState.DISABLED && styles$e.disabled, !includePadding && styles$e.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
32373
+ let className = css(styles$f.card, styles$f.draggable, layout === Layout.HORIZONTAL && styles$f.horizontalCard, layout === Layout.VERTICAL && styles$f.verticalCard, type === ItemState.DRAGGING && styles$f.dragging, type === ItemState.DISABLED && styles$f.disabled, !includePadding && styles$f.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
32432
32374
  if (!includePadding) {
32433
32375
  className += " perseus-sortable-draggable-unpadded";
32434
32376
  }
@@ -32635,7 +32577,7 @@ class Sortable extends React.Component {
32635
32577
  } = this.props;
32636
32578
  // We need to keep backwards compatbility with rules specified directly
32637
32579
  // in CSS. See sortable.less for details.
32638
- const className = css(styles$e.sortable) + " perseus-sortable";
32580
+ const className = css(styles$f.sortable) + " perseus-sortable";
32639
32581
  const syncWidth = ((_this$props$constrain = this.props.constraints) == null ? void 0 : _this$props$constrain.width) || layout === Layout.VERTICAL;
32640
32582
  const syncHeight = ((_this$props$constrain2 = this.props.constraints) == null ? void 0 : _this$props$constrain2.height) || layout === Layout.HORIZONTAL;
32641
32583
  _.each(this.state.items, function (item, i, items) {
@@ -32877,7 +32819,7 @@ Sortable.defaultProps = {
32877
32819
  linterContext: PerseusLinter.linterContextDefault,
32878
32820
  waitForTexRendererToLoad: true
32879
32821
  };
32880
- const styles$e = StyleSheet.create({
32822
+ const styles$f = StyleSheet.create({
32881
32823
  sortable: {
32882
32824
  boxSizing: "border-box",
32883
32825
  float: "left",
@@ -33039,23 +32981,23 @@ class Matcher extends React.Component {
33039
32981
  };
33040
32982
  const cellMarginPx = this.props.apiOptions.isMobile ? 8 : 5;
33041
32983
  return /*#__PURE__*/React.createElement("table", {
33042
- className: css(styles$d.widget) + " " + HACKY_CSS_CLASSNAME
32984
+ className: css(styles$e.widget) + " " + HACKY_CSS_CLASSNAME
33043
32985
  }, /*#__PURE__*/React.createElement("tbody", null, showLabels && /*#__PURE__*/React.createElement("tr", {
33044
- className: css(styles$d.row)
32986
+ className: css(styles$e.row)
33045
32987
  }, /*#__PURE__*/React.createElement("th", {
33046
- className: css(styles$d.column, styles$d.columnLabel)
32988
+ className: css(styles$e.column, styles$e.columnLabel)
33047
32989
  }, /*#__PURE__*/React.createElement(Renderer, {
33048
32990
  content: this.props.labels[0] || "...",
33049
32991
  linterContext: this.props.linterContext
33050
32992
  })), /*#__PURE__*/React.createElement("th", {
33051
- className: css(styles$d.column, styles$d.columnRight, styles$d.columnLabel)
32993
+ className: css(styles$e.column, styles$e.columnRight, styles$e.columnLabel)
33052
32994
  }, /*#__PURE__*/React.createElement(Renderer, {
33053
32995
  content: this.props.labels[1] || "...",
33054
32996
  linterContext: this.props.linterContext
33055
32997
  }))), /*#__PURE__*/React.createElement("tr", {
33056
- className: css(styles$d.row)
32998
+ className: css(styles$e.row)
33057
32999
  }, /*#__PURE__*/React.createElement("td", {
33058
- className: css(styles$d.column)
33000
+ className: css(styles$e.column)
33059
33001
  }, /*#__PURE__*/React.createElement(Sortable, {
33060
33002
  options: left,
33061
33003
  layout: Layout.VERTICAL,
@@ -33070,7 +33012,7 @@ class Matcher extends React.Component {
33070
33012
  ,
33071
33013
  ref: "left"
33072
33014
  })), /*#__PURE__*/React.createElement("td", {
33073
- className: css(styles$d.column, styles$d.columnRight)
33015
+ className: css(styles$e.column, styles$e.columnRight)
33074
33016
  }, /*#__PURE__*/React.createElement(Sortable
33075
33017
  // @ts-expect-error - TS2322 - Type 'readonly unknown[]' is not assignable to type 'readonly string[]'.
33076
33018
  , {
@@ -33123,7 +33065,7 @@ _.extend(Matcher, {
33123
33065
  });
33124
33066
  const padding = 5;
33125
33067
  const border = "1px solid #444";
33126
- const styles$d = StyleSheet.create({
33068
+ const styles$e = StyleSheet.create({
33127
33069
  widget: {
33128
33070
  paddingTop: padding,
33129
33071
  maxWidth: "100%",
@@ -33990,9 +33932,9 @@ function drawText(ctx, item) {
33990
33932
  if (item.value === null) {
33991
33933
  return;
33992
33934
  }
33993
- ctx.fillStyle = styles$c.fgColor;
33994
- ctx.font = styles$c.font;
33995
- ctx.fillText(item.value, item.pos[0] - styles$c.fontSizePx / 2 + 1, item.pos[1] + styles$c.fontSizePx / 2);
33935
+ ctx.fillStyle = styles$d.fgColor;
33936
+ ctx.font = styles$d.font;
33937
+ ctx.fillText(item.value, item.pos[0] - styles$d.fontSizePx / 2 + 1, item.pos[1] + styles$d.fontSizePx / 2);
33996
33938
  }
33997
33939
 
33998
33940
  /**
@@ -34013,16 +33955,16 @@ function drawText(ctx, item) {
34013
33955
  function drawDoubleLine(ctx, item) {
34014
33956
  // Outer line that forms both of the bond lines.
34015
33957
  let path = new Path2D();
34016
- ctx.lineWidth = 5 * styles$c.lineWidth;
34017
- ctx.strokeStyle = styles$c.fgColor;
33958
+ ctx.lineWidth = 5 * styles$d.lineWidth;
33959
+ ctx.strokeStyle = styles$d.fgColor;
34018
33960
  path.moveTo(item.startPos[0], item.startPos[1]);
34019
33961
  path.lineTo(item.endPos[0], item.endPos[1]);
34020
33962
  ctx.stroke(path);
34021
33963
 
34022
33964
  // Inner white line that separates the two bond lines.
34023
33965
  path = new Path2D();
34024
- ctx.lineWidth = 3 * styles$c.lineWidth;
34025
- ctx.strokeStyle = styles$c.bgColor;
33966
+ ctx.lineWidth = 3 * styles$d.lineWidth;
33967
+ ctx.strokeStyle = styles$d.bgColor;
34026
33968
  path.moveTo(item.startPos[0], item.startPos[1]);
34027
33969
  path.lineTo(item.endPos[0], item.endPos[1]);
34028
33970
  ctx.stroke(path);
@@ -34049,16 +33991,16 @@ function drawTripleLine(ctx, item) {
34049
33991
 
34050
33992
  // Outer line that will form the two outer bond lines.
34051
33993
  let path = new Path2D();
34052
- ctx.lineWidth = 7 * styles$c.lineWidth;
34053
- ctx.strokeStyle = styles$c.fgColor;
33994
+ ctx.lineWidth = 7 * styles$d.lineWidth;
33995
+ ctx.strokeStyle = styles$d.fgColor;
34054
33996
  path.moveTo(item.startPos[0], item.startPos[1]);
34055
33997
  path.lineTo(item.endPos[0], item.endPos[1]);
34056
33998
  ctx.stroke(path);
34057
33999
 
34058
34000
  // Middle white line that separates the bonds
34059
34001
  path = new Path2D();
34060
- ctx.lineWidth = 5 * styles$c.lineWidth;
34061
- ctx.strokeStyle = styles$c.bgColor;
34002
+ ctx.lineWidth = 5 * styles$d.lineWidth;
34003
+ ctx.strokeStyle = styles$d.bgColor;
34062
34004
  path.moveTo(item.startPos[0], item.startPos[1]);
34063
34005
  path.lineTo(item.endPos[0], item.endPos[1]);
34064
34006
  ctx.stroke(path);
@@ -34080,8 +34022,8 @@ function drawTripleLine(ctx, item) {
34080
34022
  */
34081
34023
  function drawLine(ctx, item) {
34082
34024
  const path = new Path2D();
34083
- ctx.lineWidth = styles$c.lineWidth;
34084
- ctx.strokeStyle = styles$c.fgColor;
34025
+ ctx.lineWidth = styles$d.lineWidth;
34026
+ ctx.strokeStyle = styles$d.fgColor;
34085
34027
  path.moveTo(item.startPos[0], item.startPos[1]);
34086
34028
  path.lineTo(item.endPos[0], item.endPos[1]);
34087
34029
  ctx.stroke(path);
@@ -34133,7 +34075,7 @@ function compareElements(item0, item1) {
34133
34075
  function draw(ctx, items) {
34134
34076
  items.sort(compareElements).forEach(drawItem(ctx));
34135
34077
  }
34136
- const styles$c = {
34078
+ const styles$d = {
34137
34079
  bgColor: "rgb(255, 255, 255)",
34138
34080
  fgColor: "rgb(0, 0, 0)",
34139
34081
  fontSizePx: 12,
@@ -36695,7 +36637,7 @@ class HighlightRenderer extends React.PureComponent {
36695
36637
  const rects = this.state.cachedHighlightRects;
36696
36638
  return /*#__PURE__*/React.createElement("div", null, rects.map((rect, index) => /*#__PURE__*/React.createElement("div", {
36697
36639
  key: index,
36698
- className: css(styles$b.highlightRect),
36640
+ className: css(styles$c.highlightRect),
36699
36641
  style: {
36700
36642
  // NOTE(mdr): We apply `position: absolute` here
36701
36643
  // rather than in Aphrodite styles, because
@@ -36714,7 +36656,7 @@ class HighlightRenderer extends React.PureComponent {
36714
36656
  })));
36715
36657
  }
36716
36658
  }
36717
- const styles$b = StyleSheet.create({
36659
+ const styles$c = StyleSheet.create({
36718
36660
  highlightRect: {
36719
36661
  background: "#fffabe" // highlighter yellow :)
36720
36662
  }
@@ -36795,7 +36737,7 @@ class HighlightTooltip extends React.PureComponent {
36795
36737
  // TooltipContent wouldn't let me overwrite
36796
36738
  // user-select and onClick
36797
36739
  const content = /*#__PURE__*/React.createElement("div", {
36798
- className: css(styles$a.tooltipLabel),
36740
+ className: css(styles$b.tooltipLabel),
36799
36741
  onClick: this.props.onClick
36800
36742
  }, this.props.label);
36801
36743
  const style = {
@@ -36815,7 +36757,7 @@ class HighlightTooltip extends React.PureComponent {
36815
36757
  }, /*#__PURE__*/React.createElement("div", null)));
36816
36758
  }
36817
36759
  }
36818
- const styles$a = StyleSheet.create({
36760
+ const styles$b = StyleSheet.create({
36819
36761
  tooltipLabel: {
36820
36762
  // Unlike most tooltip contents, we don't want this label to be
36821
36763
  // selectable. Selecting it is not only unhelpful, but dangerous: if
@@ -37367,7 +37309,7 @@ class HighlightableContent extends React.PureComponent {
37367
37309
  // starting point: https://phabricator.khanacademy.org/D35623?id=170698
37368
37310
  const buildHighlight = r => this._buildHighlight(r);
37369
37311
  return /*#__PURE__*/React.createElement("div", {
37370
- className: css(styles$9.container),
37312
+ className: css(styles$a.container),
37371
37313
  ref: container => this._container = container
37372
37314
  }, /*#__PURE__*/React.createElement("div", null, this.props.enabled && this._container && this._content && /*#__PURE__*/React.createElement(HighlightingUI, {
37373
37315
  buildHighlight: buildHighlight,
@@ -37388,14 +37330,14 @@ class HighlightableContent extends React.PureComponent {
37388
37330
  onAddHighlight: this._handleAddHighlight,
37389
37331
  onRemoveHighlight: this._handleRemoveHighlight
37390
37332
  })), /*#__PURE__*/React.createElement("div", {
37391
- className: css(styles$9.content),
37333
+ className: css(styles$a.content),
37392
37334
  ref: content => this._content = content
37393
37335
  }, /*#__PURE__*/React.createElement(WordIndexer, {
37394
37336
  onWordsUpdate: this._handleWordsUpdate
37395
37337
  }, this.props.children)));
37396
37338
  }
37397
37339
  }
37398
- const styles$9 = StyleSheet.create({
37340
+ const styles$a = StyleSheet.create({
37399
37341
  // We render content with z-index 1, and highlights with z-index 0, so that
37400
37342
  // content will receive the browser's native pointer events. (Highlights
37401
37343
  // have their own magic code to manage hover detection, despite being
@@ -37795,7 +37737,7 @@ class LineHeightMeasurer extends React.Component {
37795
37737
  }
37796
37738
  render() {
37797
37739
  return /*#__PURE__*/React.createElement("div", {
37798
- className: css(styles$8.measurer),
37740
+ className: css(styles$9.measurer),
37799
37741
  "aria-hidden": "true"
37800
37742
  }, /*#__PURE__*/React.createElement("div", {
37801
37743
  ref: ref => this._line = ref,
@@ -37803,7 +37745,7 @@ class LineHeightMeasurer extends React.Component {
37803
37745
  }, "Line Height Measurement"));
37804
37746
  }
37805
37747
  }
37806
- const styles$8 = StyleSheet.create({
37748
+ const styles$9 = StyleSheet.create({
37807
37749
  measurer: {
37808
37750
  position: "absolute",
37809
37751
  top: 0,
@@ -39093,6 +39035,52 @@ var Plotter$1 = {
39093
39035
  staticTransform: staticTransform
39094
39036
  };
39095
39037
 
39038
+ /**
39039
+ * This widget is for embedding Khan Academy Python programs.
39040
+ */
39041
+ function getUrlFromProgramID(programID) {
39042
+ const path = `/python-program/${programID}/embedded`;
39043
+ return toAbsoluteUrl(path);
39044
+ }
39045
+ /* This renders the program in an iframe. */
39046
+ class PythonProgram extends React.Component {
39047
+ render() {
39048
+ const url = getUrlFromProgramID(this.props.programID);
39049
+ const iframeStyle = {
39050
+ height: this.props.height,
39051
+ width: "100%"
39052
+ };
39053
+ const sandboxOptions = ["allow-popups", "allow-same-origin", "allow-scripts", "allow-top-navigation"].join(" ");
39054
+
39055
+ // We sandbox the iframe so that we allowlist only the functionality
39056
+ // that we need. This makes it a bit safer in case some content
39057
+ // creator "went wild".
39058
+ // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
39059
+ return /*#__PURE__*/React.createElement(View, {
39060
+ style: styles$8.container
39061
+ }, /*#__PURE__*/React.createElement("iframe", {
39062
+ sandbox: sandboxOptions,
39063
+ src: url,
39064
+ style: iframeStyle,
39065
+ allowFullScreen: true
39066
+ }));
39067
+ }
39068
+ }
39069
+ PythonProgram.defaultProps = {
39070
+ height: 400
39071
+ };
39072
+ const styles$8 = StyleSheet.create({
39073
+ container: {
39074
+ margin: "auto",
39075
+ width: "100%"
39076
+ }
39077
+ });
39078
+ var PythonProgram$1 = {
39079
+ name: "python-program",
39080
+ displayName: "Python Program",
39081
+ widget: PythonProgram
39082
+ };
39083
+
39096
39084
  class Separator extends React.Component {
39097
39085
  constructor(...args) {
39098
39086
  super(...args);
@@ -41528,7 +41516,7 @@ var Video$1 = {
41528
41516
  };
41529
41517
 
41530
41518
  /* eslint-disable import/no-named-as-default */
41531
- 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, LightsPuzzle$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, Plotter$1, ReactionDiagram, Sequence$1, Simulator$1, Sorter$1, Table$1, Unit, Video$1, DeprecatedStandin$1];
41519
+ 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, LightsPuzzle$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, Plotter$1, PythonProgram$1, ReactionDiagram, Sequence$1, Simulator$1, Sorter$1, Table$1, Unit, Video$1, DeprecatedStandin$1];
41532
41520
 
41533
41521
  /**
41534
41522
  * This should be called by all clients, specifying whether extra widgets are
@@ -41568,7 +41556,7 @@ const init = function init(options) {
41568
41556
 
41569
41557
  // This file is processed by a Rollup plugin (replace) to inject the production
41570
41558
  const libName = "@khanacademy/perseus";
41571
- const libVersion = "19.1.9";
41559
+ const libVersion = "19.2.1";
41572
41560
  addLibraryVersionToPerseusDebug(libName, libVersion);
41573
41561
 
41574
41562
  const apiVersion = {
@@ -43014,6 +43002,8 @@ const ItemExtras = [
43014
43002
 
43015
43003
  // prettier-ignore
43016
43004
 
43005
+ // prettier-ignore
43006
+
43017
43007
  //prettier-ignore
43018
43008
 
43019
43009
  // A background image applied to various widgets.